diff --git a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage b/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage index 29fa2ec4..88bb3bff 100644 --- a/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage +++ b/lib/coffee_script/CoffeeScript.tmbundle/Syntaxes/CoffeeScript.tmLanguage @@ -204,7 +204,7 @@ match - \b(break|when|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|where|while)\b + \b(break|catch|continue|else|finally|for|if|return|switch|then|throw|try|unless|when|while)\b name keyword.control.coffee diff --git a/lib/coffee_script/grammar.y b/lib/coffee_script/grammar.y index f89d6a9b..c4635b0d 100644 --- a/lib/coffee_script/grammar.y +++ b/lib/coffee_script/grammar.y @@ -8,7 +8,7 @@ token IDENTIFIER PROPERTY_ACCESS token CODE PARAM NEW RETURN token TRY CATCH FINALLY THROW token BREAK CONTINUE -token FOR IN WHERE WHILE +token FOR IN WHILE token SWITCH WHEN token DELETE INSTANCEOF TYPEOF token SUPER EXTENDS @@ -32,7 +32,7 @@ prechigh left '.' right INDENT left OUTDENT - right THROW FOR IN WHERE WHILE NEW SUPER + right THROW FOR IN WHILE WHEN NEW SUPER left UNLESS IF ELSE EXTENDS left ASSIGN '||=' '&&=' right RETURN @@ -313,7 +313,7 @@ rule ForSource: IN PureExpression { result = [val[1]] } | IN PureExpression - WHERE Expression { result = [val[1], val[3]] } + WHEN Expression { result = [val[1], val[3]] } ; # Switch/When blocks. diff --git a/lib/coffee_script/lexer.rb b/lib/coffee_script/lexer.rb index dc7c3eb4..67c6c1a9 100644 --- a/lib/coffee_script/lexer.rb +++ b/lib/coffee_script/lexer.rb @@ -35,18 +35,16 @@ module CoffeeScript MULTILINER = /\n/ COMMENT_CLEANER = /(^\s*#|\n\s*$)/ - # Tokens that always constitute the start of an expression. - # EXP_START = ['{', '(', '['] - - # Tokens that always constitute the end of an expression. - # EXP_END = ['}', ')', ']'] - # Assignment tokens. ASSIGN = [':', '='] # Tokens that must be balanced. BALANCED_PAIRS = [['(', ')'], ['[', ']'], ['{', '}'], [:INDENT, :OUTDENT]] + # Outdents that come before these tokens don't signify the end of the + # expression. TODO: Is this safe? + EXPRESSION_TAIL = [:CATCH, :WHEN, :ELSE, ')', ']', '}'] + # Scan by attempting to match tokens one character at a time. Slow and steady. def tokenize(code) @code = code.chomp # Cleanup code by remove extra line breaks @@ -61,6 +59,7 @@ module CoffeeScript end close_indentation remove_empty_outdents + remove_mid_expression_newlines ensure_balance(*BALANCED_PAIRS) rewrite_closing_parens @tokens @@ -154,9 +153,7 @@ module CoffeeScript token(:OUTDENT, last_indent) move_out -= last_indent end - # TODO: Figure out what to do about blocks that close, ending the expression - # versus blocks that occur mid-expression. - # token("\n", "\n") + token("\n", "\n") @indent = @indents.last || 0 end @@ -183,8 +180,6 @@ module CoffeeScript value = @chunk[OPERATOR, 1] tag_parameters if value && value.match(CODE) value ||= @chunk[0,1] - # skip_following_newlines if EXP_START.include?(value) - # remove_leading_newlines if EXP_END.include?(value) tag = ASSIGN.include?(value) ? :ASSIGN : value token(tag, value) @i += value.length @@ -215,20 +210,6 @@ module CoffeeScript end end - # Consume and ignore newlines immediately after this point. - # def skip_following_newlines - # newlines = @code[(@i+1)..-1][NEWLINE, 1] - # if newlines - # @line += newlines.length - # @i += newlines.length - # end - # end - - # Discard newlines immediately before this point. - # def remove_leading_newlines - # @tokens.pop if last_value == "\n" - # end - # Close up all remaining open blocks. def close_indentation outdent_token(@indent) @@ -259,6 +240,14 @@ module CoffeeScript end end + # Some blocks occur in the middle of expressions -- when we're expecting + # this, remove their trailing newlines. + def remove_mid_expression_newlines + scan_tokens do |prev, token, post, i| + @tokens.delete_at(i) if post && EXPRESSION_TAIL.include?(post[0]) && token[0] == "\n" && prev[0] == :OUTDENT + end + end + # We'd like to support syntax like this: # el.click(event => # el.hide()) @@ -286,6 +275,8 @@ module CoffeeScript end end + # Ensure that all listed pairs of tokens are correctly balanced throughout + # the course of the token stream. def ensure_balance(*pairs) levels = Hash.new(0) scan_tokens do |prev, token, post, i| diff --git a/test/fixtures/execution/test_array_comprehension.coffee b/test/fixtures/execution/test_array_comprehension.coffee index 4d347773..8ce1e4f6 100644 --- a/test/fixtures/execution/test_array_comprehension.coffee +++ b/test/fixtures/execution/test_array_comprehension.coffee @@ -1,4 +1,4 @@ -nums: n * n for n in [1, 2, 3] where n % 2 isnt 0 +nums: n * n for n in [1, 2, 3] when n % 2 isnt 0 results: n * 2 for n in nums # next: for n in [1, 2, 3] if n % 2 isnt 0 diff --git a/test/fixtures/execution/test_everything.coffee b/test/fixtures/execution/test_everything.coffee index 22a2972c..b3fe5f70 100644 --- a/test/fixtures/execution/test_everything.coffee +++ b/test/fixtures/execution/test_everything.coffee @@ -21,7 +21,7 @@ func: => text = c.text } - c.list: l for l in d.text.split('') where l is '-' + c.list: l for l in d.text.split('') when l is '-' c.single: c.list[1..1][0]