From 0b87387fabbb20c9a3eb542c95bb9fd3bada196c Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Tue, 13 Jul 2010 22:16:19 -0400 Subject: [PATCH] slightly nicer implementation of SplatNode.compileSplattedArray --- lib/helpers.js | 7 ++++++- lib/nodes.js | 29 ++++++++++++++--------------- src/helpers.coffee | 5 +++++ src/nodes.coffee | 22 ++++++++++------------ test/test_splats.coffee | 8 ++++++++ 5 files changed, 43 insertions(+), 28 deletions(-) diff --git a/lib/helpers.js b/lib/helpers.js index ab2f713e..ea406bbc 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,5 +1,5 @@ (function(){ - var compact, count, del, extend, flatten, helpers, include, indexOf, merge, starts; + var compact, count, del, ends, extend, flatten, helpers, include, indexOf, merge, starts; var __hasProp = Object.prototype.hasOwnProperty; if (!(typeof process !== "undefined" && process !== null)) { this.exports = this; @@ -25,6 +25,11 @@ helpers.starts = (starts = function(string, literal, start) { return string.substring(start, (start || 0) + literal.length) === literal; }); + helpers.ends = (ends = function(string, literal, back) { + var start; + start = string.length - literal.length - ((typeof back !== "undefined" && back !== null) ? back : 0); + return string.substring(start, start + literal.length) === literal; + }); helpers.compact = (compact = function(array) { var _a, _b, _c, _d, item; _a = []; _c = array; diff --git a/lib/nodes.js b/lib/nodes.js index 39b0ef5b..2ef08272 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1,5 +1,5 @@ (function(){ - var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, DOUBLE_PARENS, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, flatten, helpers, include, indexOf, literal, merge, starts, utility; + var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, DOUBLE_PARENS, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NUMBER, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, ends, flatten, helpers, include, indexOf, literal, merge, starts, utility; var __extends = function(child, parent) { var ctor = function(){ }; ctor.prototype = parent.prototype; @@ -23,6 +23,7 @@ include = _a.include; indexOf = _a.indexOf; starts = _a.starts; + ends = _a.ends; exports.BaseNode = (function() { BaseNode = function() { }; BaseNode.prototype.compile = function(o) { @@ -419,7 +420,7 @@ this.variable = this.isSuper ? null : variable; this.args = (args || []); this.compileSplatArguments = function(o) { - return SplatNode.compileMixedArray.call(this, this.args, o); + return SplatNode.compileSplattedArray.call(this, this.args, o); }; return this; }; @@ -670,7 +671,7 @@ ArrayNode = function(objects) { this.objects = objects || []; this.compileSplatLiteral = function(o) { - return SplatNode.compileMixedArray.call(this, this.objects, o); + return SplatNode.compileSplattedArray.call(this, this.objects, o); }; return this; }; @@ -1015,28 +1016,26 @@ trail = trailings ? (", " + (name) + ".length - " + trailings) : ''; return "" + (utility('slice')) + ".call(" + name + ", " + index + trail + ")"; }; - SplatNode.compileMixedArray = function(list, o) { - var _b, _c, _d, arg, args, code, i, prev; + SplatNode.compileSplattedArray = function(list, o) { + var _b, _c, arg, args, code, i, last, prev; args = []; - i = 0; - _c = list; - for (_b = 0, _d = _c.length; _b < _d; _b++) { - arg = _c[_b]; + _b = list; + for (i = 0, _c = _b.length; i < _c; i++) { + arg = _b[i]; code = arg.compile(o); + prev = args[(last = args.length - 1)]; 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 + "]"); + if (prev && starts(prev, '[') && ends(prev, ']')) { + args[last] = ("" + (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 + "])"); + } else if (prev && starts(prev, '.concat([') && ends(prev, '])')) { + args[last] = ("" + (prev.substr(0, prev.length - 2)) + ", " + code + "])"); continue; } else { code = ("[" + code + "]"); } } args.push(i === 0 ? code : (".concat(" + code + ")")); - i += 1; } return args.join(''); }; diff --git a/src/helpers.coffee b/src/helpers.coffee index 5da369ed..7f51c75b 100644 --- a/src/helpers.coffee +++ b/src/helpers.coffee @@ -22,6 +22,11 @@ helpers.include: include: (list, value) -> helpers.starts: starts: (string, literal, start) -> string.substring(start, (start or 0) + literal.length) is literal +# Peek at the end of a given string to see if it matches a sequence. +helpers.ends: ends: (string, literal, back) -> + start: string.length - literal.length - (back ? 0) + string.substring(start, start + literal.length) is literal + # Trim out all falsy values from an array. helpers.compact: compact: (array) -> item for item in array when item diff --git a/src/nodes.coffee b/src/nodes.coffee index 649851da..b9c0cc01 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -14,7 +14,7 @@ else Scope: this.Scope # Import the helpers we plan to use. -{compact, flatten, merge, del, include, indexOf, starts}: helpers +{compact, flatten, merge, del, include, indexOf, starts, ends}: helpers #### BaseNode @@ -403,7 +403,7 @@ exports.CallNode: class CallNode extends BaseNode @variable: if @isSuper then null else variable @args: (args or []) @compileSplatArguments: (o) -> - SplatNode.compileMixedArray.call(this, @args, o) + SplatNode.compileSplattedArray.call(this, @args, o) # Tag this invocation as creating a new instance. newInstance: -> @@ -625,7 +625,7 @@ exports.ArrayNode: class ArrayNode extends BaseNode constructor: (objects) -> @objects: objects or [] @compileSplatLiteral: (o) -> - SplatNode.compileMixedArray.call(this, @objects, o) + SplatNode.compileSplattedArray.call(this, @objects, o) compileNode: (o) -> o.indent: @idt 1 @@ -921,23 +921,21 @@ exports.SplatNode: class SplatNode extends BaseNode # Utility function that converts arbitrary number of elements, mixed with # splats, to a proper array - @compileMixedArray: (list, o) -> + @compileSplattedArray: (list, o) -> args: [] - i: 0 - for arg in list + for arg, i in list code: arg.compile o + prev: args[last: args.length - 1] 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]" + if prev and starts(prev, '[') and ends(prev, ']') + args[last]: "${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])" + else if prev and starts(prev, '.concat([') and ends(prev, '])') + args[last]: "${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 diff --git a/test/test_splats.coffee b/test/test_splats.coffee index 93d6dcc3..cc6e35ad 100644 --- a/test/test_splats.coffee +++ b/test/test_splats.coffee @@ -105,3 +105,11 @@ ok pen is 2 method 1, 2 ok pen is 2 + + +# Array splat expansions with assigns. +nums: [1, 2, 3] +list: [a: 0, nums..., b: 4] +ok a is 0 +ok b is 4 +ok list.join(' ') is '0 1 2 3 4'