Fixing compound assignment as a right-hand sub expression of a larger operation. Invalid in JS, valid in Coffee.

This commit is contained in:
Jeremy Ashkenas
2010-08-14 14:43:25 -04:00
parent ca18f1fad6
commit c71f2794eb
6 changed files with 32 additions and 9 deletions

View File

@@ -571,9 +571,9 @@
return new OpNode($2, $1, $3); return new OpNode($2, $1, $3);
}), o("Expression LOGIC Expression", function() { }), o("Expression LOGIC Expression", function() {
return new OpNode($2, $1, $3); return new OpNode($2, $1, $3);
}), o("Expression COMPOUND_ASSIGN Expression", function() { }), o("Value COMPOUND_ASSIGN Expression", function() {
return new OpNode($2, $1, $3); return new OpNode($2, $1, $3);
}), o("Expression COMPOUND_ASSIGN INDENT Expression OUTDENT", function() { }), o("Value COMPOUND_ASSIGN INDENT Expression OUTDENT", function() {
return new OpNode($2, $1, $4); return new OpNode($2, $1, $4);
}), o("Expression INSTANCEOF Expression", function() { }), o("Expression INSTANCEOF Expression", function() {
return new OpNode('instanceof', $1, $3); return new OpNode('instanceof', $1, $3);

View File

@@ -640,7 +640,7 @@
vars = this.compileVariables(merge(o, { vars = this.compileVariables(merge(o, {
indent: idt indent: idt
})); }));
if (this.fromNum && this.toNum && Math.abs(+this.fromNum - +this.toNum) <= 20) { if (this.fromNum && this.toNum && (Math.abs(+this.fromNum - +this.toNum) <= 20)) {
range = (function() { range = (function() {
_c = []; _c = [];
for (var _b = +this.fromNum; +this.fromNum <= +this.toNum ? _b <= +this.toNum : _b >= +this.toNum; +this.fromNum <= +this.toNum ? _b += 1 : _b -= 1){ _c.push(_b); } for (var _b = +this.fromNum; +this.fromNum <= +this.toNum ? _b <= +this.toNum : _b >= +this.toNum; +this.fromNum <= +this.toNum ? _b += 1 : _b -= 1){ _c.push(_b); }
@@ -1243,8 +1243,12 @@
OpNode.prototype.isUnary = function() { OpNode.prototype.isUnary = function() {
return !this.second; return !this.second;
}; };
OpNode.prototype.isMutator = function() {
var _b;
return ends(this.operator, '=') && !('===' === (_b = this.operator) || '!==' === _b);
};
OpNode.prototype.isChainable = function() { OpNode.prototype.isChainable = function() {
return indexOf(this.CHAINABLE, this.operator) >= 0; return include(this.CHAINABLE, this.operator);
}; };
OpNode.prototype.toString = function(idt) { OpNode.prototype.toString = function(idt) {
return OpNode.__superClass__.toString.call(this, idt, this["class"] + ' ' + this.operator); return OpNode.__superClass__.toString.call(this, idt, this["class"] + ' ' + this.operator);
@@ -1263,6 +1267,12 @@
if (this.operator === '?') { if (this.operator === '?') {
return this.compileExistence(o); return this.compileExistence(o);
} }
if (this.first instanceof OpNode && this.first.isMutator()) {
this.first = new ParentheticalNode(this.first);
}
if (this.second instanceof OpNode && this.second.isMutator()) {
this.second = new ParentheticalNode(this.second);
}
return [this.first.compile(o), this.operator, this.second.compile(o)].join(' '); return [this.first.compile(o), this.operator, this.second.compile(o)].join(' ');
}; };
OpNode.prototype.compileChain = function(o) { OpNode.prototype.compileChain = function(o) {

File diff suppressed because one or more lines are too long

View File

@@ -538,8 +538,8 @@ grammar =
o "Expression SHIFT Expression", -> new OpNode $2, $1, $3 o "Expression SHIFT Expression", -> new OpNode $2, $1, $3
o "Expression COMPARE Expression", -> new OpNode $2, $1, $3 o "Expression COMPARE Expression", -> new OpNode $2, $1, $3
o "Expression LOGIC Expression", -> new OpNode $2, $1, $3 o "Expression LOGIC Expression", -> new OpNode $2, $1, $3
o "Expression COMPOUND_ASSIGN Expression", -> new OpNode $2, $1, $3 o "Value COMPOUND_ASSIGN Expression", -> new OpNode $2, $1, $3
o "Expression COMPOUND_ASSIGN INDENT Expression OUTDENT", -> new OpNode $2, $1, $4 o "Value COMPOUND_ASSIGN INDENT Expression OUTDENT", -> new OpNode $2, $1, $4
o "Expression INSTANCEOF Expression", -> new OpNode 'instanceof', $1, $3 o "Expression INSTANCEOF Expression", -> new OpNode 'instanceof', $1, $3
o "Expression IN Expression", -> new InNode $1, $3 o "Expression IN Expression", -> new InNode $1, $3

View File

@@ -1076,8 +1076,11 @@ exports.OpNode = class OpNode extends BaseNode
isUnary: -> isUnary: ->
not @second not @second
isMutator: ->
ends(@operator, '=') and @operator not in ['===', '!==']
isChainable: -> isChainable: ->
indexOf(@CHAINABLE, @operator) >= 0 include(@CHAINABLE, @operator)
toString: (idt) -> toString: (idt) ->
super(idt, @class + ' ' + @operator) super(idt, @class + ' ' + @operator)
@@ -1088,6 +1091,8 @@ exports.OpNode = class OpNode extends BaseNode
return @compileAssignment(o) if indexOf(@ASSIGNMENT, @operator) >= 0 return @compileAssignment(o) if indexOf(@ASSIGNMENT, @operator) >= 0
return @compileUnary(o) if @isUnary() return @compileUnary(o) if @isUnary()
return @compileExistence(o) if @operator is '?' return @compileExistence(o) if @operator is '?'
@first = new ParentheticalNode(@first) if @first instanceof OpNode and @first.isMutator()
@second = new ParentheticalNode(@second) if @second instanceof OpNode and @second.isMutator()
[@first.compile(o), @operator, @second.compile(o)].join ' ' [@first.compile(o), @operator, @second.compile(o)].join ' '
# Mimic Python's chained comparisons when multiple comparison operators are # Mimic Python's chained comparisons when multiple comparison operators are

View File

@@ -129,4 +129,12 @@ obj and=
two: 2 two: 2
ok not obj.one ok not obj.one
ok obj.two is 2 ok obj.two is 2
# Compound assignment as a sub expression.
[a, b, c] = [1, 2, 3]
ok (a + b += c) is 6
ok a is 1
ok b is 5
ok c is 3