Added the ability for function declaration to have a splat at an arbitrary position, not just at the end. Still restrict their number to 1. Adjusted tests accordingly.

This commit is contained in:
matehat 2010-03-17 14:41:09 -04:00
parent fa6f1c2fb1
commit 7129f518a4
3 changed files with 62 additions and 25 deletions

View File

@ -918,7 +918,7 @@
// arrow, generates a wrapper that saves the current value of `this` through
// a closure.
CodeNode.prototype.compile_node = function compile_node(o) {
var _a, _b, _c, _d, _e, _f, _g, code, func, inner, name_part, param, params, shared_scope, splat, top;
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, code, func, i, inner, name_part, param, params, shared_scope, splat, top;
shared_scope = del(o, 'shared_scope');
top = del(o, 'top');
o.scope = shared_scope || new Scope(o.scope, this.body, this);
@ -927,22 +927,35 @@
o.indent = this.idt(this.bound ? 2 : 1);
del(o, 'no_wrap');
del(o, 'globals');
if (this.params[this.params.length - 1] instanceof SplatNode) {
splat = this.params.pop();
splat.index = this.params.length;
this.body.unshift(splat);
i = 0;
splat = undefined;
params = [];
_a = this.params;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
param = _a[_b];
if (param instanceof SplatNode && !(typeof splat !== "undefined" && splat !== null)) {
splat = param;
splat.index = i;
this.body.unshift(splat);
splat.trailings = [];
} else if ((typeof splat !== "undefined" && splat !== null)) {
splat.trailings.push(param);
} else {
params.push(param);
}
i += 1;
}
params = (function() {
_a = []; _b = this.params;
for (_c = 0, _d = _b.length; _c < _d; _c++) {
param = _b[_c];
_a.push(param.compile(o));
_d = []; _e = params;
for (_f = 0, _g = _e.length; _f < _g; _f++) {
param = _e[_f];
_d.push(param.compile(o));
}
return _a;
return _d;
}).call(this);
_e = params;
for (_f = 0, _g = _e.length; _f < _g; _f++) {
param = _e[_f];
_h = params;
for (_i = 0, _j = _h.length; _i < _j; _i++) {
param = _h[_i];
(o.scope.parameter(param));
}
code = this.body.expressions.length ? "\n" + (this.body.compile_with_declarations(o)) + "\n" : '';
@ -1011,10 +1024,17 @@
// Compiling a parameter splat means recovering the parameters that succeed
// the splat in the parameter list, by slicing the arguments object.
SplatNode.prototype.compile_param = function compile_param(o) {
var name;
var _a, _b, _c, i, name, trailing;
name = this.name.compile(o);
o.scope.find(name);
return '' + name + " = Array.prototype.slice.call(arguments, " + this.index + ")";
i = 0;
_a = this.trailings;
for (_b = 0, _c = _a.length; _b < _c; _b++) {
trailing = _a[_b];
o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]");
i += 1;
}
return '' + name + " = Array.prototype.slice.call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")";
};
// A compiling a splat as a destructuring assignment means slicing arguments
// from the right-hand-side's corresponding array.

View File

@ -717,11 +717,21 @@ exports.CodeNode: class CodeNode extends BaseNode
o.indent: @idt(if @bound then 2 else 1)
del o, 'no_wrap'
del o, 'globals'
if @params[@params.length - 1] instanceof SplatNode
splat: @params.pop()
splat.index: @params.length
@body.unshift(splat)
params: (param.compile(o) for param in @params)
i: 0
splat: undefined
params: []
for param in @params
if param instanceof SplatNode and not splat?
splat: param
splat.index: i
@body.unshift(splat)
splat.trailings: []
else if splat?
splat.trailings.push(param)
else
params.push(param)
i += 1
params: (param.compile(o) for param in params)
(o.scope.parameter(param)) for param in params
code: if @body.expressions.length then "\n${ @body.compile_with_declarations(o) }\n" else ''
name_part: if @name then ' ' + @name else ''
@ -768,8 +778,12 @@ exports.SplatNode: class SplatNode extends BaseNode
compile_param: (o) ->
name: @name.compile(o)
o.scope.find name
"$name = Array.prototype.slice.call(arguments, $@index)"
i: 0
for trailing in @trailings
o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]")
i += 1
"$name = Array.prototype.slice.call(arguments, $@index, arguments.length - ${@trailings.length})"
# A compiling a splat as a destructuring assignment means slicing arguments
# from the right-hand-side's corresponding array.
compile_value: (o, name, index) ->

View File

@ -6,13 +6,14 @@ result: func 1, 2, 3, 4, 5
ok result is "3 4 5"
gold: silver: bronze: the_field: null
gold: silver: bronze: the_field: last: null
medalists: (first, second, third, rest...) ->
medalists: (first, second, third, rest..., unlucky) ->
gold: first
silver: second
bronze: third
the_field: rest
the_field: rest.concat([last])
last: unlucky
contenders: [
"Michael Phelps"
@ -32,6 +33,7 @@ medalists "Mighty Mouse", contenders...
ok gold is "Mighty Mouse"
ok silver is "Michael Phelps"
ok bronze is "Liu Xiang"
ok last is "Usain Bolt"
ok the_field.length is 8
contenders.reverse()
@ -40,6 +42,7 @@ 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 last is "Michael Phelps"
ok the_field.length is 8
obj: {