summaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2026-01-21 19:26:42 +0100
committerMarc Vertes <mvertes@free.fr>2026-01-21 19:26:42 +0100
commitc922c797204069f42a7abf88500c5708f68a8e43 (patch)
treea0379dc6f6992f0ba077b028dfd4b031dd674d98 /parser
parentee9397bc031dc33e4f735b3331643bbf60a0d17a (diff)
feat: add support for range clause and iterators
- vm: added Pull, Next and Stop instructions, to implement iterators - lang: add Range, Next and Stop tokens - parser: handle range clause. Still naive and incomplete. - comp: generate iterator instructions from range clause. Work in progress. Only initial support for slices. Many more tests and combinations needed, but the main pattern is there now.
Diffstat (limited to 'parser')
-rw-r--r--parser/README.md4
-rw-r--r--parser/expr.go52
-rw-r--r--parser/parse.go27
3 files changed, 47 insertions, 36 deletions
diff --git a/parser/README.md b/parser/README.md
index ccf580d..dda3f25 100644
--- a/parser/README.md
+++ b/parser/README.md
@@ -59,7 +59,7 @@ Go language support:
- [x] iota expression
- [ ] defer statement
- [ ] recover statement
-- [ ] range clause
+- [x] range clause
- [ ] go statement
- [x] if statement (including else and else if)
- [x] for statement
@@ -80,7 +80,7 @@ Go language support:
- [x] call expressions
- [x] index expressions
- [x] selector expressions
-- [ ] slice expressions
+- [x] slice expressions
- [ ] type convertions
- [ ] type assertions
- [ ] parametric types (generic)
diff --git a/parser/expr.go b/parser/expr.go
index 1944827..149b5e2 100644
--- a/parser/expr.go
+++ b/parser/expr.go
@@ -17,9 +17,9 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
var ops Tokens
var ctype string
- popop := func() (t scanner.Token) {
+ popop := func() scanner.Token {
l := len(ops) - 1
- t = ops[l]
+ t := ops[l]
ops = ops[:l]
if t.Tok.IsLogicalOp() {
t.Tok = lang.Label // Implement conditional branching directly.
@@ -27,6 +27,15 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
return t
}
+ // addop adds an operator to the operator stack.
+ addop := func(t scanner.Token) {
+ // Operators on stack with a lower precedence are poped out and output first.
+ for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) {
+ out = append(out, popop())
+ }
+ ops = append(ops, t)
+ }
+
lin := len(in)
for i := 0; i < lin; i++ {
switch t := in[i]; t.Tok {
@@ -47,18 +56,19 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
case lang.Period:
// TODO: fail if next is not an ident.
t.Str += in[i+1].Str // Hardwire selector argument.
- for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) {
- out = append(out, popop())
- }
- ops = append(ops, t)
+ addop(t)
i++ // Skip over next ident.
+ case lang.Next:
+ out = append(out, t)
+
+ case lang.Range:
+ ops = ops[:len(ops)-1] // Suppress previous assign or define.
+ addop(t)
+
case lang.Colon:
t.Str = typeStr
- for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) {
- out = append(out, popop())
- }
- ops = append(ops, t)
+ addop(t)
case lang.Add, lang.And, lang.Assign, lang.Define, lang.Equal, lang.Greater, lang.Less, lang.Mul, lang.Not, lang.Sub, lang.Shl, lang.Shr:
if i == 0 || in[i-1].Tok.IsOperator() {
@@ -66,30 +76,21 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
t.Tok = lang.UnaryOp[t.Tok]
// FIXME: parsetype for composite if & or *
}
- for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) {
- out = append(out, popop())
- }
- ops = append(ops, t)
+ addop(t)
case lang.Land:
- for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) {
- out = append(out, popop())
- }
+ addop(t)
xp := strconv.Itoa(p.labelCount[p.scope])
p.labelCount[p.scope]++
out = append(out, scanner.Token{Tok: lang.JumpSetFalse, Str: p.scope + "x" + xp})
- t.Str = p.scope + "x" + xp
- ops = append(ops, t)
+ ops[len(ops)-1].Str = p.scope + "x" + xp
case lang.Lor:
- for len(ops) > 0 && p.precedence(t) < p.precedence(ops[len(ops)-1]) {
- out = append(out, popop())
- }
+ addop(t)
xp := strconv.Itoa(p.labelCount[p.scope])
p.labelCount[p.scope]++
out = append(out, scanner.Token{Tok: lang.JumpSetTrue, Str: p.scope + "x" + xp})
- t.Str = p.scope + "x" + xp
- ops = append(ops, t)
+ ops[len(ops)-1].Str = p.scope + "x" + xp
case lang.Ident:
s, sc, ok := p.Symbols.Get(t.Str, p.scope)
@@ -145,7 +146,8 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
return out, err
}
ctype = typ.String()
- p.Symbols.Add(symbol.UnsetAddr, ctype, vm.NewValue(typ), symbol.Type, typ, p.funcScope != "")
+ // p.Symbols.Add(symbol.UnsetAddr, ctype, vm.NewValue(typ), symbol.Type, typ, p.funcScope != "")
+ p.Symbols.Add(symbol.UnsetAddr, ctype, vm.NewValue(typ), symbol.Type, typ, false)
out = append(out, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: ctype})
i += n - 1
break
diff --git a/parser/parse.go b/parser/parse.go
index 46b1724..67d8657 100644
--- a/parser/parse.go
+++ b/parser/parse.go
@@ -193,25 +193,33 @@ func (p *Parser) parseGoto(in Tokens) (out Tokens, err error) {
func (p *Parser) parseFor(in Tokens) (out Tokens, err error) {
// TODO: detect invalid code.
+ var init, cond, post, body, final Tokens
fc := strconv.Itoa(p.labelCount[p.scope])
p.labelCount[p.scope]++
- var init, cond, post, body Tokens
+ breakLabel, continueLabel := p.breakLabel, p.continueLabel
+ p.pushScope("for" + fc)
+ p.breakLabel, p.continueLabel = p.scope+"e", p.scope+"b"
+ defer func() {
+ p.breakLabel, p.continueLabel = breakLabel, continueLabel
+ p.popScope()
+ }()
pre := in[1 : len(in)-1].Split(lang.Semicolon)
switch len(pre) {
case 1:
- cond = pre[0]
+ if in.Index(lang.Range) >= 0 {
+ init = pre[0]
+ // cond = Tokens{{Tok: lang.Next, Str: p.scope + "c"}}
+ // final = Tokens{{Tok: lang.Stop, Str: p.scope + "f"}}
+ cond = Tokens{{Tok: lang.Next}}
+ final = Tokens{{Tok: lang.Stop}}
+ } else {
+ cond = pre[0]
+ }
case 3:
init, cond, post = pre[0], pre[1], pre[2]
default:
return nil, ErrFor
}
- breakLabel, continueLabel := p.breakLabel, p.continueLabel
- p.pushScope("for" + fc)
- p.breakLabel, p.continueLabel = p.scope+"e", p.scope+"b"
- defer func() {
- p.breakLabel, p.continueLabel = breakLabel, continueLabel
- p.popScope()
- }()
if len(init) > 0 {
if init, err = p.parseStmt(init); err != nil {
return nil, err
@@ -239,6 +247,7 @@ func (p *Parser) parseFor(in Tokens) (out Tokens, err error) {
out = append(out,
scanner.Token{Tok: lang.Goto, Str: p.scope + "b"},
scanner.Token{Tok: lang.Label, Str: p.scope + "e"})
+ out = append(out, final...)
return out, err
}