#713: destructuring assignment is no longer statement and correctly returns RHS value
This commit is contained in:
parent
b2313beaf4
commit
7450df8104
|
@ -13,9 +13,7 @@
|
|||
task: function(name, description, action) {
|
||||
var _ref;
|
||||
if (!(action)) {
|
||||
_ref = [description, action];
|
||||
action = _ref[0];
|
||||
description = _ref[1];
|
||||
_ref = [description, action], action = _ref[0], description = _ref[1];
|
||||
}
|
||||
return (tasks[name] = {
|
||||
name: name,
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
(function() {
|
||||
var Lexer, _ref, compile, fs, lexer, parser, path;
|
||||
var Lexer, compile, fs, lexer, parser, path;
|
||||
path = require('path');
|
||||
_ref = require('./lexer');
|
||||
Lexer = _ref.Lexer;
|
||||
_ref = require('./parser');
|
||||
parser = _ref.parser;
|
||||
Lexer = require('./lexer').Lexer;
|
||||
parser = require('./parser').parser;
|
||||
if (require.extensions) {
|
||||
fs = require('fs');
|
||||
require.extensions['.coffee'] = function(module, filename) {
|
||||
|
|
|
@ -5,11 +5,8 @@
|
|||
optparse = require('./optparse');
|
||||
CoffeeScript = require('./coffee-script');
|
||||
helpers = require('./helpers');
|
||||
_ref = require('child_process');
|
||||
spawn = _ref.spawn;
|
||||
exec = _ref.exec;
|
||||
_ref = require('events');
|
||||
EventEmitter = _ref.EventEmitter;
|
||||
_ref = require('child_process'), spawn = _ref.spawn, exec = _ref.exec;
|
||||
EventEmitter = require('events').EventEmitter;
|
||||
helpers.extend(CoffeeScript, new EventEmitter);
|
||||
global.CoffeeScript = CoffeeScript;
|
||||
BANNER = 'coffee compiles CoffeeScript source files into JavaScript.\n\nUsage:\n coffee path/to/script.coffee';
|
||||
|
@ -197,9 +194,7 @@
|
|||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
token = _ref2[_i];
|
||||
_result.push((function() {
|
||||
_ref3 = [token[0], token[1].toString().replace(/\n/, '\\n')];
|
||||
tag = _ref3[0];
|
||||
value = _ref3[1];
|
||||
_ref3 = [token[0], token[1].toString().replace(/\n/, '\\n')], tag = _ref3[0], value = _ref3[1];
|
||||
return "[" + (tag) + " " + (value) + "]";
|
||||
})());
|
||||
}
|
||||
|
|
37
lib/lexer.js
37
lib/lexer.js
|
@ -1,14 +1,8 @@
|
|||
(function() {
|
||||
var ASSIGNED, CALLABLE, CODE, COFFEE_ALIASES, COFFEE_KEYWORDS, COMMENT, COMPARE, COMPOUND_ASSIGN, CONVERSIONS, HEREDOC, HEREDOC_INDENT, IDENTIFIER, JSTOKEN, JS_FORBIDDEN, JS_KEYWORDS, LINE_BREAK, LOGIC, Lexer, MATH, MULTILINER, MULTI_DENT, NEXT_CHARACTER, NOT_REGEX, NO_NEWLINE, NUMBER, OPERATOR, REGEX_END, REGEX_ESCAPE, REGEX_INTERPOLATION, REGEX_START, RESERVED, Rewriter, SHIFT, SIMPLESTR, UNARY, WHITESPACE, _ref, compact, count, include, last, starts;
|
||||
var __slice = Array.prototype.slice;
|
||||
_ref = require('./rewriter');
|
||||
Rewriter = _ref.Rewriter;
|
||||
_ref = require('./helpers');
|
||||
include = _ref.include;
|
||||
count = _ref.count;
|
||||
starts = _ref.starts;
|
||||
compact = _ref.compact;
|
||||
last = _ref.last;
|
||||
Rewriter = require('./rewriter').Rewriter;
|
||||
_ref = require('./helpers'), include = _ref.include, count = _ref.count, starts = _ref.starts, compact = _ref.compact, last = _ref.last;
|
||||
exports.Lexer = (function() {
|
||||
Lexer = function() {};
|
||||
Lexer.prototype.tokenize = function(code, options) {
|
||||
|
@ -142,9 +136,7 @@
|
|||
if (!(match = this.chunk.match(COMMENT))) {
|
||||
return false;
|
||||
}
|
||||
_ref2 = match;
|
||||
comment = _ref2[0];
|
||||
here = _ref2[1];
|
||||
_ref2 = match, comment = _ref2[0], here = _ref2[1];
|
||||
this.line += count(comment, '\n');
|
||||
this.i += comment.length;
|
||||
if (here) {
|
||||
|
@ -293,9 +285,7 @@
|
|||
Lexer.prototype.literalToken = function() {
|
||||
var _ref2, match, prev, space, spaced, tag, val, value;
|
||||
if (match = this.chunk.match(OPERATOR)) {
|
||||
_ref2 = match;
|
||||
value = _ref2[0];
|
||||
space = _ref2[1];
|
||||
_ref2 = match, value = _ref2[0], space = _ref2[1];
|
||||
if (CODE.test(value)) {
|
||||
this.tagParameters();
|
||||
}
|
||||
|
@ -373,9 +363,7 @@
|
|||
};
|
||||
Lexer.prototype.sanitizeHeredoc = function(doc, options) {
|
||||
var _ref2, attempt, herecomment, indent, match;
|
||||
_ref2 = options;
|
||||
indent = _ref2.indent;
|
||||
herecomment = _ref2.herecomment;
|
||||
_ref2 = options, indent = _ref2.indent, herecomment = _ref2.herecomment;
|
||||
if (herecomment && !include(doc, '\n')) {
|
||||
return doc;
|
||||
}
|
||||
|
@ -446,9 +434,7 @@
|
|||
_ref2 = delimited;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
pair = _ref2[_i];
|
||||
_ref3 = pair;
|
||||
open = _ref3[0];
|
||||
close = _ref3[1];
|
||||
_ref3 = pair, open = _ref3[0], close = _ref3[1];
|
||||
if (levels.length && starts(str, close, i) && last(levels) === pair) {
|
||||
levels.pop();
|
||||
i += close.length - 1;
|
||||
|
@ -478,9 +464,7 @@
|
|||
};
|
||||
Lexer.prototype.interpolateString = function(str, options) {
|
||||
var _len, _ref2, _ref3, end, escapeQuotes, escaped, expr, heredoc, i, idx, inner, interpolated, lexer, nested, pi, push, quote, s, tag, tok, token, tokens, value;
|
||||
_ref2 = options || {};
|
||||
heredoc = _ref2.heredoc;
|
||||
escapeQuotes = _ref2.escapeQuotes;
|
||||
_ref2 = options || {}, heredoc = _ref2.heredoc, escapeQuotes = _ref2.escapeQuotes;
|
||||
quote = str.charAt(0);
|
||||
if (quote !== '"' || str.length < 3) {
|
||||
return this.token('STRING', str);
|
||||
|
@ -533,14 +517,11 @@
|
|||
if (interpolated) {
|
||||
this.token('(', '(');
|
||||
}
|
||||
_ref2 = tokens;
|
||||
push = _ref2.push;
|
||||
push = tokens.push;
|
||||
_ref2 = tokens;
|
||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||
token = _ref2[i];
|
||||
_ref3 = token;
|
||||
tag = _ref3[0];
|
||||
value = _ref3[1];
|
||||
_ref3 = token, tag = _ref3[0], value = _ref3[1];
|
||||
if (tag === 'TOKENS') {
|
||||
push.apply(this.tokens, value);
|
||||
} else if (tag === 'STRING' && escapeQuotes) {
|
||||
|
|
197
lib/nodes.js
197
lib/nodes.js
|
@ -8,18 +8,8 @@
|
|||
if (typeof parent.extended === "function") parent.extended(child);
|
||||
child.__super__ = parent.prototype;
|
||||
};
|
||||
_ref = require('./scope');
|
||||
Scope = _ref.Scope;
|
||||
_ref = require('./helpers');
|
||||
compact = _ref.compact;
|
||||
flatten = _ref.flatten;
|
||||
merge = _ref.merge;
|
||||
del = _ref.del;
|
||||
include = _ref.include;
|
||||
indexOf = _ref.indexOf;
|
||||
starts = _ref.starts;
|
||||
ends = _ref.ends;
|
||||
last = _ref.last;
|
||||
Scope = require('./scope').Scope;
|
||||
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, merge = _ref.merge, del = _ref.del, include = _ref.include, indexOf = _ref.indexOf, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
|
||||
YES = function() {
|
||||
return true;
|
||||
};
|
||||
|
@ -264,7 +254,8 @@
|
|||
return this.isStatement() ? this : LiteralNode.__super__.makeReturn.call(this);
|
||||
};
|
||||
LiteralNode.prototype.isStatement = function() {
|
||||
return this.value === 'break' || this.value === 'continue' || this.value === 'debugger';
|
||||
var _ref2;
|
||||
return ('break' === (_ref2 = this.value) || 'continue' === _ref2 || 'debugger' === _ref2);
|
||||
};
|
||||
LiteralNode.prototype.isPureStatement = LiteralNode.prototype.isStatement;
|
||||
LiteralNode.prototype.isComplex = NO;
|
||||
|
@ -355,17 +346,13 @@
|
|||
var _len, _ref2, _ref3, copy, first, i, index, indexVar, prop;
|
||||
copy = new ValueNode(this.base, this.properties.slice(0));
|
||||
if (this.base.isComplex()) {
|
||||
_ref2 = this.base.compileReference(o);
|
||||
this.base = _ref2[0];
|
||||
copy.base = _ref2[1];
|
||||
_ref2 = this.base.compileReference(o), this.base = _ref2[0], copy.base = _ref2[1];
|
||||
}
|
||||
_ref2 = copy.properties;
|
||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||
prop = _ref2[i];
|
||||
if (prop instanceof IndexNode && prop.index.isComplex()) {
|
||||
_ref3 = prop.index.compileReference(o);
|
||||
index = _ref3[0];
|
||||
indexVar = _ref3[1];
|
||||
_ref3 = prop.index.compileReference(o), index = _ref3[0], indexVar = _ref3[1];
|
||||
this.properties[i] = (first = new IndexNode(index));
|
||||
copy.properties[i] = new IndexNode(indexVar);
|
||||
if (prop.soakNode) {
|
||||
|
@ -393,9 +380,7 @@
|
|||
}
|
||||
}
|
||||
if (hasSoak && this.isComplex()) {
|
||||
_ref2 = this.cacheIndexes(o);
|
||||
me = _ref2[0];
|
||||
copy = _ref2[1];
|
||||
_ref2 = this.cacheIndexes(o), me = _ref2[0], copy = _ref2[1];
|
||||
}
|
||||
if (this.parenthetical && !props.length) {
|
||||
this.base.parenthetical = true;
|
||||
|
@ -494,17 +479,13 @@
|
|||
if (this.exist) {
|
||||
if (this.variable instanceof ValueNode && last(this.variable.properties) instanceof AccessorNode) {
|
||||
methodAccessor = this.variable.properties.pop();
|
||||
_ref2 = this.variable.compileReference(o);
|
||||
first = _ref2[0];
|
||||
meth = _ref2[1];
|
||||
_ref2 = this.variable.compileReference(o), first = _ref2[0], meth = _ref2[1];
|
||||
this.first = new ValueNode(first, [methodAccessor]).compile(o);
|
||||
this.meth = new ValueNode(meth, [methodAccessor]).compile(o);
|
||||
} else {
|
||||
_ref2 = this.variable.compileReference(o, {
|
||||
precompile: true
|
||||
});
|
||||
this.first = _ref2[0];
|
||||
this.meth = _ref2[1];
|
||||
}), this.first = _ref2[0], this.meth = _ref2[1];
|
||||
}
|
||||
this.first = ("(typeof " + (this.first) + " === \"function\" ? ");
|
||||
this.last = " : undefined)";
|
||||
|
@ -646,17 +627,11 @@
|
|||
});
|
||||
_ref2 = this.from.compileReference(o, {
|
||||
precompile: true
|
||||
});
|
||||
this.from = _ref2[0];
|
||||
this.fromVar = _ref2[1];
|
||||
}), this.from = _ref2[0], this.fromVar = _ref2[1];
|
||||
_ref2 = this.to.compileReference(o, {
|
||||
precompile: true
|
||||
});
|
||||
this.to = _ref2[0];
|
||||
this.toVar = _ref2[1];
|
||||
_ref2 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)];
|
||||
this.fromNum = _ref2[0];
|
||||
this.toNum = _ref2[1];
|
||||
}), this.to = _ref2[0], this.toVar = _ref2[1];
|
||||
_ref2 = [this.fromVar.match(SIMPLENUM), this.toVar.match(SIMPLENUM)], this.fromNum = _ref2[0], this.toNum = _ref2[1];
|
||||
parts = [];
|
||||
if (this.from !== this.fromVar) {
|
||||
parts.push(this.from);
|
||||
|
@ -685,9 +660,7 @@
|
|||
};
|
||||
RangeNode.prototype.compileSimple = function(o) {
|
||||
var _ref2, from, idx, step, to;
|
||||
_ref2 = [+this.fromNum, +this.toNum];
|
||||
from = _ref2[0];
|
||||
to = _ref2[1];
|
||||
_ref2 = [+this.fromNum, +this.toNum], from = _ref2[0], to = _ref2[1];
|
||||
idx = del(o, 'index');
|
||||
step = del(o, 'step');
|
||||
step && (step = ("" + (idx) + " += " + (step.compile(o))));
|
||||
|
@ -872,9 +845,7 @@
|
|||
_ref2 = this.properties;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
prop = _ref2[_i];
|
||||
_ref3 = [prop.variable, prop.value];
|
||||
pvar = _ref3[0];
|
||||
func = _ref3[1];
|
||||
_ref3 = [prop.variable, prop.value], pvar = _ref3[0], func = _ref3[1];
|
||||
if (pvar && pvar.base.value === 'constructor' && func instanceof CodeNode) {
|
||||
if (func.bound) {
|
||||
throw new Error("cannot define a constructor as a bound function.");
|
||||
|
@ -937,28 +908,20 @@
|
|||
AssignNode.prototype.isValue = function() {
|
||||
return this.variable instanceof ValueNode;
|
||||
};
|
||||
AssignNode.prototype.makeReturn = function() {
|
||||
if (this.isStatement()) {
|
||||
return new Expressions([this, new ReturnNode(this.variable)]);
|
||||
} else {
|
||||
return AssignNode.__super__.makeReturn.call(this);
|
||||
}
|
||||
};
|
||||
AssignNode.prototype.isStatement = function() {
|
||||
return this.isValue() && (this.variable.isArray() || this.variable.isObject());
|
||||
};
|
||||
AssignNode.prototype.compileNode = function(o) {
|
||||
var end, match, name, proto, stmt, top, val;
|
||||
top = del(o, 'top');
|
||||
if (this.isStatement(o)) {
|
||||
var end, isValue, match, name, proto, stmt, top, val;
|
||||
if (isValue = this.isValue()) {
|
||||
if (this.variable.isArray() || this.variable.isObject()) {
|
||||
return this.compilePatternMatch(o);
|
||||
}
|
||||
if (this.isValue() && this.variable.isSplice()) {
|
||||
if (this.variable.isSplice()) {
|
||||
return this.compileSplice(o);
|
||||
}
|
||||
}
|
||||
top = del(o, 'top');
|
||||
stmt = del(o, 'asStatement');
|
||||
name = this.variable.compile(o);
|
||||
end = this.isValue() ? this.variable.last.replace(this.LEADING_DOT, '') : name;
|
||||
end = isValue ? this.variable.last.replace(this.LEADING_DOT, '') : name;
|
||||
match = name.match(this.PROTO_ASSIGN);
|
||||
proto = match && match[1];
|
||||
if (this.value instanceof CodeNode) {
|
||||
|
@ -973,7 +936,7 @@
|
|||
if (this.context === 'object') {
|
||||
return ("" + (name) + ": " + (val));
|
||||
}
|
||||
if (!(this.isValue() && (this.variable.hasProperties() || this.variable.namespaced))) {
|
||||
if (!(isValue && (this.variable.hasProperties() || this.variable.namespaced))) {
|
||||
o.scope.find(name);
|
||||
}
|
||||
val = ("" + (name) + " = " + (val));
|
||||
|
@ -983,22 +946,41 @@
|
|||
return top || this.parenthetical ? val : ("(" + (val) + ")");
|
||||
};
|
||||
AssignNode.prototype.compilePatternMatch = function(o) {
|
||||
var _len, _ref2, _ref3, accessClass, assigns, code, i, idx, isString, obj, oindex, olength, splat, val, valVar, value;
|
||||
var _len, _ref2, _ref3, accessClass, assigns, code, i, idx, isObject, obj, objects, oindex, olength, otop, splat, top, val, valVar, value;
|
||||
if ((value = this.value).isStatement(o)) {
|
||||
value = ClosureNode.wrap(value);
|
||||
}
|
||||
objects = this.variable.base.objects;
|
||||
if (!(objects.length)) {
|
||||
return value.compile(o);
|
||||
}
|
||||
if ((isObject = this.variable.isObject()) && objects.length === 1) {
|
||||
if ((obj = objects[0]) instanceof AssignNode) {
|
||||
_ref2 = obj, idx = _ref2.variable.base, obj = _ref2.value;
|
||||
} else {
|
||||
idx = obj;
|
||||
}
|
||||
if (!(value instanceof ValueNode)) {
|
||||
value = new ValueNode(value);
|
||||
}
|
||||
accessClass = IDENTIFIER.test(idx.value) ? AccessorNode : IndexNode;
|
||||
value.properties.push(new accessClass(idx));
|
||||
return new AssignNode(obj, value).compile(o);
|
||||
}
|
||||
top = del(o, 'top');
|
||||
otop = merge(o, {
|
||||
top: true
|
||||
});
|
||||
valVar = o.scope.freeVariable('ref');
|
||||
value = this.value.isStatement(o) ? ClosureNode.wrap(this.value) : this.value;
|
||||
assigns = [("" + (this.tab) + (valVar) + " = " + (value.compile(o)) + ";")];
|
||||
o.top = true;
|
||||
o.asStatement = true;
|
||||
assigns = [("" + (valVar) + " = " + (value.compile(o)))];
|
||||
splat = false;
|
||||
_ref2 = this.variable.base.objects;
|
||||
_ref2 = objects;
|
||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||
obj = _ref2[i];
|
||||
idx = i;
|
||||
if (this.variable.isObject()) {
|
||||
if (isObject) {
|
||||
if (obj instanceof AssignNode) {
|
||||
_ref3 = [obj.value, obj.variable.base];
|
||||
obj = _ref3[0];
|
||||
idx = _ref3[1];
|
||||
_ref3 = [obj.value, obj.variable.base], obj = _ref3[0], idx = _ref3[1];
|
||||
} else {
|
||||
idx = obj;
|
||||
}
|
||||
|
@ -1006,10 +988,9 @@
|
|||
if (!(obj instanceof ValueNode || obj instanceof SplatNode)) {
|
||||
throw new Error('pattern matching must use only identifiers on the left-hand side.');
|
||||
}
|
||||
isString = idx.value && idx.value.match(IS_STRING);
|
||||
accessClass = isString || this.variable.isArray() ? IndexNode : AccessorNode;
|
||||
if (obj instanceof SplatNode && !splat) {
|
||||
val = literal(obj.compileValue(o, valVar, oindex = indexOf(this.variable.base.objects, obj), (olength = this.variable.base.objects.length) - oindex - 1));
|
||||
accessClass = isObject && IDENTIFIER.test(idx.value) ? AccessorNode : IndexNode;
|
||||
if (!splat && obj instanceof SplatNode) {
|
||||
val = literal(obj.compileValue(o, valVar, oindex = indexOf(objects, obj), (olength = objects.length) - oindex - 1));
|
||||
splat = true;
|
||||
} else {
|
||||
if (typeof idx !== 'object') {
|
||||
|
@ -1017,10 +998,13 @@
|
|||
}
|
||||
val = new ValueNode(literal(valVar), [new accessClass(idx)]);
|
||||
}
|
||||
assigns.push(new AssignNode(obj, val).compile(o));
|
||||
assigns.push(new AssignNode(obj, val).compile(otop));
|
||||
}
|
||||
code = assigns.join("\n");
|
||||
return code;
|
||||
if (!(top)) {
|
||||
assigns.push(valVar);
|
||||
}
|
||||
code = assigns.join(', ');
|
||||
return top || this.parenthetical ? code : ("(" + (code) + ")");
|
||||
};
|
||||
AssignNode.prototype.compileSplice = function(o) {
|
||||
var from, l, name, plus, range, to, val;
|
||||
|
@ -1076,11 +1060,8 @@
|
|||
splat.trailings.push(param);
|
||||
} else {
|
||||
if (param.attach) {
|
||||
_ref3 = param;
|
||||
value = _ref3.value;
|
||||
_ref3 = [literal(o.scope.freeVariable('arg')), param.splat];
|
||||
param = _ref3[0];
|
||||
param.splat = _ref3[1];
|
||||
value = param.value;
|
||||
_ref3 = [literal(o.scope.freeVariable('arg')), param.splat], param = _ref3[0], param.splat = _ref3[1];
|
||||
this.body.unshift(new AssignNode(new ValueNode(literal('this'), [new AccessorNode(value)]), param));
|
||||
}
|
||||
if (param.splat) {
|
||||
|
@ -1117,9 +1098,7 @@
|
|||
}
|
||||
return top ? ("(" + (func) + ")") : func;
|
||||
};
|
||||
CodeNode.prototype.topSensitive = function() {
|
||||
return true;
|
||||
};
|
||||
CodeNode.prototype.topSensitive = YES;
|
||||
CodeNode.prototype.traverseChildren = function(crossScope, func) {
|
||||
return crossScope ? CodeNode.__super__.traverseChildren.call(this, crossScope, func) : null;
|
||||
};
|
||||
|
@ -1141,9 +1120,8 @@
|
|||
return this.value.compile(o);
|
||||
};
|
||||
ParamNode.prototype.toString = function() {
|
||||
var _ref2, name;
|
||||
_ref2 = this;
|
||||
name = _ref2.name;
|
||||
var name;
|
||||
name = this.name;
|
||||
if (this.attach) {
|
||||
name = '@' + name;
|
||||
}
|
||||
|
@ -1251,9 +1229,7 @@
|
|||
this.returns = true;
|
||||
return this;
|
||||
};
|
||||
WhileNode.prototype.topSensitive = function() {
|
||||
return true;
|
||||
};
|
||||
WhileNode.prototype.topSensitive = YES;
|
||||
WhileNode.prototype.compileNode = function(o) {
|
||||
var cond, post, pre, rvar, set, top;
|
||||
top = del(o, 'top') && !this.returns;
|
||||
|
@ -1364,13 +1340,8 @@
|
|||
OpNode.prototype.compileChain = function(o) {
|
||||
var _ref2, first, second, shared;
|
||||
shared = this.first.unwrap().second;
|
||||
_ref2 = shared.compileReference(o);
|
||||
this.first.second = _ref2[0];
|
||||
shared = _ref2[1];
|
||||
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)];
|
||||
first = _ref2[0];
|
||||
second = _ref2[1];
|
||||
shared = _ref2[2];
|
||||
_ref2 = shared.compileReference(o), this.first.second = _ref2[0], shared = _ref2[1];
|
||||
_ref2 = [this.first.compile(o), this.second.compile(o), shared.compile(o)], first = _ref2[0], second = _ref2[1], shared = _ref2[2];
|
||||
return "(" + (first) + ") && (" + (shared) + " " + (this.operator) + " " + (second) + ")";
|
||||
};
|
||||
OpNode.prototype.compileAssignment = function(o) {
|
||||
|
@ -1378,9 +1349,7 @@
|
|||
_ref2 = this.first.compileReference(o, {
|
||||
precompile: true,
|
||||
assignment: true
|
||||
});
|
||||
first = _ref2[0];
|
||||
firstVar = _ref2[1];
|
||||
}), first = _ref2[0], firstVar = _ref2[1];
|
||||
second = this.second.compile(o);
|
||||
if (this.second instanceof OpNode) {
|
||||
second = ("(" + (second) + ")");
|
||||
|
@ -1395,9 +1364,7 @@
|
|||
};
|
||||
OpNode.prototype.compileExistence = function(o) {
|
||||
var _ref2, ref, test;
|
||||
_ref2 = ExistenceNode.compileTest(o, this.first);
|
||||
test = _ref2[0];
|
||||
ref = _ref2[1];
|
||||
_ref2 = ExistenceNode.compileTest(o, this.first), test = _ref2[0], ref = _ref2[1];
|
||||
return "" + (test) + " ? " + (ref) + " : " + (this.second.compile(o));
|
||||
};
|
||||
OpNode.prototype.compileUnary = function(o) {
|
||||
|
@ -1428,9 +1395,7 @@
|
|||
var _ref2;
|
||||
_ref2 = this.object.compileReference(o, {
|
||||
precompile: true
|
||||
});
|
||||
this.obj1 = _ref2[0];
|
||||
this.obj2 = _ref2[1];
|
||||
}), this.obj1 = _ref2[0], this.obj2 = _ref2[1];
|
||||
return this.isArray() ? this.compileOrTest(o) : this.compileLoopTest(o);
|
||||
};
|
||||
InNode.prototype.compileOrTest = function(o) {
|
||||
|
@ -1449,12 +1414,8 @@
|
|||
var _ref2, i, l, prefix;
|
||||
_ref2 = this.array.compileReference(o, {
|
||||
precompile: true
|
||||
});
|
||||
this.arr1 = _ref2[0];
|
||||
this.arr2 = _ref2[1];
|
||||
_ref2 = [o.scope.freeVariable('i'), o.scope.freeVariable('len')];
|
||||
i = _ref2[0];
|
||||
l = _ref2[1];
|
||||
}), this.arr1 = _ref2[0], this.arr2 = _ref2[1];
|
||||
_ref2 = [o.scope.freeVariable('i'), o.scope.freeVariable('len')], i = _ref2[0], l = _ref2[1];
|
||||
prefix = this.obj1 !== this.obj2 ? this.obj1 + '; ' : '';
|
||||
return "(function(){ " + (prefix) + "for (var " + (i) + "=0, " + (l) + "=" + (this.arr1) + ".length; " + (i) + "<" + (l) + "; " + (i) + "++) { if (" + (this.arr2) + "[" + (i) + "] === " + (this.obj2) + ") return true; } return false; }).call(this)";
|
||||
};
|
||||
|
@ -1530,9 +1491,7 @@
|
|||
var _ref2, first, second;
|
||||
_ref2 = variable.compileReference(o, {
|
||||
precompile: true
|
||||
});
|
||||
first = _ref2[0];
|
||||
second = _ref2[1];
|
||||
}), first = _ref2[0], second = _ref2[1];
|
||||
return [("(typeof " + (first) + " !== \"undefined\" && " + (second) + " !== null)"), second];
|
||||
};
|
||||
return ExistenceNode;
|
||||
|
@ -1585,9 +1544,7 @@
|
|||
this.raw = !!source.raw;
|
||||
this.object = !!source.object;
|
||||
if (this.object) {
|
||||
_ref2 = [this.index, this.name];
|
||||
this.name = _ref2[0];
|
||||
this.index = _ref2[1];
|
||||
_ref2 = [this.index, this.name], this.name = _ref2[0], this.index = _ref2[1];
|
||||
}
|
||||
this.pattern = this.name instanceof ValueNode;
|
||||
if (this.index instanceof ValueNode) {
|
||||
|
@ -1743,9 +1700,7 @@
|
|||
_ref2 = this.cases;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
pair = _ref2[_i];
|
||||
_ref3 = pair;
|
||||
conditions = _ref3[0];
|
||||
block = _ref3[1];
|
||||
_ref3 = pair, conditions = _ref3[0], block = _ref3[1];
|
||||
exprs = block.expressions;
|
||||
_ref3 = flatten([conditions]);
|
||||
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
(function() {
|
||||
var BALANCED_PAIRS, EXPRESSION_CLOSE, EXPRESSION_END, EXPRESSION_START, IMPLICIT_BLOCK, IMPLICIT_CALL, IMPLICIT_END, IMPLICIT_FUNC, INVERSES, LINEBREAKS, Rewriter, SINGLE_CLOSERS, SINGLE_LINERS, _i, _len, _ref, _result, include, pair;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
_ref = require('./helpers');
|
||||
include = _ref.include;
|
||||
include = require('./helpers').include;
|
||||
exports.Rewriter = (function() {
|
||||
Rewriter = function() {};
|
||||
Rewriter.prototype.rewrite = function(tokens) {
|
||||
|
@ -55,25 +54,21 @@
|
|||
};
|
||||
Rewriter.prototype.adjustComments = function() {
|
||||
return this.scanTokens(function(token, i) {
|
||||
var _ref2, after, before, post, prev;
|
||||
var _ref, after, before, post, prev;
|
||||
if (token[0] !== 'HERECOMMENT') {
|
||||
return 1;
|
||||
}
|
||||
_ref2 = [this.tokens[i - 2], this.tokens[i - 1], this.tokens[i + 1], this.tokens[i + 2]];
|
||||
before = _ref2[0];
|
||||
prev = _ref2[1];
|
||||
post = _ref2[2];
|
||||
after = _ref2[3];
|
||||
_ref = [this.tokens[i - 2], this.tokens[i - 1], this.tokens[i + 1], this.tokens[i + 2]], before = _ref[0], prev = _ref[1], post = _ref[2], after = _ref[3];
|
||||
if (after && after[0] === 'INDENT') {
|
||||
this.tokens.splice(i + 2, 1);
|
||||
if (before && before[0] === 'OUTDENT' && post && (prev[0] === (_ref2 = post[0])) && (_ref2 === 'TERMINATOR')) {
|
||||
if (before && before[0] === 'OUTDENT' && post && (prev[0] === (_ref = post[0])) && (_ref === 'TERMINATOR')) {
|
||||
this.tokens.splice(i - 2, 1);
|
||||
} else {
|
||||
this.tokens.splice(i, 0, after);
|
||||
}
|
||||
} else if (prev && !('TERMINATOR' === (_ref2 = prev[0]) || 'INDENT' === _ref2 || 'OUTDENT' === _ref2)) {
|
||||
} else if (prev && !('TERMINATOR' === (_ref = prev[0]) || 'INDENT' === _ref || 'OUTDENT' === _ref)) {
|
||||
if (post && post[0] === 'TERMINATOR' && after && after[0] === 'OUTDENT') {
|
||||
(_ref2 = this.tokens).splice.apply(_ref2, [i + 2, 0].concat(this.tokens.splice(i, 2)));
|
||||
(_ref = this.tokens).splice.apply(_ref, [i + 2, 0].concat(this.tokens.splice(i, 2)));
|
||||
if (this.tokens[i + 2][0] !== 'TERMINATOR') {
|
||||
this.tokens.splice(i + 2, 0, ['TERMINATOR', "\n", prev[2]]);
|
||||
}
|
||||
|
@ -107,8 +102,8 @@
|
|||
var action, condition;
|
||||
if (token[0] === 'CALL_START') {
|
||||
condition = function(token, i) {
|
||||
var _ref2;
|
||||
return ((')' === (_ref2 = token[0]) || 'CALL_END' === _ref2)) || (token[0] === 'OUTDENT' && this.tokens[i - 1][0] === ')');
|
||||
var _ref;
|
||||
return ((')' === (_ref = token[0]) || 'CALL_END' === _ref)) || (token[0] === 'OUTDENT' && this.tokens[i - 1][0] === ')');
|
||||
};
|
||||
action = function(token, i) {
|
||||
var idx;
|
||||
|
@ -125,8 +120,8 @@
|
|||
var action, condition;
|
||||
if (token[0] === 'INDEX_START') {
|
||||
condition = function(token, i) {
|
||||
var _ref2;
|
||||
return (']' === (_ref2 = token[0]) || 'INDEX_END' === _ref2);
|
||||
var _ref;
|
||||
return (']' === (_ref = token[0]) || 'INDEX_END' === _ref);
|
||||
};
|
||||
action = function(token, i) {
|
||||
return (token[0] = 'INDEX_END');
|
||||
|
@ -158,15 +153,12 @@
|
|||
tok.generated = true;
|
||||
this.tokens.splice(idx, 0, tok);
|
||||
condition = function(token, i) {
|
||||
var _ref2, one, three, two;
|
||||
_ref2 = this.tokens.slice(i + 1, i + 4);
|
||||
one = _ref2[0];
|
||||
two = _ref2[1];
|
||||
three = _ref2[2];
|
||||
var _ref, one, three, two;
|
||||
_ref = this.tokens.slice(i + 1, i + 4), one = _ref[0], two = _ref[1], three = _ref[2];
|
||||
if ((this.tag(i + 1) === 'HERECOMMENT' || this.tag(i - 1) === 'HERECOMMENT')) {
|
||||
return false;
|
||||
}
|
||||
return ((('TERMINATOR' === (_ref2 = token[0]) || 'OUTDENT' === _ref2)) && !((two && two[0] === ':') || (one && one[0] === '@' && three && three[0] === ':'))) || (token[0] === ',' && one && (!('IDENTIFIER' === (_ref2 = one[0]) || 'STRING' === _ref2 || '@' === _ref2 || 'TERMINATOR' === _ref2 || 'OUTDENT' === _ref2)));
|
||||
return ((('TERMINATOR' === (_ref = token[0]) || 'OUTDENT' === _ref)) && !((two && two[0] === ':') || (one && one[0] === '@' && three && three[0] === ':'))) || (token[0] === ',' && one && (!('IDENTIFIER' === (_ref = one[0]) || 'STRING' === _ref || '@' === _ref || 'TERMINATOR' === _ref || 'OUTDENT' === _ref)));
|
||||
};
|
||||
action = function(token, i) {
|
||||
return this.tokens.splice(i, 0, ['}', '}', token[2]]);
|
||||
|
@ -181,7 +173,7 @@
|
|||
var classLine;
|
||||
classLine = false;
|
||||
return this.scanTokens(function(token, i) {
|
||||
var _ref2, action, callObject, condition, idx, next, prev, seenSingle;
|
||||
var _ref, action, callObject, condition, idx, next, prev, seenSingle;
|
||||
if (token[0] === 'CLASS') {
|
||||
classLine = true;
|
||||
}
|
||||
|
@ -199,14 +191,14 @@
|
|||
if (prev && !prev.spaced && token[0] === '?') {
|
||||
token.call = true;
|
||||
}
|
||||
if (prev && (prev.spaced && (include(IMPLICIT_FUNC, prev[0]) || prev.call) && include(IMPLICIT_CALL, token[0]) && !(token[0] === 'UNARY' && (('IN' === (_ref2 = this.tag(i + 1)) || 'OF' === _ref2 || 'INSTANCEOF' === _ref2)))) || callObject) {
|
||||
if (prev && (prev.spaced && (include(IMPLICIT_FUNC, prev[0]) || prev.call) && include(IMPLICIT_CALL, token[0]) && !(token[0] === 'UNARY' && (('IN' === (_ref = this.tag(i + 1)) || 'OF' === _ref || 'INSTANCEOF' === _ref)))) || callObject) {
|
||||
this.tokens.splice(i, 0, ['CALL_START', '(', token[2]]);
|
||||
condition = function(token, i) {
|
||||
var _ref2, post;
|
||||
var _ref, post;
|
||||
if (!seenSingle && token.fromThen) {
|
||||
return true;
|
||||
}
|
||||
if (('IF' === (_ref2 = token[0]) || 'ELSE' === _ref2 || 'UNLESS' === _ref2 || '->' === _ref2 || '=>' === _ref2)) {
|
||||
if (('IF' === (_ref = token[0]) || 'ELSE' === _ref || 'UNLESS' === _ref || '->' === _ref || '=>' === _ref)) {
|
||||
seenSingle = true;
|
||||
}
|
||||
post = this.tokens[i + 1];
|
||||
|
@ -227,20 +219,18 @@
|
|||
};
|
||||
Rewriter.prototype.addImplicitIndentation = function() {
|
||||
return this.scanTokens(function(token, i) {
|
||||
var _ref2, action, condition, indent, outdent, starter;
|
||||
var _ref, action, condition, indent, outdent, starter;
|
||||
if (token[0] === 'ELSE' && this.tag(i - 1) !== 'OUTDENT') {
|
||||
(_ref2 = this.tokens).splice.apply(_ref2, [i, 0].concat(this.indentation(token)));
|
||||
(_ref = this.tokens).splice.apply(_ref, [i, 0].concat(this.indentation(token)));
|
||||
return 2;
|
||||
}
|
||||
if (token[0] === 'CATCH' && (this.tag(i + 2) === 'TERMINATOR' || this.tag(i + 2) === 'FINALLY')) {
|
||||
(_ref2 = this.tokens).splice.apply(_ref2, [i + 2, 0].concat(this.indentation(token)));
|
||||
(_ref = this.tokens).splice.apply(_ref, [i + 2, 0].concat(this.indentation(token)));
|
||||
return 4;
|
||||
}
|
||||
if (include(SINGLE_LINERS, token[0]) && this.tag(i + 1) !== 'INDENT' && !(token[0] === 'ELSE' && this.tag(i + 1) === 'IF')) {
|
||||
starter = token[0];
|
||||
_ref2 = this.indentation(token);
|
||||
indent = _ref2[0];
|
||||
outdent = _ref2[1];
|
||||
_ref = this.indentation(token), indent = _ref[0], outdent = _ref[1];
|
||||
if (starter === 'THEN') {
|
||||
indent.fromThen = true;
|
||||
}
|
||||
|
@ -265,12 +255,12 @@
|
|||
};
|
||||
Rewriter.prototype.tagPostfixConditionals = function() {
|
||||
return this.scanTokens(function(token, i) {
|
||||
var _ref2, action, condition, original;
|
||||
if (('IF' === (_ref2 = token[0]) || 'UNLESS' === _ref2)) {
|
||||
var _ref, action, condition, original;
|
||||
if (('IF' === (_ref = token[0]) || 'UNLESS' === _ref)) {
|
||||
original = token;
|
||||
condition = function(token, i) {
|
||||
var _ref2;
|
||||
return ('TERMINATOR' === (_ref2 = token[0]) || 'INDENT' === _ref2);
|
||||
var _ref;
|
||||
return ('TERMINATOR' === (_ref = token[0]) || 'INDENT' === _ref);
|
||||
};
|
||||
action = function(token, i) {
|
||||
return token[0] !== 'INDENT' ? (original[0] = 'POST_' + original[0]) : null;
|
||||
|
@ -282,17 +272,15 @@
|
|||
});
|
||||
};
|
||||
Rewriter.prototype.ensureBalance = function(pairs) {
|
||||
var _ref2, _result, key, levels, line, open, openLine, unclosed, value;
|
||||
var _ref, _result, key, levels, line, open, openLine, unclosed, value;
|
||||
levels = {};
|
||||
openLine = {};
|
||||
this.scanTokens(function(token, i) {
|
||||
var _i, _len, _ref2, _ref3, close, open, pair;
|
||||
_ref2 = pairs;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
pair = _ref2[_i];
|
||||
_ref3 = pair;
|
||||
open = _ref3[0];
|
||||
close = _ref3[1];
|
||||
var _i, _len, _ref, _ref2, close, open, pair;
|
||||
_ref = pairs;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
pair = _ref[_i];
|
||||
_ref2 = pair, open = _ref2[0], close = _ref2[1];
|
||||
levels[open] || (levels[open] = 0);
|
||||
if (token[0] === open) {
|
||||
if (levels[open] === 0) {
|
||||
|
@ -310,10 +298,10 @@
|
|||
return 1;
|
||||
});
|
||||
unclosed = (function() {
|
||||
_result = []; _ref2 = levels;
|
||||
for (key in _ref2) {
|
||||
if (!__hasProp.call(_ref2, key)) continue;
|
||||
value = _ref2[key];
|
||||
_result = []; _ref = levels;
|
||||
for (key in _ref) {
|
||||
if (!__hasProp.call(_ref, key)) continue;
|
||||
value = _ref[key];
|
||||
if (value > 0) {
|
||||
_result.push(key);
|
||||
}
|
||||
|
@ -327,17 +315,17 @@
|
|||
}
|
||||
};
|
||||
Rewriter.prototype.rewriteClosingParens = function() {
|
||||
var _ref2, debt, key, stack, val;
|
||||
var _ref, debt, key, stack, val;
|
||||
stack = [];
|
||||
debt = {};
|
||||
_ref2 = INVERSES;
|
||||
for (key in _ref2) {
|
||||
if (!__hasProp.call(_ref2, key)) continue;
|
||||
val = _ref2[key];
|
||||
_ref = INVERSES;
|
||||
for (key in _ref) {
|
||||
if (!__hasProp.call(_ref, key)) continue;
|
||||
val = _ref[key];
|
||||
(debt[key] = 0);
|
||||
}
|
||||
return this.scanTokens(function(token, i) {
|
||||
var _ref3, inv, match, mtag, oppos, tag;
|
||||
var _ref2, inv, match, mtag, oppos, tag;
|
||||
tag = token[0];
|
||||
inv = INVERSES[token[0]];
|
||||
if (include(EXPRESSION_START, tag)) {
|
||||
|
@ -357,7 +345,7 @@
|
|||
}
|
||||
debt[mtag] += 1;
|
||||
val = [oppos, mtag === 'INDENT' ? match[1] : oppos];
|
||||
if ((this.tokens[(_ref3 = i + 2)] == null ? undefined : this.tokens[_ref3][0]) === mtag) {
|
||||
if ((this.tokens[(_ref2 = i + 2)] == null ? undefined : this.tokens[_ref2][0]) === mtag) {
|
||||
this.tokens.splice(i + 3, 0, val);
|
||||
stack.push(match);
|
||||
} else {
|
||||
|
|
50
lib/scope.js
50
lib/scope.js
|
@ -1,15 +1,11 @@
|
|||
(function() {
|
||||
var Scope, _ref, extend;
|
||||
var Scope, extend;
|
||||
var __hasProp = Object.prototype.hasOwnProperty;
|
||||
_ref = require('./helpers');
|
||||
extend = _ref.extend;
|
||||
extend = require('./helpers').extend;
|
||||
exports.Scope = (function() {
|
||||
Scope = function(parent, expressions, method) {
|
||||
var _ref2;
|
||||
_ref2 = [parent, expressions, method];
|
||||
this.parent = _ref2[0];
|
||||
this.expressions = _ref2[1];
|
||||
this.method = _ref2[2];
|
||||
var _ref;
|
||||
_ref = [parent, expressions, method], this.parent = _ref[0], this.expressions = _ref[1], this.method = _ref[2];
|
||||
this.variables = {};
|
||||
if (this.parent) {
|
||||
this.garbage = this.parent.garbage;
|
||||
|
@ -24,10 +20,10 @@
|
|||
return this.garbage.push([]);
|
||||
};
|
||||
Scope.prototype.endLevel = function() {
|
||||
var _i, _len, _ref2, _result, name;
|
||||
_result = []; _ref2 = this.garbage.pop();
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
name = _ref2[_i];
|
||||
var _i, _len, _ref, _result, name;
|
||||
_result = []; _ref = this.garbage.pop();
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
name = _ref[_i];
|
||||
if (this.variables[name] === 'var') {
|
||||
_result.push(this.variables[name] = 'reuse');
|
||||
}
|
||||
|
@ -42,11 +38,11 @@
|
|||
return false;
|
||||
};
|
||||
Scope.prototype.any = function(fn) {
|
||||
var _ref2, k, v;
|
||||
_ref2 = this.variables;
|
||||
for (v in _ref2) {
|
||||
if (!__hasProp.call(_ref2, v)) continue;
|
||||
k = _ref2[v];
|
||||
var _ref, k, v;
|
||||
_ref = this.variables;
|
||||
for (v in _ref) {
|
||||
if (!__hasProp.call(_ref, v)) continue;
|
||||
k = _ref[v];
|
||||
if (fn(v, k)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -96,12 +92,12 @@
|
|||
});
|
||||
};
|
||||
Scope.prototype.declaredVariables = function() {
|
||||
var _ref2, _result, key, val;
|
||||
var _ref, _result, key, val;
|
||||
return (function() {
|
||||
_result = []; _ref2 = this.variables;
|
||||
for (key in _ref2) {
|
||||
if (!__hasProp.call(_ref2, key)) continue;
|
||||
val = _ref2[key];
|
||||
_result = []; _ref = this.variables;
|
||||
for (key in _ref) {
|
||||
if (!__hasProp.call(_ref, key)) continue;
|
||||
val = _ref[key];
|
||||
if (val === 'var' || val === 'reuse') {
|
||||
_result.push(key);
|
||||
}
|
||||
|
@ -110,11 +106,11 @@
|
|||
}).call(this).sort();
|
||||
};
|
||||
Scope.prototype.assignedVariables = function() {
|
||||
var _ref2, _result, key, val;
|
||||
_result = []; _ref2 = this.variables;
|
||||
for (key in _ref2) {
|
||||
if (!__hasProp.call(_ref2, key)) continue;
|
||||
val = _ref2[key];
|
||||
var _ref, _result, key, val;
|
||||
_result = []; _ref = this.variables;
|
||||
for (key in _ref) {
|
||||
if (!__hasProp.call(_ref, key)) continue;
|
||||
val = _ref[key];
|
||||
if (val.assigned) {
|
||||
_result.push("" + (key) + " = " + (val.value));
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ exports.LiteralNode = class LiteralNode extends BaseNode
|
|||
# Break and continue must be treated as pure statements -- they lose their
|
||||
# meaning when wrapped in a closure.
|
||||
isStatement: ->
|
||||
@value is 'break' or @value is 'continue' or @value is 'debugger'
|
||||
@value in ['break', 'continue', 'debugger']
|
||||
isPureStatement: LiteralNode::isStatement
|
||||
|
||||
isComplex: NO
|
||||
|
@ -822,26 +822,18 @@ exports.AssignNode = class AssignNode extends BaseNode
|
|||
isValue: ->
|
||||
@variable instanceof ValueNode
|
||||
|
||||
makeReturn: ->
|
||||
if @isStatement()
|
||||
return new Expressions [this, new ReturnNode(@variable)]
|
||||
else
|
||||
super()
|
||||
|
||||
isStatement: ->
|
||||
@isValue() and (@variable.isArray() or @variable.isObject())
|
||||
|
||||
# Compile an assignment, delegating to `compilePatternMatch` or
|
||||
# `compileSplice` if appropriate. Keep track of the name of the base object
|
||||
# we've been assigned to, for correct internal references. If the variable
|
||||
# has not been seen yet within the current scope, declare it.
|
||||
compileNode: (o) ->
|
||||
if isValue = @isValue()
|
||||
return @compilePatternMatch(o) if @variable.isArray() or @variable.isObject()
|
||||
return @compileSplice(o) if @variable.isSplice()
|
||||
top = del o, 'top'
|
||||
return @compilePatternMatch(o) if @isStatement(o)
|
||||
return @compileSplice(o) if @isValue() and @variable.isSplice()
|
||||
stmt = del o, 'asStatement'
|
||||
name = @variable.compile(o)
|
||||
end = if @isValue() then @variable.last.replace(@LEADING_DOT, '') else name
|
||||
end = if isValue then @variable.last.replace(@LEADING_DOT, '') else name
|
||||
match = name.match(@PROTO_ASSIGN)
|
||||
proto = match and match[1]
|
||||
if @value instanceof CodeNode
|
||||
|
@ -849,7 +841,7 @@ exports.AssignNode = class AssignNode extends BaseNode
|
|||
@value.proto = proto if proto
|
||||
val = @value.compile o
|
||||
return "#{name}: #{val}" if @context is 'object'
|
||||
o.scope.find name unless @isValue() and (@variable.hasProperties() or @variable.namespaced)
|
||||
o.scope.find name unless isValue and (@variable.hasProperties() or @variable.namespaced)
|
||||
val = "#{name} = #{val}"
|
||||
return "#{@tab}#{val};" if stmt
|
||||
if top or @parenthetical then val else "(#{val})"
|
||||
|
@ -859,37 +851,49 @@ exports.AssignNode = class AssignNode extends BaseNode
|
|||
# See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring)
|
||||
# for details.
|
||||
compilePatternMatch: (o) ->
|
||||
if (value = @value).isStatement o then value = ClosureNode.wrap value
|
||||
{objects} = @variable.base
|
||||
return value.compile o unless objects.length
|
||||
if (isObject = @variable.isObject()) and objects.length is 1
|
||||
# Unroll simplest cases: `{v} = x` -> `v = x.v`
|
||||
if (obj = objects[0]) instanceof AssignNode
|
||||
{variable: {base: idx}, value: obj} = obj
|
||||
else
|
||||
idx = obj
|
||||
value = new ValueNode value unless value instanceof ValueNode
|
||||
accessClass = if IDENTIFIER.test idx.value then AccessorNode else IndexNode
|
||||
value.properties.push new accessClass idx
|
||||
return new AssignNode(obj, value).compile o
|
||||
top = del o, 'top'
|
||||
otop = merge o, top: yes
|
||||
valVar = o.scope.freeVariable 'ref'
|
||||
value = if @value.isStatement(o) then ClosureNode.wrap(@value) else @value
|
||||
assigns = ["#{@tab}#{valVar} = #{ value.compile(o) };"]
|
||||
o.top = true
|
||||
o.asStatement = true
|
||||
assigns = ["#{valVar} = #{ value.compile o }"]
|
||||
splat = false
|
||||
for obj, i in @variable.base.objects
|
||||
for obj, i in objects
|
||||
# A regular array pattern-match.
|
||||
idx = i
|
||||
if @variable.isObject()
|
||||
if isObject
|
||||
if obj instanceof AssignNode
|
||||
# A regular object pattern-match.
|
||||
[obj, idx] = [obj.value, obj.variable.base]
|
||||
else
|
||||
# A shorthand `{a, b, c} = val` pattern-match.
|
||||
idx = obj
|
||||
if not (obj instanceof ValueNode or obj instanceof SplatNode)
|
||||
unless obj instanceof ValueNode or obj instanceof SplatNode
|
||||
throw new Error 'pattern matching must use only identifiers on the left-hand side.'
|
||||
isString = idx.value and idx.value.match IS_STRING
|
||||
accessClass = if isString or @variable.isArray() then IndexNode else AccessorNode
|
||||
if obj instanceof SplatNode and not splat
|
||||
accessClass = if isObject and IDENTIFIER.test(idx.value) then AccessorNode else IndexNode
|
||||
if not splat and obj instanceof SplatNode
|
||||
val = literal obj.compileValue o, valVar,
|
||||
(oindex = indexOf(@variable.base.objects, obj)),
|
||||
(olength = @variable.base.objects.length) - oindex - 1
|
||||
(oindex = indexOf objects, obj),
|
||||
(olength = objects.length) - oindex - 1
|
||||
splat = true
|
||||
else
|
||||
idx = literal(if splat then "#{valVar}.length - #{olength - idx}" else idx) if typeof idx isnt 'object'
|
||||
val = new ValueNode(literal(valVar), [new accessClass(idx)])
|
||||
assigns.push(new AssignNode(obj, val).compile(o))
|
||||
code = assigns.join("\n")
|
||||
code
|
||||
val = new ValueNode literal(valVar), [new accessClass idx]
|
||||
assigns.push new AssignNode(obj, val).compile otop
|
||||
assigns.push valVar unless top
|
||||
code = assigns.join ', '
|
||||
if top or @parenthetical then code else "(#{code})"
|
||||
|
||||
# Compile the assignment from an array splice literal, using JavaScript's
|
||||
# `Array#splice` method.
|
||||
|
@ -963,8 +967,7 @@ exports.CodeNode = class CodeNode extends BaseNode
|
|||
return "(#{utility 'bind'}(#{func}, #{@context}))" if @bound
|
||||
if top then "(#{func})" else func
|
||||
|
||||
topSensitive: ->
|
||||
true
|
||||
topSensitive: YES
|
||||
|
||||
# Short-circuit traverseChildren method to prevent it from crossing scope boundaries
|
||||
# unless crossScope is true
|
||||
|
@ -1083,8 +1086,7 @@ exports.WhileNode = class WhileNode extends BaseNode
|
|||
@returns = true
|
||||
this
|
||||
|
||||
topSensitive: ->
|
||||
true
|
||||
topSensitive: YES
|
||||
|
||||
# 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
|
||||
|
|
|
@ -4,30 +4,22 @@ b = -2
|
|||
|
||||
[a, b] = [b, a]
|
||||
|
||||
ok a is -2
|
||||
ok b is -1
|
||||
eq a, -2
|
||||
eq b, -1
|
||||
|
||||
func = ->
|
||||
[a, b] = [b, a]
|
||||
|
||||
ok func().join(' ') is '-1 -2'
|
||||
eq func().join(' '), '-1 -2'
|
||||
eq a, -1
|
||||
eq b, -2
|
||||
|
||||
noop = ->
|
||||
|
||||
noop [a,b] = [c,d] = [1,2]
|
||||
|
||||
ok a is 1 and b is 2
|
||||
#713
|
||||
eq (onetwo = [1, 2]), [a, b] = [c, d] = onetwo
|
||||
ok a is c is 1 and b is d is 2
|
||||
|
||||
|
||||
# Array destructuring, including splats.
|
||||
arr = [1, 2, 3]
|
||||
|
||||
[a, b, c] = arr
|
||||
|
||||
ok a is 1
|
||||
ok b is 2
|
||||
ok c is 3
|
||||
|
||||
[x,y...,z] = [1,2,3,4,5]
|
||||
|
||||
ok x is 1
|
||||
|
|
Loading…
Reference in New Issue