defarg: removed Splat::compileParam in favor of using the normal array destructuring against `arguments`

This commit is contained in:
satyr 2010-10-26 18:52:43 +09:00
parent e7cc4e4faf
commit 4eeab947dd
3 changed files with 129 additions and 167 deletions

View File

@ -96,7 +96,7 @@
};
Base.prototype.toString = function(idt, override) {
var _i, _len, _ref2, _result, child, children, klass;
idt || (idt = '');
idt != null ? idt : idt = '';
children = ((function() {
_ref2 = this.collectChildren();
_result = [];
@ -209,7 +209,7 @@
return this;
};
Expressions.prototype.compile = function(o, level) {
o || (o = {});
o != null ? o : o = {};
return o.scope ? Expressions.__super__.compile.call(this, o, level) : this.compileRoot(o);
};
Expressions.prototype.compileNode = function(o) {
@ -464,13 +464,12 @@
exports.Call = (function() {
Call = (function() {
function Call(variable, _arg, _arg2) {
this.args = _arg != null ? _arg : [];
this.soak = _arg2;
this.args = _arg;
Call.__super__.constructor.call(this);
this["new"] = '';
this.isSuper = variable === 'super';
this.variable = this.isSuper ? null : variable;
this.args || (this.args = []);
return this;
}
return Call;
@ -595,8 +594,8 @@
exports.Extends = (function() {
Extends = (function() {
function Extends(_arg, _arg2) {
this.parent = _arg2;
this.child = _arg;
this.parent = _arg2;
Extends.__super__.constructor.call(this);
return this;
}
@ -788,8 +787,8 @@
exports.Class = (function() {
Class = (function() {
function Class(_arg, _arg2, props) {
this.parent = _arg2;
this.variable = _arg;
this.parent = _arg2;
Class.__super__.constructor.call(this);
this.properties = props || [];
this.returns = false;
@ -888,9 +887,9 @@
exports.Assign = (function() {
Assign = (function() {
function Assign(_arg, _arg2, _arg3) {
this.context = _arg3;
this.value = _arg2;
this.variable = _arg;
this.value = _arg2;
this.context = _arg3;
Assign.__super__.constructor.call(this);
return this;
}
@ -934,7 +933,7 @@
return o.level <= LEVEL_LIST ? val : "(" + val + ")";
};
Assign.prototype.compilePatternMatch = function(o) {
var _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, acc, assigns, code, i, idx, isObject, obj, objects, olength, ref, splat, top, val, valVar, value;
var _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, acc, assigns, code, i, idx, isObject, ivar, obj, objects, olength, ref, rest, splat, top, val, valVar, value;
top = o.level === LEVEL_TOP;
value = this.value;
objects = this.variable.base.objects;
@ -979,11 +978,15 @@
}
}
if (!splat && obj instanceof Splat) {
val = new Literal(obj.compileValue(o, valVar, i, olength - i - 1));
splat = true;
if (rest = olength - i - 1 || '') {
ivar = o.scope.freeVariable('i');
rest = ", " + ivar + " = " + valVar + ".length - " + rest;
}
val = new Literal(utility('slice') + (".call(" + valVar + ", " + i + rest + ")"));
splat = "" + ivar + " < " + i + " ? " + ivar + " = " + i + " : " + ivar + "++";
} else {
if (typeof idx !== 'object') {
idx = new Literal(splat ? "" + valVar + ".length - " + (olength - idx) : idx);
if (typeof idx === 'number') {
idx = new Literal(splat || idx);
acc = false;
} else {
acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0);
@ -1008,8 +1011,8 @@
exports.Code = (function() {
Code = (function() {
function Code(_arg, _arg2, tag) {
this.body = _arg2 != null ? _arg2 : new Expressions;
this.params = _arg != null ? _arg : [];
this.body = _arg2 != null ? _arg2 : new Expressions;
Code.__super__.constructor.call(this);
this.bound = tag === 'boundfunc';
if (this.bound) {
@ -1022,53 +1025,62 @@
__extends(Code, Base);
Code.prototype.children = ['params', 'body'];
Code.prototype.compileNode = function(o) {
var _len, _len2, _ref2, close, code, comm, empty, func, i, idt, name, open, param, params, scope, sharedScope, splat, value;
var _i, _j, _len, _len2, _len3, _ref2, _ref3, _result, _this, close, code, comm, exprs, func, i, idt, open, p, param, ref, scope, sharedScope, splats, v, vars, wasEmpty;
sharedScope = del(o, 'sharedScope');
o.scope = scope = sharedScope || new Scope(o.scope, this.body, this);
o.indent = this.idt(1);
empty = this.body.expressions.length === 0;
delete o.bare;
delete o.globals;
splat = null;
params = [];
vars = [];
exprs = [];
_ref2 = this.params;
for (i = 0, _len = _ref2.length; i < _len; i++) {
param = _ref2[i];
if (splat) {
if (param.attach) {
param.assign = new Assign(param.name);
this.body.expressions.splice(splat.index + 1, 0, param.assign);
} else if (param.value) {
this.body.unshift(new Assign(new Value(param.name), param.value, '?='));
}
splat.trailings.push(param);
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
param = _ref2[_i];
if (param.splat) {
splats = new Assign(new Value(new Arr((function() {
_ref3 = this.params;
_result = [];
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
p = _ref3[_j];
_result.push(p.asReference(o));
}
return _result;
}).call(this))), new Value(new Literal('arguments')));
break;
}
}
_ref3 = this.params;
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
param = _ref3[_j];
if (param.attach) {
ref = param.asReference(o);
exprs.push(new Assign(param.name, param.value ? new Op('?', ref, param.value) : ref));
} else {
if (param.attach) {
name = param.name, value = param.value, splat = param.splat;
param = new Literal(scope.freeVariable('arg'));
param.splat = splat;
this.body.unshift(new Assign(name, value ? new Op('?', param, value) : param));
} else if (param.value) {
this.body.unshift(new Assign(new Value(param.name), param.value, '?='));
}
if (param.splat) {
splat = new Splat(param.name || param);
splat.index = i;
splat.trailings = [];
splat.arglength = this.params.length;
this.body.unshift(splat);
} else {
params.push(param);
ref = param;
if (param.value) {
exprs.push(new Assign(new Value(param.name), param.value, '?='));
}
}
if (!splats) {
vars.push(ref);
}
}
scope.startLevel();
if (!(empty || this.noReturn)) {
wasEmpty = this.body.isEmpty();
if (splats) {
exprs.unshift(splats);
}
if (exprs.length) {
(_this = this.body.expressions).splice.apply(_this, [0, 0].concat(exprs));
}
if (!(wasEmpty || this.noReturn)) {
this.body.makeReturn();
}
for (i = 0, _len2 = params.length; i < _len2; i++) {
param = params[i];
scope.parameter(params[i] = param.compile(o));
if (!splats) {
for (i = 0, _len3 = vars.length; i < _len3; i++) {
v = vars[i];
scope.parameter(vars[i] = v.compile(o));
}
}
comm = this.comment ? this.comment.compile(o) + '\n' : '';
if (this.className) {
@ -1080,10 +1092,10 @@
open = "(function() {\n" + comm + idt + "function " + this.className + "(";
close = "" + (code && idt) + "}\n" + idt + "return " + this.className + ";\n" + this.tab + "})()";
} else {
open = "function(";
open = 'function(';
close = "" + (code && this.tab) + "}";
}
func = "" + open + (params.join(', ')) + ") {" + code + close;
func = "" + open + (vars.join(', ')) + ") {" + code + close;
scope.endLevel();
if (this.bound) {
return "" + (utility('bind')) + "(" + func + ", " + this.context + ")";
@ -1098,9 +1110,9 @@
exports.Param = (function() {
Param = (function() {
function Param(_arg, _arg2, _arg3) {
this.splat = _arg3;
this.value = _arg2;
this.name = _arg;
this.value = _arg2;
this.splat = _arg3;
Param.__super__.constructor.call(this);
this.attach = this.name instanceof Value;
return this;
@ -1112,6 +1124,18 @@
Param.prototype.compile = function(o) {
return this.name.compile(o, LEVEL_LIST);
};
Param.prototype.asReference = function(o) {
var node;
if (this.reference) {
return this.reference;
}
node = this.attach ? new Literal(o.scope.freeVariable('arg')) : this.name;
node = new Value(node);
if (this.splat) {
node = new Splat(node);
}
return this.reference = node;
};
return Param;
})();
exports.Splat = (function() {
@ -1132,36 +1156,6 @@
Splat.prototype.compile = function(o) {
return this.index != null ? this.compileParam(o) : this.name.compile(o);
};
Splat.prototype.compileParam = function(o) {
var _len, _ref2, assign, end, idx, len, name, param, pos, value, variadic;
name = this.name.compile(o);
o.scope.find(name);
end = '';
if (this.trailings.length) {
len = o.scope.freeVariable('len');
o.scope.assign(len, 'arguments.length');
variadic = o.scope.freeVariable('result');
o.scope.assign(variadic, len + ' >= ' + this.arglength);
end = this.trailings.length ? ", " + len + " - " + this.trailings.length : undefined;
_ref2 = this.trailings;
for (idx = 0, _len = _ref2.length; idx < _len; idx++) {
param = _ref2[idx];
if (param.attach) {
assign = param.assign, value = param.value;
param = new Literal(o.scope.freeVariable('arg'));
assign.value = value ? new Op('?', param, value) : param;
}
pos = this.trailings.length - idx;
o.scope.assign(param.compile(o), "arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]");
}
}
return "" + name + " = " + (utility('slice')) + ".call(arguments, " + this.index + end + ")";
};
Splat.prototype.compileValue = function(o, name, index, trailings) {
var trail;
trail = trailings ? ', -' + trailings : '';
return utility('slice') + (".call(" + name + ", " + index + trail + ")");
};
Splat.compileSplattedArray = function(list, o) {
var _len, arg, args, code, end, i, prev;
args = [];
@ -1343,8 +1337,8 @@
exports.In = (function() {
In = (function() {
function In(_arg, _arg2) {
this.array = _arg2;
this.object = _arg;
this.array = _arg2;
In.__super__.constructor.call(this);
return this;
}
@ -1393,10 +1387,10 @@
exports.Try = (function() {
Try = (function() {
function Try(_arg, _arg2, _arg3, _arg4) {
this.ensure = _arg4;
this.recovery = _arg3;
this.error = _arg2;
this.attempt = _arg;
this.error = _arg2;
this.recovery = _arg3;
this.ensure = _arg4;
Try.__super__.constructor.call(this);
return this;
}
@ -1622,9 +1616,9 @@
exports.Switch = (function() {
Switch = (function() {
function Switch(_arg, _arg2, _arg3) {
this.otherwise = _arg3;
this.cases = _arg2;
this.subject = _arg;
this.cases = _arg2;
this.otherwise = _arg3;
Switch.__super__.constructor.call(this);
return this;
}
@ -1686,13 +1680,13 @@
})();
exports.If = (function() {
If = (function() {
function If(condition, _arg, tags) {
function If(condition, _arg, _arg2) {
this.body = _arg;
this.tags = tags || (tags = {});
this.condition = tags.invert ? condition.invert() : condition;
this.soak = tags.soak;
this.tags = _arg2 != null ? _arg2 : {};
this.condition = this.tags.invert ? condition.invert() : condition;
this.elseBody = null;
this.isChain = false;
this.soak = this.tags.soak;
return this;
}
return If;

View File

@ -4,9 +4,9 @@
exports.Scope = (function() {
Scope = (function() {
function Scope(_arg, _arg2, _arg3) {
this.method = _arg3;
this.expressions = _arg2;
this.parent = _arg;
this.expressions = _arg2;
this.method = _arg3;
this.variables = [
{
name: 'arguments',

View File

@ -107,8 +107,7 @@ exports.Base = class Base
# `toString` representation of the node, for inspecting the parse tree.
# This is what `coffee --nodes` prints out.
toString: (idt, override) ->
idt or= ''
toString: (idt = '', override) ->
children = (child.toString idt + TAB for child in @collectChildren()).join('')
klass = override or @constructor.name + if @soak then '?' else ''
'\n' + idt + klass + children
@ -198,8 +197,7 @@ exports.Expressions = class Expressions extends Base
this
# An **Expressions** is the only node that can serve as the root.
compile: (o, level) ->
o or= {}
compile: (o = {}, level) ->
if o.scope then super o, level else @compileRoot o
compileNode: (o) ->
@ -405,12 +403,11 @@ exports.Call = class Call extends Base
children: ['variable', 'args']
constructor: (variable, @args, @soak) ->
constructor: (variable, @args = [], @soak) ->
super()
@new = ''
@isSuper = variable is 'super'
@variable = if @isSuper then null else variable
@args or= []
# Tag this invocation as creating a new instance.
newInstance: ->
@ -803,11 +800,14 @@ exports.Assign = class Assign extends Base
then [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
else idx = if obj.tags.this then obj.properties[0].name else obj
if not splat and obj instanceof Splat
val = new Literal obj.compileValue o, valVar, i, olength - i - 1
splat = true
if rest = olength - i - 1 or ''
ivar = o.scope.freeVariable 'i'
rest = ", #{ivar} = #{valVar}.length - #{rest}"
val = new Literal utility('slice') + ".call(#{valVar}, #{i}#{rest})"
splat = "#{ivar} < #{i} ? #{ivar} = #{i} : #{ivar}++"
else
if typeof idx isnt 'object'
idx = new Literal(if splat then "#{valVar}.length - #{ olength - idx }" else idx)
if typeof idx is 'number'
idx = new Literal splat or idx
acc = no
else
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
@ -847,39 +847,29 @@ exports.Code = class Code extends Base
sharedScope = del o, 'sharedScope'
o.scope = scope = sharedScope or new Scope o.scope, @body, this
o.indent = @idt 1
empty = @body.expressions.length is 0
delete o.bare
delete o.globals
splat = null
params = []
for param, i in @params
if splat
if param.attach
param.assign = new Assign param.name
@body.expressions.splice splat.index + 1, 0, param.assign
else if param.value
@body.unshift new Assign new Value(param.name), param.value, '?='
splat.trailings.push param
vars = []
exprs = []
for param in @params when param.splat
splats = new Assign new Value(new Arr(p.asReference o for p in @params)),
new Value new Literal 'arguments'
break
for param in @params
if param.attach
ref = param.asReference o
exprs.push new Assign param.name,
if param.value then new Op '?', ref, param.value else ref
else
if param.attach
{name, value, splat} = param
param = new Literal scope.freeVariable 'arg'
param.splat = splat
@body.unshift new Assign name,
if value then new Op '?', param, value else param
else if param.value
@body.unshift new Assign new Value(param.name), param.value, '?='
if param.splat
splat = new Splat param.name or param
splat.index = i
splat.trailings = []
splat.arglength = @params.length
@body.unshift splat
else
params.push param
ref = param
exprs.push new Assign new Value(param.name), param.value, '?=' if param.value
vars.push ref unless splats
scope.startLevel()
@body.makeReturn() unless empty or @noReturn
scope.parameter params[i] = param.compile o for param, i in params
wasEmpty = @body.isEmpty()
exprs.unshift splats if splats
@body.expressions.splice 0, 0, exprs... if exprs.length
@body.makeReturn() unless wasEmpty or @noReturn
scope.parameter vars[i] = v.compile o for v, i in vars unless splats
comm = if @comment then @comment.compile(o) + '\n' else ''
o.indent = @idt 2 if @className
idt = @idt 1
@ -889,9 +879,9 @@ exports.Code = class Code extends Base
open = "(function() {\n#{comm}#{idt}function #{@className}("
close = "#{ code and idt }}\n#{idt}return #{@className};\n#{@tab}})()"
else
open = "function("
open = 'function('
close = "#{ code and @tab }}"
func = "#{open}#{ params.join ', ' }) {#{code}#{close}"
func = "#{open}#{ vars.join ', ' }) {#{code}#{close}"
scope.endLevel()
return "#{ utility 'bind' }(#{func}, #{@context})" if @bound
if @tags.front then "(#{func})" else func
@ -915,6 +905,13 @@ exports.Param = class Param extends Base
compile: (o) -> @name.compile o, LEVEL_LIST
asReference: (o) ->
return @reference if @reference
node = if @attach then new Literal o.scope.freeVariable 'arg' else this.name
node = new Value node
node = new Splat node if @splat
@reference = node
#### Splat
# A splat, either as a parameter to a function, an argument to a call,
@ -933,34 +930,6 @@ exports.Splat = class Splat extends Base
compile: (o) -> if @index? then @compileParam o else @name.compile o
# Compiling a parameter splat means recovering the parameters that succeed
# the splat in the parameter list, by slicing the arguments object.
compileParam: (o) ->
name = @name.compile o
o.scope.find name
end = ''
if @trailings.length
len = o.scope.freeVariable 'len'
o.scope.assign len, 'arguments.length'
variadic = o.scope.freeVariable 'result'
o.scope.assign variadic, len + ' >= ' + @arglength
end = if @trailings.length then ", #{len} - #{@trailings.length}"
for param, idx in @trailings
if param.attach
{assign, value} = param
param = new Literal o.scope.freeVariable 'arg'
assign.value = if value then new Op '?', param, value else param
pos = @trailings.length - idx
o.scope.assign param.compile(o),
"arguments[#{variadic} ? #{len} - #{pos} : #{ @index + idx }]"
"#{name} = #{ utility 'slice' }.call(arguments, #{@index}#{end})"
# A compiling a splat as a destructuring assignment means slicing arguments
# from the right-hand-side's corresponding array.
compileValue: (o, name, index, trailings) ->
trail = if trailings then ', -' + trailings else ''
utility('slice') + ".call(#{name}, #{index}#{trail})"
# Utility function that converts arbitrary number of elements, mixed with
# splats, to a proper array
@compileSplattedArray: (list, o) ->
@ -1377,12 +1346,11 @@ exports.If = class If extends Base
children: ['condition', 'body', 'elseBody']
constructor: (condition, @body, tags) ->
@tags = tags or= {}
@condition = if tags.invert then condition.invert() else condition
@soak = tags.soak
constructor: (condition, @body, @tags = {}) ->
@condition = if @tags.invert then condition.invert() else condition
@elseBody = null
@isChain = false
{@soak} = @tags
bodyNode: -> @body?.unwrap()
elseBodyNode: -> @elseBody?.unwrap()