From 0610e20a3cab2d00da276c99ae6f2a33f001f8c2 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Tue, 16 Feb 2010 23:23:43 -0500 Subject: [PATCH] fixing the extends keyword when the expressions are complex, and should only be run once -- not that it's good style -- ticket #143 --- lib/coffee_script/cake.js | 3 ++- lib/coffee_script/lexer.js | 12 ++++++++---- lib/coffee_script/nodes.js | 15 +++++++++++++-- src/cake.coffee | 3 ++- src/lexer.coffee | 6 ++++-- src/nodes.coffee | 11 ++++++++++- 6 files changed, 39 insertions(+), 11 deletions(-) diff --git a/lib/coffee_script/cake.js b/lib/coffee_script/cake.js index f8257ad9..0370a592 100755 --- a/lib/coffee_script/cake.js +++ b/lib/coffee_script/cake.js @@ -41,7 +41,8 @@ } return _a; }; - // The CommandLine handles all of the functionality of the `coffee` utility. + // Running `cake` runs the tasks you pass asynchronously (node-style), or + // prints them out, with no arguments. exports.run = function run() { return path.exists('Cakefile', function(exists) { var args; diff --git a/lib/coffee_script/lexer.js b/lib/coffee_script/lexer.js index 7458240e..46f16b18 100644 --- a/lib/coffee_script/lexer.js +++ b/lib/coffee_script/lexer.js @@ -249,11 +249,14 @@ }; // Matches and consumes non-meaningful whitespace. lex.prototype.whitespace_token = function whitespace_token() { - var space; + var prev, space; if (!((space = this.match(WHITESPACE, 1)))) { return false; } - this.tokens[this.tokens.length - 1].spaced = true; + prev = this.tokens[this.tokens.length - 1]; + if (prev) { + prev.spaced = true; + } this.i += space.length; return true; }; @@ -276,7 +279,7 @@ // Multi-character operators are also literal tokens, so that Racc can assign // the proper order of operations. lex.prototype.literal_token = function literal_token() { - var match, tag, value; + var match, prev, tag, value; match = this.chunk.match(OPERATOR); value = match && match[1]; if (value && value.match(CODE)) { @@ -287,7 +290,8 @@ if (value === ';') { tag = 'TERMINATOR'; } - if (!this.tokens[this.tokens.length - 1].spaced && CALLABLE.indexOf(this.tag()) >= 0) { + prev = this.tokens[this.tokens.length - 1]; + if (CALLABLE.indexOf(this.tag()) >= 0 && (!prev || !prev.spaced)) { if (value === '(') { tag = 'CALL_START'; } diff --git a/lib/coffee_script/nodes.js b/lib/coffee_script/nodes.js index 03b581c8..66d99f35 100644 --- a/lib/coffee_script/nodes.js +++ b/lib/coffee_script/nodes.js @@ -480,11 +480,22 @@ }, // Hooking one constructor into another's prototype chain. compile_node: function compile_node(o) { - var child, construct, parent; + var child, child_var, construct, parent, parent_var, prefix; construct = o.scope.free_variable(); child = this.child.compile(o); parent = this.parent.compile(o); - return this.idt() + construct + ' = function(){};\n' + this.idt() + construct + '.prototype = ' + parent + ".prototype;\n" + this.idt() + child + '.__superClass__ = ' + parent + ".prototype;\n" + this.idt() + child + '.prototype = new ' + construct + "();\n" + this.idt() + child + '.prototype.constructor = ' + child + ';'; + prefix = ''; + if (!(this.child instanceof ValueNode) || this.child.has_properties() || !(this.child.unwrap() instanceof LiteralNode)) { + child_var = o.scope.free_variable(); + prefix += this.idt() + child_var + ' = ' + child + ';\n'; + child = child_var; + } + if (!(this.parent instanceof ValueNode) || this.parent.has_properties() || !(this.parent.unwrap() instanceof LiteralNode)) { + parent_var = o.scope.free_variable(); + prefix += this.idt() + parent_var + ' = ' + parent + ';\n'; + parent = parent_var; + } + return prefix + this.idt() + construct + ' = function(){};\n' + this.idt() + construct + '.prototype = ' + parent + ".prototype;\n" + this.idt() + child + '.__superClass__ = ' + parent + ".prototype;\n" + this.idt() + child + '.prototype = new ' + construct + "();\n" + this.idt() + child + '.prototype.constructor = ' + child + ';'; } })); statement(ExtendsNode); diff --git a/src/cake.coffee b/src/cake.coffee index 8d6c38f1..af49ed6b 100644 --- a/src/cake.coffee +++ b/src/cake.coffee @@ -25,7 +25,8 @@ print_tasks: -> spaces: if spaces > 0 then (' ' for i in [0..spaces]).join('') else '' puts "cake " + name + spaces + ' # ' + task.description -# The CommandLine handles all of the functionality of the `coffee` utility. +# Running `cake` runs the tasks you pass asynchronously (node-style), or +# prints them out, with no arguments. exports.run: -> path.exists 'Cakefile', (exists) -> throw new Error('Cakefile not found in ' + process.cwd()) unless exists diff --git a/src/lexer.coffee b/src/lexer.coffee index d826fba1..ab45c4cb 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -209,7 +209,8 @@ lex::outdent_token: (move_out) -> # Matches and consumes non-meaningful whitespace. lex::whitespace_token: -> return false unless space: @match WHITESPACE, 1 - @tokens[@tokens.length - 1].spaced: true + prev: @tokens[@tokens.length - 1] + prev.spaced: true if prev @i += space.length true @@ -235,7 +236,8 @@ lex::literal_token: -> tag: if value.match(ASSIGNMENT) then 'ASSIGN' else value tag: 'TERMINATOR' if value == ';' - if not @tokens[@tokens.length - 1].spaced and CALLABLE.indexOf(@tag()) >= 0 + prev: @tokens[@tokens.length - 1] + if CALLABLE.indexOf(@tag()) >= 0 and (not prev or not prev.spaced) tag: 'CALL_START' if value is '(' tag: 'INDEX_START' if value is '[' @token tag, value diff --git a/src/nodes.coffee b/src/nodes.coffee index f0fe6510..55c6aef9 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -375,7 +375,16 @@ ExtendsNode: exports.ExtendsNode: inherit Node, { construct: o.scope.free_variable() child: @child.compile(o) parent: @parent.compile(o) - @idt() + construct + ' = function(){};\n' + @idt() + + prefix: '' + if not (@child instanceof ValueNode) or @child.has_properties() or not (@child.unwrap() instanceof LiteralNode) + child_var: o.scope.free_variable() + prefix += @idt() + child_var + ' = ' + child + ';\n' + child: child_var + if not (@parent instanceof ValueNode) or @parent.has_properties() or not (@parent.unwrap() instanceof LiteralNode) + parent_var: o.scope.free_variable() + prefix += @idt() + parent_var + ' = ' + parent + ';\n' + parent: parent_var + prefix + @idt() + construct + ' = function(){};\n' + @idt() + construct + '.prototype = ' + parent + ".prototype;\n" + @idt() + child + '.__superClass__ = ' + parent + ".prototype;\n" + @idt() + child + '.prototype = new ' + construct + "();\n" + @idt() +