diff options
Diffstat (limited to 'parser')
| -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 |
6 files changed, 66 insertions, 73 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) |
