From fe04f8ce6bf9c86fb383c02186642ead433971d0 Mon Sep 17 00:00:00 2001 From: matehat Date: Thu, 18 Mar 2010 09:27:13 -0400 Subject: [PATCH] Added function call's flexibility with splats to array literals, factoring out splat compiling, and adjusted tests --- lib/nodes.js | 101 +++++++++++++++++++++++----------------- src/nodes.coffee | 60 +++++++++++++----------- test/test_splats.coffee | 19 +++++++- 3 files changed, 108 insertions(+), 72 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index 93b61946..c4c60ca6 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -419,6 +419,11 @@ exports.CallNode = (function() { CallNode = function CallNode(variable, args) { this.children = flatten([(this.variable = variable), (this.args = (args || []))]); + this.compile_splat_arguments = (function(func, obj, args) { + return (function() { + return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));; + }); + }(SplatNode.compile_mixed_array, this, [this.args])); this.prefix = ''; return this; }; @@ -473,33 +478,6 @@ } 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.substr(0, 1) === '[' && prev.substr(prev.length - 1, 1) === ']') { - args[i - 1] = '' + (prev.substr(0, prev.length - 1)) + ", " + code + "]"; - continue; - } else if (i > 1 && prev.substr(0, 9) === '.concat([' && prev.substr(prev.length - 2, 2) === '])') { - args[i - 1] = '' + (prev.substr(0, prev.length - 2)) + ", " + code + "])"; - continue; - } else { - code = "[" + code + "]"; - } - } - args.push(i === 0 ? code : ".concat(" + code + ")"); - i += 1; - } - return args.join(''); - }; return CallNode; }).call(this); //### CurryNode @@ -508,6 +486,11 @@ exports.CurryNode = (function() { CurryNode = function CurryNode(meth, args) { this.children = flatten([(this.meth = meth), (this.context = args[0]), (this.args = (args.slice(1) || []))]); + this.compile_splat_arguments = (function(func, obj, args) { + return (function() { + return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));; + }); + }(SplatNode.compile_mixed_array, this, [this.args])); return this; }; __extends(CurryNode, CallNode); @@ -725,30 +708,33 @@ exports.ArrayNode = (function() { ArrayNode = function ArrayNode(objects) { this.children = (this.objects = objects || []); + this.compile_splat_literal = (function(func, obj, args) { + return (function() { + return func.apply(obj, args.concat(Array.prototype.slice.call(arguments, 0)));; + }); + }(SplatNode.compile_mixed_array, this, [this.objects])); return this; }; __extends(ArrayNode, BaseNode); ArrayNode.prototype.type = 'Array'; ArrayNode.prototype.compile_node = function compile_node(o) { - var _a, _b, _c, code, ending, i, obj, objects; + var _a, _b, code, ending, i, obj, objects; o.indent = this.idt(1); - objects = (function() { - _a = []; _b = this.objects; - for (i = 0, _c = _b.length; i < _c; i++) { - obj = _b[i]; - _a.push((function() { - code = obj.compile(o); - if (obj instanceof CommentNode) { - return "\n" + code + "\n" + o.indent; - } else if (i === this.objects.length - 1) { - return code; - } else { - return '' + code + ", "; - } - }).call(this)); + objects = []; + _a = this.objects; + for (i = 0, _b = _a.length; i < _b; i++) { + obj = _a[i]; + code = obj.compile(o); + if (obj instanceof SplatNode) { + return this.compile_splat_literal(this.objects, o); + } else if (obj instanceof CommentNode) { + objects.push("\n" + code + "\n" + o.indent); + } else if (i === this.objects.length - 1) { + objects.push(code); + } else { + objects.push('' + code + ", "); } - return _a; - }).call(this); + } objects = objects.join(''); ending = objects.indexOf('\n') >= 0 ? "\n" + this.tab + "]" : ']'; return "[" + objects + ending; @@ -1074,6 +1060,33 @@ }; return SplatNode; }).call(this); + // Utility function that converts arbitrary number of elements, mixed with + // splats, to a proper array + SplatNode.compile_mixed_array = function compile_mixed_array(list, o) { + var _a, _b, _c, arg, args, code, i, prev; + args = []; + i = 0; + _a = list; + 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.substr(0, 1) === '[' && prev.substr(prev.length - 1, 1) === ']') { + args[i - 1] = '' + (prev.substr(0, prev.length - 1)) + ", " + code + "]"; + continue; + } else if (i > 1 && prev.substr(0, 9) === '.concat([' && prev.substr(prev.length - 2, 2) === '])') { + args[i - 1] = '' + (prev.substr(0, prev.length - 2)) + ", " + code + "])"; + continue; + } else { + code = "[" + code + "]"; + } + } + args.push(i === 0 ? code : ".concat(" + code + ")"); + i += 1; + } + return args.join(''); + }; //### WhileNode // A while loop, the only sort of low-level loop exposed by CoffeeScript. From // it, all other loops can be manufactured. Useful in cases where you need more diff --git a/src/nodes.coffee b/src/nodes.coffee index a277c41a..b86f3b41 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -329,6 +329,7 @@ exports.CallNode: class CallNode extends BaseNode constructor: (variable, args) -> @children: flatten [@variable: variable, @args: (args or [])] + @compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args @prefix: '' # Tag this invocation as creating a new instance. @@ -365,27 +366,6 @@ exports.CallNode: class CallNode extends BaseNode meth: "($temp = ${ @variable.source })${ @variable.last }" "$@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 - if not (arg instanceof SplatNode) - prev: args[i - 1] - if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']' - args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]" - continue - else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])' - args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])" - continue - else - code: "[$code]" - args.push(if i is 0 then code else ".concat($code)") - i += 1 - args.join('') - #### CurryNode @@ -398,6 +378,7 @@ exports.CurryNode: class CurryNode extends CallNode constructor: (meth, args) -> @children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])] + @compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args arguments: (o) -> for arg in @args @@ -567,17 +548,21 @@ exports.ArrayNode: class ArrayNode extends BaseNode constructor: (objects) -> @children: @objects: objects or [] - + @compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects + compile_node: (o) -> o.indent: @idt(1) - objects: for obj, i in @objects + objects: [] + for obj, i in @objects code: obj.compile(o) - if obj instanceof CommentNode - "\n$code\n$o.indent" + if obj instanceof SplatNode + return @compile_splat_literal(@objects, o) + else if obj instanceof CommentNode + objects.push "\n$code\n$o.indent" else if i is @objects.length - 1 - code + objects.push code else - "$code, " + objects.push "$code, " objects: objects.join('') ending: if objects.indexOf('\n') >= 0 then "\n$@tab]" else ']' "[$objects$ending" @@ -815,6 +800,27 @@ exports.SplatNode: class SplatNode extends BaseNode compile_value: (o, name, index) -> "Array.prototype.slice.call($name, $index)" +# Utility function that converts arbitrary number of elements, mixed with +# splats, to a proper array +SplatNode.compile_mixed_array: (list, o) -> + args: [] + i: 0 + for arg in list + code: arg.compile o + if not (arg instanceof SplatNode) + prev: args[i - 1] + if i is 1 and prev.substr(0, 1) is '[' and prev.substr(prev.length - 1, 1) is ']' + args[i - 1]: "${prev.substr(0, prev.length - 1)}, $code]" + continue + else if i > 1 and prev.substr(0, 9) is '.concat([' and prev.substr(prev.length - 2, 2) is '])' + args[i - 1]: "${prev.substr(0, prev.length - 2)}, $code])" + continue + else + code: "[$code]" + args.push(if i is 0 then code else ".concat($code)") + i += 1 + args.join('') + #### WhileNode # A while loop, the only sort of low-level loop exposed by CoffeeScript. From diff --git a/test/test_splats.coffee b/test/test_splats.coffee index 5b23bbf0..a679a2a4 100644 --- a/test/test_splats.coffee +++ b/test/test_splats.coffee @@ -58,4 +58,21 @@ obj: { @accessor(args...) } -ok obj.getNames() is 'bob jane ted' \ No newline at end of file +ok obj.getNames() is 'bob jane ted' + + +crowd: [ + contenders... + "Mighty Mouse" +] + +bests: [ + "Mighty Mouse" + contenders[0..3]... +] + +ok crowd[0] is contenders[0] +ok crowd[10] is "Mighty Mouse" + +ok bests[1] is contenders[0] +ok bests[4] is contenders[3] \ No newline at end of file