From bb2bf7ce5790b8a8373135e1a28b9e2804d211e0 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 28 Feb 2010 12:49:37 -0500 Subject: [PATCH] allowing chaining of property accesses by indentation level (really nice for Node and jQuery work) ticket #221 --- lib/lexer.js | 20 +++++++++++--------- src/lexer.coffee | 16 +++++++++------- test/test_blocks.coffee | 22 +++++++++++++++++++++- 3 files changed, 41 insertions(+), 17 deletions(-) diff --git a/lib/lexer.js b/lib/lexer.js index 59536db8..a5a581d2 100644 --- a/lib/lexer.js +++ b/lib/lexer.js @@ -223,34 +223,36 @@ this.i += indent.length; next_character = this.chunk.match(MULTI_DENT)[4]; prev = this.prev(2); - no_newlines = next_character === '.' || (this.value() && this.value().match(NO_NEWLINE) && prev && (prev[0] !== '.') && !this.value().match(CODE)); - if (no_newlines) { - return this.suppress_newlines(indent); - } size = indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length; + no_newlines = next_character === '.' || (this.value() && this.value().match(NO_NEWLINE) && prev && (prev[0] !== '.') && !this.value().match(CODE)); if (size === this.indent) { + if (no_newlines) { + return this.suppress_newlines(indent); + } return this.newline_token(indent); - } - if (size > this.indent) { + } else if (size > this.indent) { + if (no_newlines) { + return this.suppress_newlines(indent); + } diff = size - this.indent; this.token('INDENT', diff); this.indents.push(diff); } else { - this.outdent_token(this.indent - size); + this.outdent_token(this.indent - size, no_newlines); } this.indent = size; return true; }; // Record an oudent token or tokens, if we're moving back inwards past // multiple recorded indents. - Lexer.prototype.outdent_token = function outdent_token(move_out) { + Lexer.prototype.outdent_token = function outdent_token(move_out, no_newlines) { var last_indent; while (move_out > 0 && this.indents.length) { last_indent = this.indents.pop(); this.token('OUTDENT', last_indent); move_out -= last_indent; } - if (!(this.tag() === 'TERMINATOR')) { + if (!(this.tag() === 'TERMINATOR' || no_newlines)) { this.token('TERMINATOR', "\n"); } return true; diff --git a/src/lexer.coffee b/src/lexer.coffee index e824d6ea..a9714c7e 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -196,27 +196,29 @@ exports.Lexer: class Lexer @i += indent.length next_character: @chunk.match(MULTI_DENT)[4] prev: @prev(2) - no_newlines: next_character is '.' or (@value() and @value().match(NO_NEWLINE) and prev and (prev[0] isnt '.') and not @value().match(CODE)) - return @suppress_newlines(indent) if no_newlines size: indent.match(LAST_DENTS).reverse()[0].match(LAST_DENT)[1].length - return @newline_token(indent) if size is @indent - if size > @indent + no_newlines: next_character is '.' or (@value() and @value().match(NO_NEWLINE) and prev and (prev[0] isnt '.') and not @value().match(CODE)) + if size is @indent + return @suppress_newlines(indent) if no_newlines + return @newline_token(indent) + else if size > @indent + return @suppress_newlines(indent) if no_newlines diff: size - @indent @token 'INDENT', diff @indents.push diff else - @outdent_token @indent - size + @outdent_token @indent - size, no_newlines @indent: size true # Record an oudent token or tokens, if we're moving back inwards past # multiple recorded indents. - outdent_token: (move_out) -> + outdent_token: (move_out, no_newlines) -> while move_out > 0 and @indents.length last_indent: @indents.pop() @token 'OUTDENT', last_indent move_out -= last_indent - @token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR' + @token 'TERMINATOR', "\n" unless @tag() is 'TERMINATOR' or no_newlines true # Matches and consumes non-meaningful whitespace. diff --git a/test/test_blocks.coffee b/test/test_blocks.coffee index 67629dcf..532533fa 100644 --- a/test/test_blocks.coffee +++ b/test/test_blocks.coffee @@ -1,4 +1,24 @@ results: [1, 2, 3].map (x) -> x * x -ok results.join(' ') is '1 4 9', 'basic block syntax' \ No newline at end of file +ok results.join(' ') is '1 4 9', 'basic block syntax' + + +# Chained blocks, with proper indentation levels: +results: [] + +counter: { + tick: (func) -> + results.push func() + this +} + +counter + .tick -> + 3 + .tick -> + 2 + .tick -> + 1 + +ok results.join(' ') is '3 2 1' \ No newline at end of file