diff --git a/lib/lexer.js b/lib/lexer.js index 9cc03109..33b84ca1 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -139,8 +139,13 @@ tag = 'LEADING_WHEN'; } this.i += id.length; - if (!accessed && include(COFFEE_ALIASES, id)) { - tag = (id = CONVERSIONS[id]); + if (!accessed) { + if (include(COFFEE_ALIASES, id)) { + tag = (id = CONVERSIONS[id]); + } + if (this.prev() && this.prev()[0] === 'ASSIGN' && include(HALF_ASSIGNMENTS, tag)) { + return this.tag_half_assignment(tag); + } } this.token(tag, id); return true; @@ -339,7 +344,7 @@ // here. `;` and newlines are both treated as a `TERMINATOR`, we distinguish // parentheses that indicate a method call from regular parentheses, and so on. Lexer.prototype.literal_token = function literal_token() { - var last, match, prev_spaced, space, tag, value; + var match, prev_spaced, space, tag, value; match = this.chunk.match(OPERATOR); value = match && match[1]; space = match && match[2]; @@ -373,11 +378,9 @@ } this.i += value.length; if (space && prev_spaced && this.prev()[0] === 'ASSIGN' && include(HALF_ASSIGNMENTS, tag)) { - last = this.tokens.pop(); - this.tokens.push(['' + tag + "=", '' + tag + "=", last[2]]); - } else { - this.token(tag, value); + return this.tag_half_assignment(tag); } + this.token(tag, value); return true; }; // Token Manipulators @@ -404,6 +407,13 @@ indent = (doc.match(HEREDOC_INDENT) || ['']).sort()[0]; return doc.replace(new RegExp("^" + indent, 'gm'), '').replace(MULTILINER, "\\n").replace(new RegExp(quote, 'g'), '\\"'); }; + // Tag a half assignment. + Lexer.prototype.tag_half_assignment = function tag_half_assignment(tag) { + var last; + last = this.tokens.pop(); + this.tokens.push(['' + tag + "=", '' + tag + "=", last[2]]); + return true; + }; // A source of ambiguity in our grammar used to be parameter lists in function // definitions versus argument lists in function calls. Walk backwards, tagging // parameters specially in order to make things easier for the parser. diff --git a/src/lexer.coffee b/src/lexer.coffee index 2efe14f4..e650551e 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -100,7 +100,9 @@ exports.Lexer: class Lexer @identifier_error id if include RESERVED, id tag: 'LEADING_WHEN' if tag is 'WHEN' and include LINE_BREAK, @tag() @i += id.length - tag: id: CONVERSIONS[id] if not accessed and include(COFFEE_ALIASES, id) + if not accessed + tag: id: CONVERSIONS[id] if include COFFEE_ALIASES, id + return @tag_half_assignment(tag) if @prev() and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag @token(tag, id) true @@ -270,11 +272,8 @@ exports.Lexer: class Lexer tag: 'CALL_START' if value is '(' tag: 'INDEX_START' if value is '[' @i += value.length - if space and prev_spaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag - last: @tokens.pop() - @tokens.push ["$tag=", "$tag=", last[2]] - else - @token tag, value + return @tag_half_assignment(tag) if space and prev_spaced and @prev()[0] is 'ASSIGN' and include HALF_ASSIGNMENTS, tag + @token tag, value true # Token Manipulators @@ -299,6 +298,12 @@ exports.Lexer: class Lexer .replace(MULTILINER, "\\n") .replace(new RegExp(quote, 'g'), '\\"') + # Tag a half assignment. + tag_half_assignment: (tag) -> + last: @tokens.pop() + @tokens.push ["$tag=", "$tag=", last[2]] + true + # A source of ambiguity in our grammar used to be parameter lists in function # definitions versus argument lists in function calls. Walk backwards, tagging # parameters specially in order to make things easier for the parser. diff --git a/test/test_half_assignments.coffee b/test/test_half_assignments.coffee new file mode 100644 index 00000000..6752b3ae --- /dev/null +++ b/test/test_half_assignments.coffee @@ -0,0 +1,36 @@ +num: 10 +num: - 5 + +ok num is 5 + +num: -3 + +ok num is -3 + +num: +3 + +ok num is 3 + +num: * 10 + +ok num is 30 + +num: / 10 + +ok num is 3 + + +val: false +val: or 'value' + +ok val is 'value' + +val: and 'other' + +ok val is 'other' + + +val: null +val: ? 'value' + +ok val is 'value' \ No newline at end of file