mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Scoped comprehensions are back out, Do is back in.
This commit is contained in:
parent
97f8e9ce1c
commit
094b876a38
10 changed files with 219 additions and 287 deletions
|
@ -36,10 +36,7 @@
|
|||
Block: [
|
||||
o('INDENT OUTDENT', function() {
|
||||
return new Expressions;
|
||||
}), o('FullBlock')
|
||||
],
|
||||
FullBlock: [
|
||||
o('INDENT Body OUTDENT', function() {
|
||||
}), o('INDENT Body OUTDENT', function() {
|
||||
return $2;
|
||||
})
|
||||
],
|
||||
|
@ -376,9 +373,6 @@
|
|||
return new For($1, $2);
|
||||
}), o('ForBody Block', function() {
|
||||
return new For($2, $1);
|
||||
}), o('ForBody FuncGlyph FullBlock', function() {
|
||||
$1.scoped = true;
|
||||
return new For($3, $1);
|
||||
})
|
||||
],
|
||||
ForBody: [
|
||||
|
@ -554,7 +548,7 @@
|
|||
})
|
||||
]
|
||||
};
|
||||
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
|
||||
operators = [['left', '.', '?.', '::'], ['left', 'CALL_START', 'CALL_END'], ['nonassoc', '++', '--'], ['left', '?'], ['right', 'UNARY'], ['left', 'MATH'], ['left', '+', '-'], ['left', 'SHIFT'], ['left', 'RELATION'], ['left', 'COMPARE'], ['left', 'LOGIC'], ['nonassoc', 'INDENT', 'OUTDENT'], ['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS'], ['right', 'FORIN', 'FOROF', 'BY', 'WHEN'], ['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS'], ['right', 'POST_IF']];
|
||||
tokens = [];
|
||||
for (name in grammar) {
|
||||
alternatives = grammar[name];
|
||||
|
|
10
lib/lexer.js
10
lib/lexer.js
|
@ -58,6 +58,7 @@
|
|||
} else if (__indexOf.call(RELATION, tag) >= 0) {
|
||||
if (tag !== 'INSTANCEOF' && this.seenFor) {
|
||||
tag = 'FOR' + tag;
|
||||
this.seenFor = false;
|
||||
} else {
|
||||
tag = 'RELATION';
|
||||
if (this.value() === '!') {
|
||||
|
@ -251,7 +252,6 @@
|
|||
if (!(match = MULTI_DENT.exec(this.chunk))) {
|
||||
return 0;
|
||||
}
|
||||
this.seenFor = false;
|
||||
indent = match[0];
|
||||
this.line += count(indent, '\n');
|
||||
prev = last(this.tokens, 1);
|
||||
|
@ -340,7 +340,7 @@
|
|||
var match, prev, tag, value, _ref, _ref2, _ref3, _ref4;
|
||||
if (match = OPERATOR.exec(this.chunk)) {
|
||||
value = match[0];
|
||||
if (!this.seenFor && CODE.test(value)) {
|
||||
if (CODE.test(value)) {
|
||||
this.tagParameters();
|
||||
}
|
||||
} else {
|
||||
|
@ -580,7 +580,7 @@
|
|||
};
|
||||
return Lexer;
|
||||
})();
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||
JS_KEYWORDS = ['true', 'false', 'null', 'this', 'new', 'delete', 'typeof', 'in', 'instanceof', 'return', 'throw', 'break', 'continue', 'debugger', 'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally', 'class', 'extends', 'super'];
|
||||
COFFEE_KEYWORDS = ['undefined', 'then', 'unless', 'until', 'loop', 'of', 'by', 'when'];
|
||||
for (op in COFFEE_ALIASES = {
|
||||
and: '&&',
|
||||
|
@ -595,7 +595,7 @@
|
|||
}) {
|
||||
COFFEE_KEYWORDS.push(op);
|
||||
}
|
||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'do', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf'];
|
||||
RESERVED = ['case', 'default', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice', '__bind', '__indexOf'];
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
exports.RESERVED = RESERVED.concat(JS_KEYWORDS).concat(COFFEE_KEYWORDS);
|
||||
IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;
|
||||
|
@ -618,7 +618,7 @@
|
|||
TRAILING_SPACES = /\s+$/;
|
||||
NO_NEWLINE = /^(?:[-+*&|\/%=<>!.\\][<>=&|]*|and|or|is(?:nt)?|n(?:ot|ew)|delete|typeof|instanceof)$/;
|
||||
COMPOUND_ASSIGN = ['-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=', '<<=', '>>=', '>>>=', '&=', '^=', '|='];
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE'];
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO'];
|
||||
LOGIC = ['&&', '||', '&', '|', '^'];
|
||||
SHIFT = ['<<', '>>', '>>>'];
|
||||
COMPARE = ['==', '!=', '<', '>', '<=', '>='];
|
||||
|
|
27
lib/nodes.js
27
lib/nodes.js
|
@ -1505,6 +1505,9 @@
|
|||
if (op === 'in') {
|
||||
return new In(first, second);
|
||||
}
|
||||
if (op === 'do') {
|
||||
return new Call(first, first.params || []);
|
||||
}
|
||||
if (op === 'new') {
|
||||
if (first instanceof Call) {
|
||||
return first.newInstance();
|
||||
|
@ -1784,7 +1787,7 @@
|
|||
__extends(For, Base);
|
||||
function For(body, source) {
|
||||
var _ref;
|
||||
this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index, this.scoped = source.scoped;
|
||||
this.source = source.source, this.guard = source.guard, this.step = source.step, this.name = source.name, this.index = source.index;
|
||||
this.body = Expressions.wrap([body]);
|
||||
this.own = !!source.own;
|
||||
this.object = !!source.object;
|
||||
|
@ -1843,9 +1846,6 @@
|
|||
guardPart = '';
|
||||
defPart = '';
|
||||
idt1 = this.tab + TAB;
|
||||
if (this.scoped && this.jumps()) {
|
||||
throw SyntaxError('cannot use a pure statement in a scoped loop.');
|
||||
}
|
||||
if (this.range) {
|
||||
forPart = source.compile(merge(o, {
|
||||
index: ivar,
|
||||
|
@ -1877,10 +1877,7 @@
|
|||
if (this.pattern) {
|
||||
body.expressions.unshift(new Assign(this.name, new Literal("" + svar + "[" + ivar + "]")));
|
||||
}
|
||||
if (this.scoped) {
|
||||
body = Closure.wrap(body, true, !this.returns);
|
||||
}
|
||||
defPart += this.pluckDirectCall(o, body, name, index);
|
||||
defPart += this.pluckDirectCall(o, body);
|
||||
if (namePart) {
|
||||
varPart = "\n" + idt1 + namePart + ";";
|
||||
}
|
||||
|
@ -1898,8 +1895,8 @@
|
|||
}
|
||||
return "" + defPart + (resultPart || '') + this.tab + "for (" + forPart + ") {" + guardPart + varPart + body + this.tab + "}" + (returnResult || '');
|
||||
};
|
||||
For.prototype.pluckDirectCall = function(o, body, name, index) {
|
||||
var arg, args, base, defs, expr, fn, i, idx, ref, val, _len, _len2, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
|
||||
For.prototype.pluckDirectCall = function(o, body) {
|
||||
var base, defs, expr, fn, idx, ref, val, _len, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
|
||||
defs = '';
|
||||
_ref = body.expressions;
|
||||
for (idx = 0, _len = _ref.length; idx < _len; idx++) {
|
||||
|
@ -1915,19 +1912,11 @@
|
|||
fn = ((_ref5 = val.base) != null ? _ref5.unwrapAll() : void 0) || val;
|
||||
ref = new Literal(o.scope.freeVariable('fn'));
|
||||
base = new Value(ref);
|
||||
args = compact([name, index]);
|
||||
if (this.object) {
|
||||
args.reverse();
|
||||
}
|
||||
for (i = 0, _len2 = args.length; i < _len2; i++) {
|
||||
arg = args[i];
|
||||
fn.params.push(new Param(args[i] = new Literal(arg)));
|
||||
}
|
||||
if (val.base) {
|
||||
_ref6 = [base, val], val.base = _ref6[0], base = _ref6[1];
|
||||
args.unshift(new Literal('this'));
|
||||
}
|
||||
body.expressions[idx] = new Call(base, args);
|
||||
body.expressions[idx] = new Call(base, expr.args);
|
||||
defs += this.tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n';
|
||||
}
|
||||
return defs;
|
||||
|
|
317
lib/parser.js
317
lib/parser.js
File diff suppressed because one or more lines are too long
|
@ -51,31 +51,6 @@
|
|||
}
|
||||
return i - 1;
|
||||
};
|
||||
Rewriter.prototype.scanLineBack = function(i, condition) {
|
||||
var levels, token, tokens, _ref, _ref2, _ref3;
|
||||
tokens = this.tokens;
|
||||
levels = 0;
|
||||
while (token = tokens[i--]) {
|
||||
if ((_ref = token[0], __indexOf.call(LINEBREAKS, _ref) >= 0) && !token.generated) {
|
||||
return false;
|
||||
}
|
||||
if (_ref2 = token[0], __indexOf.call(EXPRESSION_START, _ref2) >= 0) {
|
||||
levels -= 1;
|
||||
} else if (_ref3 = token[0], __indexOf.call(EXPRESSION_END, _ref3) >= 0) {
|
||||
levels += 1;
|
||||
}
|
||||
if (levels > 0) {
|
||||
continue;
|
||||
}
|
||||
if (levels < 0) {
|
||||
return false;
|
||||
}
|
||||
if (condition.call(this, token, i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
Rewriter.prototype.removeLeadingNewlines = function() {
|
||||
var i, tag, _len, _ref;
|
||||
_ref = this.tokens;
|
||||
|
@ -201,11 +176,6 @@
|
|||
if (!(callObject || (prev != null ? prev.spaced : void 0) && (prev.call || (_ref3 = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref3) >= 0)) && (__indexOf.call(IMPLICIT_CALL, tag) >= 0 || !(token.spaced || token.newLine) && __indexOf.call(IMPLICIT_UNSPACED_CALL, tag) >= 0))) {
|
||||
return 1;
|
||||
}
|
||||
if ((tag === '->' || tag === '=>') && this.scanLineBack(i, function(token, i) {
|
||||
return token[0] === 'FOR';
|
||||
})) {
|
||||
return 1;
|
||||
}
|
||||
tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
this.detectEnd(i + 1, function(token, i) {
|
||||
var post, _ref;
|
||||
|
|
|
@ -105,10 +105,6 @@ grammar =
|
|||
# token stream.
|
||||
Block: [
|
||||
o 'INDENT OUTDENT', -> new Expressions
|
||||
o 'FullBlock'
|
||||
]
|
||||
|
||||
FullBlock: [
|
||||
o 'INDENT Body OUTDENT', -> $2
|
||||
]
|
||||
|
||||
|
@ -422,7 +418,6 @@ grammar =
|
|||
o 'Statement ForBody', -> new For $1, $2
|
||||
o 'Expression ForBody', -> new For $1, $2
|
||||
o 'ForBody Block', -> new For $2, $1
|
||||
o 'ForBody FuncGlyph FullBlock', -> $1.scoped = yes; new For $3, $1
|
||||
]
|
||||
|
||||
ForBody: [
|
||||
|
@ -565,7 +560,7 @@ operators = [
|
|||
['nonassoc', 'INDENT', 'OUTDENT']
|
||||
['right', '=', ':', 'COMPOUND_ASSIGN', 'RETURN', 'THROW', 'EXTENDS']
|
||||
['right', 'FORIN', 'FOROF', 'BY', 'WHEN']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
|
||||
['right', 'IF', 'ELSE', 'FOR', 'DO', 'WHILE', 'UNTIL', 'LOOP', 'SUPER', 'CLASS']
|
||||
['right', 'POST_IF']
|
||||
]
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ exports.Lexer = class Lexer
|
|||
else if tag in RELATION
|
||||
if tag isnt 'INSTANCEOF' and @seenFor
|
||||
tag = 'FOR' + tag
|
||||
@seenFor = no
|
||||
else
|
||||
tag = 'RELATION'
|
||||
if @value() is '!'
|
||||
|
@ -231,7 +232,6 @@ exports.Lexer = class Lexer
|
|||
# can close multiple indents, so we need to know how far in we happen to be.
|
||||
lineToken: ->
|
||||
return 0 unless match = MULTI_DENT.exec @chunk
|
||||
@seenFor = no
|
||||
indent = match[0]
|
||||
@line += count indent, '\n'
|
||||
prev = last @tokens, 1
|
||||
|
@ -305,7 +305,7 @@ exports.Lexer = class Lexer
|
|||
literalToken: ->
|
||||
if match = OPERATOR.exec @chunk
|
||||
[value] = match
|
||||
@tagParameters() if not @seenFor and CODE.test value
|
||||
@tagParameters() if CODE.test value
|
||||
else
|
||||
value = @chunk.charAt 0
|
||||
tag = value
|
||||
|
@ -500,7 +500,7 @@ JS_KEYWORDS = [
|
|||
'true', 'false', 'null', 'this'
|
||||
'new', 'delete', 'typeof', 'in', 'instanceof'
|
||||
'return', 'throw', 'break', 'continue', 'debugger'
|
||||
'if', 'else', 'switch', 'for', 'while', 'try', 'catch', 'finally'
|
||||
'if', 'else', 'switch', 'for', 'while', 'do', 'try', 'catch', 'finally'
|
||||
'class', 'extends', 'super'
|
||||
]
|
||||
|
||||
|
@ -521,7 +521,7 @@ COFFEE_KEYWORDS.push op for op of COFFEE_ALIASES =
|
|||
# used by CoffeeScript internally. We throw an error when these are encountered,
|
||||
# to avoid having a JavaScript error at runtime.
|
||||
RESERVED = [
|
||||
'case', 'default', 'function', 'var', 'void', 'with', 'do'
|
||||
'case', 'default', 'function', 'var', 'void', 'with'
|
||||
'const', 'let', 'enum', 'export', 'import', 'native'
|
||||
'__hasProp', '__extends', '__slice', '__bind', '__indexOf'
|
||||
]
|
||||
|
@ -609,7 +609,7 @@ COMPOUND_ASSIGN = [
|
|||
]
|
||||
|
||||
# Unary tokens.
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE']
|
||||
UNARY = ['!', '~', 'NEW', 'TYPEOF', 'DELETE', 'DO']
|
||||
|
||||
# Logical tokens.
|
||||
LOGIC = ['&&', '||', '&', '|', '^']
|
||||
|
|
|
@ -1177,6 +1177,7 @@ exports.While = class While extends Base
|
|||
exports.Op = class Op extends Base
|
||||
constructor: (op, first, second, flip) ->
|
||||
return new In first, second if op is 'in'
|
||||
return new Call first, first.params or [] if op is 'do'
|
||||
if op is 'new'
|
||||
return first.newInstance() if first instanceof Call
|
||||
first = new Parens first if first instanceof Code and first.bound
|
||||
|
@ -1423,7 +1424,7 @@ exports.Parens = class Parens extends Base
|
|||
# you can map and filter in a single pass.
|
||||
exports.For = class For extends Base
|
||||
constructor: (body, source) ->
|
||||
{@source, @guard, @step, @name, @index, @scoped} = source
|
||||
{@source, @guard, @step, @name, @index} = source
|
||||
@body = Expressions.wrap [body]
|
||||
@own = !!source.own
|
||||
@object = !!source.object
|
||||
|
@ -1466,8 +1467,6 @@ exports.For = class For extends Base
|
|||
guardPart = ''
|
||||
defPart = ''
|
||||
idt1 = @tab + TAB
|
||||
if @scoped and @jumps()
|
||||
throw SyntaxError 'cannot use a pure statement in a scoped loop.'
|
||||
if @range
|
||||
forPart = source.compile merge(o, {index: ivar, @step})
|
||||
else
|
||||
|
@ -1489,9 +1488,7 @@ exports.For = class For extends Base
|
|||
body = Expressions.wrap [new If @guard, body]
|
||||
if @pattern
|
||||
body.expressions.unshift new Assign @name, new Literal "#{svar}[#{ivar}]"
|
||||
if @scoped
|
||||
body = Closure.wrap body, true, not @returns
|
||||
defPart += @pluckDirectCall o, body, name, index
|
||||
defPart += @pluckDirectCall o, body
|
||||
varPart = "\n#{idt1}#{namePart};" if namePart
|
||||
if @object
|
||||
forPart = "#{ivar} in #{svar}"
|
||||
|
@ -1502,7 +1499,7 @@ exports.For = class For extends Base
|
|||
#{defPart}#{resultPart or ''}#{@tab}for (#{forPart}) {#{guardPart}#{varPart}#{body}#{@tab}}#{returnResult or ''}
|
||||
"""
|
||||
|
||||
pluckDirectCall: (o, body, name, index) ->
|
||||
pluckDirectCall: (o, body) ->
|
||||
defs = ''
|
||||
for expr, idx in body.expressions
|
||||
expr = expr.unwrapAll()
|
||||
|
@ -1516,14 +1513,10 @@ exports.For = class For extends Base
|
|||
fn = val.base?.unwrapAll() or val
|
||||
ref = new Literal o.scope.freeVariable 'fn'
|
||||
base = new Value ref
|
||||
args = compact [name, index]
|
||||
args.reverse() if @object
|
||||
for arg, i in args
|
||||
fn.params.push new Param args[i] = new Literal arg
|
||||
if val.base
|
||||
[val.base, base] = [base, val]
|
||||
args.unshift new Literal 'this'
|
||||
body.expressions[idx] = new Call base, args
|
||||
body.expressions[idx] = new Call base, expr.args
|
||||
defs += @tab + new Assign(ref, fn).compile(o, LEVEL_TOP) + ';\n'
|
||||
defs
|
||||
|
||||
|
|
|
@ -54,20 +54,6 @@ class exports.Rewriter
|
|||
i += 1
|
||||
i - 1
|
||||
|
||||
scanLineBack: (i, condition) ->
|
||||
{tokens} = this
|
||||
levels = 0
|
||||
while token = tokens[i--]
|
||||
return no if token[0] in LINEBREAKS and not token.generated
|
||||
if token[0] in EXPRESSION_START
|
||||
levels -= 1
|
||||
else if token[0] in EXPRESSION_END
|
||||
levels += 1
|
||||
continue if levels > 0
|
||||
return no if levels < 0
|
||||
return yes if condition.call this, token, i
|
||||
no
|
||||
|
||||
# Leading newlines would introduce an ambiguity in the grammar, so we
|
||||
# dispatch them here.
|
||||
removeLeadingNewlines: ->
|
||||
|
@ -160,8 +146,6 @@ class exports.Rewriter
|
|||
return 1 unless callObject or
|
||||
prev?.spaced and (prev.call or prev[0] in IMPLICIT_FUNC) and
|
||||
(tag in IMPLICIT_CALL or not (token.spaced or token.newLine) and tag in IMPLICIT_UNSPACED_CALL)
|
||||
if tag in ['->', '=>'] and @scanLineBack(i, (token, i) -> token[0] is 'FOR')
|
||||
return 1
|
||||
tokens.splice i, 0, ['CALL_START', '(', token[2]]
|
||||
@detectEnd i + 1, (token, i) ->
|
||||
[tag] = token
|
||||
|
|
|
@ -76,9 +76,10 @@ all = 1
|
|||
# Ensure that the closure wrapper preserves local variables.
|
||||
obj = {}
|
||||
|
||||
for method in ['one', 'two', 'three'] ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
for method in ['one', 'two', 'three']
|
||||
do (method) ->
|
||||
obj[method] = ->
|
||||
"I'm " + method
|
||||
|
||||
ok obj.one() is "I'm one"
|
||||
ok obj.two() is "I'm two"
|
||||
|
@ -94,8 +95,9 @@ ok i is 4
|
|||
|
||||
|
||||
# Ensure that local variables are closed over for range comprehensions.
|
||||
funcs = for i in [1..3] ->
|
||||
-> -i
|
||||
funcs = for i in [1..3]
|
||||
do (i) ->
|
||||
-> -i
|
||||
|
||||
eq (func() for func in funcs).join(' '), '-1 -2 -3'
|
||||
ok i is 4
|
||||
|
@ -104,8 +106,9 @@ ok i is 4
|
|||
# Even when referenced in the filter.
|
||||
list = ['one', 'two', 'three']
|
||||
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1 ->
|
||||
-> num + ' ' + i
|
||||
methods = for num, i in list when num isnt 'two' and i isnt 1
|
||||
do (num, i) ->
|
||||
-> num + ' ' + i
|
||||
|
||||
ok methods.length is 2
|
||||
ok methods[0]() is 'one 0'
|
||||
|
@ -115,19 +118,21 @@ ok methods[1]() is 'three 2'
|
|||
# Even a convoluted one.
|
||||
funcs = []
|
||||
|
||||
for i in [1..3] ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
for i in [1..3]
|
||||
do (i) ->
|
||||
x = i * 2
|
||||
((z)->
|
||||
funcs.push -> z + ' ' + i
|
||||
)(x)
|
||||
|
||||
ok (func() for func in funcs).join(', ') is '2 1, 4 2, 6 3'
|
||||
|
||||
funcs = []
|
||||
|
||||
results = for i in [1..3] ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
results = for i in [1..3]
|
||||
do (i) ->
|
||||
z = (x * 3 for x in [1..i])
|
||||
((a, b, c) -> [a, b, c].join(' ')).apply this, z
|
||||
|
||||
ok results.join(', ') is '3 , 3 6 , 3 6 9'
|
||||
|
||||
|
@ -139,9 +144,11 @@ ok(num % 2 is 0 for num in array by 2)
|
|||
|
||||
# Nested shared scopes.
|
||||
foo = ->
|
||||
for i in [0..7] =>
|
||||
for j in [0..7] =>
|
||||
-> i + j
|
||||
for i in [0..7]
|
||||
do (i) ->
|
||||
for j in [0..7]
|
||||
do (j) ->
|
||||
-> i + j
|
||||
|
||||
eq foo()[3][4](), 7
|
||||
|
||||
|
@ -150,7 +157,9 @@ eq foo()[3][4](), 7
|
|||
a = [[0], [1]]
|
||||
funcs = []
|
||||
|
||||
for [v] in a -> funcs.push -> v
|
||||
for [v] in a
|
||||
do (v) ->
|
||||
funcs.push -> v
|
||||
|
||||
eq funcs[0](), 0
|
||||
eq funcs[1](), 1
|
||||
|
@ -268,9 +277,10 @@ funcs = []
|
|||
list = ->
|
||||
[1, 2, 3]
|
||||
|
||||
for y in list() ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
for y in list()
|
||||
do (y) ->
|
||||
z = y
|
||||
funcs.push -> "y is #{y} and z is #{z}"
|
||||
|
||||
eq funcs[1](), "y is 2 and z is 2"
|
||||
|
||||
|
@ -293,13 +303,17 @@ arrayEq (break for [1..10]), []
|
|||
|
||||
# Comprehensions over function literals.
|
||||
a = 0
|
||||
for f in [-> a = 1] -> f()
|
||||
for f in [-> a = 1]
|
||||
do (f) ->
|
||||
do f
|
||||
|
||||
eq a, 1
|
||||
|
||||
|
||||
# Comprehensions that mention arguments.
|
||||
list = [arguments: 10]
|
||||
args = for f in list -> f.arguments
|
||||
args = for f in list
|
||||
do (f) ->
|
||||
f.arguments
|
||||
|
||||
eq args[0], 10
|
||||
|
|
Loading…
Reference in a new issue