Skip to content

Commit

Permalink
closes #75; implemented after-loop else clause
Browse files Browse the repository at this point in the history
  • Loading branch information
satyr committed Aug 2, 2011
1 parent 08c178a commit 62c59a7
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 72 deletions.
19 changes: 16 additions & 3 deletions lib/ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -1591,7 +1591,7 @@ exports.Assign = Assign = (function(_super){
lvar = left instanceof Var;
sign = op.replace(':', '');
name = (left.front = true, left).compile(o, LEVEL_LIST);
code = !o.level && right instanceof While && (lvar || left.isSimpleAccess())
code = !o.level && right instanceof While && !right['else'] && (lvar || left.isSimpleAccess())
? (res = o.scope.temporary('res')) + " = [];\n" + this.tab + right.makeReturn(res).compile(o) + "\n" + this.tab + name + " " + sign + " " + o.scope.free(res)
: (name + " " + sign + " ") + (right.assigned = true, right).compile(o, LEVEL_LIST);
if (lvar) {
Expand Down Expand Up @@ -2392,7 +2392,7 @@ exports.While = While = (function(_super){
this.test = test;
}
}
prototype.children = ['test', 'body', 'update'];
prototype.children = ['test', 'body', 'update', 'else'];
prototype.aSource = 'test';
prototype.aTargets = ['body', 'update'];
prototype.show = function(){
Expand All @@ -2419,6 +2419,10 @@ exports.While = While = (function(_super){
}
return this;
};
prototype.addElse = function($else){
this['else'] = $else;
return this;
};
prototype.makeReturn = function(it){
if (it) {
this.body.makeReturn(it);
Expand All @@ -2443,7 +2447,7 @@ exports.While = While = (function(_super){
return head + ') {' + this.compileBody((o.indent += TAB, o));
};
prototype.compileBody = function(o, potest){
var lines, ret, code, last, res, that;
var lines, ret, code, last, res, run, that;
lines = this.body.lines;
code = ret = '';
if (this.returns) {
Expand All @@ -2452,13 +2456,22 @@ exports.While = While = (function(_super){
}
ret = "\n" + this.tab + "return " + (res || '[]') + ";";
}
if (this['else']) {
lines.unshift(JS((run = o.scope.temporary('run')) + " = true;"));
}
if (that = this.body.compile(o, LEVEL_TOP)) {
code += "\n" + that + "\n" + this.tab;
}
code += '}';
if (potest) {
code += " while (" + potest.compile((o.tab = this.tab, o), LEVEL_PAREN) + ");";
}
if (run) {
if (this.returns) {
this['else'].makeReturn();
}
code += " if (!" + run + ") " + this.compileBlock(o, this['else']);
}
return code + ret;
};
prototype.pluckDirectCalls = function(o){
Expand Down
4 changes: 3 additions & 1 deletion lib/grammar.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,10 @@ bnf = {
return $1.addElse($3);
}), o('Expression POST_IF Expression', function(){
return If($3, $1, $2 === 'unless');
}), o('LoopHead Block', function(){
}), o('LoopHead Block', function(){
return $1.addBody($2);
}), o('LoopHead Block ELSE Block', function(){
return $1.addBody($2).addElse($4);
}), o('Expression LoopHead', function(){
return $2.addBody(Block($1));
}), o('DO Block WHILE Expression', function(){
Expand Down
132 changes: 67 additions & 65 deletions lib/parser.js

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/ast.co
Original file line number Diff line number Diff line change
Expand Up @@ -934,7 +934,7 @@ class exports.Assign extends Node
lvar = left instanceof Var
sign = op.replace \: ''
name = (left <<< {+front})compile o, LEVEL_LIST
code = if not o.level and right instanceof While and
code = if not o.level and right instanceof While and not right.else and
(lvar or left.isSimpleAccess())
# Optimize `a = while ...`.
"""#{ res = o.scope.temporary \res } = [];
Expand Down Expand Up @@ -1447,7 +1447,7 @@ class exports.While extends Node
# `while true` `until false` => `for (;;)`
import {test} if @post or test.value is not ''+!un

children: <[ test body update ]>
children: <[ test body update else ]>

aSource: \test, aTargets: <[ body update ]>

Expand All @@ -1462,6 +1462,8 @@ class exports.While extends Node
body.lines.length = 0 if top?verb is \continue and not top.label
this

addElse: (@else) -> this

makeReturn: ->
if it
then @body.makeReturn it
Expand All @@ -1484,9 +1486,13 @@ class exports.While extends Node
if (last = lines[*-1]) and last not instanceof Throw
lines[*-1] = last.makeReturn res = o.scope.assign \_results '[]'
ret = "\n#{@tab}return #{ res or '[]' };"
lines.unshift JS "#{ run = o.scope.temporary \run } = true;" if @else
code += "\n#that\n#{@tab}" if @body.compile o, LEVEL_TOP
code += \}
code += " while (#{ potest.compile o<<<{@tab} LEVEL_PAREN });" if potest
if run
@else.makeReturn() if @returns
code += " if (!#run) #{ @compileBlock o, @else }"
code + ret

pluckDirectCalls: (o) ->
Expand Down
3 changes: 2 additions & 1 deletion src/grammar.co
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ bnf =

# Loops can either be normal, with a block of expressions
# to execute, or postfix, with a single expression.
o 'LoopHead Block' -> $1.addBody $2
o 'LoopHead Block' -> $1.addBody $2
o 'LoopHead Block ELSE Block' -> $1.addBody $2 .addElse $4
o 'Expression LoopHead' -> $2.addBody Block $1
o 'DO Block WHILE Expression'
, -> new While($4, $3 is \until, true)addBody $2
Expand Down
14 changes: 14 additions & 0 deletions test/loop.co
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,17 @@ a = [1 2 3]
b = []
continue while a.pop(), b.push that
eq '3,2,1' ''+b


### `else` clause
for cond of [true false]
while cond
break
else
ok not cond

r = for i til 1 then i else [9]
eq 0 r.0

r = for i til 0 then i else [9]
eq 9 r.0

0 comments on commit 62c59a7

Please sign in to comment.