diff --git a/lib/rewriter.js b/lib/rewriter.js index 30c818cf..6c34a76d 100644 --- a/lib/rewriter.js +++ b/lib/rewriter.js @@ -16,7 +16,8 @@ this.tokens = _arg; this.removeLeadingNewlines(); this.removeMidExpressionNewlines(); - this.closeOpenPairs(); + this.closeOpenCalls(); + this.closeOpenIndexes(); this.addImplicitIndentation(); this.tagPostfixConditionals(); this.addImplicitBraces(); @@ -76,33 +77,37 @@ return 0; }); }; - exports.Rewriter.prototype.closeOpenPairs = function() { - var stack, token, _i, _len, _ref; - stack = []; - _ref = this.tokens; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - token = _ref[_i]; - switch (token[0]) { - case 'CALL_START': - case 'INDEX_START': - case '(': - case '[': - stack.push(token[0]); - break; - case 'CALL_END': - case 'INDEX_END': - case ')': - case ']': - switch (stack.pop()) { - case 'CALL_START': - token[0] = 'CALL_END'; - break; - case 'INDEX_START': - token[0] = 'INDEX_END'; - } + exports.Rewriter.prototype.closeOpenCalls = function() { + var action, condition; + condition = function(token, i) { + var _ref; + return ((_ref = token[0]) === ')' || _ref === 'CALL_END') || token[0] === 'OUTDENT' && this.tag(i - 1) === ')'; + }; + action = function(token, i) { + return this.tokens[token[0] === 'OUTDENT' ? i - 1 : i][0] = 'CALL_END'; + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'CALL_START') { + this.detectEnd(i + 1, condition, action); } - } - return this; + return 1; + }); + }; + exports.Rewriter.prototype.closeOpenIndexes = function() { + var action, condition; + condition = function(token, i) { + var _ref; + return (_ref = token[0]) === ']' || _ref === 'INDEX_END'; + }; + action = function(token, i) { + return token[0] = 'INDEX_END'; + }; + return this.scanTokens(function(token, i) { + if (token[0] === 'INDEX_START') { + this.detectEnd(i + 1, condition, action); + } + return 1; + }); }; exports.Rewriter.prototype.addImplicitBraces = function() { var action, condition, stack, start; diff --git a/src/rewriter.coffee b/src/rewriter.coffee index 50e9ec77..ac7b79ad 100644 --- a/src/rewriter.coffee +++ b/src/rewriter.coffee @@ -20,7 +20,8 @@ class exports.Rewriter rewrite: (@tokens) -> @removeLeadingNewlines() @removeMidExpressionNewlines() - @closeOpenPairs() + @closeOpenCalls() + @closeOpenIndexes() @addImplicitIndentation() @tagPostfixConditionals() @addImplicitBraces() @@ -67,19 +68,27 @@ class exports.Rewriter tokens.splice i, 1 0 - # The lexer has tagged the opening parenthesis of a method call, or the open - # bracket of an indexing operation. Match it with its paired close. - closeOpenPairs: -> - stack = [] - for token in @tokens - switch token[0] - when 'CALL_START', 'INDEX_START', '(', '[' - stack.push token[0] - when 'CALL_END', 'INDEX_END', ')', ']' - switch stack.pop() - when 'CALL_START' then token[0] = 'CALL_END' - when 'INDEX_START' then token[0] = 'INDEX_END' - this + # The lexer has tagged the opening parenthesis of a method call. Match it with + # its paired close. We have the mis-nested outdent case included here for + # calls that close on the same line, just before their outdent. + closeOpenCalls: -> + condition = (token, i) -> + token[0] in [')', 'CALL_END'] or + token[0] is 'OUTDENT' and @tag(i - 1) is ')' + action = (token, i) -> + @tokens[if token[0] is 'OUTDENT' then i - 1 else i][0] = 'CALL_END' + @scanTokens (token, i) -> + @detectEnd i + 1, condition, action if token[0] is 'CALL_START' + 1 + + # The lexer has tagged the opening parenthesis of an indexing operation call. + # Match it with its paired close. + closeOpenIndexes: -> + condition = (token, i) -> token[0] in [']', 'INDEX_END'] + action = (token, i) -> token[0] = 'INDEX_END' + @scanTokens (token, i) -> + @detectEnd i + 1, condition, action if token[0] is 'INDEX_START' + 1 # Object literals may be written with implicit braces, for simple cases. # Insert the missing braces here, so that the parser doesn't have to.