diff --git a/README.md b/README.md index 8eeaa98..b59cbd3 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,16 @@ will produce: [1, 6] [10, 20, 20, 40, 30, 60] +The `$` symbol used in front of an iteration variable gets an index of the given interation: + + [ i | i <- ["a", "b"], $i < 1 ] + [ {i, j} | i <- ["a", "b"], $i < 1, j <- [-1, -2], $j > 0 ] + +will produce: + + [ "a" ] + [ { "i": "a", "j": -2 } ] + #### Build & Test $ cd comp && export GOPATH=$GOPATH:$(pwd) diff --git a/src/comp/grammar.y b/src/comp/grammar.y index e82776f..a1cfac3 100644 --- a/src/comp/grammar.y +++ b/src/comp/grammar.y @@ -144,11 +144,8 @@ generator_list: IDENT generator expression { gDecls.Strict(true) - varAddr, err := gDecls.Declare($1, nil, TypeOfElem($3.Id)) - if err != nil { - parseError("%v", err) - } - $$ = ForEach(gLID, varAddr, $3, $2) + varAddr, iterAddr := loop($1, $3) + $$ = ForEach(gLID, varAddr, iterAddr, $3, $2) gLID++ } | generator_list ',' expression @@ -157,11 +154,8 @@ generator_list: } | generator_list ',' IDENT generator expression { - varAddr, err := gDecls.Declare($3, nil, TypeOfElem($5.Id)) - if err != nil { - parseError("%v", err) - } - $$ = $1.Nest(gLID, varAddr, $5, $4) + varAddr, iterAddr := loop($3, $5) + $$ = $1.Nest(gLID, varAddr, iterAddr, $5, $4) gLID++ } ; @@ -271,6 +265,12 @@ unary_expression: $$ = $2.Unary(OpPos(), "+") gDecls.SetType($$, ScalarType(0)) } + | '$' IDENT + { + addr := gDecls.UseIdent("$" + $2) + $$ = ExprLoad("$"+$2, addr) + gDecls.SetType($$, ScalarType(0)) + } ; multiplicative_expression: @@ -385,6 +385,20 @@ expression: %% +func loop(name string, expr Expr) (int, int) { + varAddr, err := gDecls.Declare(name, nil, TypeOfElem(expr.Id)) + if err != nil { + parseError("%v", err) + return -1, -1 + } + iterAddr, err := gDecls.Declare("$"+name, nil, ScalarType(0)); + if err != nil { + parseError("%v", err) + return -1, -1 + } + return varAddr, iterAddr +} + type ParseError struct { Line int `json:"line"` Column int `json:"column"` diff --git a/src/comp/loop.go b/src/comp/loop.go index 1ad01d9..e0eadeb 100644 --- a/src/comp/loop.go +++ b/src/comp/loop.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Ostap Cherkashin. You can use this source code +// Copyright (c) 2013 Ostap Cherkashin, Julius Chrobak. You can use this source code // under the terms of the MIT License found in the LICENSE file. package main @@ -32,14 +32,15 @@ type Loop struct { inner *Loop resAddr int varAddr int + iterAddr int list Expr sel []Expr ret Expr parallel bool } -func ForEach(lid int, varAddr int, list Expr, parallel bool) *Loop { - return &Loop{lid, nil, -1, varAddr, list, nil, BadExpr, parallel} +func ForEach(lid int, varAddr, iterAddr int, list Expr, parallel bool) *Loop { + return &Loop{lid, nil, -1, varAddr, iterAddr, list, nil, BadExpr, parallel} } func (l *Loop) Code() []Op { @@ -59,6 +60,7 @@ func (l *Loop) Code() []Op { code = append(code, OpArg(loopJump)) code = append(code, OpArg(parallel)) code = append(code, OpLoop(l.lid)) + code = append(code, OpStore(l.iterAddr)) code = append(code, OpStore(l.varAddr)) for i, s := range l.sel { // select(s) @@ -85,8 +87,8 @@ func (l *Loop) Code() []Op { return append(code, OpNext(l.lid)) } -func (l *Loop) Nest(lid int, varAddr int, list Expr, parallel bool) *Loop { - l.innermost().inner = &Loop{lid, nil, -1, varAddr, list, nil, BadExpr, parallel} +func (l *Loop) Nest(lid int, varAddr, iterAddr int, list Expr, parallel bool) *Loop { + l.innermost().inner = &Loop{lid, nil, -1, varAddr, iterAddr, list, nil, BadExpr, parallel} return l } @@ -117,7 +119,7 @@ func (l *Loop) innermost() *Loop { func (l *Loop) codeLen(selPos int) int { jump := 0 if selPos < 0 { - jump++ /* OpStore */ + jump += 2 /* OpStore - iterAddr, varAddr */ } for i := selPos + 1; i < len(l.sel); i++ { diff --git a/src/comp/machine.go b/src/comp/machine.go index a0b66a2..265c899 100644 --- a/src/comp/machine.go +++ b/src/comp/machine.go @@ -184,6 +184,7 @@ func (p *Program) Run(s *Stack) Value { sc := s.Clone() sc.Push(list[c]) + sc.Push(Number(c)) go func(_p *Program, _s *Stack) { ch <- _p.Run(_s) @@ -209,6 +210,7 @@ func (p *Program) Run(s *Stack) Value { } else { p.loops[lid] = &iterator{1, 1, list} s.Push(list[0]) + s.Push(Number(0)) } } else { i += offset @@ -219,6 +221,7 @@ func (p *Program) Run(s *Stack) Value { loop := p.loops[op.Arg] if loop.pos > -1 && loop.pos < len(loop.list) { s.Push(loop.list[loop.pos]) + s.Push(Number(loop.pos)) loop.pos += loop.step i += offset diff --git a/src/comp/web_test.go b/src/comp/web_test.go index 8a2acce..73aaecc 100644 --- a/src/comp/web_test.go +++ b/src/comp/web_test.go @@ -377,6 +377,9 @@ func ExampleComps() { run("[i * j | i <- [1, 2, 3], trunc(i), j <- [10, 20]]") run(`[ i["a"] | i <- [{a: "a"}, {"b"}, {"c"}]]`) run(`[ i["\"a\""] | i <- [{"a"}, {"b"}, {"c"}]]`) + run(`[ i | i <~ [1,2,3,4], $i == 2 ]`) + run(`[ {$i,i} | i <- ["1a","2b","3c","4d","5e","6f"], $i < 3 ]`) + run(`[{$i, i, $j, j, $k, k}|i<-["a","b","c"],j <- [-1, -2],k <- [{id:0},{id:1}], $i < 1]`) // Output: // [1,2,3] @@ -391,6 +394,9 @@ func ExampleComps() { // [10,20,20,40,30,60] // ["a","b","c"] // ["a","b","c"] + // [3] + // [{"$i":0,"i":"1a"},{"$i":1,"i":"2b"},{"$i":2,"i":"3c"}] + // [{"$i":0,"$j":0,"$k":0,"i":"a","j":-1,"k":{"id":0}},{"$i":0,"$j":0,"$k":1,"i":"a","j":-1,"k":{"id":1}},{"$i":0,"$j":1,"$k":0,"i":"a","j":-2,"k":{"id":0}},{"$i":0,"$j":1,"$k":1,"i":"a","j":-2,"k":{"id":1}}] } func ExampleFuncs() {