diff options
| -rw-r--r-- | comp/compiler.go | 85 | ||||
| -rw-r--r-- | interp/interpreter_test.go | 2 | ||||
| -rw-r--r-- | parser/decl.go | 23 | ||||
| -rw-r--r-- | parser/expr.go | 5 | ||||
| -rw-r--r-- | parser/parse.go | 17 | ||||
| -rw-r--r-- | parser/symbol.go | 89 | ||||
| -rw-r--r-- | parser/symkind_string.go | 30 | ||||
| -rw-r--r-- | parser/type.go | 17 | ||||
| -rw-r--r-- | symbol/kind_string.go | 30 | ||||
| -rw-r--r-- | symbol/symbol.go | 92 | ||||
| -rw-r--r-- | vm/type.go | 4 | ||||
| -rw-r--r-- | vm/vm.go | 4 |
12 files changed, 207 insertions, 191 deletions
diff --git a/comp/compiler.go b/comp/compiler.go index 7c21d46..49633a1 100644 --- a/comp/compiler.go +++ b/comp/compiler.go @@ -13,6 +13,7 @@ import ( "github.com/mvertes/parscan/lang" "github.com/mvertes/parscan/parser" "github.com/mvertes/parscan/scanner" + "github.com/mvertes/parscan/symbol" "github.com/mvertes/parscan/vm" ) @@ -39,7 +40,7 @@ func NewCompiler(spec *lang.Spec) *Compiler { func (c *Compiler) AddSym(name string, value vm.Value) int { p := len(c.Data) c.Data = append(c.Data, value) - c.AddSymbol(p, name, value, parser.SymValue, nil, false) + c.Symbols.Add(p, name, value, symbol.Value, nil, false) return p } @@ -47,7 +48,7 @@ func (c *Compiler) AddSym(name string, value vm.Value) int { func (c *Compiler) Generate(tokens parser.Tokens) (err error) { log.Println("Codegen tokens:", tokens) fixList := parser.Tokens{} // list of tokens to fix after all necessary information is gathered - stack := []*parser.Symbol{} // for symbolic evaluation, type checking, etc + stack := []*symbol.Symbol{} // for symbolic evaluation, type checking, etc keyList := []string{} emit := func(t scanner.Token, op vm.Op, arg ...int) { @@ -55,9 +56,9 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { fmt.Fprintf(os.Stderr, "%s:%d: %v emit %v %v\n", path.Base(file), line, t, op, arg) c.Code = append(c.Code, vm.Instruction{Pos: vm.Pos(t.Pos), Op: op, Arg: arg}) } - push := func(s *parser.Symbol) { stack = append(stack, s) } - pop := func() *parser.Symbol { l := len(stack) - 1; s := stack[l]; stack = stack[:l]; return s } - top := func() *parser.Symbol { return stack[len(stack)-1] } + push := func(s *symbol.Symbol) { stack = append(stack, s) } + pop := func() *symbol.Symbol { l := len(stack) - 1; s := stack[l]; stack = stack[:l]; return s } + top := func() *symbol.Symbol { return stack[len(stack)-1] } showStack := func() { _, file, line, _ := runtime.Caller(1) @@ -74,7 +75,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { if err != nil { return err } - push(&parser.Symbol{Kind: parser.SymConst, Value: vm.ValueOf(n), Type: vm.TypeOf(0)}) + push(&symbol.Symbol{Kind: symbol.Const, Value: vm.ValueOf(n), Type: vm.TypeOf(0)}) emit(t, vm.Push, n) case lang.String: @@ -86,19 +87,19 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { c.Data = append(c.Data, v) c.strings[s] = i } - push(&parser.Symbol{Kind: parser.SymConst, Value: v}) + push(&symbol.Symbol{Kind: symbol.Const, Value: v}) emit(t, vm.Dup, i) case lang.Add: - push(&parser.Symbol{Type: arithmeticOpType(pop(), pop())}) + push(&symbol.Symbol{Type: arithmeticOpType(pop(), pop())}) emit(t, vm.Add) case lang.Mul: - push(&parser.Symbol{Type: arithmeticOpType(pop(), pop())}) + push(&symbol.Symbol{Type: arithmeticOpType(pop(), pop())}) emit(t, vm.Mul) case lang.Sub: - push(&parser.Symbol{Type: arithmeticOpType(pop(), pop())}) + push(&symbol.Symbol{Type: arithmeticOpType(pop(), pop())}) emit(t, vm.Sub) case lang.Minus: @@ -112,32 +113,32 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { // Unary '+' is idempotent. Nothing to do. case lang.Addr: - push(&parser.Symbol{Type: vm.PointerTo(pop().Type)}) + push(&symbol.Symbol{Type: vm.PointerTo(pop().Type)}) emit(t, vm.Addr) case lang.Deref: - push(&parser.Symbol{Type: pop().Type.Elem()}) + push(&symbol.Symbol{Type: pop().Type.Elem()}) emit(t, vm.Deref) case lang.Index: - push(&parser.Symbol{Type: pop().Type.Elem()}) + push(&symbol.Symbol{Type: pop().Type.Elem()}) emit(t, vm.Index) case lang.Greater: - push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) + push(&symbol.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.Greater) case lang.Less: - push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) + push(&symbol.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.Lower) case lang.Call: s := pop() - if s.Kind != parser.SymValue { + if s.Kind != symbol.Value { typ := s.Type // TODO: pop input types (careful with variadic function). for i := 0; i < typ.Rtype.NumOut(); i++ { - push(&parser.Symbol{Type: typ.Out(i)}) + push(&symbol.Symbol{Type: typ.Out(i)}) } emit(t, vm.Call) break @@ -149,7 +150,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { rtyp := pop().Value.Value.Type() // TODO: pop input types (careful with variadic function). for i := 0; i < rtyp.NumOut(); i++ { - push(&parser.Symbol{Type: &vm.Type{Rtype: rtyp.Out(i)}}) + push(&symbol.Symbol{Type: &vm.Type{Rtype: rtyp.Out(i)}}) } emit(t, vm.CallX, t.Beg) @@ -174,11 +175,15 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { } } else { for _, fname := range keyList { - i := d.Type.FieldNameIndex(fname) + i := d.Type.FieldIndex(fname) emit(t, vm.FieldSet, i...) } keyList = []string{} } + case reflect.Slice: + emit(t, vm.Fnew, d.Index) + // if len(keyList) == 0 { + // } default: return fmt.Errorf("composite kind not supported yet: %v", d.Type.Rtype.Kind()) } @@ -197,7 +202,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { typ = d.Value.Type } v := vm.NewValue(typ) - c.AddSymbol(l, st.Str, v, parser.SymVar, typ, false) + c.Symbols.Add(l, st.Str, v, symbol.Var, typ, false) c.Data = append(c.Data, v) emit(t, vm.Assign, l) @@ -228,18 +233,18 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { emit(st, vm.Fassign, s.Index) break } - if s.Index == parser.UnsetAddr { + if s.Index == symbol.UnsetAddr { s.Index = len(c.Data) c.Data = append(c.Data, s.Value) } emit(st, vm.Assign, s.Index) case lang.Equal: - push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) + push(&symbol.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.Equal) case lang.EqualSet: - push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) + push(&symbol.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.EqualSet) case lang.Ident: @@ -254,17 +259,17 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { return fmt.Errorf("symbol not found: %s", t.Str) } push(s) - if s.Kind == parser.SymPkg { + if s.Kind == symbol.Pkg { break } if s.Local { emit(t, vm.Fdup, s.Index) } else { - if s.Index == parser.UnsetAddr { + if s.Index == symbol.UnsetAddr { s.Index = len(c.Data) c.Data = append(c.Data, s.Value) } - if s.Kind != parser.SymType { + if s.Kind != symbol.Type { emit(t, vm.Dup, s.Index) } } @@ -274,7 +279,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { s, ok := c.Symbols[t.Str] if ok { s.Value = vm.ValueOf(lc) - if s.Kind == parser.SymFunc { + if s.Kind == symbol.Func { // label is a function entry point, register its code address in data. s.Index = len(c.Data) c.Data = append(c.Data, s.Value) @@ -282,7 +287,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { c.Data[s.Index] = s.Value } } else { - c.Symbols[t.Str] = &parser.Symbol{Kind: parser.SymLabel, Value: vm.ValueOf(lc)} + c.Symbols[t.Str] = &symbol.Symbol{Kind: symbol.Label, Value: vm.ValueOf(lc)} } case lang.JumpFalse: @@ -331,7 +336,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { case lang.Period: s := pop() switch s.Kind { - case parser.SymPkg: + case symbol.Pkg: p, ok := parser.Packages[s.PkgPath] if !ok { return fmt.Errorf("package not found: %s", s.PkgPath) @@ -342,13 +347,13 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { } name := s.PkgPath + t.Str var l int - sym, _, ok := c.GetSym(name, "") + sym, _, ok := c.Symbols.Get(name, "") if ok { l = sym.Index } else { l = len(c.Data) c.Data = append(c.Data, v) - c.AddSymbol(l, name, v, parser.SymValue, v.Type, false) + c.Symbols.Add(l, name, v, symbol.Value, v.Type, false) sym = c.Symbols[name] } push(sym) @@ -379,8 +384,8 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) { } return err } -func arithmeticOpType(s1, _ *parser.Symbol) *vm.Type { return parser.SymbolType(s1) } -func booleanOpType(_, _ *parser.Symbol) *vm.Type { return vm.TypeOf(true) } +func arithmeticOpType(s1, _ *symbol.Symbol) *vm.Type { return symbol.Vtype(s1) } +func booleanOpType(_, _ *symbol.Symbol) *vm.Type { return vm.TypeOf(true) } // PrintCode pretty prints the generated code. func (c *Compiler) PrintCode() { @@ -388,7 +393,7 @@ func (c *Compiler) PrintCode() { data := map[int]string{} // data indexed by frame location for name, sym := range c.Symbols { - if sym.Kind == parser.SymLabel || sym.Kind == parser.SymFunc { + if sym.Kind == symbol.Label || sym.Kind == symbol.Func { i := int(sym.Value.Int()) labels[i] = append(labels[i], name) } @@ -413,7 +418,7 @@ func (c *Compiler) PrintCode() { extra = "// " + d } } - fmt.Fprintf(os.Stderr, "%4d %-18v %v\n", i, l, extra) + fmt.Fprintf(os.Stderr, "%4d %v %v\n", i, l, extra) } for _, label := range labels[len(c.Code)] { @@ -424,7 +429,7 @@ func (c *Compiler) PrintCode() { type entry struct { name string - *parser.Symbol + *symbol.Symbol } func (e entry) String() string { return fmt.Sprintf("name: %s, sym: %v", e.name, e.Symbol) } @@ -442,7 +447,7 @@ func (c *Compiler) PrintData() { func (c *Compiler) symbolsByIndex() map[int]entry { dict := map[int]entry{} for name, sym := range c.Symbols { - if sym.Index == parser.UnsetAddr { + if sym.Index == symbol.UnsetAddr { continue } dict[sym.Index] = entry{name, sym} @@ -520,13 +525,13 @@ func (c *Compiler) ApplyDump(d *Dump) error { return nil } -func (c *Compiler) typeSym(t *vm.Type) *parser.Symbol { +func (c *Compiler) typeSym(t *vm.Type) *symbol.Symbol { tsym, ok := c.Symbols[t.Rtype.String()] if !ok { - tsym = &parser.Symbol{Index: parser.UnsetAddr, Kind: parser.SymType, Type: t} + tsym = &symbol.Symbol{Index: symbol.UnsetAddr, Kind: symbol.Type, Type: t} c.Symbols[t.Rtype.String()] = tsym } - if tsym.Index == parser.UnsetAddr { + if tsym.Index == symbol.UnsetAddr { tsym.Index = len(c.Data) c.Data = append(c.Data, vm.NewValue(t)) } diff --git a/interp/interpreter_test.go b/interp/interpreter_test.go index 4f5690d..bc353bd 100644 --- a/interp/interpreter_test.go +++ b/interp/interpreter_test.go @@ -262,5 +262,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}`}, {src: `type T struct{N int; S string}; t := T{2, "foo"}; t`, res: `{2 foo}`}, {src: `type T struct{N int; S string}; t := T{S: "foo"}; t`, res: `{0 foo}`}, + {src: `a := []int{}`, res: `[]`}, + // {src: `a := []int{1, 2, 3}`, res: `[1 2 3]`}, }) } diff --git a/parser/decl.go b/parser/decl.go index 876b2ca..f6e8102 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -10,6 +10,7 @@ import ( "github.com/mvertes/parscan/lang" "github.com/mvertes/parscan/scanner" + "github.com/mvertes/parscan/symbol" "github.com/mvertes/parscan/vm" ) @@ -57,7 +58,7 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) { for _, lt := range decl.Split(lang.Comma) { vars = append(vars, lt[0].Str) name := strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/") - p.AddSymbol(UnsetAddr, name, nilValue, SymConst, nil, false) + p.Symbols.Add(symbol.UnsetAddr, name, nilValue, symbol.Const, nil, false) } } else { return out, err @@ -76,9 +77,9 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) { return out, err } name := strings.TrimPrefix(p.scope+"/"+vars[i], "/") - p.Symbols[name] = &Symbol{ - Kind: SymConst, - Index: UnsetAddr, + p.Symbols[name] = &symbol.Symbol{ + Kind: symbol.Const, + Index: symbol.UnsetAddr, Cval: cval, Value: vm.ValueOf(constValue(cval)), Local: p.funcScope != "", @@ -131,11 +132,11 @@ func (p *Parser) evalConstExpr(in Tokens) (cval constant.Value, length int, err case id.IsLiteral(): return constant.MakeFromLiteral(t.Str, gotok[id], 0), 1, err case id == lang.Ident: - s, _, ok := p.GetSym(t.Str, p.scope) + s, _, ok := p.Symbols.Get(t.Str, p.scope) if !ok { return nil, 0, errors.New("symbol not found") } - if s.Kind != SymConst { + if s.Kind != symbol.Const { return nil, 0, errors.New("symbol is not a constant") } return s.Cval, 1, err @@ -240,10 +241,10 @@ func (p *Parser) parseImportLine(in Tokens) (out Tokens, err error) { if n == "." { // Import package symbols in the current scope. for k, v := range pkg { - p.Symbols[k] = &Symbol{Index: UnsetAddr, PkgPath: pp, Value: v} + p.Symbols[k] = &symbol.Symbol{Index: symbol.UnsetAddr, PkgPath: pp, Value: v} } } else { - p.Symbols[n] = &Symbol{Kind: SymPkg, PkgPath: pp, Index: UnsetAddr} + p.Symbols[n] = &symbol.Symbol{Kind: symbol.Pkg, PkgPath: pp, Index: symbol.UnsetAddr} } return out, err } @@ -299,7 +300,7 @@ func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) { return out, err } typ.Name = in[0].Str - p.AddSymbol(UnsetAddr, in[0].Str, vm.NewValue(typ), SymType, typ, p.funcScope != "") + p.Symbols.Add(symbol.UnsetAddr, in[0].Str, vm.NewValue(typ), symbol.Type, typ, p.funcScope != "") return out, err } @@ -336,10 +337,10 @@ func (p *Parser) parseVarLine(in Tokens) (out Tokens, err error) { vars = append(vars, lt[0].Str) name := strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/") if p.funcScope == "" { - p.AddSymbol(UnsetAddr, name, nilValue, SymVar, nil, false) + p.Symbols.Add(symbol.UnsetAddr, name, nilValue, symbol.Var, nil, false) continue } - p.AddSymbol(p.framelen[p.funcScope], name, nilValue, SymVar, nil, false) + p.Symbols.Add(p.framelen[p.funcScope], name, nilValue, symbol.Var, nil, false) p.framelen[p.funcScope]++ } } else { diff --git a/parser/expr.go b/parser/expr.go index 1732b8d..5958279 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -7,6 +7,7 @@ import ( "github.com/mvertes/parscan/lang" "github.com/mvertes/parscan/scanner" + "github.com/mvertes/parscan/symbol" "github.com/mvertes/parscan/vm" ) @@ -42,7 +43,7 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { continue } // resolve symbol if not a selector rhs. - _, sc, ok := p.GetSym(t.Str, p.scope) + _, sc, ok := p.Symbols.Get(t.Str, p.scope) if ok { if sc != "" { t.Str = sc + "/" + t.Str @@ -111,7 +112,7 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { if err != nil { return out, ErrInvalidType } - p.AddSymbol(UnsetAddr, typ.String(), vm.NewValue(typ), SymType, typ, p.funcScope != "") + p.Symbols.Add(symbol.UnsetAddr, typ.String(), vm.NewValue(typ), symbol.Type, typ, p.funcScope != "") out = append(out, t, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: typ.String()}) i = ti vl += 2 diff --git a/parser/parse.go b/parser/parse.go index 6cfdc08..e7d5399 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -10,14 +10,15 @@ import ( "github.com/mvertes/parscan/lang" "github.com/mvertes/parscan/scanner" + "github.com/mvertes/parscan/symbol" ) // Parser represents the state of a parser. type Parser struct { *scanner.Scanner - Symbols map[string]*Symbol - function *Symbol + Symbols symbol.SymMap + function *symbol.Symbol scope string fname string pkgName string // current package name @@ -42,13 +43,15 @@ var ( // NewParser returns a new parser. func NewParser(spec *lang.Spec, noPkg bool) *Parser { - return &Parser{ + p := &Parser{ Scanner: scanner.NewScanner(spec), + Symbols: symbol.SymMap{}, noPkg: noPkg, - Symbols: initUniverse(), framelen: map[string]int{}, labelCount: map[string]int{}, } + p.Symbols.Init() + return p } // Scan performs lexical analysis on s and returns Tokens or an error. @@ -255,9 +258,9 @@ func (p *Parser) parseFunc(in Tokens) (out Tokens, err error) { p.fname = fname ofunc := p.function funcScope := p.funcScope - s, _, ok := p.GetSym(fname, p.scope) + s, _, ok := p.Symbols.Get(fname, p.scope) if !ok { - s = &Symbol{Used: true} + s = &symbol.Symbol{Used: true} p.Symbols[p.scope+fname] = s } p.pushScope(fname) @@ -282,7 +285,7 @@ func (p *Parser) parseFunc(in Tokens) (out Tokens, err error) { if err != nil { return out, err } - s.Kind = SymFunc + s.Kind = symbol.Func s.Type = typ p.function = s diff --git a/parser/symbol.go b/parser/symbol.go deleted file mode 100644 index 3ad8fda..0000000 --- a/parser/symbol.go +++ /dev/null @@ -1,89 +0,0 @@ -package parser - -import ( - "fmt" - "go/constant" - "strings" - - "github.com/mvertes/parscan/vm" -) - -// SymKind represents the symbol kind. -type SymKind int - -// Symbol kinds. -const ( - SymValue SymKind = iota // a value defined in the runtime - SymType // a type - SymLabel // a label indication a position in the VM code - SymConst // a constant - SymVar // a variable, located in the VM memory - SymFunc // a function, located in the VM code - SymPkg // a package -) - -//go:generate stringer -type=SymKind - -// UnsetAddr denotes an unset symbol index (vs 0). -const UnsetAddr = -65535 - -// Symbol structure used in parser and compiler. -type Symbol struct { - Kind SymKind - 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 // -} - -// SymbolType returns the VM type of a symbol. -func SymbolType(s *Symbol) *vm.Type { - if s.Type != nil { - return s.Type - } - return vm.TypeOf(s.Value) -} - -// AddSymbol adds a new named value at memory position i in the parser symbol table. -func (p *Parser) AddSymbol(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} -} - -// GetSym searches for an existing symbol starting from the deepest scope. -func (p *Parser) GetSym(name, scope string) (sym *Symbol, sc string, ok bool) { - for { - if sym, ok = p.Symbols[scope+"/"+name]; ok { - return sym, scope, ok - } - i := strings.LastIndex(scope, "/") - if i == -1 { - i = 0 - } - if scope = scope[:i]; scope == "" { - break - } - } - sym, ok = p.Symbols[name] - return sym, scope, ok -} - -func initUniverse() map[string]*Symbol { - return map[string]*Symbol{ - "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: vm.ValueOf(true), Type: vm.TypeOf(true)}, - "false": {Index: UnsetAddr, Value: vm.ValueOf(false), Type: vm.TypeOf(false)}, - - "println": {Index: UnsetAddr, Value: vm.ValueOf(func(v ...any) { fmt.Println(v...) })}, - } -} diff --git a/parser/symkind_string.go b/parser/symkind_string.go deleted file mode 100644 index dc6a33d..0000000 --- a/parser/symkind_string.go +++ /dev/null @@ -1,30 +0,0 @@ -// Code generated by "stringer -type=SymKind"; DO NOT EDIT. - -package parser - -import "strconv" - -func _() { - // An "invalid array index" compiler error signifies that the constant values have changed. - // Re-run the stringer command to generate them again. - var x [1]struct{} - _ = x[SymValue-0] - _ = x[SymType-1] - _ = x[SymLabel-2] - _ = x[SymConst-3] - _ = x[SymVar-4] - _ = x[SymFunc-5] - _ = x[SymPkg-6] -} - -const _SymKind_name = "SymValueSymTypeSymLabelSymConstSymVarSymFuncSymPkg" - -var _SymKind_index = [...]uint8{0, 8, 15, 23, 31, 37, 44, 50} - -func (i SymKind) String() string { - idx := int(i) - 0 - if i < 0 || idx >= len(_SymKind_index)-1 { - return "SymKind(" + strconv.FormatInt(int64(i), 10) + ")" - } - return _SymKind_name[_SymKind_index[idx]:_SymKind_index[idx+1]] -} diff --git a/parser/type.go b/parser/type.go index 6f75f6f..12bc06b 100644 --- a/parser/type.go +++ b/parser/type.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/mvertes/parscan/lang" + "github.com/mvertes/parscan/symbol" "github.com/mvertes/parscan/vm" ) @@ -100,8 +101,8 @@ func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) { case lang.Ident: // TODO: selector expression (pkg.type) - s, _, ok := p.GetSym(in[0].Str, p.scope) - if !ok || s.Kind != SymType { + s, _, ok := p.Symbols.Get(in[0].Str, p.scope) + if !ok || s.Kind != symbol.Type { return nil, fmt.Errorf("%w: %s", ErrInvalidType, in[0].Str) } return s.Type, nil @@ -174,16 +175,16 @@ func (p *Parser) addSymVar(index int, name string, typ *vm.Type, flag typeFlag, zv := vm.NewValue(typ) switch flag { case parseTypeIn: - p.AddSymbol(-index-2, name, zv, SymVar, typ, true) + p.Symbols.Add(-index-2, name, zv, symbol.Var, typ, true) case parseTypeOut: - p.AddSymbol(p.framelen[p.funcScope], name, zv, SymVar, typ, true) + p.Symbols.Add(p.framelen[p.funcScope], name, zv, symbol.Var, typ, true) p.framelen[p.funcScope]++ case parseTypeVar: if !local { - p.AddSymbol(UnsetAddr, name, zv, SymVar, typ, local) + p.Symbols.Add(symbol.UnsetAddr, name, zv, symbol.Var, typ, local) break } - p.AddSymbol(p.framelen[p.funcScope], name, zv, SymVar, typ, local) + p.Symbols.Add(p.framelen[p.funcScope], name, zv, symbol.Var, typ, local) p.framelen[p.funcScope]++ } } @@ -193,8 +194,8 @@ func (p *Parser) hasFirstParam(in Tokens) bool { if in[0].Tok != lang.Ident { return false } - s, _, ok := p.GetSym(in[0].Str, p.scope) - return !ok || s.Kind != SymType + s, _, ok := p.Symbols.Get(in[0].Str, p.scope) + return !ok || s.Kind != symbol.Type } // typeStartIndex returns the index of the start of type expression in tokens, or -1. diff --git a/symbol/kind_string.go b/symbol/kind_string.go new file mode 100644 index 0000000..07dbd6a --- /dev/null +++ b/symbol/kind_string.go @@ -0,0 +1,30 @@ +// Code generated by "stringer -type=Kind"; DO NOT EDIT. + +package symbol + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Value-0] + _ = x[Type-1] + _ = x[Label-2] + _ = x[Const-3] + _ = x[Var-4] + _ = x[Func-5] + _ = x[Pkg-6] +} + +const _Kind_name = "ValueTypeLabelConstVarFuncPkg" + +var _Kind_index = [...]uint8{0, 5, 9, 14, 19, 22, 26, 29} + +func (i Kind) String() string { + idx := int(i) - 0 + if i < 0 || idx >= len(_Kind_index)-1 { + return "Kind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Kind_name[_Kind_index[idx]:_Kind_index[idx+1]] +} diff --git a/symbol/symbol.go b/symbol/symbol.go new file mode 100644 index 0000000..31869fd --- /dev/null +++ b/symbol/symbol.go @@ -0,0 +1,92 @@ +// Package symbol implements symbol utilities. +package symbol + +import ( + "fmt" + "go/constant" + "strings" + + "github.com/mvertes/parscan/vm" +) + +// Kind represents the symbol kind. +type Kind int + +// Symbol kinds. +const ( + Value Kind = iota // a value defined in the runtime + Type // a type + Label // a label indicating a position in the VM code + Const // a constant + Var // a variable, located in the VM memory + Func // a function, located in the VM code + Pkg // a package +) + +//go:generate stringer -type=Kind + +// UnsetAddr denotes an unset symbol index (vs 0). +const UnsetAddr = -65535 + +// Symbol structure used in parser and compiler. +type Symbol struct { + Kind Kind + 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 // +} + +// Vtype returns the VM type of a symbol. +func Vtype(s *Symbol) *vm.Type { + if s.Type != nil { + return s.Type + } + return vm.TypeOf(s.Value) +} + +// SymMap is a map of Symbols. +type SymMap map[string]*Symbol + +// Add adds a new named symbol value at memory position i. +func (sm SymMap) Add(i int, name string, v vm.Value, k Kind, t *vm.Type, local bool) { + name = strings.TrimPrefix(name, "/") + sm[name] = &Symbol{Kind: k, Index: i, Local: local, Value: v, Type: t} +} + +// Get searches for an existing symbol starting from the deepest scope. +func (sm SymMap) Get(name, scope string) (sym *Symbol, sc string, ok bool) { + for { + if sym, ok = sm[scope+"/"+name]; ok { + return sym, scope, ok + } + i := strings.LastIndex(scope, "/") + if i == -1 { + i = 0 + } + if scope = scope[:i]; scope == "" { + break + } + } + sym, ok = sm[name] + return sym, scope, ok +} + +// Init fills the symbol map with default Go symbols. +func (sm SymMap) Init() { + sm["any"] = &Symbol{Kind: Type, Index: UnsetAddr, Type: vm.TypeOf((*any)(nil)).Elem()} + sm["bool"] = &Symbol{Kind: Type, Index: UnsetAddr, Type: vm.TypeOf((*bool)(nil)).Elem()} + sm["error"] = &Symbol{Kind: Type, Index: UnsetAddr, Type: vm.TypeOf((*error)(nil)).Elem()} + sm["int"] = &Symbol{Kind: Type, Index: UnsetAddr, Type: vm.TypeOf((*int)(nil)).Elem()} + sm["string"] = &Symbol{Kind: Type, Index: UnsetAddr, Type: vm.TypeOf((*string)(nil)).Elem()} + + sm["nil"] = &Symbol{Index: UnsetAddr} + sm["iota"] = &Symbol{Kind: Const, Index: UnsetAddr} + sm["true"] = &Symbol{Index: UnsetAddr, Value: vm.ValueOf(true), Type: vm.TypeOf(true)} + sm["false"] = &Symbol{Index: UnsetAddr, Value: vm.ValueOf(false), Type: vm.TypeOf(false)} + + sm["println"] = &Symbol{Index: UnsetAddr, Value: vm.ValueOf(func(v ...any) { fmt.Println(v...) })} +} @@ -95,8 +95,8 @@ func StructOf(fields []*Type) *Type { return &Type{Rtype: reflect.StructOf(rf)} } -// FieldNameIndex returns the index of struct field name. -func (t *Type) FieldNameIndex(name string) []int { +// FieldIndex returns the index of struct field name. +func (t *Type) FieldIndex(name string) []int { for _, f := range reflect.VisibleFields(t.Rtype) { if f.Name == name { return f.Index @@ -69,7 +69,7 @@ type Instruction struct { } func (i Instruction) String() (s string) { - s = fmt.Sprintf("%4d: %v", i.Pos, i.Op) + s = fmt.Sprintf("%3d: %v", i.Pos, i.Op) var sb strings.Builder for _, a := range i.Arg { sb.WriteString(fmt.Sprintf(" %v", a)) @@ -100,7 +100,7 @@ func (m *Machine) Run() (err error) { sp = len(mem) // stack pointer c := m.code[ip] if debug { - log.Printf("ip:%-4d sp:%-4d fp:%-4d op:[%-18v] mem:%v\n", ip, sp, fp, c, Vstring(mem)) + log.Printf("ip:%-3d sp:%-3d fp:%-3d op:[%-20v] mem:%v\n", ip, sp, fp, c, Vstring(mem)) } ic++ switch c.Op { |
