From 60f6ebc8d8369721e105d826145af2b8856ac67e Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Tue, 27 Jan 2026 16:37:02 +0100 Subject: fix: improve multiple define The VM Vassign instruction now takes an argument to indicates the number of assignations to perform on the stack. Definitions with a function returning multiple values now work. There is still some simplifications, and also to apply the same strategy to var declarations with assign. --- comp/compiler.go | 28 +++++++++++++++++++--------- interp/interpreter_test.go | 14 +++++++------- parser/decl.go | 2 +- parser/parse.go | 8 ++++---- vm/vm.go | 9 +++++++-- 5 files changed, 38 insertions(+), 23 deletions(-) diff --git a/comp/compiler.go b/comp/compiler.go index 37ed0bd..ebb9926 100644 --- a/comp/compiler.go +++ b/comp/compiler.go @@ -208,15 +208,25 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { c.emit(t, vm.Grow, t.Arg[0].(int)) case lang.Define: - rhs := pop() - typ := rhs.Type - if typ == nil { - typ = rhs.Value.Type + showStack(stack) + n := t.Arg[0].(int) + l := len(stack) + rhs := stack[l-n:] + stack = stack[:l-n] + l = len(stack) + lhs := stack[l-n:] + stack = stack[:l-n] + showStack(stack) + for i, r := range rhs { + // Propage type of rhs to lhs. + typ := r.Type + if typ == nil { + typ = r.Value.Type + } + lhs[i].Type = typ + c.Data[lhs[i].Index] = vm.NewValue(typ) } - lhs := pop() - lhs.Type = typ - c.Data[lhs.Index] = vm.NewValue(typ) - c.emit(t, vm.Vassign) + c.emit(t, vm.Vassign, n) case lang.Assign: rhs := pop() @@ -234,7 +244,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { c.Data[lhs.Index] = vm.NewValue(rhs.Type) c.Symbols[lhs.Name].Type = rhs.Type } - c.emit(t, vm.Vassign) + c.emit(t, vm.Vassign, t.Arg[0].(int)) case lang.IndexAssign: s := stack[len(stack)-3] diff --git a/interp/interpreter_test.go b/interp/interpreter_test.go index e6274a4..4e8721a 100644 --- a/interp/interpreter_test.go +++ b/interp/interpreter_test.go @@ -72,13 +72,13 @@ func TestExpr(t *testing.T) { func TestAssign(t *testing.T) { run(t, []etest{ - {src: "var a int = 1; a", res: "1"}, // #00 - {src: "var a, b int = 1, 2; b", res: "2"}, // #01 - {src: "var a, b int; a, b = 1, 2; b", res: "2"}, // #02 - {src: "a, b := 1, 2; b", res: "2"}, // #03 - {src: "func f() int {return 2}; a := f(); a", res: "2"}, // #04 - // {src: "func f() (int, int) {return 2, 3}; a, b := f(), b", res: "3"}, // #05 - // {src: "func f() (int, int) {return 2, 3}; var a, b = f(), b", res: "3"}, // #06 + {src: "var a int = 1; a", res: "1"}, // #00 + {src: "var a, b int = 1, 2; b", res: "2"}, // #01 + {src: "var a, b int; a, b = 1, 2; b", res: "2"}, // #02 + {src: "a, b := 1, 2; b", res: "2"}, // #03 + {src: "func f() int {return 2}; a := f(); a", res: "2"}, // #04 + {src: "func f() (int, int) {return 2, 3}; a, b := f(); b", res: "3"}, // #05 + // {src: "func f() (int, int) {return 2, 3}; var a, b = f(); b", res: "3"}, // #06 }) } diff --git a/parser/decl.go b/parser/decl.go index 378eb56..0ba0075 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -358,7 +358,7 @@ func (p *Parser) parseVarLine(in Tokens) (out Tokens, err error) { } out = append(out, newIdent(vars[i], 0)) out = append(out, v...) - out = append(out, newToken(lang.Assign, "", 0)) + out = append(out, newToken(lang.Assign, "", 0, 1)) } return out, err } diff --git a/parser/parse.go b/parser/parse.go index 9c1fd13..68721f2 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -184,11 +184,11 @@ func (p *Parser) parseAssign(in Tokens, aindex int) (out Tokens, err error) { // Map elements cannot be assigned directly, but only through IndexAssign. out = out[:len(out)-1] out = append(out, toks...) - out = append(out, newToken(lang.IndexAssign, "", in[aindex].Pos)) + out = append(out, newToken(lang.IndexAssign, "", in[aindex].Pos, len(lhs))) } else { out = append(out, toks...) if out[len(out)-1].Tok != lang.Range { - out = append(out, newToken(in[aindex].Tok, "", in[aindex].Pos)) + out = append(out, newToken(in[aindex].Tok, "", in[aindex].Pos, len(lhs))) } } return out, err @@ -215,10 +215,10 @@ func (p *Parser) parseAssign(in Tokens, aindex int) (out Tokens, err error) { // Map elements cannot be assigned directly, but only through IndexAssign. out = out[:len(out)-1] out = append(out, toks...) - out = append(out, newToken(lang.IndexAssign, "", in[aindex].Pos)) + out = append(out, newToken(lang.IndexAssign, "", in[aindex].Pos, 1)) } else { out = append(out, toks...) - out = append(out, newToken(in[aindex].Tok, "", in[aindex].Pos)) + out = append(out, newToken(in[aindex].Tok, "", in[aindex].Pos, 1)) } } return out, err diff --git a/vm/vm.go b/vm/vm.go index f5bb78e..96d61eb 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -311,8 +311,13 @@ func (m *Machine) Run() (err error) { mem[sp-3].SetMapIndex(mem[sp-2].Value, mem[sp-1].Value) mem = mem[:sp-2] case Vassign: - mem[sp-2].Set(mem[sp-1].Value) - mem = mem[:sp-2] + n := c.Arg[0] + for i := 0; i < n; i++ { + mem[sp-n-i-1].Set(mem[sp-n+i].Value) + } + mem = mem[:sp-n-1] + // mem[sp-2].Set(mem[sp-1].Value) + // mem = mem[:sp-2] } ip++ } -- cgit v1.2.3