From 9a7420ccd05395af34cced848a6f181a34e6b495 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sat, 8 May 2010 12:44:54 -0400 Subject: [PATCH] adding support for calling variadic functions with less than the requested number of arguments. --- lib/nodes.js | 14 +++++++++----- src/nodes.coffee | 10 +++++++--- test/test_splats.coffee | 17 ++++++++++++++++- 3 files changed, 32 insertions(+), 9 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index d7542098..f07f6a5c 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1060,8 +1060,9 @@ if (param instanceof SplatNode && !(typeof splat !== "undefined" && splat !== null)) { splat = param; splat.index = i; - this.body.unshift(splat); splat.trailings = []; + splat.arglength = this.params.length; + this.body.unshift(splat); } else if ((typeof splat !== "undefined" && splat !== null)) { splat.trailings.push(param); } else { @@ -1153,15 +1154,18 @@ // 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 _b, _c, len, name, pos, trailing; + var _b, _c, idx, len, name, pos, trailing, variadic; name = this.name.compile(o); o.scope.find(name); len = o.scope.free_variable(); o.scope.assign(len, "arguments.length"); + variadic = o.scope.free_variable(); + o.scope.assign(variadic, ("" + len + " >= " + this.arglength)); _b = this.trailings; - for (pos = 0, _c = _b.length; pos < _c; pos++) { - trailing = _b[pos]; - o.scope.assign(trailing.compile(o), ("arguments[" + len + " - " + (this.trailings.length + pos) + "]")); + for (idx = 0, _c = _b.length; idx < _c; idx++) { + trailing = _b[idx]; + pos = this.trailings.length - idx; + o.scope.assign(trailing.compile(o), ("arguments[" + variadic + " ? " + len + " - " + pos + " : " + (this.index + idx) + "]")); } return "" + name + " = " + (utility('slice')) + ".call(arguments, " + this.index + ", " + len + " - " + (this.trailings.length) + ")"; }; diff --git a/src/nodes.coffee b/src/nodes.coffee index 26552cd2..7061b2ad 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -773,8 +773,9 @@ exports.CodeNode: class CodeNode extends BaseNode if param instanceof SplatNode and not splat? splat: param splat.index: i - @body.unshift(splat) splat.trailings: [] + splat.arglength: @params.length + @body.unshift(splat) else if splat? splat.trailings.push(param) else @@ -830,8 +831,11 @@ exports.SplatNode: class SplatNode extends BaseNode o.scope.find name len: o.scope.free_variable() o.scope.assign len, "arguments.length" - for trailing, pos in @trailings - o.scope.assign(trailing.compile(o), "arguments[$len - ${@trailings.length + pos}]") + variadic: o.scope.free_variable() + o.scope.assign variadic, "$len >= $@arglength" + for trailing, idx in @trailings + pos: @trailings.length - idx + o.scope.assign(trailing.compile(o), "arguments[$variadic ? $len - $pos : ${@index + idx}]") "$name = ${utility('slice')}.call(arguments, $@index, $len - ${@trailings.length})" # A compiling a splat as a destructuring assignment means slicing arguments diff --git a/test/test_splats.coffee b/test/test_splats.coffee index 00dec887..5b89e773 100644 --- a/test/test_splats.coffee +++ b/test/test_splats.coffee @@ -89,4 +89,19 @@ class Child extends Parent nums: [3, 2, 1] super nums... -ok (new Child()).meth().join(' ') is '3 2 1' \ No newline at end of file +ok (new Child()).meth().join(' ') is '3 2 1' + + +# Functions with splats being called with too few arguments. +pen: null +method: (first, variable..., penultimate, ultimate) -> + pen: penultimate + +method 1, 2, 3, 4, 5, 6, 7, 8, 9 +ok pen is 8 + +method 1, 2, 3 +ok pen is 2 + +method 1, 2 +ok pen is 2