mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 11:31:20 -05:00
nodes: object literals are now parenthesized based on @tags.front (which indicates if the node leads an expression statement), fixing #542
This commit is contained in:
37
lib/nodes.js
37
lib/nodes.js
@@ -37,7 +37,6 @@
|
|||||||
return code;
|
return code;
|
||||||
};
|
};
|
||||||
Base.prototype.compileClosure = function(o) {
|
Base.prototype.compileClosure = function(o) {
|
||||||
this.tab = o.indent;
|
|
||||||
o.sharedScope = o.scope;
|
o.sharedScope = o.scope;
|
||||||
return Closure.wrap(this).compile(o);
|
return Closure.wrap(this).compile(o);
|
||||||
};
|
};
|
||||||
@@ -232,6 +231,7 @@
|
|||||||
Expressions.prototype.compileExpression = function(node, o) {
|
Expressions.prototype.compileExpression = function(node, o) {
|
||||||
var compiledNode;
|
var compiledNode;
|
||||||
this.tab = o.indent;
|
this.tab = o.indent;
|
||||||
|
node.tags.front = true;
|
||||||
compiledNode = node.compile(merge(o, {
|
compiledNode = node.compile(merge(o, {
|
||||||
top: true
|
top: true
|
||||||
}));
|
}));
|
||||||
@@ -364,8 +364,8 @@
|
|||||||
Value.prototype.isStatement = function(o) {
|
Value.prototype.isStatement = function(o) {
|
||||||
return this.base.isStatement(o) && !this.properties.length;
|
return this.base.isStatement(o) && !this.properties.length;
|
||||||
};
|
};
|
||||||
Value.prototype.isNumber = function() {
|
Value.prototype.isSimpleNumber = function() {
|
||||||
return this.base instanceof Literal && NUMBER.test(this.base.value);
|
return this.base instanceof Literal && SIMPLENUM.test(this.base.value);
|
||||||
};
|
};
|
||||||
Value.prototype.cacheReference = function(o) {
|
Value.prototype.cacheReference = function(o) {
|
||||||
var base, bref, name, nref;
|
var base, bref, name, nref;
|
||||||
@@ -389,6 +389,7 @@
|
|||||||
return [base.push(name), new Value(bref || base.base, [nref || name])];
|
return [base.push(name), new Value(bref || base.base, [nref || name])];
|
||||||
};
|
};
|
||||||
Value.prototype.compile = function(o) {
|
Value.prototype.compile = function(o) {
|
||||||
|
this.base.tags.front = this.tags.front;
|
||||||
return !o.top || this.properties.length ? Value.__super__.compile.call(this, o) : this.base.compile(o);
|
return !o.top || this.properties.length ? Value.__super__.compile.call(this, o) : this.base.compile(o);
|
||||||
};
|
};
|
||||||
Value.prototype.compileNode = function(o) {
|
Value.prototype.compileNode = function(o) {
|
||||||
@@ -401,7 +402,7 @@
|
|||||||
this.base.parenthetical = true;
|
this.base.parenthetical = true;
|
||||||
}
|
}
|
||||||
code = this.base.compile(o);
|
code = this.base.compile(o);
|
||||||
if (props[0] instanceof Accessor && this.isNumber() || o.top && this.base instanceof ObjectLiteral) {
|
if (props[0] instanceof Accessor && this.isSimpleNumber()) {
|
||||||
code = ("(" + code + ")");
|
code = ("(" + code + ")");
|
||||||
}
|
}
|
||||||
for (_i = 0, _len = props.length; _i < _len; _i++) {
|
for (_i = 0, _len = props.length; _i < _len; _i++) {
|
||||||
@@ -540,16 +541,17 @@
|
|||||||
return node;
|
return node;
|
||||||
};
|
};
|
||||||
Call.prototype.compileNode = function(o) {
|
Call.prototype.compileNode = function(o) {
|
||||||
var _i, _j, _len, _len2, _ref2, _ref3, _ref4, _result, arg, args, left, node, rite, val;
|
var _i, _j, _len, _len2, _ref2, _ref3, _ref4, _ref5, _result, arg, args, left, node, rite, val;
|
||||||
if (node = this.unfoldSoak(o)) {
|
if (node = this.unfoldSoak(o)) {
|
||||||
return node.compile(o);
|
return node.compile(o);
|
||||||
}
|
}
|
||||||
|
(((_ref2 = this.variable) != null) ? (_ref2.tags.front = this.tags.front) : undefined);
|
||||||
if (this.exist) {
|
if (this.exist) {
|
||||||
if (val = this.variable) {
|
if (val = this.variable) {
|
||||||
if (!(val instanceof Value)) {
|
if (!(val instanceof Value)) {
|
||||||
val = new Value(val);
|
val = new Value(val);
|
||||||
}
|
}
|
||||||
_ref2 = val.cacheReference(o), left = _ref2[0], rite = _ref2[1];
|
_ref3 = val.cacheReference(o), left = _ref3[0], rite = _ref3[1];
|
||||||
rite = new Call(rite, this.args);
|
rite = new Call(rite, this.args);
|
||||||
} else {
|
} else {
|
||||||
left = new Literal(this.superReference(o));
|
left = new Literal(this.superReference(o));
|
||||||
@@ -560,16 +562,16 @@
|
|||||||
rite = rite.compile(o);
|
rite = rite.compile(o);
|
||||||
return ("(" + left + " ? undefined : " + rite + ")");
|
return ("(" + left + " ? undefined : " + rite + ")");
|
||||||
}
|
}
|
||||||
for (_i = 0, _len = (_ref3 = this.args).length; _i < _len; _i++) {
|
for (_i = 0, _len = (_ref4 = this.args).length; _i < _len; _i++) {
|
||||||
arg = _ref3[_i];
|
arg = _ref4[_i];
|
||||||
if (arg instanceof Splat) {
|
if (arg instanceof Splat) {
|
||||||
return this.compileSplat(o);
|
return this.compileSplat(o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args = (function() {
|
args = (function() {
|
||||||
_result = [];
|
_result = [];
|
||||||
for (_j = 0, _len2 = (_ref4 = this.args).length; _j < _len2; _j++) {
|
for (_j = 0, _len2 = (_ref5 = this.args).length; _j < _len2; _j++) {
|
||||||
arg = _ref4[_j];
|
arg = _ref5[_j];
|
||||||
_result.push((arg.parenthetical = true) && arg.compile(o));
|
_result.push((arg.parenthetical = true) && arg.compile(o));
|
||||||
}
|
}
|
||||||
return _result;
|
return _result;
|
||||||
@@ -803,7 +805,6 @@
|
|||||||
})();
|
})();
|
||||||
__extends(ObjectLiteral, Base);
|
__extends(ObjectLiteral, Base);
|
||||||
ObjectLiteral.prototype.children = ['properties'];
|
ObjectLiteral.prototype.children = ['properties'];
|
||||||
ObjectLiteral.prototype.topSensitive = YES;
|
|
||||||
ObjectLiteral.prototype.compileNode = function(o) {
|
ObjectLiteral.prototype.compileNode = function(o) {
|
||||||
var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
|
var _i, _len, _ref2, _result, i, indent, join, lastNoncom, nonComments, obj, prop, props, top;
|
||||||
top = del(o, 'top');
|
top = del(o, 'top');
|
||||||
@@ -838,7 +839,7 @@
|
|||||||
}).call(this);
|
}).call(this);
|
||||||
props = props.join('');
|
props = props.join('');
|
||||||
obj = ("{" + (props ? '\n' + props + '\n' + this.idt() : '') + "}");
|
obj = ("{" + (props ? '\n' + props + '\n' + this.idt() : '') + "}");
|
||||||
return top ? ("(" + obj + ")") : obj;
|
return this.tags.front ? ("(" + obj + ")") : obj;
|
||||||
};
|
};
|
||||||
ObjectLiteral.prototype.assigns = function(name) {
|
ObjectLiteral.prototype.assigns = function(name) {
|
||||||
var _i, _len, _ref2, prop;
|
var _i, _len, _ref2, prop;
|
||||||
@@ -1207,9 +1208,8 @@
|
|||||||
if (this.bound) {
|
if (this.bound) {
|
||||||
return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")");
|
return ("" + (utility('bind')) + "(" + func + ", " + (this.context) + ")");
|
||||||
}
|
}
|
||||||
return top ? ("(" + func + ")") : func;
|
return this.tags.front ? ("(" + func + ")") : func;
|
||||||
};
|
};
|
||||||
Code.prototype.topSensitive = YES;
|
|
||||||
Code.prototype.traverseChildren = function(crossScope, func) {
|
Code.prototype.traverseChildren = function(crossScope, func) {
|
||||||
return crossScope ? Code.__super__.traverseChildren.call(this, crossScope, func) : undefined;
|
return crossScope ? Code.__super__.traverseChildren.call(this, crossScope, func) : undefined;
|
||||||
};
|
};
|
||||||
@@ -1371,9 +1371,7 @@
|
|||||||
exports.Op = (function() {
|
exports.Op = (function() {
|
||||||
Op = (function() {
|
Op = (function() {
|
||||||
function Op(op, first, second, flip) {
|
function Op(op, first, second, flip) {
|
||||||
if (first instanceof Value && first.base instanceof ObjectLiteral) {
|
if (op === 'new') {
|
||||||
first = new Parens(first);
|
|
||||||
} else if (op === 'new') {
|
|
||||||
if (first instanceof Call) {
|
if (first instanceof Call) {
|
||||||
return first.newInstance();
|
return first.newInstance();
|
||||||
}
|
}
|
||||||
@@ -1430,6 +1428,9 @@
|
|||||||
return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator);
|
return Op.__super__.toString.call(this, idt, this.constructor.name + ' ' + this.operator);
|
||||||
};
|
};
|
||||||
Op.prototype.compileNode = function(o) {
|
Op.prototype.compileNode = function(o) {
|
||||||
|
if (this.second) {
|
||||||
|
this.first.tags.front = this.tags.front;
|
||||||
|
}
|
||||||
if (this.isChainable() && this.first.unwrap() instanceof Op && this.first.unwrap().isChainable()) {
|
if (this.isChainable() && this.first.unwrap() instanceof Op && this.first.unwrap().isChainable()) {
|
||||||
return this.compileChain(o);
|
return this.compileChain(o);
|
||||||
}
|
}
|
||||||
@@ -1960,7 +1961,7 @@
|
|||||||
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
TRAILING_WHITESPACE = /[ \t]+$/gm;
|
||||||
IDENTIFIER = /^[$A-Za-z_][$\w]*$/;
|
IDENTIFIER = /^[$A-Za-z_][$\w]*$/;
|
||||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i;
|
||||||
SIMPLENUM = /^-?\d+$/;
|
SIMPLENUM = /^[+-]?\d+$/;
|
||||||
IS_STRING = /^['"]/;
|
IS_STRING = /^['"]/;
|
||||||
utility = function(name) {
|
utility = function(name) {
|
||||||
var ref;
|
var ref;
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ exports.Base = class Base
|
|||||||
# Statements converted into expressions via closure-wrapping share a scope
|
# Statements converted into expressions via closure-wrapping share a scope
|
||||||
# object with their parent closure, to preserve the expected lexical scope.
|
# object with their parent closure, to preserve the expected lexical scope.
|
||||||
compileClosure: (o) ->
|
compileClosure: (o) ->
|
||||||
@tab = o.indent
|
|
||||||
o.sharedScope = o.scope
|
o.sharedScope = o.scope
|
||||||
Closure.wrap(this).compile o
|
Closure.wrap(this).compile o
|
||||||
|
|
||||||
@@ -223,6 +222,7 @@ exports.Expressions = class Expressions extends Base
|
|||||||
# statement, ask the statement to do so.
|
# statement, ask the statement to do so.
|
||||||
compileExpression: (node, o) ->
|
compileExpression: (node, o) ->
|
||||||
@tab = o.indent
|
@tab = o.indent
|
||||||
|
node.tags.front = true
|
||||||
compiledNode = node.compile merge o, top: true
|
compiledNode = node.compile merge o, top: true
|
||||||
if node.isStatement(o) then compiledNode else "#{@idt()}#{compiledNode};"
|
if node.isStatement(o) then compiledNode else "#{@idt()}#{compiledNode};"
|
||||||
|
|
||||||
@@ -345,8 +345,8 @@ exports.Value = class Value extends Base
|
|||||||
isStatement: (o) ->
|
isStatement: (o) ->
|
||||||
@base.isStatement(o) and not @properties.length
|
@base.isStatement(o) and not @properties.length
|
||||||
|
|
||||||
isNumber: ->
|
isSimpleNumber: ->
|
||||||
@base instanceof Literal and NUMBER.test @base.value
|
@base instanceof Literal and SIMPLENUM.test @base.value
|
||||||
|
|
||||||
# A reference has base part (`this` value) and name part.
|
# A reference has base part (`this` value) and name part.
|
||||||
# We cache them separately for compiling complex expressions.
|
# We cache them separately for compiling complex expressions.
|
||||||
@@ -369,6 +369,7 @@ exports.Value = class Value extends Base
|
|||||||
|
|
||||||
# Override compile to unwrap the value when possible.
|
# Override compile to unwrap the value when possible.
|
||||||
compile: (o) ->
|
compile: (o) ->
|
||||||
|
@base.tags.front = @tags.front
|
||||||
if not o.top or @properties.length then super(o) else @base.compile(o)
|
if not o.top or @properties.length then super(o) else @base.compile(o)
|
||||||
|
|
||||||
# We compile a value to JavaScript by compiling and joining each property.
|
# We compile a value to JavaScript by compiling and joining each property.
|
||||||
@@ -380,9 +381,7 @@ exports.Value = class Value extends Base
|
|||||||
props = @properties
|
props = @properties
|
||||||
@base.parenthetical = yes if @parenthetical and not props.length
|
@base.parenthetical = yes if @parenthetical and not props.length
|
||||||
code = @base.compile o
|
code = @base.compile o
|
||||||
if props[0] instanceof Accessor and @isNumber() or
|
code = "(#{code})" if props[0] instanceof Accessor and @isSimpleNumber()
|
||||||
o.top and @base instanceof ObjectLiteral
|
|
||||||
code = "(#{code})"
|
|
||||||
(code += prop.compile o) for prop in props
|
(code += prop.compile o) for prop in props
|
||||||
return code
|
return code
|
||||||
|
|
||||||
@@ -493,6 +492,7 @@ exports.Call = class Call extends Base
|
|||||||
# Compile a vanilla function call.
|
# Compile a vanilla function call.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
return node.compile o if node = @unfoldSoak o
|
return node.compile o if node = @unfoldSoak o
|
||||||
|
@variable?.tags.front = @tags.front
|
||||||
if @exist
|
if @exist
|
||||||
if val = @variable
|
if val = @variable
|
||||||
val = new Value val unless val instanceof Value
|
val = new Value val unless val instanceof Value
|
||||||
@@ -701,8 +701,6 @@ exports.ObjectLiteral = class ObjectLiteral extends Base
|
|||||||
|
|
||||||
children: ['properties']
|
children: ['properties']
|
||||||
|
|
||||||
topSensitive: YES
|
|
||||||
|
|
||||||
constructor: (props) ->
|
constructor: (props) ->
|
||||||
super()
|
super()
|
||||||
@objects = @properties = props or []
|
@objects = @properties = props or []
|
||||||
@@ -727,7 +725,7 @@ exports.ObjectLiteral = class ObjectLiteral extends Base
|
|||||||
indent + prop.compile(o) + join
|
indent + prop.compile(o) + join
|
||||||
props = props.join('')
|
props = props.join('')
|
||||||
obj = "{#{ if props then '\n' + props + '\n' + @idt() else '' }}"
|
obj = "{#{ if props then '\n' + props + '\n' + @idt() else '' }}"
|
||||||
if top then "(#{obj})" else obj
|
if @tags.front then "(#{obj})" else obj
|
||||||
|
|
||||||
assigns: (name) ->
|
assigns: (name) ->
|
||||||
for prop in @properties when prop.assigns name then return yes
|
for prop in @properties when prop.assigns name then return yes
|
||||||
@@ -1024,9 +1022,7 @@ exports.Code = class Code extends Base
|
|||||||
func = "#{open}#{ params.join(', ') }) {#{code}#{close}"
|
func = "#{open}#{ params.join(', ') }) {#{code}#{close}"
|
||||||
o.scope.endLevel()
|
o.scope.endLevel()
|
||||||
return "#{utility 'bind'}(#{func}, #{@context})" if @bound
|
return "#{utility 'bind'}(#{func}, #{@context})" if @bound
|
||||||
if top then "(#{func})" else func
|
if @tags.front then "(#{func})" else func
|
||||||
|
|
||||||
topSensitive: YES
|
|
||||||
|
|
||||||
# Short-circuit traverseChildren method to prevent it from crossing scope boundaries
|
# Short-circuit traverseChildren method to prevent it from crossing scope boundaries
|
||||||
# unless crossScope is true
|
# unless crossScope is true
|
||||||
@@ -1194,9 +1190,7 @@ exports.Op = class Op extends Base
|
|||||||
children: ['first', 'second']
|
children: ['first', 'second']
|
||||||
|
|
||||||
constructor: (op, first, second, flip) ->
|
constructor: (op, first, second, flip) ->
|
||||||
if first instanceof Value and first.base instanceof ObjectLiteral
|
if op is 'new'
|
||||||
first = new Parens first
|
|
||||||
else if op is 'new'
|
|
||||||
return first.newInstance() if first instanceof Call
|
return first.newInstance() if first instanceof Call
|
||||||
first = new Parens first if first instanceof Code and first.bound
|
first = new Parens first if first instanceof Code and first.bound
|
||||||
super()
|
super()
|
||||||
@@ -1229,6 +1223,7 @@ exports.Op = class Op extends Base
|
|||||||
super(idt, @constructor.name + ' ' + @operator)
|
super(idt, @constructor.name + ' ' + @operator)
|
||||||
|
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
|
@first.tags.front = @tags.front if @second
|
||||||
return @compileChain(o) if @isChainable() and @first.unwrap() instanceof Op and @first.unwrap().isChainable()
|
return @compileChain(o) if @isChainable() and @first.unwrap() instanceof Op and @first.unwrap().isChainable()
|
||||||
return @compileAssignment(o) if include @ASSIGNMENT, @operator
|
return @compileAssignment(o) if include @ASSIGNMENT, @operator
|
||||||
return @compileUnary(o) if @isUnary()
|
return @compileUnary(o) if @isUnary()
|
||||||
@@ -1688,7 +1683,7 @@ TRAILING_WHITESPACE = /[ \t]+$/gm
|
|||||||
|
|
||||||
IDENTIFIER = /^[$A-Za-z_][$\w]*$/
|
IDENTIFIER = /^[$A-Za-z_][$\w]*$/
|
||||||
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i
|
NUMBER = /^0x[\da-f]+|^(?:\d+(\.\d+)?|\.\d+)(?:e[+-]?\d+)?$/i
|
||||||
SIMPLENUM = /^-?\d+$/
|
SIMPLENUM = /^[+-]?\d+$/
|
||||||
|
|
||||||
# Is a literal value a string?
|
# Is a literal value a string?
|
||||||
IS_STRING = /^['"]/
|
IS_STRING = /^['"]/
|
||||||
|
|||||||
@@ -236,3 +236,7 @@ result = obj.object()
|
|||||||
eq result.one, 1
|
eq result.one, 1
|
||||||
eq result.two, 2
|
eq result.two, 2
|
||||||
eq result.two, obj.list()[1]
|
eq result.two, obj.list()[1]
|
||||||
|
|
||||||
|
|
||||||
|
#542: Objects leading expression statement should be parenthesized.
|
||||||
|
{f: -> ok yes }.f() + 1
|
||||||
|
|||||||
Reference in New Issue
Block a user