From 880c5c8083ab918057de02ddf3b336b8cd1baa5c Mon Sep 17 00:00:00 2001 From: Timothy Jones Date: Fri, 22 Oct 2010 00:34:51 +1300 Subject: [PATCH] Fixing destructor in magicked for. Also making destructors in range loops syntax errors. --- lib/nodes.js | 25 ++++++++++++++----------- src/nodes.coffee | 21 +++++++++++---------- test/test_comprehensions.coffee | 4 ++++ 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/lib/nodes.js b/lib/nodes.js index ae4ea370..2919285e 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1624,7 +1624,11 @@ if (this.index instanceof Value) { throw SyntaxError('index cannot be a pattern matching expression'); } + this.range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; this.pattern = this.name instanceof Value; + if (this.range && this.pattern) { + throw SyntaxError('cannot pattern match a range loop'); + } this.returns = false; return this; }; @@ -1648,17 +1652,16 @@ return ''; }; For.prototype.compileNode = function(o) { - var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, range, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, unstepPart, varPart, vars; + var body, codeInBody, forPart, guardPart, idt1, index, ivar, lastLine, lvar, name, namePart, nvar, ref, resultPart, returnResult, rvar, scope, source, sourcePart, stepPart, svar, topLevel, unstepPart, varPart, vars; topLevel = del(o, 'top') && !this.returns; - range = this.source instanceof Value && this.source.base instanceof Range && !this.source.properties.length; - source = range ? this.source.base : this.source; + source = this.range ? this.source.base : this.source; codeInBody = !this.body.containsPureStatement() && this.body.contains(function(node) { return node instanceof Code; }); scope = o.scope; name = this.name && this.name.compile(o); index = this.index && this.index.compile(o); - if (name && !this.pattern && (range || !codeInBody)) { + if (name && !this.pattern && (this.range || !codeInBody)) { scope.find(name, { immediate: true }); @@ -1671,11 +1674,11 @@ if (!topLevel) { rvar = scope.freeVariable('result'); } - ivar = range ? name : index; + ivar = this.range ? name : index; if (!ivar || codeInBody) { ivar = scope.freeVariable('i'); } - if (name && !range && codeInBody) { + if (name && !this.range && codeInBody) { nvar = scope.freeVariable('i'); } varPart = ''; @@ -1683,7 +1686,7 @@ unstepPart = ''; body = Expressions.wrap([this.body]); idt1 = this.idt(1); - if (range) { + if (this.range) { forPart = source.compile(merge(o, { index: ivar, step: this.step @@ -1717,7 +1720,7 @@ body = Expressions.wrap([new If(this.guard, body)]); } if (codeInBody) { - if (range) { + if (this.range) { body.unshift(new Literal("var " + name + " = " + ivar)); } if (namePart) { @@ -1737,10 +1740,10 @@ o.indent = this.idt(1); body = Expressions.wrap([new Literal(body.compile(o))]); if (index) { - body.push(new Assign(new Literal(index), new Literal(ivar))); + body.push(new Assign(this.index, new Literal(ivar))); } if (name) { - body.push(new Assign(new Literal(name), new Literal(nvar || ivar))); + body.push(new Assign(this.name, new Literal(nvar || ivar))); } } else { if (namePart) { @@ -1761,7 +1764,7 @@ indent: idt1, top: true })); - vars = range ? name : "" + name + ", " + ivar; + vars = this.range ? name : "" + name + ", " + ivar; return "" + resultPart + (this.tab) + "for (" + forPart + ") {" + guardPart + "\n" + varPart + body + "\n" + (this.tab) + "}" + unstepPart + returnResult; }; return For; diff --git a/src/nodes.coffee b/src/nodes.coffee index 597e5ab9..8120ba43 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -1405,7 +1405,9 @@ exports.For = class For extends Base @object = !!source.object [@name, @index] = [@index, @name] if @object throw SyntaxError 'index cannot be a pattern matching expression' if @index instanceof Value + @range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length @pattern = @name instanceof Value + throw SyntaxError 'cannot pattern match a range loop' if @range and @pattern @returns = false makeReturn: -> @@ -1423,24 +1425,23 @@ exports.For = class For extends Base # some cannot. compileNode: (o) -> topLevel = del(o, 'top') and not @returns - range = @source instanceof Value and @source.base instanceof Range and not @source.properties.length - source = if range then @source.base else @source + source = if @range then @source.base else @source codeInBody = not @body.containsPureStatement() and @body.contains (node) -> node instanceof Code scope = o.scope name = @name and @name.compile o index = @index and @index.compile o - scope.find(name, immediate: yes) if name and not @pattern and (range or not codeInBody) + scope.find(name, immediate: yes) if name and not @pattern and (@range or not codeInBody) scope.find(index, immediate: yes) if index rvar = scope.freeVariable 'result' unless topLevel - ivar = if range then name else index + ivar = if @range then name else index ivar = scope.freeVariable 'i' if not ivar or codeInBody - nvar = scope.freeVariable 'i' if name and not range and codeInBody + nvar = scope.freeVariable 'i' if name and not @range and codeInBody varPart = '' guardPart = '' unstepPart = '' body = Expressions.wrap [@body] idt1 = @idt 1 - if range + if @range forPart = source.compile merge o, {index: ivar, @step} else svar = sourcePart = @source.compile o @@ -1463,7 +1464,7 @@ exports.For = class For extends Base if @guard body = Expressions.wrap [new If @guard, body] if codeInBody - body.unshift new Literal "var #{name} = #{ivar}" if range + body.unshift new Literal "var #{name} = #{ivar}" if @range body.unshift new Literal "var #{namePart}" if namePart body.unshift new Literal "var #{index} = #{ivar}" if index lastLine = body.expressions.pop() @@ -1472,8 +1473,8 @@ exports.For = class For extends Base body.push lastLine o.indent = @idt 1 body = Expressions.wrap [new Literal body.compile o] - body.push new Assign new Literal(index), new Literal ivar if index - body.push new Assign new Literal(name), new Literal nvar or ivar if name + body.push new Assign @index, new Literal ivar if index + body.push new Assign @name, new Literal nvar or ivar if name else varPart = "#{idt1}#{namePart};\n" if namePart if forPart and name is ivar @@ -1483,7 +1484,7 @@ exports.For = class For extends Base forPart = "#{ivar} in #{sourcePart}" guardPart = "\n#{idt1}if (!#{utility('hasProp')}.call(#{svar}, #{ivar})) continue;" unless @raw body = body.compile merge o, indent: idt1, top: true - vars = if range then name else "#{name}, #{ivar}" + vars = if @range then name else "#{name}, #{ivar}" """ #{resultPart}#{@tab}for (#{forPart}) {#{guardPart} #{varPart}#{body} diff --git a/test/test_comprehensions.coffee b/test/test_comprehensions.coffee index 2aff0bff..b4d14e76 100644 --- a/test/test_comprehensions.coffee +++ b/test/test_comprehensions.coffee @@ -95,6 +95,10 @@ for i in [0] ok count is 0 ok i is 50 +for [a, b] in [[0, 1]] then -> +ok a is 0 +ok b is 1 + # Even when referenced in the filter. list = ['one', 'two', 'three']