Added the ability to put as many splats in a function call as one wants. Also optimized the assembly into static arrays. Adjusted tests accordingly.

This commit is contained in:
matehat 2010-03-17 12:25:04 -04:00
parent 70cfc9500e
commit 2bd1c3acca
3 changed files with 70 additions and 26 deletions

View File

@ -431,17 +431,21 @@
};
// Compile a vanilla function call.
CallNode.prototype.compile_node = function compile_node(o) {
var _a, _b, _c, _d, arg, args;
if (this.args[this.args.length - 1] instanceof SplatNode) {
return this.compile_splat(o);
var _a, _b, _c, _d, _e, _f, _g, arg, args;
_a = this.args;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
arg = _a[_b];
if (arg instanceof SplatNode) {
return this.compile_splat(o);
}
}
args = (function() {
_a = []; _b = this.args;
for (_c = 0, _d = _b.length; _c < _d; _c++) {
arg = _b[_c];
_a.push(arg.compile(o));
_d = []; _e = this.args;
for (_f = 0, _g = _e.length; _f < _g; _f++) {
arg = _e[_f];
_d.push(arg.compile(o));
}
return _a;
return _d;
}).call(this).join(', ');
if (this.variable === 'super') {
return this.compile_super(args, o);
@ -459,7 +463,7 @@
// If you call a function with a splat, it's converted into a JavaScript
// `.apply()` call to allow an array of arguments to be passed.
CallNode.prototype.compile_splat = function compile_splat(o) {
var _a, _b, _c, arg, args, code, i, meth, obj, temp;
var meth, obj, temp;
meth = this.variable.compile(o);
obj = this.variable.source || 'this';
if (obj.match(/\(/)) {
@ -467,19 +471,34 @@
obj = temp;
meth = "(" + temp + " = " + (this.variable.source) + ")" + (this.variable.last);
}
args = (function() {
_a = []; _b = this.args;
for (i = 0, _c = _b.length; i < _c; i++) {
arg = _b[i];
_a.push((function() {
code = arg.compile(o);
code = arg instanceof SplatNode ? code : "[" + code + "]";
return i === 0 ? code : ".concat(" + code + ")";
}).call(this));
return '' + this.prefix + (meth) + ".apply(" + obj + ", " + (this.compile_splat_arguments(o)) + ")";
};
// Converts arbitrary number of arguments, mixed with splats, to
// a proper array to pass to an `.apply()` call
CallNode.prototype.compile_splat_arguments = function compile_splat_arguments(o) {
var _a, _b, _c, arg, args, code, i, prev;
args = [];
i = 0;
_a = this.args;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
arg = _a[_b];
code = arg.compile(o);
if (!(arg instanceof SplatNode)) {
prev = args[i - 1];
if (i === 1 && prev[0] === '[' && prev[prev.length - 1] === ']') {
args[i - 1] = '' + (prev.slice(0, prev.length - 2)) + ", " + code + "]";
continue;
} else if (i > 1 && prev[8] === '[' && prev[prev.length - 2] === ']') {
args[i - 1] = '' + (prev.slice(0, prev.length - 2)) + ", " + code + "])";
continue;
} else {
code = "[" + code + "]";
}
}
return _a;
}).call(this);
return '' + this.prefix + (meth) + ".apply(" + obj + ", " + (args.join('')) + ")";
args.push(i === 0 ? code : ".concat(" + code + ")");
i += 1;
}
return args.join('');
};
return CallNode;
}).call(this);

View File

@ -338,7 +338,8 @@ exports.CallNode: class CallNode extends BaseNode
# Compile a vanilla function call.
compile_node: (o) ->
return @compile_splat(o) if @args[@args.length - 1] instanceof SplatNode
for arg in @args
return @compile_splat(o) if arg instanceof SplatNode
args: (arg.compile(o) for arg in @args).join(', ')
return @compile_super(args, o) if @variable is 'super'
"$@prefix${@variable.compile(o)}($args)"
@ -362,11 +363,28 @@ exports.CallNode: class CallNode extends BaseNode
temp: o.scope.free_variable()
obj: temp
meth: "($temp = ${ @variable.source })${ @variable.last }"
args: for arg, i in @args
"$@prefix${meth}.apply($obj, ${ @compile_splat_arguments(o) })"
# Converts arbitrary number of arguments, mixed with splats, to
# a proper array to pass to an `.apply()` call
compile_splat_arguments: (o) ->
args: []
i: 0
for arg in @args
code: arg.compile o
code: if arg instanceof SplatNode then code else "[$code]"
if i is 0 then code else ".concat($code)"
"$@prefix${meth}.apply($obj, ${ args.join('') })"
if not (arg instanceof SplatNode)
prev: args[i - 1]
if i is 1 and prev[0] is '[' and prev[prev.length - 1] is ']'
args[i - 1] = "${prev[0...prev.length - 2]}, $code]"
continue
else if i > 1 and prev[8] is '[' and prev[prev.length - 2] is ']'
args[i - 1] = "${prev[0...prev.length - 2]}, $code])"
continue
else
code: "[$code]"
args.push(if i is 0 then code else ".concat($code)")
i += 1
args.join('')
#### ExtendsNode

View File

@ -34,6 +34,13 @@ ok silver is "Michael Phelps"
ok bronze is "Liu Xiang"
ok the_field.length is 8
contenders.reverse()
medalists contenders[0...2]..., "Mighty Mouse", contenders[2...contenders.length]...
ok gold is "Usain Bolt"
ok silver is "Asafa Powell"
ok bronze is "Mighty Mouse"
ok the_field.length is 8
obj: {
name: 'bob'