Comprehensions over break and continue
This commit is contained in:
parent
34b16699fa
commit
b56b08387d
21
lib/nodes.js
21
lib/nodes.js
|
@ -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;
|
||||||
|
|
|
@ -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: ->
|
||||||
|
|
|
@ -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]), []
|
||||||
|
|
|
@ -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, []
|
||||||
|
|
Loading…
Reference in New Issue