Skip to content

Commit

Permalink
nested loops no longer have flat results, but comprehensions still do,
Browse files Browse the repository at this point in the history
…closes #173
  • Loading branch information
gkz committed Oct 3, 2012
1 parent 6168229 commit 7a4a4ce
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 41 deletions.
68 changes: 53 additions & 15 deletions lib/ast.js
Expand Up @@ -3028,8 +3028,12 @@ exports.While = While = (function(superclass){
};
prototype.isStatement = prototype.isArray = YES;
prototype.makeComprehension = function(toAdd, loops){
this.isComprehension = true;
while (loops.length) {
toAdd = loops.pop().addBody(Block(toAdd));
if (!toAdd.isComprehension) {
toAdd.inComprehension = true;
}
}
return this.addBody(Block(toAdd));
};
Expand Down Expand Up @@ -3066,7 +3070,7 @@ exports.While = While = (function(superclass){
return this;
};
prototype.makeReturn = function(it){
var ref$;
var ref$, last;
if (it) {
if (this.objComp) {
this.body = Block(this.body.makeObjReturn(it));
Expand All @@ -3077,9 +3081,14 @@ exports.While = While = (function(superclass){
if (!(this.body || this.index)) {
this.addBody(Block(Var(this.index = 'ridx$')));
}
this.body.makeReturn(it);
if ((ref$ = this['else']) != null) {
ref$.makeReturn(it);
last = (ref$ = this.body.lines) != null ? ref$[ref$.length - 1] : void 8;
if ((this.isComprehension || this.inComprehension) && !(last != null && last.isComprehension)) {
this.body.makeReturn(it);
if ((ref$ = this['else']) != null) {
ref$.makeReturn(it);
}
} else {
this.resVar = it;
}
}
} else {
Expand Down Expand Up @@ -3112,22 +3121,51 @@ exports.While = While = (function(superclass){
return head + ') {' + this.compileBody((o.indent += TAB, o));
};
prototype.compileBody = function(o){
var lines, yet, tab, ret, code, empty, key$, res, ref$, that;
var lines, yet, tab, mid, ret, code, empty, last, hasLoop, res, temp, key$, ref$, that;
o['break'] = o['continue'] = true;
lines = this.body.lines, yet = this.yet, tab = this.tab;
code = ret = '';
code = ret = mid = '';
empty = this.objComp ? '{}' : '[]';
last = lines != null ? lines[lines.length - 1] : void 8;
if (!((this.isComprehension || this.inComprehension) && !(last != null && last.isComprehension))) {
this.traverseChildren(function(it){
if (it instanceof While) {
hasLoop = true;
}
});
if (this.returns && !this.resVar) {
this.resVar = res = o.scope.assign('results$', empty);
}
if (this.resVar && (last instanceof While || hasLoop)) {
temp = o.scope.temporary('lresult');
lines.unshift(Assign(Var(temp), Arr(), '='));
if (lines[key$ = lines.length - 1] != null) {
lines[key$] = lines[key$].makeReturn(temp);
}
mid += TAB + "" + Chain(Var(this.resVar)).add(Index(Key('push'), '.', true)).add(Call([Chain(Var(temp))])).compile(o) + ";\n" + this.tab;
} else {
this.hasReturned = true;
if (this.resVar) {
this.body.makeReturn(this.resVar);
if ((ref$ = this['else']) != null) {
ref$.makeReturn();
}
}
}
}
if (this.returns) {
if (this.objComp) {
this.body = Block(this.body.makeObjReturn('results$'));
}
if (this.guard && this.objComp) {
this.body = If(this.guard, this.body);
}
empty = this.objComp ? '{}' : '[]';
if (lines[key$ = lines.length - 1] != null) {
lines[key$] = lines[key$].makeReturn(res = o.scope.assign('results$', empty));
if ((!last instanceof While && !this.hasReturned) || this.isComprehension || this.inComprehension) {
if (lines[key$ = lines.length - 1] != null) {
lines[key$] = lines[key$].makeReturn(res = o.scope.assign('results$', empty));
}
}
ret = "\n" + this.tab + "return " + (res || empty) + ";";
ret += "\n" + this.tab + "return " + (res || empty) + ";";
if ((ref$ = this['else']) != null) {
ref$.makeReturn();
}
Expand All @@ -3136,6 +3174,7 @@ exports.While = While = (function(superclass){
if (that = this.body.compile(o, LEVEL_TOP)) {
code += "\n" + that + "\n" + tab;
}
code += mid;
code += '}';
if (this.post) {
code += " while (" + this.test.compile((o.tab = tab, o), LEVEL_PAREN) + ");";
Expand Down Expand Up @@ -3441,21 +3480,20 @@ exports.Case = Case = (function(superclass){
return this;
};
prototype.compileCase = function(o, tab, nobr, bool, type, target){
var res$, i$, ref$, len$, test, j$, ref1$, len1$, t, tests, i, tar, binary, that, code, lines, last, ft;
res$ = [];
var tests, i$, ref$, len$, test, j$, ref1$, len1$, t, i, tar, binary, that, code, lines, last, ft;
tests = [];
for (i$ = 0, len$ = (ref$ = this.tests).length; i$ < len$; ++i$) {
test = ref$[i$];
test = test.expandSlice(o).unwrap();
if (test instanceof Arr && type !== 'match') {
for (j$ = 0, len1$ = (ref1$ = test.items).length; j$ < len1$; ++j$) {
t = ref1$[j$];
res$.push(t);
tests.push(t);
}
} else {
res$.push(test);
tests.push(test);
}
}
tests = res$;
tests.length || tests.push(Literal('void'));
if (type === 'match') {
for (i = 0, len$ = tests.length; i < len$; ++i) {
Expand Down
14 changes: 10 additions & 4 deletions lib/grammar.js
Expand Up @@ -68,14 +68,16 @@ bnf = {
return Chain(new For({
from: $2,
op: $3,
to: $4
to: $4,
inComprehension: true
}));
}), o('[ Expression TO Expression BY Expression ]', function(){
return Chain(new For({
from: $2,
op: $3,
to: $4,
step: $6
step: $6,
inComprehension: true
}));
}), o('Chain DOT [ Expression TO Expression ]', function(){
return Chain(Slice({
Expand Down Expand Up @@ -520,18 +522,22 @@ bnf = {
};
operators = [['left', 'POST_IF', 'FOR', 'WHILE'], ['right', 'BACKPIPE'], ['right', ',', 'ASSIGN', 'HURL', 'EXTENDS', 'INDENT', 'SWITCH', 'CASE', 'TO', 'BY', 'LABEL', 'WHERE'], ['left', 'PIPE'], ['right', 'LOGIC'], ['left', 'BITWISE'], ['right', 'COMPARE'], ['left', 'RELATION'], ['right', 'CONCAT'], ['left', 'SHIFT', 'IMPORT', 'CLONEPORT'], ['left', '+-'], ['left', 'MATH'], ['right', 'UNARY'], ['right', 'POWER'], ['right', 'COMPOSE'], ['nonassoc', 'CREMENT'], ['left', 'BACKTICK']];
tokens = (function(){
var ref$, i$, ref1$, len$, j$, ref2$, len1$, results$ = [];
var ref$, lresult$, i$, ref1$, len$, lresult1$, j$, ref2$, len1$, results$ = [];
for (name in ref$ = bnf) {
alts = ref$[name];
lresult$ = [];
for (i$ = 0, len$ = (ref1$ = alts).length; i$ < len$; ++i$) {
alt = ref1$[i$];
lresult1$ = [];
for (j$ = 0, len1$ = (ref2$ = alt[0]).length; j$ < len1$; ++j$) {
token = ref2$[j$];
if (!(token in bnf)) {
results$.push(token);
lresult1$.push(token);
}
}
lresult$.push(lresult1$);
}
results$.push(lresult$);
}
return results$;
}()).join(' ');
Expand Down
6 changes: 4 additions & 2 deletions lib/parser.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 38 additions & 10 deletions src/ast.ls
Expand Up @@ -1853,7 +1853,10 @@ class exports.While extends Node
::isStatement = ::isArray = YES

makeComprehension: (toAdd, loops) ->
while loops.length then toAdd = loops.pop!addBody Block toAdd
@is-comprehension = true
while loops.length
toAdd = loops.pop!addBody Block toAdd
toAdd <<< {+in-comprehension} if not toAdd.is-comprehension
@addBody Block toAdd

getJump: (ctx or {}) ->
Expand All @@ -1877,8 +1880,12 @@ class exports.While extends Node
else
unless @body or @index
@addBody Block Var @index = \ridx$
@body.makeReturn it
@else?makeReturn it
last = @body.lines?[*-1]
if (@is-comprehension or @in-comprehension) and not last?is-comprehension
@body.makeReturn it
@else?makeReturn it
else
@res-var = it
else
@getJump! or @returns = true
this
Expand All @@ -1900,16 +1907,36 @@ class exports.While extends Node
compileBody: (o) ->
o.break = o.continue = true
{body: {lines}, yet, tab} = this
code = ret = ''
code = ret = mid = ''
empty = if @objComp then '{}' else '[]'
last = lines?[*-1]
unless (@is-comprehension or @in-comprehension) and not last?is-comprehension
var has-loop
@traverseChildren !-> if it instanceof While then has-loop := true
if @returns and not @res-var
@res-var = res = o.scope.assign \results$ empty
if @res-var and (last instanceof While or has-loop)
temp = o.scope.temporary \lresult
lines.unshift Assign (Var temp), Arr!, \=
lines[*-1]?=makeReturn temp
mid += "#TAB#{Chain Var @res-var
.add Index (Key \push), \., true
.add Call [Chain Var temp] .compile o };\n#{@tab}"
else
@has-returned = true
if @res-var
@body.makeReturn @res-var
@else?makeReturn!
if @returns
@body = Block @body.makeObjReturn \results$ if @objComp
@body = If @guard, @body if @guard and @objComp
empty = if @objComp then '{}' else '[]'
lines[*-1]?=makeReturn res = o.scope.assign \results$ empty
ret = "\n#{@tab}return #{ res or empty };"
if (not last instanceof While and not @has-returned) or @is-comprehension or @in-comprehension
lines[*-1]?=makeReturn res = o.scope.assign \results$ empty
ret += "\n#{@tab}return #{ res or empty };"
@else?makeReturn!
yet and lines.unshift JS "#yet = false;"
code += "\n#that\n#tab" if @body.compile o, LEVEL_TOP
code += mid
code += \}
code += " while (#{ @test.compile o<<<{tab} LEVEL_PAREN });" if @post
if yet
Expand Down Expand Up @@ -2111,11 +2138,12 @@ class exports.Case extends Node
this

compileCase: (o, tab, nobr, bool, type, target) ->
tests = for test in @tests
tests = []
for test in @tests
test.=expandSlice(o)unwrap!
if test instanceof Arr and type isnt \match
for t in test.items then t
else test
for t in test.items then tests.push t
else tests.push test
tests.length or tests.push Literal \void
if type is \match
for test, i in tests
Expand Down
4 changes: 2 additions & 2 deletions src/grammar.ls
Expand Up @@ -106,9 +106,9 @@ bnf =
, -> Chain(Chain Var \flip$ .add Call [$3]).flipIt!add Call [$5]

o '[ Expression TO Expression ]'
, -> Chain new For from: $2, op: $3, to: $4
, -> Chain new For from: $2, op: $3, to: $4, in-comprehension: true
o '[ Expression TO Expression BY Expression ]'
, -> Chain new For from: $2, op: $3, to: $4, step: $6
, -> Chain new For from: $2, op: $3, to: $4, step: $6, in-comprehension: true

o 'Chain DOT [ Expression TO Expression ]'
, -> Chain Slice type: $5, target: $1, from: $4, to: $6
Expand Down

0 comments on commit 7a4a4ce

Please sign in to comment.