From c922c797204069f42a7abf88500c5708f68a8e43 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Wed, 21 Jan 2026 19:26:42 +0100 Subject: 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. --- comp/compiler.go | 48 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 15 deletions(-) (limited to 'comp') diff --git a/comp/compiler.go b/comp/compiler.go index 4c691b2..55a3166 100644 --- a/comp/compiler.go +++ b/comp/compiler.go @@ -51,6 +51,14 @@ func errorf(format string, v ...any) error { return fmt.Errorf(loc+format, v...) } +func showStack(stack []*symbol.Symbol) { + _, file, line, _ := runtime.Caller(1) + fmt.Fprintf(os.Stderr, "%s%d: showstack: %d\n", path.Base(file), line, len(stack)) + for i, s := range stack { + fmt.Fprintf(os.Stderr, " stack[%d]: %v\n", i, s) + } +} + // Generate generates vm code and data from parsed tokens. func (c *Compiler) Generate(tokens parser.Tokens) (err error) { log.Println("Codegen tokens:", tokens) @@ -68,14 +76,6 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { pop := func() *symbol.Symbol { l := len(stack) - 1; s := stack[l]; stack = stack[:l]; return s } popflen := func() int { le := len(flen) - 1; l := flen[le]; flen = flen[:le]; return l } - showStack := func() { - _, file, line, _ := runtime.Caller(1) - fmt.Fprintf(os.Stderr, "%s%d: showstack: %d\n", path.Base(file), line, len(stack)) - for i, s := range stack { - fmt.Fprintf(os.Stderr, " stack[%d]: %v\n", i, s) - } - } - for _, t := range tokens { switch t.Tok { case lang.Int: @@ -128,7 +128,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { emit(t, vm.Deref) case lang.Index: - showStack() + showStack(stack) pop() s := pop() if s.Type.Rtype.Kind() == reflect.Map { @@ -147,7 +147,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { emit(t, vm.Lower) case lang.Call: - showStack() + showStack(stack) narg := t.Beg // FIXME: t.Beg is hijacked to store the number of function parameters. s := stack[len(stack)-1-narg] if s.Kind != symbol.Value { @@ -163,7 +163,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { } emit(t, vm.Call, narg) - showStack() + showStack(stack) break } fallthrough // A symValue must be called through callX. @@ -211,7 +211,6 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { emit(t, vm.Grow, t.Beg) case lang.Define: - showStack() rhs := pop() typ := rhs.Type if typ == nil { @@ -223,7 +222,6 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { emit(t, vm.Vassign) case lang.Assign: - showStack() rhs := pop() lhs := pop() if lhs.Local { @@ -264,7 +262,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { case lang.Ident: s, ok := c.Symbols[t.Str] if !ok { - // it could be either an undefined symbol or a key ident in a literal composite expr. + // It could be either an undefined symbol or a key ident in a literal composite expr. s = &symbol.Symbol{Name: t.Str} } log.Println("Ident symbol", t.Str, s.Local, s.Index, s.Type) @@ -368,7 +366,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { if len(stack) < 1 { return errorf("missing symbol") } - showStack() + showStack(stack) s := pop() switch s.Kind { case symbol.Pkg: @@ -414,6 +412,26 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { return fmt.Errorf("field or method not found: %s", t.Str[1:]) } + case lang.Next: + k := stack[len(stack)-2] + emit(t, vm.Next, k.Index) + + case lang.Range: + // FIXME: handle all iterator types. + // set the correct type to the iterator variables. + switch t := top().Type; t.Rtype.Kind() { + case reflect.Slice: + k := stack[len(stack)-2] + k.Type = c.Symbols["int"].Type + c.Data[k.Index] = vm.NewValue(k.Type) + case reflect.Map: + // FIXME: handle map + } + emit(t, vm.Pull) + + case lang.Stop: + emit(t, vm.Stop) + case lang.Return: emit(t, vm.Return, t.Beg, t.End) -- cgit v1.2.3