diff --git a/lib/nodes.js b/lib/nodes.js index e779e963..e1b8e67d 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -67,9 +67,7 @@ del(this.options, 'operation'); } top = this.top_sensitive() ? this.options.top : del(this.options, 'top'); - closure = this.is_statement() && !this.is_pure_statement() && !top && !this.options.returns && !(this instanceof CommentNode) && !this.contains(function(node) { - return node.is_pure_statement(); - }); + closure = this.is_statement() && !this.is_pure_statement() && !top && !this.options.returns && !(this instanceof CommentNode); return closure ? this.compile_closure(this.options) : this.compile_node(this.options); }; // Statements converted into expressions via closure-wrapping share a scope @@ -1346,11 +1344,11 @@ } set_result = rvar ? this.idt() + rvar + ' = []; ' : this.idt(); return_result = rvar || ''; - top_level && !this.contains(function(n) { - return n.is_pure_statement(); - }) && this.contains(function(n) { + if (top_level && body.contains(function(n) { return n instanceof CodeNode; - }) ? (body = ClosureNode.wrap(body, true)) : null; + })) { + body = ClosureNode.wrap(body, true); + } if (!(top_level)) { body = PushNode.wrap(rvar, body); } @@ -1542,8 +1540,15 @@ //### ClosureNode // A faux-node used to wrap an expressions body in a closure. ClosureNode = (exports.ClosureNode = { + // Wrap the expressions body, unless it contains a pure statement, + // in which case, no dice. wrap: function wrap(expressions, statement) { var call, func; + if (expressions.contains(function(n) { + return n.is_pure_statement(); + })) { + return expressions; + } func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions]))); call = new CallNode(new ValueNode(func, [new AccessorNode(literal('call'))]), [literal('this')]); return statement ? Expressions.wrap([call]) : call; diff --git a/src/nodes.coffee b/src/nodes.coffee index 493ec609..9da33555 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -54,8 +54,7 @@ exports.BaseNode: class BaseNode del @options, 'operation' unless this instanceof ValueNode top: if @top_sensitive() then @options.top else del @options, 'top' closure: @is_statement() and not @is_pure_statement() and not top and - not @options.returns and not (this instanceof CommentNode) and - not @contains (node) -> node.is_pure_statement() + not @options.returns and not (this instanceof CommentNode) if closure then @compile_closure(@options) else @compile_node(@options) # Statements converted into expressions via closure-wrapping share a scope @@ -1024,8 +1023,7 @@ exports.ForNode: class ForNode extends BaseNode for_part: "$ivar = 0, $lvar = ${svar}.length; $ivar < $lvar; $step_part" set_result: if rvar then @idt() + rvar + ' = []; ' else @idt() return_result: rvar or '' - if top_level and not @contains((n) -> n.is_pure_statement()) and @contains((n) -> n instanceof CodeNode) - body: ClosureNode.wrap(body, true) + body: ClosureNode.wrap(body, true) if top_level and body.contains (n) -> n instanceof CodeNode body: PushNode.wrap(rvar, body) unless top_level if o.returns return_result: 'return ' + return_result @@ -1172,7 +1170,10 @@ PushNode: exports.PushNode: { # A faux-node used to wrap an expressions body in a closure. ClosureNode: exports.ClosureNode: { + # Wrap the expressions body, unless it contains a pure statement, + # in which case, no dice. wrap: (expressions, statement) -> + return expressions if expressions.contains (n) -> n.is_pure_statement() func: new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions]))) call: new CallNode(new ValueNode(func, [new AccessorNode(literal('call'))]), [literal('this')]) if statement then Expressions.wrap([call]) else call diff --git a/test/test_break.coffee b/test/test_break.coffee index e4e5c4f0..303a7f72 100644 --- a/test/test_break.coffee +++ b/test/test_break.coffee @@ -1,21 +1,21 @@ # Test with break at the top level. -a: [1,2,3] +array: [1,2,3] call_with_lambda: (l) -> null -for i in a - a: call_with_lambda(->) +for i in array + result: call_with_lambda(->) if i == 2 puts "i = 2" else break -ok a is null +ok result is null # Test with break *not* at the top level. some_func: (input) -> takes_lambda: (l) -> null for i in [1,2] - arbitraty_var: takes_lambda(->) + result: takes_lambda(->) if input == 1 return 1 else