mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Fixing inconsistencies for index variables
See the tests added to test_comprehensions.coffee. Previously, after `for i in [1..3]`, i was 4. Also, index variables were never set to any value in comprehensions containing both a closure and a break or return.
This commit is contained in:
parent
0e395569ee
commit
5005cb606f
13 changed files with 148 additions and 7 deletions
|
@ -36,6 +36,8 @@
|
|||
})();
|
||||
script = _j;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
};
|
||||
if (window.addEventListener) {
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
arg = _ref[_i];
|
||||
_result.push(invoke(arg));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
});
|
||||
};
|
||||
|
@ -64,6 +66,8 @@
|
|||
desc = task.description ? ("# " + (task.description)) : '';
|
||||
puts("cake " + name + spaces + " " + desc);
|
||||
}
|
||||
|
||||
|
||||
return switches.length ? puts(oparse.help()) : undefined;
|
||||
};
|
||||
missingTask = function(task) {
|
||||
|
|
|
@ -70,6 +70,8 @@
|
|||
file = files[_k];
|
||||
_result2.push(compile(path.join(source, file)));
|
||||
}
|
||||
|
||||
|
||||
return _result2;
|
||||
});
|
||||
} else if (topLevel || path.extname(source) === '.coffee') {
|
||||
|
@ -86,6 +88,8 @@
|
|||
})();
|
||||
source = _j;
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
};
|
||||
compileScript = function(file, input, base) {
|
||||
|
@ -97,6 +101,8 @@
|
|||
req = _ref2[_i];
|
||||
require(helpers.starts(req, '.') ? fs.realpathSync(req) : req);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
try {
|
||||
t = (task = {
|
||||
|
@ -197,6 +203,8 @@
|
|||
return "[" + tag + " " + value + "]";
|
||||
})());
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
})();
|
||||
return puts(strings.join(' '));
|
||||
|
|
|
@ -604,15 +604,21 @@
|
|||
tokens.push(token);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (name === 'Root') {
|
||||
alt[1] = ("return " + (alt[1]));
|
||||
}
|
||||
return alt;
|
||||
})());
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
})();
|
||||
}
|
||||
|
||||
|
||||
exports.parser = new Parser({
|
||||
tokens: tokens.join(' '),
|
||||
bnf: grammar,
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return -1;
|
||||
}));
|
||||
exports.include = function(list, value) {
|
||||
|
@ -32,6 +34,8 @@
|
|||
_result.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
};
|
||||
exports.count = function(string, letter) {
|
||||
|
@ -51,6 +55,8 @@
|
|||
val = properties[key];
|
||||
object[key] = val;
|
||||
}
|
||||
|
||||
|
||||
return object;
|
||||
});
|
||||
exports.flatten = (flatten = function(array) {
|
||||
|
@ -64,6 +70,8 @@
|
|||
flattened.push(element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return flattened;
|
||||
});
|
||||
exports.del = function(obj, key) {
|
||||
|
|
|
@ -6,4 +6,6 @@
|
|||
val = _ref[key];
|
||||
(exports[key] = val);
|
||||
}
|
||||
|
||||
|
||||
}).call(this);
|
||||
|
|
|
@ -226,6 +226,8 @@
|
|||
}
|
||||
tokens.push(['+', '+']);
|
||||
}
|
||||
|
||||
|
||||
tokens.pop();
|
||||
if ((((_ref4 = tokens[0]) != null) ? _ref4[0] : undefined) !== 'STRING') {
|
||||
this.tokens.push(['STRING', '""'], ['+', '+']);
|
||||
|
@ -480,6 +482,8 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (!levels.length) {
|
||||
break;
|
||||
|
@ -550,6 +554,8 @@
|
|||
this.token('STRING', this.makeString(value, '"', heredoc));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (interpolated) {
|
||||
this.token(')', ')');
|
||||
}
|
||||
|
@ -600,6 +606,8 @@
|
|||
})) {
|
||||
COFFEE_KEYWORDS.push(op);
|
||||
}
|
||||
|
||||
|
||||
RESERVED = ['case', 'default', 'do', 'function', 'var', 'void', 'with', 'const', 'let', 'enum', 'export', 'import', 'native', '__hasProp', '__extends', '__slice'];
|
||||
JS_FORBIDDEN = JS_KEYWORDS.concat(RESERVED);
|
||||
IDENTIFIER = /^([$A-Za-z_][$\w]*)([^\n\S]*:(?!:))?/;
|
||||
|
|
66
lib/nodes.js
66
lib/nodes.js
|
@ -58,6 +58,8 @@
|
|||
node = pair[i];
|
||||
(pair[i] = node.compile(o));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return pair;
|
||||
};
|
||||
|
@ -106,6 +108,8 @@
|
|||
child = _ref2[_i];
|
||||
_result.push(child.toString(idt + TAB));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this).join('');
|
||||
klass = override || this.constructor.name + (this.soakNode ? '?' : '');
|
||||
|
@ -126,8 +130,12 @@
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
};
|
||||
Base.prototype.collectChildren = function() {
|
||||
|
@ -208,6 +216,8 @@
|
|||
node = _ref2[_i];
|
||||
_result.push(this.compileExpression(node, merge(o)));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this).join('\n');
|
||||
};
|
||||
|
@ -411,6 +421,8 @@
|
|||
prop = props[_i];
|
||||
(code += prop.compile(o));
|
||||
}
|
||||
|
||||
|
||||
return code;
|
||||
};
|
||||
Value.prototype.unfoldSoak = function(o) {
|
||||
|
@ -436,6 +448,8 @@
|
|||
return ifn;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
};
|
||||
return Value;
|
||||
|
@ -542,6 +556,8 @@
|
|||
}
|
||||
ifn = If.unfoldSoak(o, call, 'variable');
|
||||
}
|
||||
|
||||
|
||||
return ifn;
|
||||
};
|
||||
Call.prototype.compileNode = function(o) {
|
||||
|
@ -556,12 +572,16 @@
|
|||
return this.compileSplat(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
args = (function() {
|
||||
_result = [];
|
||||
for (_j = 0, _len2 = (_ref4 = this.args).length; _j < _len2; _j++) {
|
||||
arg = _ref4[_j];
|
||||
_result.push((arg.parenthetical = true) && arg.compile(o));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this).join(', ');
|
||||
return this.isSuper ? this.compileSuper(args, o) : ("" + (this.prefix()) + (this.variable.compile(o)) + "(" + args + ")");
|
||||
|
@ -792,6 +812,8 @@
|
|||
_result.push(prop);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this);
|
||||
lastNoncom = last(nonComments);
|
||||
|
@ -810,6 +832,8 @@
|
|||
return indent + prop.compile(o) + join;
|
||||
}).call(this));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this);
|
||||
props = props.join('');
|
||||
|
@ -824,6 +848,8 @@
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
return ObjectLiteral;
|
||||
|
@ -852,12 +878,16 @@
|
|||
return this.compileSplatLiteral(o);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
objects = [];
|
||||
for (i = 0, _len2 = (_ref3 = this.objects).length; i < _len2; i++) {
|
||||
obj = _ref3[i];
|
||||
code = obj.compile(o);
|
||||
objects.push(obj instanceof Comment ? ("\n" + code + "\n" + (o.indent)) : (i === this.objects.length - 1 ? code : code + ', '));
|
||||
}
|
||||
|
||||
|
||||
objects = objects.join('');
|
||||
return 0 < objects.indexOf('\n') ? ("[\n" + (o.indent) + objects + "\n" + (this.tab) + "]") : ("[" + objects + "]");
|
||||
};
|
||||
|
@ -869,6 +899,8 @@
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
return ArrayLiteral;
|
||||
|
@ -957,6 +989,8 @@
|
|||
}
|
||||
props.push(prop);
|
||||
}
|
||||
|
||||
|
||||
constructor.className = className.match(/[\w\d\$_]+$/);
|
||||
if (me) {
|
||||
constructor.body.unshift(new Literal("" + me + " = this"));
|
||||
|
@ -1082,6 +1116,8 @@
|
|||
}
|
||||
assigns.push(new Assign(obj, val).compile(otop));
|
||||
}
|
||||
|
||||
|
||||
if (!top) {
|
||||
assigns.push(valVar);
|
||||
}
|
||||
|
@ -1159,6 +1195,8 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
o.scope.startLevel();
|
||||
params = (function() {
|
||||
_result = [];
|
||||
|
@ -1166,6 +1204,8 @@
|
|||
param = params[_i];
|
||||
_result.push(param.compile(o));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
})();
|
||||
if (!(empty || this.noReturn)) {
|
||||
|
@ -1175,6 +1215,8 @@
|
|||
param = params[_i];
|
||||
(o.scope.parameter(param));
|
||||
}
|
||||
|
||||
|
||||
comm = this.comment ? this.comment.compile(o) + '\n' : '';
|
||||
if (this.className) {
|
||||
o.indent = this.idt(2);
|
||||
|
@ -1262,6 +1304,8 @@
|
|||
pos = this.trailings.length - idx;
|
||||
o.scope.assign(trailing.compile(o), "arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
return "" + name + " = " + (utility('slice')) + ".call(arguments, " + (this.index) + end + ")";
|
||||
};
|
||||
|
@ -1291,6 +1335,8 @@
|
|||
}
|
||||
args[++end] = i === 0 ? code : (".concat(" + code + ")");
|
||||
}
|
||||
|
||||
|
||||
return args.join('');
|
||||
};
|
||||
return Splat;
|
||||
|
@ -1492,6 +1538,8 @@
|
|||
item = _ref2[i];
|
||||
_result.push("" + (i ? this.obj2 : this.obj1) + " === " + (item.compile(o)));
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this);
|
||||
return "(" + (tests.join(' || ')) + ")";
|
||||
|
@ -1657,7 +1705,7 @@
|
|||
return '';
|
||||
};
|
||||
For.prototype.compileNode = function(o) {
|
||||
var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, range, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, varPart, vars;
|
||||
var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, range, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, unstepPart, varPart, vars;
|
||||
topLevel = del(o, 'top') && !this.returns;
|
||||
range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length;
|
||||
source = range ? this.source.base : this.source;
|
||||
|
@ -1689,6 +1737,7 @@
|
|||
}
|
||||
varPart = '';
|
||||
guardPart = '';
|
||||
unstepPart = '';
|
||||
body = Expressions.wrap([this.body]);
|
||||
idt1 = this.idt(1);
|
||||
if (range) {
|
||||
|
@ -1724,10 +1773,12 @@
|
|||
if (this.guard) {
|
||||
body = Expressions.wrap([new If(this.guard, body)]);
|
||||
}
|
||||
if (codeInBody && !body.containsPureStatement()) {
|
||||
if (codeInBody) {
|
||||
if (range) {
|
||||
body.unshift(new Literal("var " + name + " = " + ivar));
|
||||
}
|
||||
}
|
||||
if (codeInBody && !body.containsPureStatement()) {
|
||||
if (namePart) {
|
||||
body.unshift(new Literal("var " + namePart));
|
||||
}
|
||||
|
@ -1754,6 +1805,9 @@
|
|||
if (namePart) {
|
||||
varPart = ("" + idt1 + namePart + ";\n");
|
||||
}
|
||||
if (forPart && name === ivar) {
|
||||
unstepPart = this.step ? ("\n" + name + " -= " + (this.step.compile(o)) + ";") : ("\n" + name + "--;");
|
||||
}
|
||||
}
|
||||
if (this.object) {
|
||||
forPart = ("" + ivar + " in " + sourcePart);
|
||||
|
@ -1766,7 +1820,7 @@
|
|||
top: true
|
||||
}));
|
||||
vars = range ? name : ("" + name + ", " + ivar);
|
||||
return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + returnResult;
|
||||
return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}\n" + unstepPart + "\n" + returnResult;
|
||||
};
|
||||
return For;
|
||||
})();
|
||||
|
@ -1792,6 +1846,8 @@
|
|||
pair = _ref2[_i];
|
||||
pair[1].makeReturn();
|
||||
}
|
||||
|
||||
|
||||
if (this.otherwise) {
|
||||
this.otherwise.makeReturn();
|
||||
}
|
||||
|
@ -1813,11 +1869,15 @@
|
|||
}
|
||||
code += ("\n" + (this.idt(1)) + "case " + (condition.compile(o)) + ":");
|
||||
}
|
||||
|
||||
|
||||
code += ("\n" + (block.compile(o)));
|
||||
if (!(last(exprs) instanceof Return)) {
|
||||
code += ("\n" + idt + "break;");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (this.otherwise) {
|
||||
code += ("\n" + (this.idt(1)) + "default:\n" + (this.otherwise.compile(o)));
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (isOption && !matchedRule) {
|
||||
throw new Error("unrecognized option: " + arg);
|
||||
}
|
||||
|
@ -36,6 +38,8 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return options;
|
||||
};
|
||||
OptionParser.prototype.help = function() {
|
||||
|
@ -51,6 +55,8 @@
|
|||
letPart = rule.shortFlag ? rule.shortFlag + ', ' : ' ';
|
||||
lines.push(' ' + letPart + rule.longFlag + spaces + rule.description);
|
||||
}
|
||||
|
||||
|
||||
return "\n" + (lines.join('\n')) + "\n";
|
||||
};
|
||||
return OptionParser;
|
||||
|
@ -71,6 +77,8 @@
|
|||
return buildRule.apply(buildRule, tuple);
|
||||
})());
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
};
|
||||
buildRule = function(shortFlag, longFlag, description, options) {
|
||||
|
@ -98,10 +106,14 @@
|
|||
l = _ref[_j];
|
||||
result.push('-' + l);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
result.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
};
|
||||
}).call(this);
|
||||
|
|
|
@ -90,6 +90,8 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return i ? this.tokens.splice(0, i) : undefined;
|
||||
};
|
||||
exports.Rewriter.prototype.removeMidExpressionNewlines = function() {
|
||||
|
@ -296,6 +298,8 @@
|
|||
throw Error("too many " + (token[1]) + " on line " + (token[2] + 1));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
});
|
||||
unclosed = (function() {
|
||||
|
@ -306,6 +310,8 @@
|
|||
_result.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
})();
|
||||
if (unclosed.length) {
|
||||
|
@ -319,6 +325,8 @@
|
|||
for (key in INVERSES) {
|
||||
(debt[key] = 0);
|
||||
}
|
||||
|
||||
|
||||
return this.scanTokens(function(token, i, tokens) {
|
||||
var inv, match, mtag, oppos, tag, val;
|
||||
if (include(EXPRESSION_START, tag = token[0])) {
|
||||
|
@ -366,6 +374,8 @@
|
|||
EXPRESSION_START.push(INVERSES[rite] = left);
|
||||
EXPRESSION_END.push(INVERSES[left] = rite);
|
||||
}
|
||||
|
||||
|
||||
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
|
||||
IMPLICIT_FUNC = ['IDENTIFIER', 'SUPER', ')', 'CALL_END', ']', 'INDEX_END', '@', 'THIS'];
|
||||
IMPLICIT_CALL = ['IDENTIFIER', 'NUMBER', 'STRING', 'JS', 'REGEX', 'NEW', 'PARAM_START', 'CLASS', 'IF', 'UNLESS', 'TRY', 'SWITCH', 'THIS', 'BOOL', 'UNARY', '@', '->', '=>', '[', '(', '{', '--', '++'];
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
_result.push(vars[name] = 'reuse');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
};
|
||||
Scope.prototype.find = function(name, options) {
|
||||
|
@ -53,6 +55,8 @@
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
Scope.prototype.parameter = function(name) {
|
||||
|
@ -108,6 +112,8 @@
|
|||
_result.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
}).call(this).sort();
|
||||
};
|
||||
|
@ -121,6 +127,8 @@
|
|||
_result.push("" + key + " = " + (val.value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _result;
|
||||
};
|
||||
Scope.prototype.compiledDeclarations = function() {
|
||||
|
|
|
@ -1428,6 +1428,7 @@ exports.For = class For extends Base
|
|||
nvar = scope.freeVariable 'i' if name and not range and codeInBody
|
||||
varPart = ''
|
||||
guardPart = ''
|
||||
unstepPart = ''
|
||||
body = Expressions.wrap([@body])
|
||||
idt1 = @idt 1
|
||||
if range
|
||||
|
@ -1452,8 +1453,9 @@ exports.For = class For extends Base
|
|||
body = Push.wrap(rvar, body) unless topLevel
|
||||
if @guard
|
||||
body = Expressions.wrap([new If(@guard, body)])
|
||||
if codeInBody and not body.containsPureStatement()
|
||||
if codeInBody
|
||||
body.unshift new Literal "var #{name} = #{ivar}" if range
|
||||
if codeInBody and not body.containsPureStatement()
|
||||
body.unshift new Literal "var #{namePart}" if namePart
|
||||
body.unshift new Literal "var #{index} = #{ivar}" if index
|
||||
lastLine = body.expressions.pop()
|
||||
|
@ -1466,6 +1468,8 @@ exports.For = class For extends Base
|
|||
body.push new Assign new Literal(name), new Literal nvar or ivar if name
|
||||
else
|
||||
varPart = "#{idt1}#{namePart};\n" if namePart
|
||||
if forPart and name is ivar
|
||||
unstepPart = if @step then "\n#{name} -= #{ @step.compile(o) };" else "\n#{name}--;"
|
||||
if @object
|
||||
forPart = "#{ivar} in #{sourcePart}"
|
||||
guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw
|
||||
|
@ -1474,7 +1478,9 @@ exports.For = class For extends Base
|
|||
"""
|
||||
#{resultPart}#{@tab}for (#{forPart}) {#{guardPart}
|
||||
#{varPart}#{body}
|
||||
#{@tab}}#{returnResult}
|
||||
#{@tab}}
|
||||
#{unstepPart}
|
||||
#{returnResult}
|
||||
"""
|
||||
|
||||
#### Switch
|
||||
|
|
|
@ -23,6 +23,8 @@ negs = negs[0..2]
|
|||
result = nums.concat(negs).join(', ')
|
||||
|
||||
ok result is '3, 6, 9, -20, -19, -18'
|
||||
ok i is 3
|
||||
ok x is -10
|
||||
|
||||
|
||||
# With range comprehensions, you can loop in steps.
|
||||
|
@ -70,17 +72,22 @@ ok obj.one() is "I'm one"
|
|||
ok obj.two() is "I'm two"
|
||||
ok obj.three() is "I'm three"
|
||||
|
||||
i = 0
|
||||
for i in [1..3]
|
||||
-> 'func'
|
||||
break if false
|
||||
ok i is 3
|
||||
|
||||
|
||||
# Ensure that local variables are closed over for range comprehensions.
|
||||
funcs = for i in [1..3]
|
||||
-> -i
|
||||
|
||||
ok (func() for func in funcs).join(' ') is '-1 -2 -3'
|
||||
ok i is 3
|
||||
|
||||
|
||||
# Ensure that closing over local variables doesn't break scoping laws.
|
||||
ok i is 3
|
||||
|
||||
for i in [0]
|
||||
count = 0
|
||||
i = 50
|
||||
|
|
Loading…
Add table
Reference in a new issue