From 2bd1c3accabff37db5a36a3b6de1c7984c956fb8 Mon Sep 17 00:00:00 2001 From: matehat Date: Wed, 17 Mar 2010 12:25:04 -0400 Subject: [PATCH] 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. --- lib/nodes.js | 61 +++++++++++++++++++++++++++-------------- src/nodes.coffee | 28 +++++++++++++++---- test/test_splats.coffee | 7 +++++ 3 files changed, 70 insertions(+), 26 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index 7ad5d5a2..e290e5c5 100644 --- a/lib/nodes.js +++ b/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 - 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); diff --git a/src/nodes.coffee b/src/nodes.coffee index f530efc5..c16d6ab1 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -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 diff --git a/test/test_splats.coffee b/test/test_splats.coffee index 87b0afd7..070718e6 100644 --- a/test/test_splats.coffee +++ b/test/test_splats.coffee @@ -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'