summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2026-01-08 23:46:02 +0100
committerMarc Vertes <mvertes@free.fr>2026-01-08 23:46:02 +0100
commit6ae0a2530c9a57fc093d2159591d9cae8140d641 (patch)
tree8c445c99bf3140930ead8ad8c70ebbed9838074e
parent6875facb39de63eb6353be2f700b9eacb631e9fa (diff)
fix: improve composite literal for slices
-rw-r--r--comp/compiler.go19
-rw-r--r--interp/interpreter_test.go4
-rw-r--r--parser/expr.go21
-rw-r--r--symbol/symbol.go19
-rw-r--r--vm/op_string.go39
-rw-r--r--vm/vm.go10
6 files changed, 73 insertions, 39 deletions
diff --git a/comp/compiler.go b/comp/compiler.go
index 9d787b6..5d55be4 100644
--- a/comp/compiler.go
+++ b/comp/compiler.go
@@ -176,10 +176,18 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) {
showStack()
pop()
ks := pop()
+ ts := top()
switch ks.Kind {
case symbol.Const:
- if v := ks.Value.Value; v.CanInt() {
- emit(t, vm.FieldFset)
+ switch ts.Type.Rtype.Kind() {
+ case reflect.Struct:
+ if v := ks.Value.Value; v.CanInt() {
+ emit(t, vm.FieldFset)
+ }
+ case reflect.Slice:
+ if v := ks.Value.Value; v.CanInt() {
+ emit(t, vm.IndexSet)
+ }
}
case symbol.Unset:
j := top().Type.FieldIndex(ks.Name)
@@ -249,7 +257,11 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) {
c.Data = append(c.Data, s.Value)
}
if s.Kind == symbol.Type {
- emit(t, vm.Fnew, s.Index)
+ if s.Type.Rtype.Kind() == reflect.Slice {
+ emit(t, vm.Fnew, s.Index, s.SliceLen)
+ } else {
+ emit(t, vm.Fnew, s.Index)
+ }
} else {
emit(t, vm.Dup, s.Index)
}
@@ -265,7 +277,6 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) {
s.Index = len(c.Data)
c.Data = append(c.Data, s.Value)
flen = append(flen, len(stack))
- log.Println("### func label:", lc, s.Index, s.Value.Value, c.Data[0].Value)
} else {
c.Data[s.Index] = s.Value
}
diff --git a/interp/interpreter_test.go b/interp/interpreter_test.go
index 5d0dd55..c7c3cbc 100644
--- a/interp/interpreter_test.go
+++ b/interp/interpreter_test.go
@@ -269,7 +269,7 @@ func TestComposite(t *testing.T) {
{src: `type T struct{N int; S string}; var t T; t = T{2, "foo"}; t`, res: `{2 foo}`}, // #03
{src: `type T struct{N int; S string}; t := T{2, "foo"}; t`, res: `{2 foo}`}, // #04
{src: `type T struct{N int; S string}; t := T{S: "foo"}; t`, res: `{0 foo}`}, // #05
- // {src: `a := []int{}`, res: `[]`}, // #06
- // {src: `a := []int{1, 2, 3}`, res: `[1 2 3]`}, // #07
+ {src: `a := []int{}`, res: `[]`}, // #06
+ {src: `a := []int{1, 2, 3}; a`, res: `[1 2 3]`}, // #07
})
}
diff --git a/parser/expr.go b/parser/expr.go
index 3895ea8..e00113f 100644
--- a/parser/expr.go
+++ b/parser/expr.go
@@ -128,6 +128,18 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
ops = append(ops, scanner.Token{Tok: lang.Composite, Pos: t.Pos, Str: typeStr})
case lang.BracketBlock:
+ if i == 0 || in[i-1].Tok.IsOperator() {
+ // array or slice type expression
+ typ, err := p.parseTypeExpr(in[i:])
+ if err != nil {
+ return out, err
+ }
+ typeStr = typ.String()
+ p.Symbols.Add(symbol.UnsetAddr, typ.String(), vm.NewValue(typ), symbol.Type, typ, p.funcScope != "")
+ out = append(out, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: typeStr})
+ i++
+ break
+ }
toks, err := p.parseExprStr(t.Block(), typeStr)
if err != nil {
return out, err
@@ -135,9 +147,6 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
out = append(out, toks...)
ops = append(ops, scanner.Token{Tok: lang.Index, Pos: t.Pos})
- case lang.Comment:
- // return out, nil
-
case lang.Struct:
typ, err := p.parseTypeExpr(in[i : i+2])
if err != nil {
@@ -146,9 +155,10 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
typeStr = typ.String()
p.Symbols.Add(symbol.UnsetAddr, typ.String(), vm.NewValue(typ), symbol.Type, typ, p.funcScope != "")
out = append(out, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: typeStr})
- log.Println("### typ:", typ)
i++
+ case lang.Comment:
+
default:
log.Println("unxexpected token:", t)
}
@@ -168,6 +178,7 @@ func (p *Parser) parseComposite(s, typ string) (Tokens, error) {
noColon := len(tokens) > 0 && tokens.Index(lang.Colon) == -1
var result Tokens
+ var sliceLen int
for i, sub := range tokens.Split(lang.Comma) {
toks, err := p.parseExpr(sub, typ)
if err != nil {
@@ -178,10 +189,12 @@ func (p *Parser) parseComposite(s, typ string) (Tokens, error) {
result = append(result, scanner.Token{Tok: lang.Int, Str: strconv.Itoa(i)})
result = append(result, toks...)
result = append(result, scanner.Token{Tok: lang.Colon, Str: ":"})
+ sliceLen++
} else {
result = append(result, toks...)
}
}
+ p.Symbols[typ].SliceLen = sliceLen
return result, nil
}
diff --git a/symbol/symbol.go b/symbol/symbol.go
index 96c860f..2ed8907 100644
--- a/symbol/symbol.go
+++ b/symbol/symbol.go
@@ -31,15 +31,16 @@ const UnsetAddr = -65535
// Symbol structure used in parser and compiler.
type Symbol struct {
- Kind Kind
- Name string //
- Index int // address of symbol in frame
- PkgPath string //
- Type *vm.Type //
- Value vm.Value //
- Cval constant.Value //
- Local bool // if true address is relative to local frame, otherwise global
- Used bool //
+ Kind Kind
+ Name string //
+ Index int // address of symbol in frame
+ PkgPath string //
+ Type *vm.Type //
+ Value vm.Value //
+ SliceLen int // initial slice length (slice types only)
+ Cval constant.Value //
+ Local bool // if true address is relative to local frame, otherwise global
+ Used bool //
}
// func (s *Symbol) String() string {
diff --git a/vm/op_string.go b/vm/op_string.go
index 15cc938..a39dcfa 100644
--- a/vm/op_string.go
+++ b/vm/op_string.go
@@ -30,28 +30,29 @@ func _() {
_ = x[Greater-19]
_ = x[Grow-20]
_ = x[Index-21]
- _ = x[Jump-22]
- _ = x[JumpTrue-23]
- _ = x[JumpFalse-24]
- _ = x[JumpSetTrue-25]
- _ = x[JumpSetFalse-26]
- _ = x[Lower-27]
- _ = x[Loweri-28]
- _ = x[Mul-29]
- _ = x[New-30]
- _ = x[Negate-31]
- _ = x[Not-32]
- _ = x[Pop-33]
- _ = x[Push-34]
- _ = x[Return-35]
- _ = x[Sub-36]
- _ = x[Subi-37]
- _ = x[Swap-38]
+ _ = x[IndexSet-22]
+ _ = x[Jump-23]
+ _ = x[JumpTrue-24]
+ _ = x[JumpFalse-25]
+ _ = x[JumpSetTrue-26]
+ _ = x[JumpSetFalse-27]
+ _ = x[Lower-28]
+ _ = x[Loweri-29]
+ _ = x[Mul-30]
+ _ = x[New-31]
+ _ = x[Negate-32]
+ _ = x[Not-33]
+ _ = x[Pop-34]
+ _ = x[Push-35]
+ _ = x[Return-36]
+ _ = x[Sub-37]
+ _ = x[Subi-38]
+ _ = x[Swap-39]
}
-const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupFnewEqualEqualSetExitFieldFieldSetFieldFsetGreaterGrowIndexJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNegateNotPopPushReturnSubSubiSwap"
+const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupFnewEqualEqualSetExitFieldFieldSetFieldFsetGreaterGrowIndexIndexSetJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNegateNotPopPushReturnSubSubiSwap"
-var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 60, 65, 73, 77, 82, 90, 99, 106, 110, 115, 119, 127, 136, 147, 159, 164, 170, 173, 176, 182, 185, 188, 192, 198, 201, 205, 209}
+var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 60, 65, 73, 77, 82, 90, 99, 106, 110, 115, 123, 127, 135, 144, 155, 167, 172, 178, 181, 184, 190, 193, 196, 200, 206, 209, 213, 217}
func (i Op) String() string {
idx := int(i) - 0
diff --git a/vm/vm.go b/vm/vm.go
index ed27148..b5c6cf5 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -41,6 +41,7 @@ const (
Greater // n1 n2 -- cond; cond = n1 > n2
Grow // -- ; sp += $1
Index // a i -- a[i] ;
+ IndexSet // a i v -- a; a[i] = v
Jump // -- ; ip += $1
JumpTrue // cond -- ; if cond { ip += $1 }
JumpFalse // cond -- ; if cond { ip += $1 }
@@ -170,6 +171,10 @@ func (m *Machine) Run() (err error) {
mem = append(mem, mem[c.Arg[0]+fp-1])
case Fnew:
mem = append(mem, NewValue(mem[c.Arg[0]].Type))
+ if len(c.Arg) > 1 {
+ mem[len(mem)-1].Grow(c.Arg[1])
+ mem[len(mem)-1].SetLen(c.Arg[1])
+ }
case Field:
fv := mem[sp-1].FieldByIndex(c.Arg)
if !fv.CanSet() {
@@ -262,8 +267,11 @@ func (m *Machine) Run() (err error) {
case Index:
mem[sp-2].Value = mem[sp-2].Index(int(mem[sp-1].Int()))
mem = mem[:sp-1]
+ case IndexSet:
+ log.Println("## IndexSet:", sp-3, mem[sp-3].Type)
+ mem[sp-3].Value.Index(int(mem[sp-2].Int())).Set(mem[sp-1].Value)
+ mem = mem[:sp-2]
case Vassign:
- // mem[sp-1].Set(mem[sp-2].Value)
mem[sp-2].Set(mem[sp-1].Value)
mem = mem[:sp-2]
}