mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-14 01:07:55 -05:00
Merge branch 'splats' of git://github.com/matehat/coffee-script
This commit is contained in:
111
lib/nodes.js
111
lib/nodes.js
@@ -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 - 1)) + ", " + 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);
|
||||
@@ -899,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);
|
||||
@@ -908,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" : '';
|
||||
@@ -992,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.
|
||||
|
||||
@@ -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 - 1]}, $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
|
||||
|
||||
@@ -699,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 ''
|
||||
@@ -750,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) ->
|
||||
|
||||
@@ -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,8 +33,17 @@ 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()
|
||||
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: {
|
||||
name: 'bob'
|
||||
|
||||
Reference in New Issue
Block a user