diff --git a/lib/coffee_script/lexer.js b/lib/coffee_script/lexer.js index 99a16654..1f1f2d13 100644 --- a/lib/coffee_script/lexer.js +++ b/lib/coffee_script/lexer.js @@ -314,10 +314,10 @@ num = 0; pos = string.indexOf(letter); while (pos !== -1) { - count += 1; + num += 1; pos = string.indexOf(letter, pos + 1); } - return count; + return num; }; // Attempt to match a string against the current chunk, returning the indexed // match. diff --git a/lib/coffee_script/nodes.js b/lib/coffee_script/nodes.js index 72ebf3e7..9af2a9a1 100644 --- a/lib/coffee_script/nodes.js +++ b/lib/coffee_script/nodes.js @@ -1,5 +1,5 @@ (function(){ - var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, Expressions, ExtendsNode, IndexNode, LiteralNode, Node, ObjectNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThisNode, ValueNode, any, compact, del, dup, flatten, inherit, merge, statement; + var AccessorNode, ArrayNode, AssignNode, CallNode, ClosureNode, CodeNode, CommentNode, Expressions, ExtendsNode, IndexNode, LiteralNode, Node, ObjectNode, PushNode, RangeNode, ReturnNode, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThisNode, ValueNode, WhileNode, any, compact, del, dup, flatten, inherit, merge, statement; var __hasProp = Object.prototype.hasOwnProperty; process.mixin(require('./scope')); // The abstract base class for all CoffeeScript nodes. @@ -372,7 +372,7 @@ compile: function compile(o) { o = o || { }; - return o.scope ? compile.__superClass__.constructor.call(this, o) : this.compile_root(o); + return o.scope ? Node.prototype.compile.call(this, o) : this.compile_root(o); }, // Compile each expression in the Expressions body. compile_node: function compile_node(o) { @@ -998,4 +998,36 @@ return "Array.prototype.slice.call(" + this.name + ', ' + this.index + ')'; } })); + // A while loop, the only sort of low-level loop exposed by CoffeeScript. From + // it, all other loops can be manufactured. + WhileNode = (exports.WhileNode = inherit(Node, { + constructor: function constructor(condition, body) { + this.children = [(this.condition = condition), (this.body = body)]; + return this; + }, + top_sensitive: function top_sensitive() { + return true; + }, + compile_node: function compile_node(o) { + var cond, post, pre, returns, rvar, set, top; + returns = del(o, 'returns'); + top = del(o, 'top') && !returns; + o.indent = this.idt(1); + o.top = true; + cond = this.condition.compile(o); + set = ''; + if (!top) { + rvar = o.scope.free_variable(); + set = this.idt() + rvar + ' = [];\n'; + this.body = PushNode.wrap(rvar, this.body); + } + post = returns ? '\n' + this.idt() + 'return ' + rvar + ';' : ''; + pre = set + this.idt() + 'while (' + cond + ')'; + if (!this.body) { + return pre + ' null;' + post; + } + return pre + ' {\n' + this.body.compile(o) + '\n' + this.idt() + '}' + post; + } + })); + statement(WhileNode); })(); \ No newline at end of file diff --git a/src/lexer.coffee b/src/lexer.coffee index d09512d2..48f4031f 100644 --- a/src/lexer.coffee +++ b/src/lexer.coffee @@ -246,9 +246,9 @@ lex::count: (string, letter) -> num: 0 pos: string.indexOf(letter) while pos isnt -1 - count += 1 + num += 1 pos: string.indexOf(letter, pos + 1) - count + num # Attempt to match a string against the current chunk, returning the indexed # match. diff --git a/src/nodes.coffee b/src/nodes.coffee index ee022a64..9217f46f 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -182,7 +182,7 @@ Expressions: exports.Expressions: inherit Node, { compile: (o) -> o ||= {} - if o.scope then super(o) else @compile_root(o) + if o.scope then Node::compile.call(this, o) else @compile_root(o) # Compile each expression in the Expressions body. compile_node: (o) -> @@ -711,6 +711,37 @@ SplatNode: exports.SplatNode: inherit Node, { } +# A while loop, the only sort of low-level loop exposed by CoffeeScript. From +# it, all other loops can be manufactured. +WhileNode: exports.WhileNode: inherit Node, { + + constructor: (condition, body) -> + @children:[@condition: condition, @body: body] + this + + top_sensitive: -> + true + + compile_node: (o) -> + returns: del(o, 'returns') + top: del(o, 'top') and not returns + o.indent: @idt(1) + o.top: true + cond: @condition.compile(o) + set: '' + if not top + rvar: o.scope.free_variable() + set: @idt() + rvar + ' = [];\n' + @body: PushNode.wrap(rvar, @body) + post: if returns then '\n' + @idt() + 'return ' + rvar + ';' else '' + pre: set + @idt() + 'while (' + cond + ')' + return pre + ' null;' + post if not @body + pre + ' {\n' + @body.compile(o) + '\n' + @idt() + '}' + post + +} + +statement WhileNode +