diff options
Diffstat (limited to 'parser')
| -rw-r--r-- | parser/compiler.go | 106 | ||||
| -rw-r--r-- | parser/decl.go | 20 | ||||
| -rw-r--r-- | parser/interpreter_test.go | 7 | ||||
| -rw-r--r-- | parser/symbol.go | 26 | ||||
| -rw-r--r-- | parser/type.go | 7 |
5 files changed, 105 insertions, 61 deletions
diff --git a/parser/compiler.go b/parser/compiler.go index 36aa9d8..bb88026 100644 --- a/parser/compiler.go +++ b/parser/compiler.go @@ -13,9 +13,9 @@ import ( type Compiler struct { *Parser - vm.Code // produced code, to fill VM with - Data []any // 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 []reflect.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 +28,7 @@ func NewCompiler(scanner *scanner.Scanner) *Compiler { } } -func (c *Compiler) AddSym(name string, value any) int { +func (c *Compiler) AddSym(name string, value reflect.Value) int { p := len(c.Data) c.Data = append(c.Data, value) c.Parser.AddSym(p, name, value) @@ -51,7 +51,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { if err != nil { return err } - push(&symbol{kind: symConst, value: n}) + push(&symbol{kind: symConst, value: reflect.ValueOf(n), Type: reflect.TypeOf(0)}) emit(int64(t.Pos), vm.Push, int64(n)) case lang.String: @@ -59,10 +59,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, s) + c.Data = append(c.Data, reflect.ValueOf(s)) c.strings[s] = i } - push(&symbol{kind: symConst, value: s}) + push(&symbol{kind: symConst, value: reflect.ValueOf(s)}) emit(int64(t.Pos), vm.Dup, int64(i)) case lang.Add: @@ -87,25 +87,40 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { case lang.Plus: // Nothing to do. - case lang.Address: - emit(int64(t.Pos), vm.Address) + case lang.Addr: + push(&symbol{Type: reflect.PointerTo(pop().Type)}) + emit(int64(t.Pos), vm.Addr) case lang.Deref: + push(&symbol{Type: pop().Type.Elem()}) emit(int64(t.Pos), vm.Deref) case lang.Index: + push(&symbol{Type: pop().Type.Elem()}) emit(int64(t.Pos), vm.Index) case lang.Greater: + push(&symbol{Type: booleanOpType(pop(), pop())}) emit(int64(t.Pos), vm.Greater) case lang.Less: + push(&symbol{Type: booleanOpType(pop(), pop())}) emit(int64(t.Pos), vm.Lower) case lang.Call: + typ := pop().Type + // TODO: pop input types (careful with variadic function) + for i := 0; i < typ.NumOut(); i++ { + push(&symbol{Type: typ.Out(i)}) + } emit(int64(t.Pos), vm.Call) case lang.CallX: + typ := pop().Type + // TODO: pop input types (careful with variadic function) + for i := 0; i < typ.NumOut(); i++ { + push(&symbol{Type: typ.Out(i)}) + } emit(int64(t.Pos), vm.CallX, int64(t.Beg)) case lang.Grow: @@ -115,9 +130,10 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { // TODO: support assignment to local, composite objects st := tokens[i-1] l := len(c.Data) - c.Data = append(c.Data, nil) - // TODO: symbol should be added at parse, not here. - c.addSym(l, st.Str, nil, symVar, nil, false) + typ := pop().Type + v := reflect.New(typ).Elem() + c.addSym(l, st.Str, v, symVar, typ, false) + c.Data = append(c.Data, v) emit(int64(st.Pos), vm.Assign, int64(l)) case lang.Assign: @@ -130,7 +146,16 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { if !ok { return fmt.Errorf("symbol not found: %s", st.Str) } + typ := pop().Type + if s.Type == nil { + s.Type = typ + s.value = reflect.New(typ).Elem() + } if s.local { + if !s.used { + emit(int64(st.Pos), vm.New, int64(s.index), int64(c.typeSym(s.Type).index)) + s.used = true + } emit(int64(st.Pos), vm.Fassign, int64(s.index)) break } @@ -141,9 +166,11 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { emit(int64(st.Pos), vm.Assign, int64(s.index)) case lang.Equal: + push(&symbol{Type: booleanOpType(pop(), pop())}) emit(int64(t.Pos), vm.Equal) case lang.EqualSet: + push(&symbol{Type: booleanOpType(pop(), pop())}) emit(int64(t.Pos), vm.EqualSet) case lang.Ident: @@ -172,64 +199,64 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { lc := len(c.Code) s, ok := c.symbols[t.Str] if ok { - s.value = lc + s.value = reflect.ValueOf(lc) if s.kind == symFunc { // label is a function entry point, register its code address in data. s.index = len(c.Data) - c.Data = append(c.Data, lc) + c.Data = append(c.Data, s.value) } else { - c.Data[s.index] = lc + c.Data[s.index] = s.value } } else { - c.symbols[t.Str] = &symbol{kind: symLabel, value: lc} + c.symbols[t.Str] = &symbol{kind: symLabel, value: reflect.ValueOf(lc)} } case lang.JumpFalse: label := t.Str[10:] - i := 0 + var i int64 if s, ok := c.symbols[label]; !ok { // t.Beg contains the position in code which needs to be fixed. t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.(int) - len(c.Code) + i = s.value.Int() - int64(len(c.Code)) } - emit(int64(t.Pos), vm.JumpFalse, int64(i)) + emit(int64(t.Pos), vm.JumpFalse, i) case lang.JumpSetFalse: label := t.Str[13:] - i := 0 + var i int64 if s, ok := c.symbols[label]; !ok { // t.Beg contains the position in code which needs to be fixed. t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.(int) - len(c.Code) + i = s.value.Int() - int64(len(c.Code)) } - emit(int64(t.Pos), vm.JumpSetFalse, int64(i)) + emit(int64(t.Pos), vm.JumpSetFalse, i) case lang.JumpSetTrue: label := t.Str[12:] - i := 0 + var i int64 if s, ok := c.symbols[label]; !ok { // t.Beg contains the position in code which needs to be fixed. t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.(int) - len(c.Code) + i = s.value.Int() - int64(len(c.Code)) } emit(int64(t.Pos), vm.JumpSetTrue, int64(i)) case lang.Goto: label := t.Str[5:] - i := 0 + var i int64 if s, ok := c.symbols[label]; !ok { t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = s.value.(int) - len(c.Code) + i = s.value.Int() - int64(len(c.Code)) } - emit(int64(t.Pos), vm.Jump, int64(i)) + emit(int64(t.Pos), vm.Jump, i) case lang.Period: if f, ok := pop().Type.FieldByName("X" + t.Str[1:]); ok { @@ -264,16 +291,14 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { if !ok { return fmt.Errorf("label not found: %q", label) } - c.Code[t.Beg][2] = int64(s.value.(int) - t.Beg) + c.Code[t.Beg][2] = s.value.Int() - int64(t.Beg) } return err } -func arithmeticOpType(s1, s2 *symbol) reflect.Type { - // TODO: make it complete - return symtype(s1) -} +func arithmeticOpType(s1, s2 *symbol) reflect.Type { return symtype(s1) } +func booleanOpType(s1, s2 *symbol) reflect.Type { return reflect.TypeOf(true) } func (c *Compiler) PrintCode() { labels := map[int][]string{} // labels indexed by code location @@ -281,7 +306,7 @@ func (c *Compiler) PrintCode() { for name, sym := range c.symbols { if sym.kind == symLabel || sym.kind == symFunc { - i := sym.value.(int) + i := int(sym.value.Int()) labels[i] = append(labels[i], name) } if sym.used { @@ -329,7 +354,7 @@ func (c *Compiler) PrintData() { } fmt.Println("# Data:") for i, d := range c.Data { - fmt.Printf("%4d %T %v %v\n", i, d, d, dict[i]) + fmt.Printf("%4d %T %v %v\n", i, d.Interface(), d, dict[i]) } } @@ -341,6 +366,19 @@ func (c *Compiler) NumIn(i int) (int, bool) { return -1, false } +func (c *Compiler) typeSym(t reflect.Type) *symbol { + tsym, ok := c.symbols[t.String()] + if !ok { + tsym = &symbol{index: unsetAddr, kind: symType, Type: t} + c.symbols[t.String()] = tsym + } + if tsym.index == unsetAddr { + tsym.index = len(c.Data) + c.Data = append(c.Data, reflect.New(t).Elem()) + } + return tsym +} + func slint64(a []int) []int64 { r := make([]int64, len(a)) for i, v := range a { diff --git a/parser/decl.go b/parser/decl.go index 782b57a..54a2989 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -4,12 +4,15 @@ import ( "errors" "go/constant" "go/token" + "reflect" "strings" "github.com/gnolang/parscan/lang" "github.com/gnolang/parscan/scanner" ) +var nilValue = reflect.ValueOf(nil) + func (p *Parser) ParseConst(in Tokens) (out Tokens, err error) { if len(in) < 2 { return out, errors.New("missing expression") @@ -51,8 +54,8 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) { if errors.Is(err, MissingTypeErr) { for _, lt := range decl.Split(lang.Comma) { vars = append(vars, lt[0].Str) - // TODO: compute type from rhs - p.addSym(unsetAddr, strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/"), nil, symConst, nil, false) + name := strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/") + p.addSym(unsetAddr, name, nilValue, symConst, nil, false) } } else { return out, err @@ -75,7 +78,7 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) { kind: symConst, index: unsetAddr, cval: cval, - value: constValue(cval), + value: reflect.ValueOf(constValue(cval)), local: p.funcScope != "", used: true, } @@ -222,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, nil, symType, typ, p.funcScope != "") + p.addSym(unsetAddr, in[0].Str, reflect.New(typ).Elem(), symType, typ, p.funcScope != "") return out, err } @@ -257,8 +260,13 @@ func (p *Parser) parseVarLine(in Tokens) (out Tokens, err error) { if errors.Is(err, MissingTypeErr) { for _, lt := range decl.Split(lang.Comma) { vars = append(vars, lt[0].Str) - // TODO: compute type from rhs - p.addSym(unsetAddr, strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/"), nil, symVar, nil, false) + name := strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/") + if p.funcScope == "" { + p.addSym(unsetAddr, name, nilValue, symVar, nil, false) + continue + } + p.addSym(p.framelen[p.funcScope], name, nilValue, symVar, nil, false) + p.framelen[p.funcScope]++ } } else { return out, err diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go index 9555475..9110e3c 100644 --- a/parser/interpreter_test.go +++ b/parser/interpreter_test.go @@ -52,7 +52,7 @@ func run(t *testing.T, tests []etest) { func TestExpr(t *testing.T) { run(t, []etest{ - {src: "", res: "<nil>"}, + {src: "", res: "<invalid reflect.Value>"}, {src: "1+2", res: "3"}, {src: "1+", err: "block not terminated"}, {src: "a := 1 + 2; b := 0; a + 1", res: "4"}, @@ -92,7 +92,7 @@ func TestFunc(t *testing.T) { {src: "func f() int {return 2}; a := f(); a", res: "2"}, {src: "func f() int {return 2}; f()", res: "2"}, {src: "func f(a int) int {return a+2}; f(3)", res: "5"}, - {src: "func f(a int) int {if a < 4 {a = 5}; return a }; f(3)", res: "5"}, + {src: "func f(a int) int {if a < 4 {a = 5}; return a}; f(3)", res: "5"}, {src: "func f(a int) int {return a+2}; 7 - f(3)", res: "2"}, {src: "func f(a int) int {return a+2}; f(5) - f(3)", res: "2"}, {src: "func f(a int) int {return a+2}; f(3) - 2", res: "3"}, @@ -195,7 +195,8 @@ func TestArray(t *testing.T) { func TestPointer(t *testing.T) { run(t, []etest{ {src: "var a *int; a", res: "<nil>"}, - //{src: "var a int = 2; var b *int = &a; b", res: "2"}, + {src: "var a int; var b *int = &a; *b", res: "0"}, + {src: "var a int = 2; var b *int = &a; *b", res: "2"}, }) } diff --git a/parser/symbol.go b/parser/symbol.go index 7edcef3..6c5ab9b 100644 --- a/parser/symbol.go +++ b/parser/symbol.go @@ -22,12 +22,12 @@ const unsetAddr = -65535 type symbol struct { kind symKind - index int // address of symbol in frame - value any - cval constant.Value - Type reflect.Type - local bool // if true address is relative to local frame, otherwise global - used bool + index int // address of symbol in frame + value reflect.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 { @@ -37,11 +37,13 @@ func symtype(s *symbol) reflect.Type { return reflect.TypeOf(s.value) } -func (p *Parser) AddSym(i int, name string, v any) { p.addSym(i, name, v, symValue, nil, false) } +func (p *Parser) AddSym(i int, name string, v reflect.Value) { + p.addSym(i, name, v, symValue, nil, false) +} -func (p *Parser) addSym(i int, name string, v any, k symKind, t reflect.Type, local bool) { +func (p *Parser) addSym(i int, name string, v reflect.Value, k symKind, t reflect.Type, local bool) { name = strings.TrimPrefix(name, "/") - p.symbols[name] = &symbol{kind: k, index: i, local: local, value: v, Type: t, used: true} + p.symbols[name] = &symbol{kind: k, index: i, local: local, value: v, Type: t} } // getSym searches for an existing symbol starting from the deepest scope. @@ -72,9 +74,9 @@ func initUniverse() map[string]*symbol { "nil": {index: unsetAddr}, "iota": {kind: symConst, index: unsetAddr}, - "true": {index: unsetAddr, value: true, Type: reflect.TypeOf(true)}, - "false": {index: unsetAddr, value: false, Type: reflect.TypeOf(false)}, + "true": {index: unsetAddr, value: reflect.ValueOf(true), Type: reflect.TypeOf(true)}, + "false": {index: unsetAddr, value: reflect.ValueOf(false), Type: reflect.TypeOf(false)}, - "println": {index: unsetAddr, value: func(v ...any) { fmt.Println(v...) }}, + "println": {index: unsetAddr, value: reflect.ValueOf(func(v ...any) { fmt.Println(v...) })}, } } diff --git a/parser/type.go b/parser/type.go index 31af1e3..ff16e4f 100644 --- a/parser/type.go +++ b/parser/type.go @@ -170,12 +170,7 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type } func (p *Parser) addSymVar(index int, name string, typ reflect.Type, flag typeFlag, local bool) { - var zv any = reflect.New(typ).Elem() - switch typ.Kind() { - case reflect.Struct, reflect.Array, reflect.Slice, reflect.Pointer: - default: - zv = zv.(reflect.Value).Interface() - } + zv := reflect.New(typ).Elem() switch flag { case parseTypeIn: p.addSym(-index-2, name, zv, symVar, typ, true) |
