dynakeys: can now do destructuring assignments

This commit is contained in:
satyr 2010-10-24 16:59:23 +09:00
parent 85c8a6780a
commit a458c4a905
5 changed files with 66 additions and 37 deletions

View File

@ -923,7 +923,7 @@
return o.level <= LEVEL_LIST ? val : "(" + val + ")";
};
Assign.prototype.compilePatternMatch = function(o) {
var _len, _ref2, _ref3, _ref4, _ref5, accessClass, assigns, code, i, idx, isObject, obj, objects, olength, ref, splat, top, val, valVar, value;
var _len, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, acc, assigns, code, i, idx, isObject, obj, objects, olength, ref, splat, top, val, valVar, value;
top = o.level === LEVEL_TOP;
value = this.value;
objects = this.variable.base.objects;
@ -935,10 +935,15 @@
if (obj instanceof Assign) {
_ref2 = obj, (_ref3 = _ref2.variable, idx = _ref3.base, _ref3), obj = _ref2.value;
} else {
idx = isObject ? obj.tags["this"] ? obj.properties[0].name : obj : new Literal(0);
if (obj.base instanceof Parens) {
_ref4 = this.matchParens(o, obj), obj = _ref4[0], idx = _ref4[1];
} else {
idx = isObject ? obj.tags["this"] ? obj.properties[0].name : obj : new Literal(0);
}
}
accessClass = IDENTIFIER.test(idx.value) ? Accessor : Index;
(value = Value.wrap(value)).properties.push(new accessClass(idx));
acc = IDENTIFIER.test(idx.unwrap().value || 0);
value = Value.wrap(value);
value.properties.push(new (acc ? Accessor : Index)(idx));
return new Assign(obj, value).compile(o);
}
valVar = value.compile(o, LEVEL_LIST);
@ -953,23 +958,29 @@
idx = i;
if (isObject) {
if (obj instanceof Assign) {
_ref4 = obj, (_ref5 = _ref4.variable, idx = _ref5.base, _ref5), obj = _ref4.value;
_ref5 = obj, (_ref6 = _ref5.variable, idx = _ref6.base, _ref6), obj = _ref5.value;
} else {
idx = obj.tags["this"] ? obj.properties[0].name : obj;
if (obj.base instanceof Parens) {
_ref7 = this.matchParens(o, obj), obj = _ref7[0], idx = _ref7[1];
} else {
idx = obj.tags["this"] ? obj.properties[0].name : obj;
}
}
}
if (!(obj instanceof Value || obj instanceof Splat)) {
throw SyntaxError('pattern matching must use only identifiers on the left-hand side.');
throw SyntaxError('destructuring assignment must use only identifiers on the left-hand side.');
}
accessClass = isObject && IDENTIFIER.test(idx.value) ? Accessor : Index;
if (!splat && obj instanceof Splat) {
val = new Literal(obj.compileValue(o, valVar, i, olength - i - 1));
splat = true;
} else {
if (typeof idx !== 'object') {
idx = new Literal(splat ? "" + valVar + ".length - " + (olength - idx) : idx);
acc = false;
} else {
acc = isObject && IDENTIFIER.test(idx.unwrap().value || 0);
}
val = new Value(new Literal(valVar), [new accessClass(idx)]);
val = new Value(new Literal(valVar), [new (acc ? Accessor : Index)(idx)]);
}
assigns.push(new Assign(obj, val).compile(o, LEVEL_LIST));
}
@ -984,6 +995,16 @@
_ref2 = this.variable.cacheReference(o), left = _ref2[0], rite = _ref2[1];
return new Op(this.context.slice(0, -1), left, new Assign(rite, this.value)).compile(o);
};
Assign.prototype.matchParens = function(o, obj) {
var _ref2, idx;
while (obj !== (obj = obj.unwrap())) {
}
if (!(obj instanceof Literal || obj instanceof Value)) {
throw SyntaxError('nonreference in destructuring assignment shorthand.');
}
return _ref2 = Value.wrap(obj).cacheReference(o), obj = _ref2[0], idx = _ref2[1], _ref2;
};
return Assign;
})();
exports.Code = (function() {
@ -1264,9 +1285,6 @@
Op.prototype.isUnary = function() {
return !this.second;
};
Op.prototype.isComplex = function() {
return this.operator !== '!' || this.first.isComplex();
};
Op.prototype.isChainable = function() {
var _ref2;
return (_ref2 = this.operator) === '<' || _ref2 === '>' || _ref2 === '>=' || _ref2 === '<=' || _ref2 === '===' || _ref2 === '!==';

View File

@ -60,10 +60,7 @@
if (token[0] !== 'HERECOMMENT') {
return 1;
}
before = tokens[i - 2];
prev = tokens[i - 1];
post = tokens[i + 1];
after = tokens[i + 2];
before = tokens[i - 2], prev = tokens[i - 1], post = tokens[i + 1], after = tokens[i + 2];
if ((after != null ? after[0] : undefined) === 'INDENT') {
tokens.splice(i + 2, 1);
if ((before != null ? before[0] : undefined) === 'OUTDENT' && (post != null ? post[0] : undefined) === 'TERMINATOR') {
@ -145,7 +142,7 @@
if ('HERECOMMENT' === this.tag(i + 1) || 'HERECOMMENT' === this.tag(i - 1)) {
return false;
}
_ref = this.tokens.slice(i + 1, i + 4), one = _ref[0], two = _ref[1], three = _ref[2];
_ref = this.tokens, one = _ref[i + 1], two = _ref[i + 2], three = _ref[i + 3];
tag = token[0];
return (tag === 'TERMINATOR' || tag === 'OUTDENT') && !((two != null ? two[0] : undefined) === ':' || (one != null ? one[0] : undefined) === '@' && (three != null ? three[0] : undefined) === ':' || (one != null ? one[0] : undefined) === '(') || tag === ',' && one && ((_ref2 = one[0]) !== 'IDENTIFIER' && _ref2 !== 'NUMBER' && _ref2 !== 'STRING' && _ref2 !== '@' && _ref2 !== 'TERMINATOR' && _ref2 !== 'OUTDENT' && _ref2 !== '(');
};
@ -192,8 +189,7 @@
if (tag === 'CLASS') {
classLine = true;
}
prev = tokens[i - 1];
next = tokens[i + 1];
prev = tokens[i - 1], next = tokens[i + 1];
callObject = !classLine && tag === 'INDENT' && next && next.generated && next[0] === '{' && prev && (_ref = prev[0], __indexOf.call(IMPLICIT_FUNC, _ref) >= 0);
seenSingle = false;
if (__indexOf.call(LINEBREAKS, tag) >= 0) {

View File

@ -786,12 +786,16 @@ exports.Assign = class Assign extends Base
if obj instanceof Assign
{variable: {base: idx}, value: obj} = obj
else
idx = if isObject
if obj.tags.this then obj.properties[0].name else obj
if obj.base instanceof Parens
[obj, idx] = @matchParens o, obj
else
new Literal 0
accessClass = if IDENTIFIER.test idx.value then Accessor else Index
(value = Value.wrap value).properties.push new accessClass idx
idx = if isObject
if obj.tags.this then obj.properties[0].name else obj
else
new Literal 0
acc = IDENTIFIER.test idx.unwrap().value or 0
value = Value.wrap 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
assigns = []
@ -808,17 +812,23 @@ exports.Assign = class Assign extends Base
{variable: {base: idx}, value: obj} = obj
else
# A shorthand `{a, b, @c} = val` pattern-match.
idx = if obj.tags.this then obj.properties[0].name else obj
if obj.base instanceof Parens
[obj, idx] = @matchParens o, obj
else
idx = if obj.tags.this then obj.properties[0].name else obj
unless obj instanceof Value or obj instanceof Splat
throw SyntaxError 'pattern matching must use only identifiers on the left-hand side.'
accessClass = if isObject and IDENTIFIER.test(idx.value) then Accessor else Index
throw SyntaxError \
'destructuring assignment must use only identifiers on the left-hand side.'
if not splat and obj instanceof Splat
val = new Literal obj.compileValue o, valVar, i, olength - i - 1
splat = true
else
if typeof idx isnt 'object'
idx = new Literal(if splat then "#{valVar}.length - #{ olength - idx }" else idx)
val = new Value new Literal(valVar), [new accessClass idx]
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]
assigns.push new Assign(obj, val).compile o, LEVEL_LIST
assigns.push valVar unless top
code = assigns.join ', '
@ -831,6 +841,13 @@ exports.Assign = class Assign extends Base
[left, rite] = @variable.cacheReference o
return new Op(@context.slice(0, -1), left, new Assign(rite, @value)).compile o
matchParens: (o, obj) ->
until obj is obj = obj.unwrap() then
unless obj instanceof Literal or obj instanceof Value
throw SyntaxError 'nonreference in destructuring assignment shorthand.'
[obj, idx] = Value.wrap(obj).cacheReference o
#### Code
# A function definition. This is the only node that creates a new Scope.
@ -1067,8 +1084,6 @@ exports.Op = class Op extends Base
isUnary: -> not @second
isComplex: -> @operator isnt '!' or @first.isComplex()
# Am I capable of
# [Python-style comparison chaining](http://docs.python.org/reference/expressions.html#notin)?
isChainable: -> @operator in ['<', '>', '>=', '<=', '===', '!==']

View File

@ -60,10 +60,7 @@ class exports.Rewriter
adjustComments: ->
@scanTokens (token, i, tokens) ->
return 1 unless token[0] is 'HERECOMMENT'
before = tokens[i - 2]
prev = tokens[i - 1]
post = tokens[i + 1]
after = tokens[i + 2]
{(i-2): before, (i-1): prev, (i+1): post, (i+2): after} = tokens
if after?[0] is 'INDENT'
tokens.splice i + 2, 1
if before?[0] is 'OUTDENT' and post?[0] is 'TERMINATOR'
@ -122,7 +119,7 @@ class exports.Rewriter
stack = []
condition = (token, i) ->
return false if 'HERECOMMENT' in [@tag(i + 1), @tag(i - 1)]
[one, two, three] = @tokens.slice i + 1, i + 4
{(i+1): one, (i+2): two, (i+3): three} = @tokens
[tag] = token
tag in ['TERMINATOR', 'OUTDENT'] and
not (two?[0] is ':' or one?[0] is '@' and three?[0] is ':' or one?[0] is '(') or
@ -163,8 +160,7 @@ class exports.Rewriter
@scanTokens (token, i, tokens) ->
tag = token[0]
classLine = yes if tag is 'CLASS'
prev = tokens[i - 1]
next = tokens[i + 1]
{(i-1): prev, (i+1): next} = tokens
callObject = not classLine and tag is 'INDENT' and
next and next.generated and next[0] is '{' and
prev and prev[0] in IMPLICIT_FUNC

View File

@ -248,6 +248,10 @@ eq obj[1], 1
eq 'braceless dynamic key',
(key for key of """braceless #{ 0 of ((0):(0)) and 'dynamic' } key""": 0)[0]
obj.key = 'val'
obj.val = ok
{(obj.key)} = obj
eq ok, obj.key
#542: Objects leading expression statement should be parenthesized.
{f: -> ok yes }.f() + 1