diff --git a/lib/coffee_script/grammar.y b/lib/coffee_script/grammar.y index 1bbdde76..1a14e4c7 100644 --- a/lib/coffee_script/grammar.y +++ b/lib/coffee_script/grammar.y @@ -80,6 +80,7 @@ rule Block: INDENT Expressions OUTDENT { result = val[1] } + | INDENT OUTDENT { result = Expressions.new([]) } ; # All tokens that can terminate an expression. @@ -186,10 +187,7 @@ rule # Function definition. Code: ParamList "=>" Block { result = CodeNode.new(val[0], val[2]) } - | ParamList "=>" Expression { result = CodeNode.new(val[0], Expressions.new([val[2]])) } | "=>" Block { result = CodeNode.new([], val[1]) } - | "=>" Expression { result = CodeNode.new([], Expressions.new([val[1]])) } - | "=>" { result = CodeNode.new([], Expressions.new([])) } ; # The parameters to a function definition. @@ -306,7 +304,7 @@ rule # The while loop. (there is no do..while). While: - WHILE Expression Block { result = WhileNode.new(val[1], val[2]) } + WHILE Expression Block { result = WhileNode.new(val[1], val[2]) } ; # Array comprehensions, including guard and current index. @@ -325,9 +323,9 @@ rule # The source of the array comprehension can optionally be filtered. ForSource: - IN Expression { result = [val[1]] } + IN Expression { result = [val[1]] } | IN Expression - WHEN Expression { result = [val[1], val[3]] } + WHEN Expression { result = [val[1], val[3]] } ; # Switch/When blocks. @@ -336,8 +334,6 @@ rule Whens OUTDENT { result = val[3].rewrite_condition(val[1]) } | SWITCH Expression INDENT Whens ELSE Block OUTDENT { result = val[3].rewrite_condition(val[1]).add_else(val[5]) } - | SWITCH Expression INDENT - Whens ELSE Expression OUTDENT { result = val[3].rewrite_condition(val[1]).add_else(val[5]) } ; # The inner list of whens. @@ -387,8 +383,8 @@ rule # The full complement of if blocks, including postfix one-liner ifs and unlesses. If: IfBlock IfEnd { result = val[0].add_else(val[1]) } - | Expression IF Expression { result = IfNode.new(val[2], Expressions.new([val[0]]), nil, {:statement => true}) } - | Expression UNLESS Expression { result = IfNode.new(val[2], Expressions.new([val[0]]), nil, {:statement => true, :invert => true}) } + | Expression IF Expression { result = IfNode.new(val[2], Expressions.new([val[0]]), nil, {:statement => true}) } + | Expression UNLESS Expression { result = IfNode.new(val[2], Expressions.new([val[0]]), nil, {:statement => true, :invert => true}) } ; end diff --git a/lib/coffee_script/lexer.rb b/lib/coffee_script/lexer.rb index 5f5fcbf8..20f227ca 100644 --- a/lib/coffee_script/lexer.rb +++ b/lib/coffee_script/lexer.rb @@ -44,6 +44,10 @@ module CoffeeScript # Outdents that come before these tokens don't signify the end of the # expression. TODO: Is this safe? EXPRESSION_TAIL = [:CATCH, :WHEN, :ELSE, ')', ']', '}'] + + # Single-line flavors of block expressions that have unclosed endings. + # The grammar can't disambiguate them, so we insert the implicit indentation. + SINGLE_LINERS = [:ELSE, "=>"] # The inverse mappings of token pairs we're trying to fix up. INVERSES = {:INDENT => :OUTDENT, :OUTDENT => :INDENT, '(' => ')', ')' => '('} @@ -250,12 +254,12 @@ module CoffeeScript # blocks, so it doesn't need to. def add_implicit_indentation scan_tokens do |prev, token, post, i| - if token[0] == :ELSE && post[0] != :INDENT + if SINGLE_LINERS.include?(token[0]) && post[0] != :INDENT line = token[1].line @tokens.insert(i + 1, [:INDENT, Value.new(2, line)]) loop do i += 1 - if !@tokens[i] || ["\n", ")", :OUTDENT].include?(@tokens[i][0]) + if !@tokens[i] || @tokens[i][0] == "\n" @tokens.insert(i, [:OUTDENT, Value.new(2, line)]) break end diff --git a/lib/coffee_script/narwhal/coffee-script.coffee b/lib/coffee_script/narwhal/coffee-script.coffee index 95846c94..0d57256e 100644 --- a/lib/coffee_script/narwhal/coffee-script.coffee +++ b/lib/coffee_script/narwhal/coffee-script.coffee @@ -20,7 +20,9 @@ checkForErrors: coffeeProcess => # Run a simple REPL, round-tripping to the CoffeeScript compiler for every # command. exports.run: args => - return true if args.length + if args.length + exports.evalCS(File.read(path)) for path in args + return true while true try @@ -46,13 +48,3 @@ exports.compile: source => # Evaluating a string of CoffeeScript first compiles it externally. exports.evalCS: source => eval(exports.compile(source)) - -# Make a factory for the CoffeeScript environment. -exports.makeNarwhalFactory: path => - code: exports.compileFile(path) - factoryText: "function(require,exports,module,system,print){" + code + "/**/\n}" - if system.engine is "rhino" - Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null) - else - # eval requires parentheses, but parentheses break compileFunction. - eval("(" + factoryText + ")") diff --git a/lib/coffee_script/narwhal/lib/coffee-script.js b/lib/coffee_script/narwhal/lib/coffee-script.js index 9677a324..0b63db0e 100644 --- a/lib/coffee_script/narwhal/lib/coffee-script.js +++ b/lib/coffee_script/narwhal/lib/coffee-script.js @@ -18,8 +18,15 @@ // Run a simple REPL, round-tripping to the CoffeeScript compiler for every // command. exports.run = function(args) { - var result; + var __a, __b, __c, __d, path, result; if (args.length) { + __a = args; + __d = []; + for (__b=0, __c=__a.length; __b<__c; __b++) { + path = __a[__b]; + __d[__b] = exports.evalCS(File.read(path)); + } + __d; return true; } while (true) { @@ -53,16 +60,4 @@ exports.evalCS = function(source) { return eval(exports.compile(source)); }; - // Make a factory for the CoffeeScript environment. - exports.makeNarwhalFactory = function(path) { - var code, factoryText; - code = exports.compileFile(path); - factoryText = "function(require,exports,module,system,print){" + code + "/**/\n}"; - if (system.engine === "rhino") { - return Packages.org.mozilla.javascript.Context.getCurrentContext().compileFunction(global, factoryText, path, 0, null); - } else { - // eval requires parentheses, but parentheses break compileFunction. - return eval("(" + factoryText + ")"); - } - }; })(); \ No newline at end of file diff --git a/lib/coffee_script/narwhal/lib/coffee-script/loader.js b/lib/coffee_script/narwhal/lib/coffee-script/loader.js index 1a79dbbb..609385a7 100644 --- a/lib/coffee_script/narwhal/lib/coffee-script/loader.js +++ b/lib/coffee_script/narwhal/lib/coffee-script/loader.js @@ -6,13 +6,15 @@ }; loader = { // Reload the coffee-script environment from source. - reload: function(topId, path) { + reload: function(topId) { coffeescript = coffeescript || require('coffee-script'); - return (factories[topId] = coffeescript.makeNarwhalFactory(path)); + return (factories[topId] = function() { + return coffeescript; + }); }, // Ensure that the coffee-script environment is loaded. - load: function(topId, path) { - return factories[topId] = factories[topId] || this.reload(topId, path); + load: function(topId) { + return factories[topId] = factories[topId] || this.reload(topId); } }; require.loader.loaders.unshift([".coffee", loader]); diff --git a/lib/coffee_script/narwhal/loader.coffee b/lib/coffee_script/narwhal/loader.coffee index ccdcacbf..e55f7ba7 100644 --- a/lib/coffee_script/narwhal/loader.coffee +++ b/lib/coffee_script/narwhal/loader.coffee @@ -6,13 +6,13 @@ factories: {} loader: { # Reload the coffee-script environment from source. - reload: topId, path => + reload: topId => coffeescript ||= require('coffee-script') - factories[topId]: coffeescript.makeNarwhalFactory(path) + factories[topId]: => coffeescript # Ensure that the coffee-script environment is loaded. - load: topId, path => - factories[topId] ||= this.reload(topId, path) + load: topId => + factories[topId] ||= this.reload(topId) } diff --git a/lib/coffee_script/nodes.rb b/lib/coffee_script/nodes.rb index 5aa5d277..82077906 100644 --- a/lib/coffee_script/nodes.rb +++ b/lib/coffee_script/nodes.rb @@ -693,8 +693,8 @@ module CoffeeScript end # Rewrite a chain of IfNodes to add a default case as the final else. - def add_else(expressions) - chain? ? @else_body.add_else(expressions) : @else_body = expressions.unwrap + def add_else(exprs) + chain? ? @else_body.add_else(exprs) : @else_body = (exprs && exprs.unwrap) self end