From 296808d4d3805d4d4fbdf44815fd17e06db00b84 Mon Sep 17 00:00:00 2001 From: matehat Date: Mon, 22 Mar 2010 01:52:47 -0400 Subject: [PATCH] Added splats positional flexibility to pattern matching --- lib/nodes.js | 20 ++++++++++++-------- src/nodes.coffee | 18 +++++++++++++----- test/test_pattern_matching.coffee | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 13 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index 0ea0010c..88ffa512 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -934,12 +934,13 @@ // See the [ECMAScript Harmony Wiki](http://wiki.ecmascript.org/doku.php?id=harmony:destructuring) // for details. AssignNode.prototype.compile_pattern_match = function compile_pattern_match(o) { - var _a, _b, _c, access_class, assigns, code, i, idx, obj, val, val_var, value; + var _a, _b, _c, access_class, assigns, code, i, idx, obj, oindex, olength, splatted, val, val_var, value; val_var = o.scope.free_variable(); value = this.value.is_statement() ? ClosureNode.wrap(this.value) : this.value; assigns = ['' + this.tab + val_var + " = " + (value.compile(o)) + ";"]; o.top = true; o.as_statement = true; + splatted = false; _a = this.variable.base.objects; for (i = 0, _b = _a.length; i < _b; i++) { obj = _a[i]; @@ -950,12 +951,11 @@ idx = _c[1]; } access_class = this.variable.is_array() ? IndexNode : AccessorNode; - if (obj instanceof SplatNode) { - val = literal(obj.compile_value(o, val_var, this.variable.base.objects.indexOf(obj))); + if (obj instanceof SplatNode && !splatted) { + val = literal(obj.compile_value(o, val_var, ((oindex = this.variable.base.objects.indexOf(obj))), ((olength = this.variable.base.objects.length)) - oindex - 1)); + splatted = true; } else { - if (!(typeof idx === 'object')) { - idx = literal(idx); - } + typeof idx !== 'object' ? splatted ? (idx = literal('' + (val_var) + ".length - " + (olength - idx))) : (idx = literal(idx)) : null; val = new ValueNode(literal(val_var), [new access_class(idx)]); } assigns.push(new AssignNode(obj, val).compile(o)); @@ -1123,8 +1123,12 @@ }; // A compiling a splat as a destructuring assignment means slicing arguments // from the right-hand-side's corresponding array. - SplatNode.prototype.compile_value = function compile_value(o, name, index) { - return "Array.prototype.slice.call(" + name + ", " + index + ")"; + SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) { + if ((typeof trailings !== "undefined" && trailings !== null)) { + return "Array.prototype.slice.call(" + name + ", " + index + ", " + (name) + ".length - " + trailings + ")"; + } else { + return "Array.prototype.slice.call(" + name + ", " + index + ")"; + } }; return SplatNode; }).call(this); diff --git a/src/nodes.coffee b/src/nodes.coffee index a3cdd484..dbb33640 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -708,14 +708,21 @@ exports.AssignNode: class AssignNode extends BaseNode assigns: ["$@tab$val_var = ${ value.compile(o) };"] o.top: true o.as_statement: true + splatted: false for obj, i in @variable.base.objects idx: i [obj, idx]: [obj.value, obj.variable.base] if @variable.is_object() access_class: if @variable.is_array() then IndexNode else AccessorNode - if obj instanceof SplatNode - val: literal(obj.compile_value(o, val_var, @variable.base.objects.indexOf(obj))) + if obj instanceof SplatNode and not splatted + val: literal(obj.compile_value(o, val_var, (oindex: @variable.base.objects.indexOf(obj)), + (olength: @variable.base.objects.length) - oindex - 1)) + splatted: true else - idx: literal(idx) unless typeof idx is 'object' + if typeof idx isnt 'object' + if splatted + idx: literal("${val_var}.length - ${olength - idx}") + else + idx: literal(idx) val: new ValueNode(literal(val_var), [new access_class(idx)]) assigns.push(new AssignNode(obj, val).compile(o)) code: assigns.join("\n") @@ -829,8 +836,9 @@ exports.SplatNode: class SplatNode extends BaseNode # A compiling a splat as a destructuring assignment means slicing arguments # from the right-hand-side's corresponding array. - compile_value: (o, name, index) -> - "Array.prototype.slice.call($name, $index)" + compile_value: (o, name, index, trailings) -> + if trailings? then "Array.prototype.slice.call($name, $index, ${name}.length - $trailings)" \ + else "Array.prototype.slice.call($name, $index)" # Utility function that converts arbitrary number of elements, mixed with # splats, to a proper array diff --git a/test/test_pattern_matching.coffee b/test/test_pattern_matching.coffee index 46b8428a..63b025a6 100644 --- a/test/test_pattern_matching.coffee +++ b/test/test_pattern_matching.coffee @@ -28,6 +28,20 @@ ok a is 1 ok b is 2 ok c is 3 +[x,y...,z]: [1,2,3,4,5] + +ok x is 1 +ok y.length is 3 +ok z is 5 + +[x, [y, mids..., last], z..., end]: [1, [10, 20, 30, 40], 2,3,4, 5] + +ok x is 1 +ok y is 10 +ok mids.length is 2 and mids[1] is 30 +ok last is 40 +ok z.length is 3 and z[2] is 4 +ok end is 5 obj: {x: 10, y: 20, z: 30}