made In node invertible

This commit is contained in:
satyr
2010-10-21 09:16:17 +09:00
parent 53fbfc7d15
commit 31746ce692
7 changed files with 111 additions and 87 deletions

View File

@@ -547,46 +547,46 @@
})
],
Operation: [
o("UNARY Expression", function() {
o('UNARY Expression', function() {
return new Op($1, $2);
}), o("- Expression", function() {
}), o('- Expression', function() {
return new Op('-', $2);
}, {
prec: 'UNARY'
}), o("+ Expression", function() {
}), o('+ Expression', function() {
return new Op('+', $2);
}, {
prec: 'UNARY'
}), o("-- SimpleAssignable", function() {
}), o('-- SimpleAssignable', function() {
return new Op('--', $2);
}), o("++ SimpleAssignable", function() {
}), o('++ SimpleAssignable', function() {
return new Op('++', $2);
}), o("SimpleAssignable --", function() {
}), o('SimpleAssignable --', function() {
return new Op('--', $1, null, true);
}), o("SimpleAssignable ++", function() {
}), o('SimpleAssignable ++', function() {
return new Op('++', $1, null, true);
}), o("Expression + Expression", function() {
}), o('Expression + Expression', function() {
return new Op('+', $1, $3);
}), o("Expression - Expression", function() {
}), o('Expression - Expression', function() {
return new Op('-', $1, $3);
}), o("Expression == Expression", function() {
}), o('Expression == Expression', function() {
return new Op('==', $1, $3);
}), o("Expression != Expression", function() {
}), o('Expression != Expression', function() {
return new Op('!=', $1, $3);
}), o("Expression MATH Expression", function() {
}), o('Expression MATH Expression', function() {
return new Op($2, $1, $3);
}), o("Expression SHIFT Expression", function() {
}), o('Expression SHIFT Expression', function() {
return new Op($2, $1, $3);
}), o("Expression COMPARE Expression", function() {
}), o('Expression COMPARE Expression', function() {
return new Op($2, $1, $3);
}), o("Expression LOGIC Expression", function() {
}), o('Expression LOGIC Expression', function() {
return new Op($2, $1, $3);
}), o("SimpleAssignable COMPOUND_ASSIGN Expression", function() {
}), o('Expression RELATION Expression', function() {
return $2.charAt(0) === '!' ? new Op($2.slice(1), $1, $3).invert() : new Op($2, $1, $3);
}), o('SimpleAssignable COMPOUND_ASSIGN Expression', function() {
return new Assign($1, $3, $2);
}), o("SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT", function() {
}), o('SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT', function() {
return new Assign($1, $4, $2);
}), o("Expression RELATION Expression", function() {
return $2.charAt(0) === '!' ? $2 === '!in' ? new Op('!', new In($1, $3)) : new Op('!', new Parens(new Op($2.slice(1), $1, $3))) : $2 === 'in' ? new In($1, $3) : new Op($2, $1, $3);
})
]
};

View File

@@ -48,7 +48,7 @@
}
forcedIdentifier = colon || this.tagAccessor();
tag = 'IDENTIFIER';
if ((__indexOf.call(JS_KEYWORDS, id) >= 0) || !forcedIdentifier && (__indexOf.call(COFFEE_KEYWORDS, id) >= 0)) {
if (__indexOf.call(JS_KEYWORDS, id) >= 0 || !forcedIdentifier && __indexOf.call(COFFEE_KEYWORDS, id) >= 0) {
tag = id.toUpperCase();
if (tag === 'WHEN' && (_ref2 = this.tag(), __indexOf.call(LINE_BREAK, _ref2) >= 0)) {
tag = 'LEADING_WHEN';

View File

@@ -1019,6 +1019,10 @@
};
Assign.prototype.compilePatternMatch = function(o) {
var _len, _ref2, _ref3, accessClass, assigns, code, i, idx, isObject, obj, objects, olength, otop, ref, splat, top, val, valVar, value;
top = del(o, 'top');
otop = merge(o, {
top: true
});
if ((value = this.value).isStatement(o)) {
value = Closure.wrap(value);
}
@@ -1027,7 +1031,7 @@
return value.compile(o);
}
isObject = this.variable.isObject();
if (o.top && olength === 1 && !((obj = objects[0]) instanceof Splat)) {
if (top && olength === 1 && !((obj = objects[0]) instanceof Splat)) {
if (obj instanceof Assign) {
_ref2 = obj, idx = _ref2.variable.base, obj = _ref2.value;
} else {
@@ -1035,12 +1039,8 @@
}
accessClass = IDENTIFIER.test(idx.value) ? Accessor : Index;
(value = Value.wrap(value)).properties.push(new accessClass(idx));
return new Assign(obj, value).compile(o);
return new Assign(obj, value).compile(otop);
}
top = del(o, 'top');
otop = merge(o, {
top: true
});
valVar = value.compile(o);
assigns = [];
splat = false;
@@ -1345,6 +1345,9 @@
exports.Op = (function() {
Op = (function() {
function Op(op, first, second, flip) {
if (op === 'in') {
return new In(first, second);
}
if (op === 'new') {
if (first instanceof Call) {
return first.newInstance();
@@ -1452,25 +1455,29 @@
})();
__extends(In, Base);
In.prototype.children = ['object', 'array'];
In.prototype.invert = function() {
this.negated = !this.negated;
return this;
};
In.prototype.compileNode = function(o) {
var code;
code = this.array instanceof Value && this.array.isArray() ? this.compileOrTest(o) : this.compileLoopTest(o);
return this.parenthetical ? code : "(" + code + ")";
return this.array instanceof Value && this.array.isArray() ? this.compileOrTest(o) : this.compileLoopTest(o);
};
In.prototype.compileOrTest = function(o) {
var _len, _ref2, _ref3, _result, i, item, ref, sub, tests;
var _len, _ref2, _ref3, _ref4, _result, cmp, cnj, i, item, ref, sub, tests;
_ref2 = this.object.compileReference(o, {
precompile: true
}), sub = _ref2[0], ref = _ref2[1];
_ref3 = this.negated ? [' !== ', ' && '] : [' === ', ' || '], cmp = _ref3[0], cnj = _ref3[1];
tests = (function() {
_result = [];
for (i = 0, _len = (_ref3 = this.array.base.objects).length; i < _len; i++) {
item = _ref3[i];
_result.push("" + (i ? ref : sub) + " === " + (item.compile(o)));
for (i = 0, _len = (_ref4 = this.array.base.objects).length; i < _len; i++) {
item = _ref4[i];
_result.push((i ? ref : sub) + cmp + item.compile(o));
}
return _result;
}).call(this);
return tests.join(' || ');
tests = tests.join(cnj);
return this.parenthetical ? tests : "(" + tests + ")";
};
In.prototype.compileLoopTest = function(o) {
var _ref2, code, ref, sub;
@@ -1479,8 +1486,16 @@
}), {
precompile: true
}), sub = _ref2[0], ref = _ref2[1];
code = utility('indexOf') + (".call(" + (this.array.compile(o)) + ", " + ref + ") >= 0");
return sub === ref ? code : sub + ', ' + code;
code = utility('indexOf') + (".call(" + (this.array.compile(o)) + ", " + ref + ") ");
code += this.negated ? '< 0' : '>= 0';
if (sub === ref) {
return code;
}
code = sub + ', ' + code;
return this.parenthetical ? code : "(" + code + ")";
};
In.prototype.toString = function(idt) {
return In.__super__.toString.call(this, idt, this.constructor.name + (this.negated ? '!' : ''));
};
return In;
})();

File diff suppressed because one or more lines are too long

View File

@@ -71,7 +71,7 @@
} else {
tokens.splice(i, 0, after);
}
} else if (prev && !((_ref = prev[0]) === 'TERMINATOR' || _ref === 'INDENT' || _ref === 'OUTDENT')) {
} else if (prev && ((_ref = prev[0]) !== 'TERMINATOR' && _ref !== 'INDENT' && _ref !== 'OUTDENT')) {
if (((post != null) ? post[0] : undefined) === 'TERMINATOR' && ((after != null) ? after[0] : undefined) === 'OUTDENT') {
tokens.splice.apply(tokens, [i + 2, 0].concat(tokens.splice(i, 2)));
if (tokens[i + 2][0] !== 'TERMINATOR') {
@@ -147,7 +147,7 @@
}
_ref = this.tokens.slice(i + 1, i + 4), one = _ref[0], two = _ref[1], three = _ref[2];
tag = token[0];
return (tag === 'TERMINATOR' || tag === 'OUTDENT') && !(((two != null) ? two[0] : undefined) === ':' || ((one != null) ? one[0] : undefined) === '@' && ((three != null) ? three[0] : undefined) === ':') || tag === ',' && !((_ref2 = (one != null) ? one[0] : undefined) === 'IDENTIFIER' || _ref2 === 'NUMBER' || _ref2 === 'STRING' || _ref2 === '@' || _ref2 === 'TERMINATOR' || _ref2 === 'OUTDENT');
return (tag === 'TERMINATOR' || tag === 'OUTDENT') && !(((two != null) ? two[0] : undefined) === ':' || ((one != null) ? one[0] : undefined) === '@' && ((three != null) ? three[0] : undefined) === ':') || tag === ',' && ((_ref2 = (one != null) ? one[0] : undefined) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT');
};
action = function(token, i) {
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
@@ -201,7 +201,7 @@
if (prev && !prev.spaced && tag === '?') {
token.call = true;
}
if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && ((__indexOf.call(IMPLICIT_CALL, tag) >= 0) || !token.spaced && (__indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0)))) {
if (!(callObject || ((prev != null) ? prev.spaced : undefined) && (prev.call || (_ref2 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref2) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !token.spaced && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
return 1;
}
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
@@ -217,7 +217,7 @@
if (tag === 'PROPERTY_ACCESS' && this.tag(i - 1) === 'OUTDENT') {
return true;
}
return !token.generated && this.tag(i - 1) !== ',' && (__indexOf.call(IMPLICIT_END, tag) >= 0) && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && !(_ref3 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref3) >= 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
return !token.generated && this.tag(i - 1) !== ',' && __indexOf.call(IMPLICIT_END, tag) >= 0 && (tag !== 'INDENT' || (this.tag(i - 2) !== 'CLASS' && (_ref3 = this.tag(i - 1), __indexOf.call(IMPLICIT_BLOCK, _ref3) < 0) && !((post = this.tokens[i + 1]) && post.generated && post[0] === '{')));
}, action);
if (prev[0] === '?') {
prev[0] = 'FUNC_EXIST';
@@ -237,7 +237,7 @@
tokens.splice.apply(tokens, [i + 2, 0].concat(this.indentation(token)));
return 4;
}
if ((__indexOf.call(SINGLE_LINERS, tag) >= 0) && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
if (__indexOf.call(SINGLE_LINERS, tag) >= 0 && this.tag(i + 1) !== 'INDENT' && !(tag === 'ELSE' && this.tag(i + 1) === 'IF')) {
starter = tag;
_ref2 = this.indentation(token), indent = _ref2[0], outdent = _ref2[1];
if (starter === 'THEN') {
@@ -247,7 +247,7 @@
tokens.splice(i + 1, 0, indent);
condition = function(token, i) {
var _ref3;
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && !(starter === 'IF' || starter === 'THEN'));
return token[1] !== ';' && (_ref3 = token[0], __indexOf.call(SINGLE_CLOSERS, _ref3) >= 0) && !(token[0] === 'ELSE' && (starter !== 'IF' && starter !== 'THEN'));
};
action = function(token, i) {
return this.tokens.splice(this.tag(i - 1) === ',' ? i - 1 : i, 0, outdent);
@@ -269,7 +269,7 @@
};
return this.scanTokens(function(token, i) {
var _ref, original;
if (!((_ref = token[0]) === 'IF' || _ref === 'UNLESS')) {
if ((_ref = token[0]) !== 'IF' && _ref !== 'UNLESS') {
return 1;
}
original = token;
@@ -330,7 +330,7 @@
stack.push(token);
return 1;
}
if (!(__indexOf.call(EXPRESSION_END, tag) >= 0)) {
if (__indexOf.call(EXPRESSION_END, tag) < 0) {
return 1;
}
if (debt[inv = INVERSES[tag]] > 0) {

View File

@@ -525,37 +525,34 @@ grammar =
# -type rule, but in order to make the precedence binding possible, separate
# rules are necessary.
Operation: [
o "UNARY Expression", -> new Op $1, $2
o "- Expression", (-> new Op '-', $2), prec: 'UNARY'
o "+ Expression", (-> new Op '+', $2), prec: 'UNARY'
o 'UNARY Expression', -> new Op $1 , $2
o '- Expression', (-> new Op '-', $2), prec: 'UNARY'
o '+ Expression', (-> new Op '+', $2), prec: 'UNARY'
o "-- SimpleAssignable", -> new Op '--', $2
o "++ SimpleAssignable", -> new Op '++', $2
o "SimpleAssignable --", -> new Op '--', $1, null, true
o "SimpleAssignable ++", -> new Op '++', $1, null, true
o '-- SimpleAssignable', -> new Op '--', $2
o '++ SimpleAssignable', -> new Op '++', $2
o 'SimpleAssignable --', -> new Op '--', $1, null, true
o 'SimpleAssignable ++', -> new Op '++', $1, null, true
o "Expression + Expression", -> new Op '+', $1, $3
o "Expression - Expression", -> new Op '-', $1, $3
o "Expression == Expression", -> new Op '==', $1, $3
o "Expression != Expression", -> new Op '!=', $1, $3
o 'Expression + Expression', -> new Op '+' , $1, $3
o 'Expression - Expression', -> new Op '-' , $1, $3
o 'Expression == Expression', -> new Op '==', $1, $3
o 'Expression != Expression', -> new Op '!=', $1, $3
o "Expression MATH Expression", -> new Op $2, $1, $3
o "Expression SHIFT Expression", -> new Op $2, $1, $3
o "Expression COMPARE Expression", -> new Op $2, $1, $3
o "Expression LOGIC Expression", -> new Op $2, $1, $3
o "SimpleAssignable COMPOUND_ASSIGN Expression",
-> new Assign $1, $3, $2
o "SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT",
-> new Assign $1, $4, $2
o "Expression RELATION Expression", ->
o 'Expression MATH Expression', -> new Op $2, $1, $3
o 'Expression SHIFT Expression', -> new Op $2, $1, $3
o 'Expression COMPARE Expression', -> new Op $2, $1, $3
o 'Expression LOGIC Expression', -> new Op $2, $1, $3
o 'Expression RELATION Expression', ->
if $2.charAt(0) is '!'
if $2 is '!in'
new Op '!', new In $1, $3
else
new Op '!', new Parens new Op $2.slice(1), $1, $3
new Op($2.slice(1), $1, $3).invert()
else
if $2 is 'in' then new In $1, $3 else new Op $2, $1, $3
new Op $2, $1, $3
o 'SimpleAssignable COMPOUND_ASSIGN Expression',
-> new Assign $1, $3, $2
o 'SimpleAssignable COMPOUND_ASSIGN INDENT Expression OUTDENT',
-> new Assign $1, $4, $2
]

View File

@@ -881,11 +881,13 @@ exports.Assign = class Assign extends Base
# See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring)
# for details.
compilePatternMatch: (o) ->
top = del o, 'top'
otop = merge o, top: yes
if (value = @value).isStatement o then value = Closure.wrap value
{objects} = @variable.base
return value.compile o unless olength = objects.length
isObject = @variable.isObject()
if o.top and olength is 1 and (obj = objects[0]) not instanceof Splat
if top and olength is 1 and (obj = objects[0]) not instanceof Splat
# Unroll simplest cases: `{v} = x` -> `v = x.v`
if obj instanceof Assign
{variable: {base: idx}, value: obj} = obj
@@ -895,9 +897,7 @@ exports.Assign = class Assign extends Base
else new Literal 0
accessClass = if IDENTIFIER.test idx.value then Accessor else Index
(value = Value.wrap value).properties.push new accessClass idx
return new Assign(obj, value).compile o
top = del o, 'top'
otop = merge o, top: yes
return new Assign(obj, value).compile otop
valVar = value.compile o
assigns = []
splat = false
@@ -1180,6 +1180,7 @@ exports.Op = class Op extends Base
children: ['first', 'second']
constructor: (op, first, second, flip) ->
return new In first, second if op is 'in'
if op is 'new'
return first.newInstance() if first instanceof Call
first = new Parens first if first instanceof Code and first.bound
@@ -1252,23 +1253,34 @@ exports.In = class In extends Base
constructor: (@object, @array) ->
super()
invert: ->
@negated = not @negated
this
compileNode: (o) ->
code = if @array instanceof Value and @array.isArray()
if @array instanceof Value and @array.isArray()
@compileOrTest o
else
@compileLoopTest o
if @parenthetical then code else "(#{code})"
compileOrTest: (o) ->
[sub, ref] = @object.compileReference o, precompile: yes
[cmp, cnj] = if @negated then [' !== ', ' && '] else [' === ', ' || ']
tests = for item, i in @array.base.objects
"#{ if i then ref else sub } === #{ item.compile o }"
tests.join ' || '
(if i then ref else sub) + cmp + item.compile o
tests = tests.join cnj
if @parenthetical then tests else "(#{tests})"
compileLoopTest: (o) ->
[sub, ref] = @object.compileReference merge(o, top: yes), precompile: yes
code = utility('indexOf') + ".call(#{ @array.compile o }, #{ref}) >= 0"
if sub is ref then code else sub + ', ' + code
code = utility('indexOf') + ".call(#{ @array.compile o }, #{ref}) "
code += (if @negated then '< 0' else '>= 0')
return code if sub is ref
code = sub + ', ' + code
if @parenthetical then code else "(#{code})"
toString: (idt) ->
super idt, @constructor.name + if @negated then '!' else ''
#### Try