optimized splatting assignment

This commit is contained in:
satyr 2010-10-26 20:51:02 +09:00
parent e36746d367
commit 1cb6464948
3 changed files with 42 additions and 29 deletions

View File

@ -933,15 +933,15 @@
return o.level <= LEVEL_LIST ? val : "(" + val + ")";
};
Assign.prototype.compilePatternMatch = function(o) {
var _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, acc, assigns, code, i, idx, isObject, ivar, obj, objects, olength, ref, rest, splat, top, val, valVar, value;
var _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, acc, assigns, code, i, idx, isObject, ivar, obj, objects, olen, ref, rest, splat, top, val, value, vvar;
top = o.level === LEVEL_TOP;
value = this.value;
objects = this.variable.base.objects;
if (!(olength = objects.length)) {
if (!(olen = objects.length)) {
return value.compile(o);
}
isObject = this.variable.isObject();
if (top && olength === 1 && !((obj = objects[0]) instanceof Splat)) {
if (top && olen === 1 && !((obj = objects[0]) instanceof Splat)) {
if (obj instanceof Assign) {
_ref2 = obj, (_ref3 = _ref2.variable, idx = _ref3.base, _ref3), obj = _ref2.value;
} else {
@ -956,12 +956,12 @@
value.properties.push(new (acc ? Accessor : Index)(idx));
return new Assign(obj, value).compile(o);
}
valVar = value.compile(o, LEVEL_LIST);
vvar = value.compile(o, LEVEL_LIST);
assigns = [];
splat = false;
if (!IDENTIFIER.test(valVar) || this.variable.assigns(valVar)) {
assigns.push("" + (ref = o.scope.freeVariable('ref')) + " = " + valVar);
valVar = ref;
if (!IDENTIFIER.test(vvar) || this.variable.assigns(vvar)) {
assigns.push("" + (ref = o.scope.freeVariable('ref')) + " = " + vvar);
vvar = ref;
}
for (i = 0, _len = objects.length; i < _len; i++) {
obj = objects[i];
@ -978,12 +978,15 @@
}
}
if (!splat && obj instanceof Splat) {
if (rest = olength - i - 1 || '') {
val = "" + olen + " <= " + vvar + ".length ? " + (utility('slice')) + ".call(" + vvar + ", " + i;
if (rest = olen - i - 1) {
ivar = o.scope.freeVariable('i');
rest = ", " + ivar + " = " + valVar + ".length - " + rest;
val += ", " + ivar + " = " + vvar + ".length - " + rest + ") : (" + ivar + " = " + i + ", [])";
} else {
val += ") : []";
}
val = new Literal(utility('slice') + (".call(" + valVar + ", " + i + rest + ")"));
splat = "" + ivar + " < " + i + " ? " + ivar + " = " + i + " : " + ivar + "++";
val = new Literal(val);
splat = "" + ivar + "++";
} else {
if (obj instanceof Splat) {
obj = obj.name.compile(o);
@ -995,12 +998,12 @@
} else {
acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0);
}
val = new Value(new Literal(valVar), [new (acc ? Accessor : Index)(idx)]);
val = new Value(new Literal(vvar), [new (acc ? Accessor : Index)(idx)]);
}
assigns.push(new Assign(obj, val).compile(o, LEVEL_LIST));
}
if (!top) {
assigns.push(valVar);
assigns.push(vvar);
}
code = assigns.join(', ');
return o.level < LEVEL_LIST ? code : "(" + code + ")";

View File

@ -764,9 +764,9 @@ exports.Assign = class Assign extends Base
top = o.level is LEVEL_TOP
{value} = this
{objects} = @variable.base
return value.compile o unless olength = objects.length
return value.compile o unless olen = objects.length
isObject = @variable.isObject()
if top and olength is 1 and (obj = objects[0]) not instanceof Splat
if top and olen is 1 and (obj = objects[0]) not instanceof Splat
# Unroll simplest cases: `{v} = x` -> `v = x.v`
if obj instanceof Assign
{variable: {base: idx}, value: obj} = obj
@ -781,12 +781,12 @@ exports.Assign = class Assign extends Base
value = new Value value
value.properties.push new (if acc then Accessor else Index) idx
return new Assign(obj, value).compile o
valVar = value.compile o, LEVEL_LIST
vvar = value.compile o, LEVEL_LIST
assigns = []
splat = false
if not IDENTIFIER.test(valVar) or @variable.assigns(valVar)
assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{valVar}"
valVar = ref
if not IDENTIFIER.test(vvar) or @variable.assigns(vvar)
assigns.push "#{ ref = o.scope.freeVariable 'ref' } = #{vvar}"
vvar = ref
for obj, i in objects
# A regular array pattern-match.
idx = i
@ -800,11 +800,14 @@ exports.Assign = class Assign extends Base
then [obj, idx] = new Value(obj.unwrapAll()).cacheReference o
else idx = if obj.tags.this then obj.properties[0].name else obj
if not splat and obj instanceof Splat
if rest = olength - i - 1 or ''
val = "#{olen} <= #{vvar}.length ? #{ utility 'slice' }.call(#{vvar}, #{i}"
if rest = olen - i - 1
ivar = o.scope.freeVariable 'i'
rest = ", #{ivar} = #{valVar}.length - #{rest}"
val = new Literal utility('slice') + ".call(#{valVar}, #{i}#{rest})"
splat = "#{ivar} < #{i} ? #{ivar} = #{i} : #{ivar}++"
val += ", #{ivar} = #{vvar}.length - #{rest}) : (#{ivar} = #{i}, [])"
else
val += ") : []"
val = new Literal val
splat = "#{ivar}++"
else
if obj instanceof Splat
obj = obj.name.compile o
@ -815,9 +818,9 @@ exports.Assign = class Assign extends Base
acc = no
else
acc = isObject and IDENTIFIER.test idx.unwrap().value or 0
val = new Value new Literal(valVar), [new (if acc then Accessor else Index) idx]
val = new Value new Literal(vvar), [new (if acc then Accessor else Index) idx]
assigns.push new Assign(obj, val).compile o, LEVEL_LIST
assigns.push valVar unless top
assigns.push vvar unless top
code = assigns.join ', '
if o.level < LEVEL_LIST then code else "(#{code})"

View File

@ -29,21 +29,28 @@ ok sumOfArgs(1, 2, 3, 4, 5) is 15
ok context.arg is 1
((splat..., @arg) ->).call context, 1, 2, 3
ok context.arg is 3
eq context.arg, 3
((@arg...) ->).call context, 1, 2, 3
ok context.arg.join ' ' is '1 2 3'
eq context.arg.join(' '), '1 2 3'
class Klass
constructor: (@one, @two) ->
obj = new Klass 1, 2
ok obj.one is 1
ok obj.two is 2
eq obj.one, 1
eq obj.two, 2
# Default arguments.
obj = f: (q = 123, @p = 456) -> q
eq obj.f(), 123
eq obj.p , 456
withSplats = (a = 2, b..., c = 3, d = 5) -> a * (b.length + 1) * c * d
eq 30, withSplats()
eq 15, withSplats 1
eq 5, withSplats 1, 1
eq 1, withSplats 1, 1, 1
eq 2, withSplats 1, 1, 1, 1