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() {
|
Base.prototype.makeReturn = function() {
|
||||||
return new Return(this);
|
return new Return(this);
|
||||||
};
|
};
|
||||||
Base.prototype.contains = function(block, arg) {
|
Base.prototype.contains = function(pred) {
|
||||||
var contains;
|
var contains;
|
||||||
contains = false;
|
contains = false;
|
||||||
this.traverseChildren(false, function(node, arg) {
|
this.traverseChildren(false, function(node) {
|
||||||
var rearg;
|
if (pred(node)) {
|
||||||
return (rearg = block(node, arg)) === true ? !(contains = true) : arg != null ? rearg : void 0;
|
contains = true;
|
||||||
}, arg);
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
return contains;
|
return contains;
|
||||||
};
|
};
|
||||||
Base.prototype.containsType = function(type) {
|
Base.prototype.containsType = function(type) {
|
||||||
|
@ -85,11 +87,7 @@
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Base.prototype.containsPureStatement = function() {
|
Base.prototype.containsPureStatement = function() {
|
||||||
return this.isPureStatement() || this.contains(function(node, func) {
|
return this.isPureStatement() || this.contains(function(node) {
|
||||||
return func(node) || (node instanceof While || node instanceof For ? function(node) {
|
|
||||||
return node instanceof Return;
|
|
||||||
} : func);
|
|
||||||
}, function(node) {
|
|
||||||
return node.isPureStatement();
|
return node.isPureStatement();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -136,12 +134,12 @@
|
||||||
});
|
});
|
||||||
return nodes;
|
return nodes;
|
||||||
};
|
};
|
||||||
Base.prototype.traverseChildren = function(crossScope, func, arg) {
|
Base.prototype.traverseChildren = function(crossScope, func) {
|
||||||
return this.eachChild(function(child) {
|
return this.eachChild(function(child) {
|
||||||
if ((arg = func(child, arg)) === false) {
|
if (func(child) === false) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return child.traverseChildren(crossScope, func, arg);
|
return child.traverseChildren(crossScope, func);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Base.prototype.invert = function() {
|
Base.prototype.invert = function() {
|
||||||
|
@ -1199,14 +1197,31 @@
|
||||||
__extends(While, Base);
|
__extends(While, Base);
|
||||||
While.prototype.children = ['condition', 'guard', 'body'];
|
While.prototype.children = ['condition', 'guard', 'body'];
|
||||||
While.prototype.isStatement = YES;
|
While.prototype.isStatement = YES;
|
||||||
While.prototype.addBody = function(body) {
|
While.prototype.addBody = function(_arg) {
|
||||||
this.body = body;
|
this.body = _arg;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
While.prototype.makeReturn = function() {
|
While.prototype.makeReturn = function() {
|
||||||
this.returns = true;
|
this.returns = true;
|
||||||
return this;
|
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) {
|
While.prototype.compileNode = function(o) {
|
||||||
var body, code, rvar, set;
|
var body, code, rvar, set;
|
||||||
o.indent = this.idt(1);
|
o.indent = this.idt(1);
|
||||||
|
@ -1488,12 +1503,12 @@
|
||||||
})();
|
})();
|
||||||
exports.For = (function() {
|
exports.For = (function() {
|
||||||
For = (function() {
|
For = (function() {
|
||||||
function For(_arg, head) {
|
function For(body, head) {
|
||||||
this.body = _arg;
|
|
||||||
if (head.index instanceof Value) {
|
if (head.index instanceof Value) {
|
||||||
throw SyntaxError('index cannot be a pattern matching expression');
|
throw SyntaxError('index cannot be a pattern matching expression');
|
||||||
}
|
}
|
||||||
extend(this, head);
|
extend(this, head);
|
||||||
|
this.body = Expressions.wrap([body]);
|
||||||
if (!this.object) {
|
if (!this.object) {
|
||||||
this.step || (this.step = new Literal(1));
|
this.step || (this.step = new Literal(1));
|
||||||
}
|
}
|
||||||
|
@ -1510,6 +1525,7 @@
|
||||||
this.returns = true;
|
this.returns = true;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
For.prototype.containsPureStatement = While.prototype.containsPureStatement;
|
||||||
For.prototype.compileReturnValue = function(val, o) {
|
For.prototype.compileReturnValue = function(val, o) {
|
||||||
if (this.returns) {
|
if (this.returns) {
|
||||||
return '\n' + new Return(new Literal(val)).compile(o);
|
return '\n' + new Return(new Literal(val)).compile(o);
|
||||||
|
@ -1522,11 +1538,11 @@
|
||||||
For.prototype.compileNode = function(o) {
|
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;
|
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;
|
scope = o.scope;
|
||||||
|
body = this.body;
|
||||||
name = !this.pattern && ((_ref2 = this.name) != null ? _ref2.compile(o) : void 0);
|
name = !this.pattern && ((_ref2 = this.name) != null ? _ref2.compile(o) : void 0);
|
||||||
index = (_ref3 = this.index) != null ? _ref3.compile(o) : void 0;
|
index = (_ref3 = this.index) != null ? _ref3.compile(o) : void 0;
|
||||||
ivar = !index ? scope.freeVariable('i') : index;
|
ivar = !index ? scope.freeVariable('i') : index;
|
||||||
varPart = guardPart = defPart = retPart = '';
|
varPart = guardPart = defPart = retPart = '';
|
||||||
body = Expressions.wrap([this.body]);
|
|
||||||
idt = this.idt(1);
|
idt = this.idt(1);
|
||||||
if (name) {
|
if (name) {
|
||||||
scope.find(name, {
|
scope.find(name, {
|
||||||
|
|
|
@ -85,11 +85,12 @@ exports.Base = class Base
|
||||||
# Recursively traverses down the *children* of the nodes, yielding to a block
|
# 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
|
# and returning true when the block finds a match. `contains` does not cross
|
||||||
# scope boundaries.
|
# scope boundaries.
|
||||||
contains: (block, arg) ->
|
contains: (pred) ->
|
||||||
contains = no
|
contains = no
|
||||||
@traverseChildren false, (node, arg) ->
|
@traverseChildren no, (node) ->
|
||||||
if (rearg = block node, arg) is true then not contains = true else if arg? then rearg
|
if pred node
|
||||||
, arg
|
contains = yes
|
||||||
|
return no
|
||||||
contains
|
contains
|
||||||
|
|
||||||
# Is this node of a certain type, or does it contain the type?
|
# 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
|
# Convenience for the most common use of contains. Does the node contain
|
||||||
# a pure statement?
|
# a pure statement?
|
||||||
containsPureStatement: ->
|
containsPureStatement: ->
|
||||||
@isPureStatement() or @contains (node, func) ->
|
@isPureStatement() or @contains (node) -> node.isPureStatement()
|
||||||
func(node) or if node instanceof While or node instanceof For
|
|
||||||
(node) -> node instanceof Return
|
|
||||||
else func
|
|
||||||
, (node) -> node.isPureStatement()
|
|
||||||
|
|
||||||
# `toString` representation of the node, for inspecting the parse tree.
|
# `toString` representation of the node, for inspecting the parse tree.
|
||||||
# This is what `coffee --nodes` prints out.
|
# This is what `coffee --nodes` prints out.
|
||||||
|
@ -125,10 +122,10 @@ exports.Base = class Base
|
||||||
@eachChild (node) -> nodes.push node
|
@eachChild (node) -> nodes.push node
|
||||||
nodes
|
nodes
|
||||||
|
|
||||||
traverseChildren: (crossScope, func, arg) ->
|
traverseChildren: (crossScope, func) ->
|
||||||
@eachChild (child) ->
|
@eachChild (child) ->
|
||||||
return false if (arg = func child, arg) is false
|
return false if func(child) is false
|
||||||
child.traverseChildren crossScope, func, arg
|
child.traverseChildren crossScope, func
|
||||||
|
|
||||||
invert: ->
|
invert: ->
|
||||||
new Op '!', this
|
new Op '!', this
|
||||||
|
@ -996,14 +993,21 @@ exports.While = class While extends Base
|
||||||
@condition = if options?.invert then condition.invert() else condition
|
@condition = if options?.invert then condition.invert() else condition
|
||||||
@guard = options?.guard
|
@guard = options?.guard
|
||||||
|
|
||||||
addBody: (body) ->
|
addBody: (@body) ->
|
||||||
@body = body
|
|
||||||
this
|
this
|
||||||
|
|
||||||
makeReturn: ->
|
makeReturn: ->
|
||||||
@returns = true
|
@returns = true
|
||||||
this
|
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
|
# 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
|
# *while* can be used as a part of a larger expression -- while loops may
|
||||||
# return an array containing the computed result of each iteration.
|
# return an array containing the computed result of each iteration.
|
||||||
|
@ -1259,10 +1263,11 @@ exports.For = class For extends Base
|
||||||
|
|
||||||
isStatement: YES
|
isStatement: YES
|
||||||
|
|
||||||
constructor: (@body, head) ->
|
constructor: (body, head) ->
|
||||||
if head.index instanceof Value
|
if head.index instanceof Value
|
||||||
throw SyntaxError 'index cannot be a pattern matching expression'
|
throw SyntaxError 'index cannot be a pattern matching expression'
|
||||||
extend this, head
|
extend this, head
|
||||||
|
@body = Expressions.wrap [body]
|
||||||
@step or= new Literal 1 unless @object
|
@step or= new Literal 1 unless @object
|
||||||
@pattern = @name instanceof Value
|
@pattern = @name instanceof Value
|
||||||
@returns = false
|
@returns = false
|
||||||
|
@ -1271,6 +1276,8 @@ exports.For = class For extends Base
|
||||||
@returns = true
|
@returns = true
|
||||||
this
|
this
|
||||||
|
|
||||||
|
containsPureStatement: While::containsPureStatement
|
||||||
|
|
||||||
compileReturnValue: (val, o) ->
|
compileReturnValue: (val, o) ->
|
||||||
return '\n' + new Return(new Literal val).compile o if @returns
|
return '\n' + new Return(new Literal val).compile o if @returns
|
||||||
return '\n' + val if val
|
return '\n' + val if val
|
||||||
|
@ -1282,11 +1289,11 @@ exports.For = class For extends Base
|
||||||
# some cannot.
|
# some cannot.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
{scope} = o
|
{scope} = o
|
||||||
|
{body} = this
|
||||||
name = not @pattern and @name?.compile o
|
name = not @pattern and @name?.compile o
|
||||||
index = @index?.compile o
|
index = @index?.compile o
|
||||||
ivar = if not index then scope.freeVariable 'i' else index
|
ivar = if not index then scope.freeVariable 'i' else index
|
||||||
varPart = guardPart = defPart = retPart = ''
|
varPart = guardPart = defPart = retPart = ''
|
||||||
body = Expressions.wrap [@body]
|
|
||||||
idt = @idt 1
|
idt = @idt 1
|
||||||
scope.find(name, immediate: yes) if name
|
scope.find(name, immediate: yes) if name
|
||||||
scope.find(index, immediate: yes) if index
|
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
|
# Comprehensions only wrap their last line in a closure, allowing other lines
|
||||||
# to have pure expressions in them.
|
# to have pure expressions in them.
|
||||||
func = -> for i in [1]
|
func = -> for i in [1]
|
||||||
return if false
|
break if i is 2
|
||||||
j for j in [1]
|
j for j in [1]
|
||||||
|
|
||||||
ok func()[0][0] is 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