Comprehensions over break and continue

This commit is contained in:
Jeremy Ashkenas 2010-12-23 08:50:34 -08:00
parent 34b16699fa
commit b56b08387d
4 changed files with 47 additions and 14 deletions

View File

@ -210,7 +210,7 @@
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
exp = _ref[_i]; exp = _ref[_i];
if (exp.jumps(o)) { if (exp.jumps(o)) {
return true; return exp;
} }
} }
}; };
@ -338,7 +338,11 @@
if ((_ref = this.value) !== 'break' && _ref !== 'continue' && _ref !== 'debugger') { if ((_ref = this.value) !== 'break' && _ref !== 'continue' && _ref !== 'debugger') {
return false; return false;
} }
return !(o && (o.loop || o.block && (this.value !== 'continue'))); if (!(o && (o.loop || o.block && (this.value !== 'continue')))) {
return this;
} else {
return false;
}
}; };
Literal.prototype.compile = function() { Literal.prototype.compile = function() {
if (this.value.reserved) { if (this.value.reserved) {
@ -360,7 +364,7 @@
Return.prototype.children = ['expression']; Return.prototype.children = ['expression'];
Return.prototype.isStatement = YES; Return.prototype.isStatement = YES;
Return.prototype.makeReturn = THIS; Return.prototype.makeReturn = THIS;
Return.prototype.jumps = YES; Return.prototype.jumps = THIS;
Return.prototype.compile = function(o, level) { Return.prototype.compile = function(o, level) {
var expr, _ref; var expr, _ref;
expr = (_ref = this.expression) != null ? _ref.makeReturn() : void 0; expr = (_ref = this.expression) != null ? _ref.makeReturn() : void 0;
@ -1445,7 +1449,7 @@
if (node.jumps({ if (node.jumps({
loop: true loop: true
})) { })) {
return true; return node;
} }
} }
return false; return false;
@ -1795,6 +1799,9 @@
var body, defPart, forPart, guardPart, idt1, index, ivar, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, svar, varPart, _ref; var body, defPart, forPart, guardPart, idt1, index, ivar, lastJumps, lvar, name, namePart, ref, resultPart, returnResult, rvar, scope, source, stepPart, svar, varPart, _ref;
body = Expressions.wrap([this.body]); body = Expressions.wrap([this.body]);
lastJumps = (_ref = last(body.expressions)) != null ? _ref.jumps() : void 0; lastJumps = (_ref = last(body.expressions)) != null ? _ref.jumps() : void 0;
if (lastJumps && lastJumps instanceof Return) {
this.returns = false;
}
source = this.range ? this.source.base : this.source; source = this.range ? this.source.base : this.source;
scope = o.scope; scope = o.scope;
name = this.name && this.name.compile(o, LEVEL_LIST); name = this.name && this.name.compile(o, LEVEL_LIST);
@ -1809,7 +1816,7 @@
immediate: true immediate: true
}); });
} }
if (this.returns && !lastJumps) { if (this.returns) {
rvar = scope.freeVariable('results'); rvar = scope.freeVariable('results');
} }
ivar = (this.range ? name : index) || scope.freeVariable('i'); ivar = (this.range ? name : index) || scope.freeVariable('i');
@ -1843,7 +1850,7 @@
forPart = "" + ivar + " = 0, " + lvar + " = " + svar + ".length; " + ivar + " < " + lvar + "; " + stepPart; forPart = "" + ivar + " = 0, " + lvar + " = " + svar + ".length; " + ivar + " < " + lvar + "; " + stepPart;
} }
} }
if (this.returns && !lastJumps) { if (this.returns) {
resultPart = "" + this.tab + rvar + " = [];\n"; resultPart = "" + this.tab + rvar + " = [];\n";
returnResult = "\n" + this.tab + "return " + rvar + ";"; returnResult = "\n" + this.tab + "return " + rvar + ";";
body = Push.wrap(rvar, body); body = Push.wrap(rvar, body);
@ -1931,7 +1938,7 @@
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
_ref2 = _ref[_i], conds = _ref2[0], block = _ref2[1]; _ref2 = _ref[_i], conds = _ref2[0], block = _ref2[1];
if (block.jumps(o)) { if (block.jumps(o)) {
return true; return block;
} }
} }
return (_ref3 = this.otherwise) != null ? _ref3.jumps(o) : void 0; return (_ref3 = this.otherwise) != null ? _ref3.jumps(o) : void 0;

View File

@ -186,7 +186,7 @@ exports.Expressions = class Expressions extends Base
jumps: (o) -> jumps: (o) ->
for exp in @expressions for exp in @expressions
return true if exp.jumps o return exp if exp.jumps o
# An Expressions node does not return its entire body, rather it # An Expressions node does not return its entire body, rather it
# ensures that the final expression is returned. # ensures that the final expression is returned.
@ -283,7 +283,7 @@ exports.Literal = class Literal extends Base
jumps: (o) -> jumps: (o) ->
return no unless @value in ['break', 'continue', 'debugger'] return no unless @value in ['break', 'continue', 'debugger']
not (o and (o.loop or o.block and (@value isnt 'continue'))) if not (o and (o.loop or o.block and (@value isnt 'continue'))) then this else no
compile: -> compile: ->
if @value.reserved then "\"#{@value}\"" else @value if @value.reserved then "\"#{@value}\"" else @value
@ -302,7 +302,7 @@ exports.Return = class Return extends Base
isStatement: YES isStatement: YES
makeReturn: THIS makeReturn: THIS
jumps: YES jumps: THIS
compile: (o, level) -> compile: (o, level) ->
expr = @expression?.makeReturn() expr = @expression?.makeReturn()
@ -1139,7 +1139,7 @@ exports.While = class While extends Base
{expressions} = @body {expressions} = @body
return no unless expressions.length return no unless expressions.length
for node in expressions for node in expressions
return yes if node.jumps loop: yes return node if node.jumps loop: yes
no no
# The main difference from a JavaScript *while* is that the CoffeeScript # The main difference from a JavaScript *while* is that the CoffeeScript
@ -1444,13 +1444,14 @@ exports.For = class For extends Base
compileNode: (o) -> compileNode: (o) ->
body = Expressions.wrap [@body] body = Expressions.wrap [@body]
lastJumps = last(body.expressions)?.jumps() lastJumps = last(body.expressions)?.jumps()
@returns = no if lastJumps and lastJumps instanceof Return
source = if @range then @source.base else @source source = if @range then @source.base else @source
scope = o.scope scope = o.scope
name = @name and @name.compile o, LEVEL_LIST name = @name and @name.compile o, LEVEL_LIST
index = @index and @index.compile o, LEVEL_LIST index = @index and @index.compile o, LEVEL_LIST
scope.find(name, immediate: yes) if name and not @pattern scope.find(name, immediate: yes) if name and not @pattern
scope.find(index, immediate: yes) if index scope.find(index, immediate: yes) if index
rvar = scope.freeVariable 'results' if @returns and not lastJumps rvar = scope.freeVariable 'results' if @returns
ivar = (if @range then name else index) or scope.freeVariable 'i' ivar = (if @range then name else index) or scope.freeVariable 'i'
name = ivar if @pattern name = ivar if @pattern
varPart = '' varPart = ''
@ -1472,7 +1473,7 @@ exports.For = class For extends Base
lvar = scope.freeVariable 'len' lvar = scope.freeVariable 'len'
stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++" stepPart = if @step then "#{ivar} += #{ @step.compile(o, LEVEL_OP) }" else "#{ivar}++"
forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}" forPart = "#{ivar} = 0, #{lvar} = #{svar}.length; #{ivar} < #{lvar}; #{stepPart}"
if @returns and not lastJumps if @returns
resultPart = "#{@tab}#{rvar} = [];\n" resultPart = "#{@tab}#{rvar} = [];\n"
returnResult = "\n#{@tab}return #{rvar};" returnResult = "\n#{@tab}return #{rvar};"
body = Push.wrap rvar, body body = Push.wrap rvar, body
@ -1530,7 +1531,7 @@ exports.Switch = class Switch extends Base
jumps: (o = {block: yes}) -> jumps: (o = {block: yes}) ->
for [conds, block] in @cases for [conds, block] in @cases
return yes if block.jumps o return block if block.jumps o
@otherwise?.jumps o @otherwise?.jumps o
makeReturn: -> makeReturn: ->

View File

@ -279,3 +279,10 @@ result = try
i i
eq result, 10 eq result, 10
# Comprehensions over break.
arrayEq (break for [1..10]), []
# Comprehensions over continue.
arrayEq (break for [1..10]), []

View File

@ -51,3 +51,21 @@ ok list.join(' ') is '8 6 4 2'
#759: `if` within `while` condition #759: `if` within `while` condition
2 while if 1 then 0 2 while if 1 then 0
# While over break.
i = 0
result = while i < 10
i++
break
arrayEq result, []
# While over continue.
i = 0
result = while i < 10
i++
continue
arrayEq result, []