dynakeys: can now do destructuring assignments
This commit is contained in:
parent
85c8a6780a
commit
a458c4a905
42
lib/nodes.js
42
lib/nodes.js
|
@ -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 === '!==';
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 ['<', '>', '>=', '<=', '===', '!==']
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue