diff options
| author | Marc Vertes <mvertes@free.fr> | 2024-03-11 08:46:20 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-03-11 08:46:20 +0100 |
| commit | 73eb1891da7171f2bea0d3eb36e3458f267e6f19 (patch) | |
| tree | feacda8284413bcf2e7f5c712882cfe41ebe1594 | |
| parent | e02428ebd435dd2366231918f2388ab4fccf50c8 (diff) | |
| parent | 8c4fa9d85cd274439dbd7d0a5c699fe1cea557dc (diff) | |
Merge pull request #2 from mvertes/vm-type
feat: add type representation in vm package
| -rw-r--r-- | parser/compiler.go | 65 | ||||
| -rw-r--r-- | parser/decl.go | 8 | ||||
| -rw-r--r-- | parser/interpreter.go | 2 | ||||
| -rw-r--r-- | parser/parse.go | 4 | ||||
| -rw-r--r-- | parser/symbol.go | 31 | ||||
| -rw-r--r-- | parser/type.go | 29 | ||||
| -rw-r--r-- | vm/type.go | 74 | ||||
| -rw-r--r-- | vm/vm.go | 88 | ||||
| -rw-r--r-- | vm/vm_test.go | 12 |
9 files changed, 189 insertions, 124 deletions
diff --git a/parser/compiler.go b/parser/compiler.go index c77538d..7a60565 100644 --- a/parser/compiler.go +++ b/parser/compiler.go @@ -3,7 +3,6 @@ package parser import ( "fmt" "log" - "reflect" "strconv" "github.com/mvertes/parscan/lang" @@ -13,9 +12,9 @@ import ( type Compiler struct { *Parser - vm.Code // produced code, to fill VM with - Data []reflect.Value // produced data, will be at the bottom of VM stack - Entry int // offset in Code to start execution from (skip function defintions) + vm.Code // produced code, to fill VM with + Data []vm.Value // produced data, will be at the bottom of VM stack + Entry int // offset in Code to start execution from (skip function defintions) strings map[string]int // locations of strings in Data } @@ -28,7 +27,7 @@ func NewCompiler(scanner *scanner.Scanner) *Compiler { } } -func (c *Compiler) AddSym(name string, value reflect.Value) int { +func (c *Compiler) AddSym(name string, value vm.Value) int { p := len(c.Data) c.Data = append(c.Data, value) c.Parser.AddSym(p, name, value) @@ -51,7 +50,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { if err != nil { return err } - push(&symbol{kind: symConst, value: reflect.ValueOf(n), Type: reflect.TypeOf(0)}) + push(&symbol{kind: symConst, value: vm.ValueOf(n), Type: vm.TypeOf(0)}) emit(int64(t.Pos), vm.Push, int64(n)) case lang.String: @@ -59,10 +58,10 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { i, ok := c.strings[s] if !ok { i = len(c.Data) - c.Data = append(c.Data, reflect.ValueOf(s)) + c.Data = append(c.Data, vm.ValueOf(s)) c.strings[s] = i } - push(&symbol{kind: symConst, value: reflect.ValueOf(s)}) + push(&symbol{kind: symConst, value: vm.ValueOf(s)}) emit(int64(t.Pos), vm.Dup, int64(i)) case lang.Add: @@ -88,7 +87,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { // Nothing to do. case lang.Addr: - push(&symbol{Type: reflect.PointerTo(pop().Type)}) + push(&symbol{Type: vm.PointerTo(pop().Type)}) emit(int64(t.Pos), vm.Addr) case lang.Deref: @@ -110,7 +109,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { case lang.Call: typ := pop().Type // TODO: pop input types (careful with variadic function) - for i := 0; i < typ.NumOut(); i++ { + for i := 0; i < typ.Rtype.NumOut(); i++ { push(&symbol{Type: typ.Out(i)}) } emit(int64(t.Pos), vm.Call) @@ -118,7 +117,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { case lang.CallX: typ := pop().Type // TODO: pop input types (careful with variadic function) - for i := 0; i < typ.NumOut(); i++ { + for i := 0; i < typ.Rtype.NumOut(); i++ { push(&symbol{Type: typ.Out(i)}) } emit(int64(t.Pos), vm.CallX, int64(t.Beg)) @@ -131,7 +130,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { st := tokens[i-1] l := len(c.Data) typ := pop().Type - v := reflect.New(typ).Elem() + v := vm.NewValue(typ) c.addSym(l, st.Str, v, symVar, typ, false) c.Data = append(c.Data, v) emit(int64(st.Pos), vm.Assign, int64(l)) @@ -149,7 +148,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { typ := pop().Type if s.Type == nil { s.Type = typ - s.value = reflect.New(typ).Elem() + s.value = vm.NewValue(typ) } if s.local { if !s.used { @@ -199,7 +198,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { lc := len(c.Code) s, ok := c.symbols[t.Str] if ok { - s.value = reflect.ValueOf(lc) + s.value = vm.ValueOf(lc) if s.kind == symFunc { // label is a function entry point, register its code address in data. s.index = len(c.Data) @@ -208,7 +207,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { c.Data[s.index] = s.value } } else { - c.symbols[t.Str] = &symbol{kind: symLabel, value: reflect.ValueOf(lc)} + c.symbols[t.Str] = &symbol{kind: symLabel, value: vm.ValueOf(lc)} } case lang.JumpFalse: @@ -219,7 +218,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.Int() - int64(len(c.Code)) + i = s.value.Data.Int() - int64(len(c.Code)) } emit(int64(t.Pos), vm.JumpFalse, i) @@ -231,7 +230,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.Int() - int64(len(c.Code)) + i = s.value.Data.Int() - int64(len(c.Code)) } emit(int64(t.Pos), vm.JumpSetFalse, i) @@ -243,7 +242,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.Int() - int64(len(c.Code)) + i = s.value.Data.Int() - int64(len(c.Code)) } emit(int64(t.Pos), vm.JumpSetTrue, int64(i)) @@ -254,12 +253,12 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.Int() - int64(len(c.Code)) + i = s.value.Data.Int() - int64(len(c.Code)) } emit(int64(t.Pos), vm.Jump, i) case lang.Period: - if f, ok := pop().Type.FieldByName("X" + t.Str[1:]); ok { + if f, ok := pop().Type.Rtype.FieldByName("X" + t.Str[1:]); ok { emit(append([]int64{int64(t.Pos), vm.Field}, slint64(f.Index)...)...) break } @@ -291,14 +290,14 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { if !ok { return fmt.Errorf("label not found: %q", label) } - c.Code[t.Beg][2] = s.value.Int() - int64(t.Beg) + c.Code[t.Beg][2] = s.value.Data.Int() - int64(t.Beg) } return err } -func arithmeticOpType(s1, s2 *symbol) reflect.Type { return symtype(s1) } -func booleanOpType(s1, s2 *symbol) reflect.Type { return reflect.TypeOf(true) } +func arithmeticOpType(s1, s2 *symbol) *vm.Type { return symtype(s1) } +func booleanOpType(s1, s2 *symbol) *vm.Type { return vm.TypeOf(true) } func (c *Compiler) PrintCode() { labels := map[int][]string{} // labels indexed by code location @@ -306,7 +305,7 @@ func (c *Compiler) PrintCode() { for name, sym := range c.symbols { if sym.kind == symLabel || sym.kind == symFunc { - i := int(sym.value.Int()) + i := int(sym.value.Data.Int()) labels[i] = append(labels[i], name) } if sym.used { @@ -354,27 +353,19 @@ func (c *Compiler) PrintData() { } fmt.Println("# Data:") for i, d := range c.Data { - fmt.Printf("%4d %T %v %v\n", i, d.Interface(), d, dict[i]) + fmt.Printf("%4d %T %v %v\n", i, d.Data.Interface(), d.Data, dict[i]) } } -func (c *Compiler) NumIn(i int) (int, bool) { - t := reflect.TypeOf(c.Data[i]) - if t.Kind() == reflect.Func { - return t.NumIn(), t.IsVariadic() - } - return -1, false -} - -func (c *Compiler) typeSym(t reflect.Type) *symbol { - tsym, ok := c.symbols[t.String()] +func (c *Compiler) typeSym(t *vm.Type) *symbol { + tsym, ok := c.symbols[t.Rtype.String()] if !ok { tsym = &symbol{index: unsetAddr, kind: symType, Type: t} - c.symbols[t.String()] = tsym + c.symbols[t.Rtype.String()] = tsym } if tsym.index == unsetAddr { tsym.index = len(c.Data) - c.Data = append(c.Data, reflect.New(t).Elem()) + c.Data = append(c.Data, vm.NewValue(t)) } return tsym } diff --git a/parser/decl.go b/parser/decl.go index 2c8941d..d794131 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -4,14 +4,14 @@ import ( "errors" "go/constant" "go/token" - "reflect" "strings" "github.com/mvertes/parscan/lang" "github.com/mvertes/parscan/scanner" + "github.com/mvertes/parscan/vm" ) -var nilValue = reflect.ValueOf(nil) +var nilValue = vm.ValueOf(nil) func (p *Parser) ParseConst(in Tokens) (out Tokens, err error) { if len(in) < 2 { @@ -78,7 +78,7 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) { kind: symConst, index: unsetAddr, cval: cval, - value: reflect.ValueOf(constValue(cval)), + value: vm.ValueOf(constValue(cval)), local: p.funcScope != "", used: true, } @@ -225,7 +225,7 @@ func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) { if err != nil { return out, err } - p.addSym(unsetAddr, in[0].Str, reflect.New(typ).Elem(), symType, typ, p.funcScope != "") + p.addSym(unsetAddr, in[0].Str, vm.NewValue(typ), symType, typ, p.funcScope != "") return out, err } diff --git a/parser/interpreter.go b/parser/interpreter.go index 037ae5f..c5e463a 100644 --- a/parser/interpreter.go +++ b/parser/interpreter.go @@ -41,7 +41,7 @@ func (i *Interpreter) Eval(src string) (res any, err error) { i.PrintCode() } err = i.Run() - return i.Top(), err + return i.Top().Data, err } func max(a, b int) int { diff --git a/parser/parse.go b/parser/parse.go index 59083b6..ffa8102 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -420,8 +420,8 @@ func (p *Parser) ParseReturn(in Tokens) (out Tokens, err error) { // TODO: the function symbol should be already present in the parser context. // otherwise no way to handle anonymous func. s := p.function - in[0].Beg = s.Type.NumOut() - in[0].End = s.Type.NumIn() + in[0].Beg = s.Type.Rtype.NumOut() + in[0].End = s.Type.Rtype.NumIn() out = append(out, in[0]) return out, err } diff --git a/parser/symbol.go b/parser/symbol.go index 6c5ab9b..c75f241 100644 --- a/parser/symbol.go +++ b/parser/symbol.go @@ -3,8 +3,9 @@ package parser import ( "fmt" "go/constant" - "reflect" "strings" + + "github.com/mvertes/parscan/vm" ) type symKind int @@ -23,25 +24,25 @@ const unsetAddr = -65535 type symbol struct { kind symKind index int // address of symbol in frame - value reflect.Value // + Type *vm.Type // + value vm.Value // cval constant.Value // - Type reflect.Type // local bool // if true address is relative to local frame, otherwise global used bool // } -func symtype(s *symbol) reflect.Type { +func symtype(s *symbol) *vm.Type { if s.Type != nil { return s.Type } - return reflect.TypeOf(s.value) + return vm.TypeOf(s.value) } -func (p *Parser) AddSym(i int, name string, v reflect.Value) { +func (p *Parser) AddSym(i int, name string, v vm.Value) { p.addSym(i, name, v, symValue, nil, false) } -func (p *Parser) addSym(i int, name string, v reflect.Value, k symKind, t reflect.Type, local bool) { +func (p *Parser) addSym(i int, name string, v vm.Value, k symKind, t *vm.Type, local bool) { name = strings.TrimPrefix(name, "/") p.symbols[name] = &symbol{kind: k, index: i, local: local, value: v, Type: t} } @@ -66,17 +67,17 @@ func (p *Parser) getSym(name, scope string) (sym *symbol, sc string, ok bool) { func initUniverse() map[string]*symbol { return map[string]*symbol{ - "any": {kind: symType, index: unsetAddr, Type: reflect.TypeOf((*any)(nil)).Elem()}, - "bool": {kind: symType, index: unsetAddr, Type: reflect.TypeOf((*bool)(nil)).Elem()}, - "error": {kind: symType, index: unsetAddr, Type: reflect.TypeOf((*error)(nil)).Elem()}, - "int": {kind: symType, index: unsetAddr, Type: reflect.TypeOf((*int)(nil)).Elem()}, - "string": {kind: symType, index: unsetAddr, Type: reflect.TypeOf((*string)(nil)).Elem()}, + "any": {kind: symType, index: unsetAddr, Type: vm.TypeOf((*any)(nil)).Elem()}, + "bool": {kind: symType, index: unsetAddr, Type: vm.TypeOf((*bool)(nil)).Elem()}, + "error": {kind: symType, index: unsetAddr, Type: vm.TypeOf((*error)(nil)).Elem()}, + "int": {kind: symType, index: unsetAddr, Type: vm.TypeOf((*int)(nil)).Elem()}, + "string": {kind: symType, index: unsetAddr, Type: vm.TypeOf((*string)(nil)).Elem()}, "nil": {index: unsetAddr}, "iota": {kind: symConst, index: unsetAddr}, - "true": {index: unsetAddr, value: reflect.ValueOf(true), Type: reflect.TypeOf(true)}, - "false": {index: unsetAddr, value: reflect.ValueOf(false), Type: reflect.TypeOf(false)}, + "true": {index: unsetAddr, value: vm.ValueOf(true), Type: vm.TypeOf(true)}, + "false": {index: unsetAddr, value: vm.ValueOf(false), Type: vm.TypeOf(false)}, - "println": {index: unsetAddr, value: reflect.ValueOf(func(v ...any) { fmt.Println(v...) })}, + "println": {index: unsetAddr, value: vm.ValueOf(func(v ...any) { fmt.Println(v...) })}, } } diff --git a/parser/type.go b/parser/type.go index 012a574..cd63a46 100644 --- a/parser/type.go +++ b/parser/type.go @@ -3,10 +3,10 @@ package parser import ( "errors" "fmt" - "reflect" "strings" "github.com/mvertes/parscan/lang" + "github.com/mvertes/parscan/vm" ) type typeFlag int @@ -27,7 +27,7 @@ var ( // ParseTypeExpr parses a list of tokens defining a type expresssion and returns // the corresponding runtime type or an error. -func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) { +func (p *Parser) ParseTypeExpr(in Tokens) (typ *vm.Type, err error) { switch in[0].Id { case lang.BracketBlock: typ, err := p.ParseTypeExpr(in[1:]) @@ -47,16 +47,16 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) { if !ok { return nil, fmt.Errorf("invalid size") } - return reflect.ArrayOf(size, typ), nil + return vm.ArrayOf(size, typ), nil } - return reflect.SliceOf(typ), nil + return vm.SliceOf(typ), nil case lang.Mul: typ, err := p.ParseTypeExpr(in[1:]) if err != nil { return nil, err } - return reflect.PointerTo(typ), nil + return vm.PointerTo(typ), nil case lang.Func: // Get argument and return token positions depending on function pattern: @@ -95,7 +95,7 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) { if err != nil { return nil, err } - return reflect.FuncOf(arg, ret, false), nil + return vm.FuncOf(arg, ret, false), nil case lang.Ident: // TODO: selector expression (pkg.type) @@ -112,18 +112,19 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) { if in, err = p.Scan(in[1].Block(), false); err != nil { return nil, err } - var fields []reflect.StructField + var fields []*vm.Type for _, lt := range in.Split(lang.Semicolon) { types, names, err := p.parseParamTypes(lt, parseTypeType) + fmt.Println("### Names:", names, types) if err != nil { return nil, err } for i, name := range names { - fields = append(fields, reflect.StructField{Name: "X" + name, Type: types[i]}) + fields = append(fields, &vm.Type{Name: name, Rtype: types[i].Rtype}) // TODO: handle embedded fields } } - return reflect.StructOf(fields), nil + return vm.StructOf(fields), nil default: return nil, fmt.Errorf("%w: %v", TypeNotImplementedErr, in[0].Name()) @@ -132,7 +133,7 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) { // parseParamTypes parses a list of comma separated typed parameters and returns a list of // runtime types. Implicit parameter names and types are supported. -func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type, vars []string, err error) { +func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []*vm.Type, vars []string, err error) { // Parse from right to left, to allow multiple comma separated parameters of the same type. list := in.Split(lang.Comma) for i := len(list) - 1; i >= 0; i-- { @@ -150,7 +151,7 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type return nil, nil, MissingTypeErr } // Type was ommitted, apply the previous one from the right. - types = append([]reflect.Type{types[0]}, types...) + types = append([]*vm.Type{types[0]}, types...) p.addSymVar(i, param, types[0], flag, local) vars = append(vars, param) continue @@ -163,14 +164,14 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type if param != "" { p.addSymVar(i, param, typ, flag, local) } - types = append([]reflect.Type{typ}, types...) + types = append([]*vm.Type{typ}, types...) vars = append(vars, param) } return types, vars, err } -func (p *Parser) addSymVar(index int, name string, typ reflect.Type, flag typeFlag, local bool) { - zv := reflect.New(typ).Elem() +func (p *Parser) addSymVar(index int, name string, typ *vm.Type, flag typeFlag, local bool) { + zv := vm.NewValue(typ) switch flag { case parseTypeIn: p.addSym(-index-2, name, zv, symVar, typ, true) diff --git a/vm/type.go b/vm/type.go new file mode 100644 index 0000000..d29de48 --- /dev/null +++ b/vm/type.go @@ -0,0 +1,74 @@ +package vm + +import "reflect" + +// Runtime type and value representations (based on reflect). + +// Type is the representation of a runtime type. +type Type struct { + Name string + Rtype reflect.Type +} + +func (t *Type) Elem() *Type { + return &Type{Rtype: t.Rtype.Elem()} +} + +func (t *Type) Out(i int) *Type { + return &Type{Rtype: t.Rtype.Out(i)} +} + +// Value is the representation of a runtime value. +type Value struct { + Type *Type + Data reflect.Value +} + +// NewValue returns an addressable zero value for the specified type. +func NewValue(typ *Type) Value { + return Value{Type: typ, Data: reflect.New(typ.Rtype).Elem()} +} + +// TypeOf returns the runtime type of v. +func TypeOf(v any) *Type { + t := reflect.TypeOf(v) + return &Type{Name: t.Name(), Rtype: t} +} + +// ValueOf returns the runtime value of v. +func ValueOf(v any) Value { + return Value{Data: reflect.ValueOf(v)} +} + +func PointerTo(t *Type) *Type { + return &Type{Rtype: reflect.PointerTo(t.Rtype)} +} + +func ArrayOf(size int, t *Type) *Type { + return &Type{Rtype: reflect.ArrayOf(size, t.Rtype)} +} + +func SliceOf(t *Type) *Type { + return &Type{Rtype: reflect.SliceOf(t.Rtype)} +} + +func FuncOf(arg, ret []*Type, variadic bool) *Type { + a := make([]reflect.Type, len(arg)) + for i, e := range arg { + a[i] = e.Rtype + } + r := make([]reflect.Type, len(ret)) + for i, e := range ret { + r[i] = e.Rtype + } + return &Type{Rtype: reflect.FuncOf(a, r, variadic)} +} + +func StructOf(fields []*Type) *Type { + rf := make([]reflect.StructField, len(fields)) + for i, f := range fields { + rf[i].Name = "X" + f.Name + rf[i].Type = f.Rtype + } + return &Type{Rtype: reflect.StructOf(rf)} +} @@ -89,10 +89,10 @@ type Code [][]int64 // Machine represents a virtual machine. type Machine struct { - code Code // code to execute - mem []reflect.Value // memory, as a stack - ip, fp int // instruction and frame pointer - ic uint64 // instruction counter, incremented at each instruction executed + code Code // code to execute + mem []Value // memory, as a stack + ip, fp int // instruction and frame pointer + ic uint64 // instruction counter, incremented at each instruction executed // flags uint // to set options such as restrict CallX, etc... } @@ -123,27 +123,27 @@ func (m *Machine) Run() (err error) { ic++ switch op := code[ip]; op[1] { case Add: - mem[sp-2] = reflect.ValueOf(int(mem[sp-2].Int() + mem[sp-1].Int())) + mem[sp-2] = ValueOf(int(mem[sp-2].Data.Int() + mem[sp-1].Data.Int())) mem = mem[:sp-1] case Mul: - mem[sp-2] = reflect.ValueOf(int(mem[sp-2].Int() * mem[sp-1].Int())) + mem[sp-2] = ValueOf(int(mem[sp-2].Data.Int() * mem[sp-1].Data.Int())) mem = mem[:sp-1] case Addr: - mem[sp-1] = mem[sp-1].Addr() + mem[sp-1].Data = mem[sp-1].Data.Addr() case Assign: - mem[op[2]].Set(mem[sp-1]) + mem[op[2]].Data.Set(mem[sp-1].Data) mem = mem[:sp-1] case Fassign: - mem[fp+int(op[2])-1].Set(mem[sp-1]) + mem[fp+int(op[2])-1].Data.Set(mem[sp-1].Data) mem = mem[:sp-1] case Call: - nip := int(mem[sp-1].Int()) - mem = append(mem[:sp-1], reflect.ValueOf(ip+1), reflect.ValueOf(fp)) + nip := int(mem[sp-1].Data.Int()) + mem = append(mem[:sp-1], ValueOf(ip+1), ValueOf(fp)) ip = nip fp = sp + 1 continue case Calli: - mem = append(mem, reflect.ValueOf(ip+1), reflect.ValueOf(fp)) + mem = append(mem, ValueOf(ip+1), ValueOf(fp)) fp = sp + 2 ip += int(op[2]) continue @@ -151,57 +151,57 @@ func (m *Machine) Run() (err error) { l := int(op[2]) in := make([]reflect.Value, l) for i := range in { - in[i] = mem[sp-2-i] + in[i] = mem[sp-2-i].Data } - f := mem[sp-1] + f := mem[sp-1].Data mem = mem[:sp-l-1] for _, v := range f.Call(in) { - mem = append(mem, v) + mem = append(mem, Value{Data: v}) } case Deref: - mem[sp-1] = mem[sp-1].Elem() + mem[sp-1].Data = mem[sp-1].Data.Elem() case Dup: mem = append(mem, mem[int(op[2])]) case New: - mem[int(op[2])+fp-1] = reflect.New(mem[int(op[3])].Type()).Elem() + mem[int(op[2])+fp-1] = NewValue(mem[int(op[3])].Type) case Equal: - mem[sp-2] = reflect.ValueOf(mem[sp-2].Equal(mem[sp-1])) + mem[sp-2] = ValueOf(mem[sp-2].Data.Equal(mem[sp-1].Data)) mem = mem[:sp-1] case EqualSet: - if mem[sp-2].Equal(mem[sp-1]) { + if mem[sp-2].Data.Equal(mem[sp-1].Data) { // If equal then lhs and rhs are popped, replaced by test result, as in Equal. - mem[sp-2] = reflect.ValueOf(true) + mem[sp-2] = ValueOf(true) mem = mem[:sp-1] } else { // If not equal then the lhs is let on stack for further processing. // This is used to simplify bytecode in case clauses of switch statments. - mem[sp-1] = reflect.ValueOf(false) + mem[sp-1] = ValueOf(false) } case Exit: return err case Fdup: mem = append(mem, mem[int(op[2])+fp-1]) case Field: - mem[sp-1] = mem[sp-1].FieldByIndex(slint(op[2:])) + mem[sp-1].Data = mem[sp-1].Data.FieldByIndex(slint(op[2:])) case Jump: ip += int(op[2]) continue case JumpTrue: - cond := mem[sp-1].Bool() + cond := mem[sp-1].Data.Bool() mem = mem[:sp-1] if cond { ip += int(op[2]) continue } case JumpFalse: - cond := mem[sp-1].Bool() + cond := mem[sp-1].Data.Bool() mem = mem[:sp-1] if !cond { ip += int(op[2]) continue } case JumpSetTrue: - cond := mem[sp-1].Bool() + cond := mem[sp-1].Data.Bool() if cond { ip += int(op[2]) // Note that stack is not modified if cond is true @@ -209,7 +209,7 @@ func (m *Machine) Run() (err error) { } mem = mem[:sp-1] case JumpSetFalse: - cond := mem[sp-1].Bool() + cond := mem[sp-1].Data.Bool() if !cond { ip += int(op[2]) // Note that stack is not modified if cond is false @@ -217,39 +217,39 @@ func (m *Machine) Run() (err error) { } mem = mem[:sp-1] case Greater: - mem[sp-2] = reflect.ValueOf(mem[sp-1].Int() > mem[sp-2].Int()) + mem[sp-2] = ValueOf(mem[sp-1].Data.Int() > mem[sp-2].Data.Int()) mem = mem[:sp-1] case Lower: - mem[sp-2] = reflect.ValueOf(mem[sp-1].Int() < mem[sp-2].Int()) + mem[sp-2] = ValueOf(mem[sp-1].Data.Int() < mem[sp-2].Data.Int()) mem = mem[:sp-1] case Loweri: - mem[sp-1] = reflect.ValueOf(mem[sp-1].Int() < op[2]) + mem[sp-1] = ValueOf(mem[sp-1].Data.Int() < op[2]) case Not: - mem[sp-1] = reflect.ValueOf(!mem[sp-1].Bool()) + mem[sp-1] = ValueOf(!mem[sp-1].Data.Bool()) case Pop: mem = mem[:sp-int(op[2])] case Push: //mem = append(mem, reflect.ValueOf(int(op[2]))) - mem = append(mem, reflect.New(reflect.TypeOf(0)).Elem()) - mem[sp].SetInt(op[2]) + mem = append(mem, NewValue(TypeOf(0))) + mem[sp].Data.SetInt(op[2]) case Grow: - mem = append(mem, make([]reflect.Value, op[2])...) + mem = append(mem, make([]Value, op[2])...) case Return: - ip = int(mem[fp-2].Int()) + ip = int(mem[fp-2].Data.Int()) ofp := fp - fp = int(mem[fp-1].Int()) + fp = int(mem[fp-1].Data.Int()) mem = append(mem[:ofp-int(op[2])-int(op[3])-1], mem[sp-int(op[2]):]...) continue case Sub: - mem[sp-2] = reflect.ValueOf(int(mem[sp-1].Int() - mem[sp-2].Int())) + mem[sp-2] = ValueOf(int(mem[sp-1].Data.Int() - mem[sp-2].Data.Int())) mem = mem[:sp-1] case Subi: - mem[sp-1] = reflect.ValueOf(int(mem[sp-1].Int() - op[2])) + mem[sp-1] = ValueOf(int(mem[sp-1].Data.Int() - op[2])) case Index: - mem[sp-2] = mem[sp-1].Index(int(mem[sp-2].Int())) + mem[sp-2].Data = mem[sp-1].Data.Index(int(mem[sp-2].Data.Int())) mem = mem[:sp-1] case Vassign: - mem[sp-1].Set(mem[sp-2]) + mem[sp-1].Data.Set(mem[sp-2].Data) mem = mem[:sp-2] } ip++ @@ -263,18 +263,18 @@ func (m *Machine) PushCode(code ...[]int64) (p int) { } func (m *Machine) SetIP(ip int) { m.ip = ip } -func (m *Machine) Push(v ...reflect.Value) (l int) { +func (m *Machine) Push(v ...Value) (l int) { l = len(m.mem) m.mem = append(m.mem, v...) return l } -func (m *Machine) Pop() (v reflect.Value) { +func (m *Machine) Pop() (v Value) { l := len(m.mem) - 1 v = m.mem[l] m.mem = m.mem[:l] return v } -func (m *Machine) Top() (v reflect.Value) { +func (m *Machine) Top() (v Value) { if l := len(m.mem); l > 0 { v = m.mem[l-1] } @@ -315,13 +315,13 @@ func slint(a []int64) []int { return r } -func Vstring(lv []reflect.Value) string { +func Vstring(lv []Value) string { s := "[" for _, v := range lv { if s != "[" { s += " " } - s += fmt.Sprintf("%v", v) + s += fmt.Sprintf("%v", v.Data) } return s + "]" } diff --git a/vm/vm_test.go b/vm/vm_test.go index 07c063e..fb71176 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -3,7 +3,6 @@ package vm import ( "fmt" "log" - "reflect" "testing" ) @@ -50,11 +49,10 @@ func BenchmarkVM(b *testing.B) { } var tests = []struct { - //sym []any // initial memory values - sym []reflect.Value // initial memory values - code [][]int64 // bytecode to execute - start, end int // - mem string // expected memory content + sym []Value // initial memory values + code [][]int64 // bytecode to execute + start, end int // + mem string // expected memory content }{{ // #00 -- A simple addition. code: [][]int64{ {0, Push, 1}, @@ -64,7 +62,7 @@ var tests = []struct { }, start: 0, end: 1, mem: "[3]", }, { // #01 -- Calling a function defined outside the VM. - sym: []reflect.Value{reflect.ValueOf(fmt.Println), reflect.ValueOf("Hello")}, + sym: []Value{ValueOf(fmt.Println), ValueOf("Hello")}, code: [][]int64{ {0, Dup, 0}, {0, CallX, 1}, |
