mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
fixing issue #485, unary minus following an existential operator.
This commit is contained in:
parent
49020208f9
commit
1c7d51a2c4
7 changed files with 32 additions and 21 deletions
|
@ -565,7 +565,7 @@
|
|||
return new OpNode('&&', $1, $3);
|
||||
}), o("Expression || Expression", function() {
|
||||
return new OpNode('||', $1, $3);
|
||||
}), o("Expression ? Expression", function() {
|
||||
}), o("Expression OP? Expression", function() {
|
||||
return new OpNode('?', $1, $3);
|
||||
}), o("Expression -= Expression", function() {
|
||||
return new OpNode('-=', $1, $3);
|
||||
|
@ -596,7 +596,7 @@
|
|||
})
|
||||
]
|
||||
};
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']];
|
||||
operators = [["left", '?'], ["nonassoc", 'UMINUS', 'UPLUS', '!', '!!', '~', '++', '--'], ["left", '*', '/', '%'], ["left", '+', '-'], ["left", '<<', '>>', '>>>'], ["left", '&', '|', '^'], ["left", '<=', '<', '>', '>='], ["right", 'DELETE', 'INSTANCEOF', 'TYPEOF'], ["left", '==', '!='], ["left", '&&', '||', 'OP?'], ["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?='], ["left", '.'], ["right", 'INDENT'], ["left", 'OUTDENT'], ["right", 'WHEN', 'LEADING_WHEN', 'IN', 'OF', 'BY', 'THROW'], ["right", 'FOR', 'WHILE', 'UNTIL', 'LOOP', 'NEW', 'SUPER', 'CLASS'], ["left", 'EXTENDS'], ["right", 'ASSIGN', 'RETURN'], ["right", '->', '=>', 'UNLESS', 'IF', 'ELSE']];
|
||||
tokens = [];
|
||||
_a = grammar;
|
||||
for (name in _a) { if (__hasProp.call(_a, name)) {
|
||||
|
|
|
@ -306,6 +306,8 @@
|
|||
}
|
||||
} else if (value === ';') {
|
||||
tag = 'TERMINATOR';
|
||||
} else if (value === '?' && prevSpaced) {
|
||||
tag = 'OP?';
|
||||
} else if (include(CALLABLE, this.tag()) && !prevSpaced) {
|
||||
if (value === '(') {
|
||||
tag = 'CALL_START';
|
||||
|
@ -363,6 +365,9 @@
|
|||
};
|
||||
Lexer.prototype.tagHalfAssignment = function(tag) {
|
||||
var last;
|
||||
if (tag === 'OP?') {
|
||||
tag = '?';
|
||||
}
|
||||
last = this.tokens.pop();
|
||||
this.tokens.push([("" + tag + "="), ("" + tag + "="), last[2]]);
|
||||
return true;
|
||||
|
@ -600,7 +605,7 @@
|
|||
NOT_REGEX = ['NUMBER', 'REGEX', '++', '--', 'FALSE', 'NULL', 'TRUE', ']'];
|
||||
CALLABLE = ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::'];
|
||||
LINE_BREAK = ['INDENT', 'OUTDENT', 'TERMINATOR'];
|
||||
HALF_ASSIGNMENTS = ['-', '+', '/', '*', '%', '||', '&&', '?'];
|
||||
HALF_ASSIGNMENTS = ['-', '+', '/', '*', '%', '||', '&&', '?', 'OP?'];
|
||||
CONVERSIONS = {
|
||||
'and': '&&',
|
||||
'or': '||',
|
||||
|
|
10
lib/nodes.js
10
lib/nodes.js
|
@ -96,10 +96,10 @@
|
|||
BaseNode.prototype.traverse = function(block) {
|
||||
return this.traverseChildren(true, block);
|
||||
};
|
||||
BaseNode.prototype.toString = function(idt) {
|
||||
var _b, _c, _d, _e, child;
|
||||
BaseNode.prototype.toString = function(idt, override) {
|
||||
var _b, _c, _d, _e, child, children;
|
||||
idt = idt || '';
|
||||
return '\n' + idt + this['class'] + (function() {
|
||||
children = (function() {
|
||||
_b = []; _d = this.collectChildren();
|
||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||
child = _d[_c];
|
||||
|
@ -107,6 +107,7 @@
|
|||
}
|
||||
return _b;
|
||||
}).call(this).join('');
|
||||
return '\n' + idt + (override || this['class']) + children;
|
||||
};
|
||||
BaseNode.prototype.eachChild = function(func) {
|
||||
var _b, _c, _d, _e, _f, _g, _h, attr, child;
|
||||
|
@ -1114,6 +1115,9 @@
|
|||
OpNode.prototype.isChainable = function() {
|
||||
return indexOf(this.CHAINABLE, this.operator) >= 0;
|
||||
};
|
||||
OpNode.prototype.toString = function(idt) {
|
||||
return OpNode.__superClass__.toString.call(this, idt, this['class'] + ' ' + this.operator);
|
||||
};
|
||||
OpNode.prototype.compileNode = function(o) {
|
||||
o.operation = true;
|
||||
if (this.isChainable() && this.first.unwrap() instanceof OpNode && this.first.unwrap().isChainable()) {
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -538,7 +538,7 @@ grammar: {
|
|||
|
||||
o "Expression && Expression", -> new OpNode '&&', $1, $3
|
||||
o "Expression || Expression", -> new OpNode '||', $1, $3
|
||||
o "Expression ? Expression", -> new OpNode '?', $1, $3
|
||||
o "Expression OP? Expression", -> new OpNode '?', $1, $3
|
||||
|
||||
o "Expression -= Expression", -> new OpNode '-=', $1, $3
|
||||
o "Expression += Expression", -> new OpNode '+=', $1, $3
|
||||
|
@ -579,7 +579,7 @@ operators: [
|
|||
["left", '<=', '<', '>', '>=']
|
||||
["right", 'DELETE', 'INSTANCEOF', 'TYPEOF']
|
||||
["left", '==', '!=']
|
||||
["left", '&&', '||']
|
||||
["left", '&&', '||', 'OP?']
|
||||
["right", '-=', '+=', '/=', '*=', '%=', '||=', '&&=', '?=']
|
||||
["left", '.']
|
||||
["right", 'INDENT']
|
||||
|
|
|
@ -98,8 +98,8 @@ exports.Lexer: class Lexer
|
|||
else if include(RESERVED, id)
|
||||
@identifierError id
|
||||
unless forcedIdentifier
|
||||
tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id
|
||||
return @tagHalfAssignment tag if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id
|
||||
return @tagHalfAssignment tag if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag
|
||||
@token tag, id
|
||||
@token ']', ']' if close_index
|
||||
true
|
||||
|
@ -264,6 +264,8 @@ exports.Lexer: class Lexer
|
|||
@assignmentError() if include JS_FORBIDDEN, @value
|
||||
else if value is ';'
|
||||
tag: 'TERMINATOR'
|
||||
else if value is '?' and prevSpaced
|
||||
tag: 'OP?'
|
||||
else if include(CALLABLE, @tag()) and not prevSpaced
|
||||
if value is '('
|
||||
tag: 'CALL_START'
|
||||
|
@ -309,6 +311,7 @@ exports.Lexer: class Lexer
|
|||
|
||||
# Tag a half assignment.
|
||||
tagHalfAssignment: (tag) ->
|
||||
tag: '?' if tag is 'OP?'
|
||||
last: @tokens.pop()
|
||||
@tokens.push ["$tag=", "$tag=", last[2]]
|
||||
true
|
||||
|
@ -554,7 +557,7 @@ CALLABLE: ['IDENTIFIER', 'SUPER', ')', ']', '}', 'STRING', '@', 'THIS', '?', '::
|
|||
LINE_BREAK: ['INDENT', 'OUTDENT', 'TERMINATOR']
|
||||
|
||||
# Half-assignments...
|
||||
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?']
|
||||
HALF_ASSIGNMENTS: ['-', '+', '/', '*', '%', '||', '&&', '?', 'OP?']
|
||||
|
||||
# Conversions from CoffeeScript operators into JavaScript ones.
|
||||
CONVERSIONS: {
|
||||
|
|
|
@ -78,3 +78,8 @@ ok result
|
|||
# Safely calls values off of non-existent variables.
|
||||
result: nothing?.value
|
||||
ok result is undefined
|
||||
|
||||
|
||||
# Assign to the result of an exsitential operation with a minus.
|
||||
x: null ? - 1
|
||||
ok x is - 1
|
||||
|
|
Loading…
Add table
Reference in a new issue