mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
satyr 1612b04 ... enabled break/continue in comprehensions.
This commit is contained in:
parent
6aaa2eb4d0
commit
5aa21c363d
3 changed files with 66 additions and 35 deletions
52
lib/nodes.js
52
lib/nodes.js
|
@ -70,13 +70,15 @@
|
|||
Base.prototype.makeReturn = function() {
|
||||
return new Return(this);
|
||||
};
|
||||
Base.prototype.contains = function(block, arg) {
|
||||
Base.prototype.contains = function(pred) {
|
||||
var contains;
|
||||
contains = false;
|
||||
this.traverseChildren(false, function(node, arg) {
|
||||
var rearg;
|
||||
return (rearg = block(node, arg)) === true ? !(contains = true) : arg != null ? rearg : void 0;
|
||||
}, arg);
|
||||
this.traverseChildren(false, function(node) {
|
||||
if (pred(node)) {
|
||||
contains = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return contains;
|
||||
};
|
||||
Base.prototype.containsType = function(type) {
|
||||
|
@ -85,11 +87,7 @@
|
|||
});
|
||||
};
|
||||
Base.prototype.containsPureStatement = function() {
|
||||
return this.isPureStatement() || this.contains(function(node, func) {
|
||||
return func(node) || (node instanceof While || node instanceof For ? function(node) {
|
||||
return node instanceof Return;
|
||||
} : func);
|
||||
}, function(node) {
|
||||
return this.isPureStatement() || this.contains(function(node) {
|
||||
return node.isPureStatement();
|
||||
});
|
||||
};
|
||||
|
@ -136,12 +134,12 @@
|
|||
});
|
||||
return nodes;
|
||||
};
|
||||
Base.prototype.traverseChildren = function(crossScope, func, arg) {
|
||||
Base.prototype.traverseChildren = function(crossScope, func) {
|
||||
return this.eachChild(function(child) {
|
||||
if ((arg = func(child, arg)) === false) {
|
||||
if (func(child) === false) {
|
||||
return false;
|
||||
}
|
||||
return child.traverseChildren(crossScope, func, arg);
|
||||
return child.traverseChildren(crossScope, func);
|
||||
});
|
||||
};
|
||||
Base.prototype.invert = function() {
|
||||
|
@ -1199,14 +1197,31 @@
|
|||
__extends(While, Base);
|
||||
While.prototype.children = ['condition', 'guard', 'body'];
|
||||
While.prototype.isStatement = YES;
|
||||
While.prototype.addBody = function(body) {
|
||||
this.body = body;
|
||||
While.prototype.addBody = function(_arg) {
|
||||
this.body = _arg;
|
||||
return this;
|
||||
};
|
||||
While.prototype.makeReturn = function() {
|
||||
this.returns = true;
|
||||
return this;
|
||||
};
|
||||
While.prototype.containsPureStatement = function() {
|
||||
var _ref2, expressions, i, ret;
|
||||
expressions = this.body.expressions;
|
||||
i = expressions.length;
|
||||
if ((_ref2 = expressions[--i]) != null ? _ref2.containsPureStatement() : void 0) {
|
||||
return true;
|
||||
}
|
||||
ret = function(node) {
|
||||
return node instanceof Return;
|
||||
};
|
||||
while (i--) {
|
||||
if (expressions[i].contains(ret)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
While.prototype.compileNode = function(o) {
|
||||
var body, code, rvar, set;
|
||||
o.indent = this.idt(1);
|
||||
|
@ -1488,12 +1503,12 @@
|
|||
})();
|
||||
exports.For = (function() {
|
||||
For = (function() {
|
||||
function For(_arg, head) {
|
||||
this.body = _arg;
|
||||
function For(body, head) {
|
||||
if (head.index instanceof Value) {
|
||||
throw SyntaxError('index cannot be a pattern matching expression');
|
||||
}
|
||||
extend(this, head);
|
||||
this.body = Expressions.wrap([body]);
|
||||
if (!this.object) {
|
||||
this.step || (this.step = new Literal(1));
|
||||
}
|
||||
|
@ -1510,6 +1525,7 @@
|
|||
this.returns = true;
|
||||
return this;
|
||||
};
|
||||
For.prototype.containsPureStatement = While.prototype.containsPureStatement;
|
||||
For.prototype.compileReturnValue = function(val, o) {
|
||||
if (this.returns) {
|
||||
return '\n' + new Return(new Literal(val)).compile(o);
|
||||
|
@ -1522,11 +1538,11 @@
|
|||
For.prototype.compileNode = function(o) {
|
||||
var _ref2, _ref3, _ref4, _ref5, _ref6, body, code, cond, defPart, forPart, guardPart, idt, index, ivar, lvar, name, namePart, pvar, retPart, rvar, scope, sourcePart, step, svar, tail, tvar, varPart, vars;
|
||||
scope = o.scope;
|
||||
body = this.body;
|
||||
name = !this.pattern && ((_ref2 = this.name) != null ? _ref2.compile(o) : void 0);
|
||||
index = (_ref3 = this.index) != null ? _ref3.compile(o) : void 0;
|
||||
ivar = !index ? scope.freeVariable('i') : index;
|
||||
varPart = guardPart = defPart = retPart = '';
|
||||
body = Expressions.wrap([this.body]);
|
||||
idt = this.idt(1);
|
||||
if (name) {
|
||||
scope.find(name, {
|
||||
|
|
|
@ -85,11 +85,12 @@ exports.Base = class Base
|
|||
# Recursively traverses down the *children* of the nodes, yielding to a block
|
||||
# and returning true when the block finds a match. `contains` does not cross
|
||||
# scope boundaries.
|
||||
contains: (block, arg) ->
|
||||
contains: (pred) ->
|
||||
contains = no
|
||||
@traverseChildren false, (node, arg) ->
|
||||
if (rearg = block node, arg) is true then not contains = true else if arg? then rearg
|
||||
, arg
|
||||
@traverseChildren no, (node) ->
|
||||
if pred node
|
||||
contains = yes
|
||||
return no
|
||||
contains
|
||||
|
||||
# Is this node of a certain type, or does it contain the type?
|
||||
|
@ -99,11 +100,7 @@ exports.Base = class Base
|
|||
# Convenience for the most common use of contains. Does the node contain
|
||||
# a pure statement?
|
||||
containsPureStatement: ->
|
||||
@isPureStatement() or @contains (node, func) ->
|
||||
func(node) or if node instanceof While or node instanceof For
|
||||
(node) -> node instanceof Return
|
||||
else func
|
||||
, (node) -> node.isPureStatement()
|
||||
@isPureStatement() or @contains (node) -> node.isPureStatement()
|
||||
|
||||
# `toString` representation of the node, for inspecting the parse tree.
|
||||
# This is what `coffee --nodes` prints out.
|
||||
|
@ -125,10 +122,10 @@ exports.Base = class Base
|
|||
@eachChild (node) -> nodes.push node
|
||||
nodes
|
||||
|
||||
traverseChildren: (crossScope, func, arg) ->
|
||||
traverseChildren: (crossScope, func) ->
|
||||
@eachChild (child) ->
|
||||
return false if (arg = func child, arg) is false
|
||||
child.traverseChildren crossScope, func, arg
|
||||
return false if func(child) is false
|
||||
child.traverseChildren crossScope, func
|
||||
|
||||
invert: ->
|
||||
new Op '!', this
|
||||
|
@ -996,14 +993,21 @@ exports.While = class While extends Base
|
|||
@condition = if options?.invert then condition.invert() else condition
|
||||
@guard = options?.guard
|
||||
|
||||
addBody: (body) ->
|
||||
@body = body
|
||||
addBody: (@body) ->
|
||||
this
|
||||
|
||||
makeReturn: ->
|
||||
@returns = true
|
||||
this
|
||||
|
||||
containsPureStatement: ->
|
||||
{expressions} = @body
|
||||
i = expressions.length
|
||||
return true if expressions[--i]?.containsPureStatement()
|
||||
ret = (node) -> node instanceof Return
|
||||
return true while i-- when expressions[i].contains ret
|
||||
false
|
||||
|
||||
# The main difference from a JavaScript *while* is that the CoffeeScript
|
||||
# *while* can be used as a part of a larger expression -- while loops may
|
||||
# return an array containing the computed result of each iteration.
|
||||
|
@ -1259,10 +1263,11 @@ exports.For = class For extends Base
|
|||
|
||||
isStatement: YES
|
||||
|
||||
constructor: (@body, head) ->
|
||||
constructor: (body, head) ->
|
||||
if head.index instanceof Value
|
||||
throw SyntaxError 'index cannot be a pattern matching expression'
|
||||
extend this, head
|
||||
@body = Expressions.wrap [body]
|
||||
@step or= new Literal 1 unless @object
|
||||
@pattern = @name instanceof Value
|
||||
@returns = false
|
||||
|
@ -1271,6 +1276,8 @@ exports.For = class For extends Base
|
|||
@returns = true
|
||||
this
|
||||
|
||||
containsPureStatement: While::containsPureStatement
|
||||
|
||||
compileReturnValue: (val, o) ->
|
||||
return '\n' + new Return(new Literal val).compile o if @returns
|
||||
return '\n' + val if val
|
||||
|
@ -1282,11 +1289,11 @@ exports.For = class For extends Base
|
|||
# some cannot.
|
||||
compileNode: (o) ->
|
||||
{scope} = o
|
||||
{body} = this
|
||||
name = not @pattern and @name?.compile o
|
||||
index = @index?.compile o
|
||||
ivar = if not index then scope.freeVariable 'i' else index
|
||||
varPart = guardPart = defPart = retPart = ''
|
||||
body = Expressions.wrap [@body]
|
||||
idt = @idt 1
|
||||
scope.find(name, immediate: yes) if name
|
||||
scope.find(index, immediate: yes) if index
|
||||
|
|
|
@ -114,6 +114,14 @@ ok val[0] is i
|
|||
# Comprehensions only wrap their last line in a closure, allowing other lines
|
||||
# to have pure expressions in them.
|
||||
func = -> for i in [1]
|
||||
return if false
|
||||
break if i is 2
|
||||
j for j in [1]
|
||||
|
||||
ok func()[0][0] is 1
|
||||
|
||||
i = 6
|
||||
odds = while i--
|
||||
continue unless i & 1
|
||||
i
|
||||
|
||||
ok odds.join(', ') is '5, 3, 1'
|
||||
|
|
Loading…
Add table
Reference in a new issue