diff options
| author | Marc Vertes <mvertes@free.fr> | 2025-11-27 12:40:35 +0100 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2025-11-27 12:40:35 +0100 |
| commit | d99d69391eeae129cad2d5c2c90ce700db01b11c (patch) | |
| tree | 0286d21e88919b9a9f86081d057b065c19f8ec38 | |
| parent | aed20c1c453e50f716c454c0bd7e4995a0f5d898 (diff) | |
chore: move compiler and interpreter in their own packages
| -rw-r--r-- | compiler/compiler.go (renamed from parser/compiler.go) | 224 | ||||
| -rw-r--r-- | interpreter/dump_test.go (renamed from parser/dump_test.go) | 8 | ||||
| -rw-r--r-- | interpreter/interpreter_test.go (renamed from parser/interpreter_test.go) | 6 | ||||
| -rw-r--r-- | main.go | 8 | ||||
| -rw-r--r-- | parser/decl.go | 38 | ||||
| -rw-r--r-- | parser/expr.go | 4 | ||||
| -rw-r--r-- | parser/interpreter.go | 11 | ||||
| -rw-r--r-- | parser/package.go | 2 | ||||
| -rw-r--r-- | parser/parse.go | 20 | ||||
| -rw-r--r-- | parser/symbol.go | 88 | ||||
| -rw-r--r-- | parser/symkind_string.go | 28 | ||||
| -rw-r--r-- | parser/type.go | 18 |
12 files changed, 227 insertions, 228 deletions
diff --git a/parser/compiler.go b/compiler/compiler.go index 501fb25..d63dd14 100644 --- a/parser/compiler.go +++ b/compiler/compiler.go @@ -1,4 +1,4 @@ -package parser +package compiler import ( "fmt" @@ -10,13 +10,14 @@ import ( "strconv" "github.com/mvertes/parscan/lang" + "github.com/mvertes/parscan/parser" "github.com/mvertes/parscan/scanner" "github.com/mvertes/parscan/vm" ) // Compiler represents the state of a compiler. type Compiler struct { - *Parser + *parser.Parser 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) @@ -27,7 +28,7 @@ type Compiler struct { // NewCompiler returns a new compiler state for a given scanner. func NewCompiler(scanner *scanner.Scanner) *Compiler { return &Compiler{ - Parser: NewParser(scanner, true), + Parser: parser.NewParser(scanner, true), Entry: -1, strings: map[string]int{}, } @@ -37,23 +38,23 @@ func NewCompiler(scanner *scanner.Scanner) *Compiler { 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) + c.AddSymbol(p, name, value, parser.SymValue, nil, false) return p } // Codegen generates vm code from parsed tokens. -func (c *Compiler) Codegen(tokens Tokens) (err error) { +func (c *Compiler) Codegen(tokens parser.Tokens) (err error) { log.Println("Codegen tokens:", tokens) - fixList := Tokens{} // list of tokens to fix after we gathered all necessary information - stack := []*symbol{} // for symbolic evaluation, type checking, etc + fixList := parser.Tokens{} // list of tokens to fix after all necessary information is gathered + stack := []*parser.Symbol{} // for symbolic evaluation, type checking, etc emit := func(t scanner.Token, op vm.Op, arg ...int) { _, file, line, _ := runtime.Caller(1) 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 *symbol) { stack = append(stack, s) } - pop := func() *symbol { l := len(stack) - 1; s := stack[l]; stack = stack[:l]; return s } + 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 } for i, t := range tokens { switch t.Tok { @@ -62,7 +63,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { if err != nil { return err } - push(&symbol{kind: symConst, value: vm.ValueOf(n), typ: vm.TypeOf(0)}) + push(&parser.Symbol{Kind: parser.SymConst, Value: vm.ValueOf(n), Type: vm.TypeOf(0)}) emit(t, vm.Push, n) case lang.String: @@ -74,19 +75,19 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { c.Data = append(c.Data, v) c.strings[s] = i } - push(&symbol{kind: symConst, value: v}) + push(&parser.Symbol{Kind: parser.SymConst, Value: v}) emit(t, vm.Dup, i) case lang.Add: - push(&symbol{typ: arithmeticOpType(pop(), pop())}) + push(&parser.Symbol{Type: arithmeticOpType(pop(), pop())}) emit(t, vm.Add) case lang.Mul: - push(&symbol{typ: arithmeticOpType(pop(), pop())}) + push(&parser.Symbol{Type: arithmeticOpType(pop(), pop())}) emit(t, vm.Mul) case lang.Sub: - push(&symbol{typ: arithmeticOpType(pop(), pop())}) + push(&parser.Symbol{Type: arithmeticOpType(pop(), pop())}) emit(t, vm.Sub) case lang.Minus: @@ -100,32 +101,32 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { // Unary '+' is idempotent. Nothing to do. case lang.Addr: - push(&symbol{typ: vm.PointerTo(pop().typ)}) + push(&parser.Symbol{Type: vm.PointerTo(pop().Type)}) emit(t, vm.Addr) case lang.Deref: - push(&symbol{typ: pop().typ.Elem()}) + push(&parser.Symbol{Type: pop().Type.Elem()}) emit(t, vm.Deref) case lang.Index: - push(&symbol{typ: pop().typ.Elem()}) + push(&parser.Symbol{Type: pop().Type.Elem()}) emit(t, vm.Index) case lang.Greater: - push(&symbol{typ: booleanOpType(pop(), pop())}) + push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.Greater) case lang.Less: - push(&symbol{typ: booleanOpType(pop(), pop())}) + push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.Lower) case lang.Call: s := pop() - if s.kind != symValue { - typ := s.typ + if s.Kind != parser.SymValue { + typ := s.Type // TODO: pop input types (careful with variadic function). for i := 0; i < typ.Rtype.NumOut(); i++ { - push(&symbol{typ: typ.Out(i)}) + push(&parser.Symbol{Type: typ.Out(i)}) } emit(t, vm.Call) break @@ -134,10 +135,10 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { fallthrough // A symValue must be called through callX. case lang.CallX: - rtyp := pop().value.Data.Type() + rtyp := pop().Value.Data.Type() // TODO: pop input types (careful with variadic function). for i := 0; i < rtyp.NumOut(); i++ { - push(&symbol{typ: &vm.Type{Rtype: rtyp.Out(i)}}) + push(&parser.Symbol{Type: &vm.Type{Rtype: rtyp.Out(i)}}) } emit(t, vm.CallX, t.Beg) @@ -168,12 +169,12 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { st := tokens[i-1] l := len(c.Data) d := pop() - typ := d.typ + typ := d.Type if typ == nil { - typ = d.value.Type + typ = d.Value.Type } v := vm.NewValue(typ) - c.addSym(l, st.Str, v, symVar, typ, false) + c.AddSymbol(l, st.Str, v, parser.SymVar, typ, false) c.Data = append(c.Data, v) emit(t, vm.Assign, l) @@ -183,39 +184,39 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { emit(t, vm.Vassign) break } - s, ok := c.symbols[st.Str] + s, ok := c.Symbols[st.Str] if !ok { return fmt.Errorf("symbol not found: %s", st.Str) } d := pop() - typ := d.typ + typ := d.Type if typ == nil { - typ = d.value.Type + typ = d.Value.Type } - if s.typ == nil { - s.typ = typ - s.value = vm.NewValue(typ) + if s.Type == nil { + s.Type = typ + s.Value = vm.NewValue(typ) } - if s.local { - if !s.used { - emit(st, vm.New, s.index, c.typeSym(s.typ).index) - s.used = true + if s.Local { + if !s.Used { + emit(st, vm.New, s.Index, c.typeSym(s.Type).Index) + s.Used = true } - emit(st, vm.Fassign, s.index) + emit(st, vm.Fassign, s.Index) break } - if s.index == unsetAddr { - s.index = len(c.Data) - c.Data = append(c.Data, s.value) + if s.Index == parser.UnsetAddr { + s.Index = len(c.Data) + c.Data = append(c.Data, s.Value) } - emit(st, vm.Assign, s.index) + emit(st, vm.Assign, s.Index) case lang.Equal: - push(&symbol{typ: booleanOpType(pop(), pop())}) + push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.Equal) case lang.EqualSet: - push(&symbol{typ: booleanOpType(pop(), pop())}) + push(&parser.Symbol{Type: booleanOpType(pop(), pop())}) emit(t, vm.EqualSet) case lang.Ident: @@ -225,111 +226,110 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { continue } } - s, ok := c.symbols[t.Str] + s, ok := c.Symbols[t.Str] if !ok { return fmt.Errorf("symbol not found: %s", t.Str) } push(s) - if s.kind == symPkg { + if s.Kind == parser.SymPkg { break } - if s.local { - emit(t, vm.Fdup, s.index) + if s.Local { + emit(t, vm.Fdup, s.Index) } else { - if s.index == unsetAddr { - s.index = len(c.Data) - c.Data = append(c.Data, s.value) + if s.Index == parser.UnsetAddr { + s.Index = len(c.Data) + c.Data = append(c.Data, s.Value) } - log.Println(t, ": emit(", t.Pos, vm.Dup, s.index, ")") - emit(t, vm.Dup, s.index) + emit(t, vm.Dup, s.Index) } case lang.Label: lc := len(c.Code) - s, ok := c.symbols[t.Str] + s, ok := c.Symbols[t.Str] if ok { - s.value = vm.ValueOf(lc) - if s.kind == symFunc { + s.Value = vm.ValueOf(lc) + if s.Kind == parser.SymFunc { // label is a function entry point, register its code address in data. - s.index = len(c.Data) - c.Data = append(c.Data, s.value) + s.Index = len(c.Data) + c.Data = append(c.Data, s.Value) } else { - c.Data[s.index] = s.value + c.Data[s.Index] = s.Value } } else { - c.symbols[t.Str] = &symbol{kind: symLabel, value: vm.ValueOf(lc)} + c.Symbols[t.Str] = &parser.Symbol{Kind: parser.SymLabel, Value: vm.ValueOf(lc)} } case lang.JumpFalse: var i int - if s, ok := c.symbols[t.Str]; !ok { + if s, ok := c.Symbols[t.Str]; !ok { // t.Beg contains the position in code which needs to be fixed. t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = int(s.value.Data.Int()) - len(c.Code) + i = int(s.Value.Data.Int()) - len(c.Code) } emit(t, vm.JumpFalse, i) case lang.JumpSetFalse: var i int - if s, ok := c.symbols[t.Str]; !ok { + if s, ok := c.Symbols[t.Str]; !ok { // t.Beg contains the position in code which needs to be fixed. t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = int(s.value.Data.Int()) - len(c.Code) + i = int(s.Value.Data.Int()) - len(c.Code) } emit(t, vm.JumpSetFalse, i) case lang.JumpSetTrue: var i int - if s, ok := c.symbols[t.Str]; !ok { + if s, ok := c.Symbols[t.Str]; !ok { // t.Beg contains the position in code which needs to be fixed. t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = int(s.value.Data.Int()) - len(c.Code) + i = int(s.Value.Data.Int()) - len(c.Code) } emit(t, vm.JumpSetTrue, i) case lang.Goto: var i int - if s, ok := c.symbols[t.Str]; !ok { + if s, ok := c.Symbols[t.Str]; !ok { t.Beg = len(c.Code) fixList = append(fixList, t) } else { - i = int(s.value.Data.Int()) - len(c.Code) + i = int(s.Value.Data.Int()) - len(c.Code) } emit(t, vm.Jump, i) case lang.Period: s := pop() - switch s.kind { - case symPkg: - p, ok := packages[s.pkgPath] + switch s.Kind { + case parser.SymPkg: + p, ok := parser.Packages[s.PkgPath] if !ok { - return fmt.Errorf("package not found: %s", s.pkgPath) + return fmt.Errorf("package not found: %s", s.PkgPath) } v, ok := p[t.Str[1:]] if !ok { - return fmt.Errorf("symbol not found in package %s: %s", s.pkgPath, t.Str[1:]) + return fmt.Errorf("symbol not found in package %s: %s", s.PkgPath, t.Str[1:]) } - name := s.pkgPath + t.Str + name := s.PkgPath + t.Str var l int - sym, _, ok := c.getSym(name, "") + sym, _, ok := c.GetSym(name, "") if ok { - l = sym.index + l = sym.Index } else { l = len(c.Data) c.Data = append(c.Data, v) - c.addSym(l, name, v, symValue, v.Type, false) - sym = c.symbols[name] + c.AddSymbol(l, name, v, parser.SymValue, v.Type, false) + sym = c.Symbols[name] } push(sym) emit(t, vm.Dup, l) default: - if f, ok := s.typ.Rtype.FieldByName(t.Str[1:]); ok { + if f, ok := s.Type.Rtype.FieldByName(t.Str[1:]); ok { emit(t, vm.Field, f.Index...) break } @@ -346,31 +346,29 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) { // Finally we fix unresolved labels for jump destinations. for _, t := range fixList { - s, ok := c.symbols[t.Str] + s, ok := c.Symbols[t.Str] if !ok { return fmt.Errorf("label not found: %q", t.Str) } - c.Code[t.Beg].Arg[0] = int(s.value.Data.Int()) - t.Beg - + c.Code[t.Beg].Arg[0] = int(s.Value.Data.Int()) - t.Beg } 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) *vm.Type { return symtype(s1) } -func booleanOpType(_, _ *symbol) *vm.Type { return vm.TypeOf(true) } - -// PrintCode pretty prints the generated code in compiler. +// PrintCode pretty prints the generated code. func (c *Compiler) PrintCode() { labels := map[int][]string{} // labels indexed by code location data := map[int]string{} // data indexed by frame location - for name, sym := range c.symbols { - if sym.kind == symLabel || sym.kind == symFunc { - i := int(sym.value.Data.Int()) + for name, sym := range c.Symbols { + if sym.Kind == parser.SymLabel || sym.Kind == parser.SymFunc { + i := int(sym.Value.Data.Int()) labels[i] = append(labels[i], name) } - if sym.used { - data[sym.index] = name + if sym.Used { + data[sym.Index] = name } } @@ -401,18 +399,18 @@ func (c *Compiler) PrintCode() { type entry struct { name string - *symbol + *parser.Symbol } func (e entry) String() string { - if e.symbol != nil { + if e.Symbol != nil { return fmt.Sprintf("name: %s,local: %t, i: %d, k: %d, t: %s, v: %v", e.name, - e.local, - e.index, - e.kind, - e.typ, - e.value, + e.Local, + e.Index, + e.Kind, + e.Type, + e.Value, ) } return e.name @@ -430,11 +428,11 @@ func (c *Compiler) PrintData() { func (c *Compiler) symbolsByIndex() map[int]entry { dict := map[int]entry{} - for name, sym := range c.symbols { - if sym.index == unsetAddr { + for name, sym := range c.Symbols { + if sym.Index == parser.UnsetAddr { continue } - dict[sym.index] = entry{name, sym} + dict[sym.Index] = entry{name, sym} } return dict } @@ -466,10 +464,10 @@ func (c *Compiler) Dump() *Dump { for i, d := range c.Data { e := dict[i] dv[i] = &DumpValue{ - Index: e.index, + Index: e.Index, Name: e.name, - Kind: int(e.kind), - Type: e.typ.Name, + Kind: int(e.Kind), + Type: e.Type.Name, Value: d.Data.Interface(), } } @@ -487,13 +485,13 @@ func (c *Compiler) ApplyDump(d *Dump) error { } if dv.Name != e.name || - dv.Type != e.typ.Name || - dv.Kind != int(e.kind) { + dv.Type != e.Type.Name || + dv.Kind != int(e.Kind) { return fmt.Errorf("entry with index %d does not match with provided entry. "+ "dumpValue: %s, %s, %d. memoryValue: %s, %s, %d", dv.Index, dv.Name, dv.Type, dv.Kind, - e.name, e.typ, e.kind) + e.name, e.Type, e.Kind) } if dv.Index >= len(c.Data) { @@ -509,14 +507,14 @@ func (c *Compiler) ApplyDump(d *Dump) error { return nil } -func (c *Compiler) typeSym(t *vm.Type) *symbol { - tsym, ok := c.symbols[t.Rtype.String()] +func (c *Compiler) typeSym(t *vm.Type) *parser.Symbol { + tsym, ok := c.Symbols[t.Rtype.String()] if !ok { - tsym = &symbol{index: unsetAddr, kind: symType, typ: t} - c.symbols[t.Rtype.String()] = tsym + tsym = &parser.Symbol{Index: parser.UnsetAddr, Kind: parser.SymType, Type: t} + c.Symbols[t.Rtype.String()] = tsym } - if tsym.index == unsetAddr { - tsym.index = len(c.Data) + if tsym.Index == parser.UnsetAddr { + tsym.Index = len(c.Data) c.Data = append(c.Data, vm.NewValue(t)) } return tsym diff --git a/parser/dump_test.go b/interpreter/dump_test.go index db86c48..dd172b9 100644 --- a/parser/dump_test.go +++ b/interpreter/dump_test.go @@ -1,14 +1,14 @@ -package parser_test +package interpreter_test import ( "testing" - "github.com/mvertes/parscan/parser" + "github.com/mvertes/parscan/interpreter" ) func TestDump(t *testing.T) { initProgram := "var a int = 2+1; a" - interp := parser.NewInterpreter(GoScanner) + interp := interpreter.NewInterpreter(GoScanner) r, e := interp.Eval(initProgram) t.Log(r, e) if e != nil { @@ -24,7 +24,7 @@ func TestDump(t *testing.T) { d := interp.Dump() t.Log(d) - interp = parser.NewInterpreter(GoScanner) + interp = interpreter.NewInterpreter(GoScanner) r, e = interp.Eval(initProgram) t.Log(r, e) if e != nil { diff --git a/parser/interpreter_test.go b/interpreter/interpreter_test.go index bbe0e2c..800ace5 100644 --- a/parser/interpreter_test.go +++ b/interpreter/interpreter_test.go @@ -1,12 +1,12 @@ -package parser_test +package interpreter_test import ( "fmt" "log" "testing" + "github.com/mvertes/parscan/interpreter" "github.com/mvertes/parscan/lang/golang" - "github.com/mvertes/parscan/parser" "github.com/mvertes/parscan/scanner" ) @@ -27,7 +27,7 @@ func gen(test etest) func(*testing.T) { if test.skip { t.Skip() } - interp := parser.NewInterpreter(GoScanner) + interp := interpreter.NewInterpreter(GoScanner) errStr := "" r, e := interp.Eval(test.src) t.Log(r, e) @@ -11,8 +11,8 @@ import ( "reflect" "strings" + "github.com/mvertes/parscan/interpreter" "github.com/mvertes/parscan/lang/golang" - "github.com/mvertes/parscan/parser" "github.com/mvertes/parscan/scanner" ) @@ -76,7 +76,7 @@ func run(arg []string) (err error) { } args := rflag.Args() - interp := parser.NewInterpreter(scanner.NewScanner(golang.GoSpec)) + intpr := interpreter.NewInterpreter(scanner.NewScanner(golang.GoSpec)) var in io.Reader if str != "" { @@ -94,13 +94,13 @@ func run(arg []string) (err error) { } if isatty(in) { - return repl(interp, in) + return repl(intpr, in) } buf, err := io.ReadAll(in) if err != nil { return err } - _, err = interp.Eval(string(buf)) + _, err = intpr.Eval(string(buf)) return err } diff --git a/parser/decl.go b/parser/decl.go index 094fa9f..876b2ca 100644 --- a/parser/decl.go +++ b/parser/decl.go @@ -26,7 +26,7 @@ func (p *Parser) parseConst(in Tokens) (out Tokens, err error) { return out, err } var cnt int64 - p.symbols["iota"].cval = constant.Make(cnt) + p.Symbols["iota"].Cval = constant.Make(cnt) var prev Tokens for i, lt := range in.Split(lang.Semicolon) { if i > 0 && len(lt) == 1 { @@ -39,7 +39,7 @@ func (p *Parser) parseConst(in Tokens) (out Tokens, err error) { out = append(out, ot...) prev = lt[1:] cnt++ - p.symbols["iota"].cval = constant.Make(cnt) + p.Symbols["iota"].Cval = constant.Make(cnt) } return out, err } @@ -57,7 +57,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.addSym(unsetAddr, name, nilValue, symConst, nil, false) + p.AddSymbol(UnsetAddr, name, nilValue, SymConst, nil, false) } } else { return out, err @@ -76,13 +76,13 @@ 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, - cval: cval, - value: vm.ValueOf(constValue(cval)), - local: p.funcScope != "", - used: true, + p.Symbols[name] = &Symbol{ + Kind: SymConst, + Index: UnsetAddr, + Cval: cval, + Value: vm.ValueOf(constValue(cval)), + Local: p.funcScope != "", + Used: true, } // TODO: type conversion when applicable. } @@ -131,14 +131,14 @@ 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.GetSym(t.Str, p.scope) if !ok { return nil, 0, errors.New("symbol not found") } - if s.kind != symConst { + if s.Kind != SymConst { return nil, 0, errors.New("symbol is not a constant") } - return s.cval, 1, err + return s.Cval, 1, err case id == lang.Call: // TODO: implement support for type conversions and builtin calls. panic("not implemented yet") @@ -223,7 +223,7 @@ func (p *Parser) parseImportLine(in Tokens) (out Tokens, err error) { return out, fmt.Errorf("invalid argument %v", in[0]) } pp := in[l-1].Block() - pkg, ok := packages[pp] + pkg, ok := Packages[pp] if !ok { // TODO: try to import source package from here. return out, fmt.Errorf("package not found: %s", pp) @@ -240,10 +240,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{Index: UnsetAddr, PkgPath: pp, Value: v} } } else { - p.symbols[n] = &symbol{kind: symPkg, pkgPath: pp, index: unsetAddr} + p.Symbols[n] = &Symbol{Kind: SymPkg, PkgPath: pp, Index: UnsetAddr} } return out, err } @@ -299,7 +299,7 @@ func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) { return out, err } typ.Name = in[0].Str - p.addSym(unsetAddr, in[0].Str, vm.NewValue(typ), symType, typ, p.funcScope != "") + p.AddSymbol(UnsetAddr, in[0].Str, vm.NewValue(typ), SymType, typ, p.funcScope != "") return out, err } @@ -336,10 +336,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.addSym(unsetAddr, name, nilValue, symVar, nil, false) + p.AddSymbol(UnsetAddr, name, nilValue, SymVar, nil, false) continue } - p.addSym(p.framelen[p.funcScope], name, nilValue, symVar, nil, false) + p.AddSymbol(p.framelen[p.funcScope], name, nilValue, SymVar, nil, false) p.framelen[p.funcScope]++ } } else { diff --git a/parser/expr.go b/parser/expr.go index 23534e5..f2dbce3 100644 --- a/parser/expr.go +++ b/parser/expr.go @@ -40,7 +40,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.GetSym(t.Str, p.scope) if ok { if sc != "" { t.Str = sc + "/" + t.Str @@ -98,7 +98,7 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) { if err != nil { return out, ErrInvalidType } - p.addSym(unsetAddr, typ.String(), vm.NewValue(typ), symType, typ, p.funcScope != "") + p.AddSymbol(UnsetAddr, typ.String(), vm.NewValue(typ), SymType, 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/interpreter.go b/parser/interpreter.go index 6f354d9..06a4bc1 100644 --- a/parser/interpreter.go +++ b/parser/interpreter.go @@ -1,8 +1,9 @@ -package parser +package interpreter import ( "reflect" + "github.com/mvertes/parscan/compiler" "github.com/mvertes/parscan/scanner" "github.com/mvertes/parscan/vm" ) @@ -11,13 +12,13 @@ const debug = true // Interpreter represents the state of an interpreter. type Interpreter struct { - *Compiler + *compiler.Compiler *vm.Machine } // NewInterpreter returns a new interpreter state. func NewInterpreter(s *scanner.Scanner) *Interpreter { - return &Interpreter{NewCompiler(s), &vm.Machine{}} + return &Interpreter{compiler.NewCompiler(s), &vm.Machine{}} } // Eval interprets a src program and return the last produced value if any, or an error. @@ -39,8 +40,8 @@ func (i *Interpreter) Eval(src string) (res reflect.Value, err error) { } i.Push(i.Data[dataOffset:]...) i.PushCode(i.Code[codeOffset:]...) - if s, ok := i.symbols["main"]; ok { - i.PushCode(vm.Instruction{Op: vm.Calli, Arg: []int{int(i.Data[s.index].Data.Int())}}) + if s, ok := i.Symbols["main"]; ok { + i.PushCode(vm.Instruction{Op: vm.Calli, Arg: []int{int(i.Data[s.Index].Data.Int())}}) } i.PushCode(vm.Instruction{Op: vm.Exit}) i.SetIP(max(codeOffset, i.Entry)) diff --git a/parser/package.go b/parser/package.go index f03c59f..67e2867 100644 --- a/parser/package.go +++ b/parser/package.go @@ -6,7 +6,7 @@ import ( "github.com/mvertes/parscan/vm" ) -var packages = map[string]map[string]vm.Value{ +var Packages = map[string]map[string]vm.Value{ "fmt": fmtPkg, } diff --git a/parser/parse.go b/parser/parse.go index 266ce8b..3a7ce5e 100644 --- a/parser/parse.go +++ b/parser/parse.go @@ -16,8 +16,8 @@ import ( type Parser struct { *scanner.Scanner - symbols map[string]*symbol - function *symbol + Symbols map[string]*Symbol + function *Symbol scope string fname string pkgName string // current package name @@ -45,7 +45,7 @@ func NewParser(scanner *scanner.Scanner, noPkg bool) *Parser { return &Parser{ Scanner: scanner, noPkg: noPkg, - symbols: initUniverse(), + Symbols: initUniverse(), framelen: map[string]int{}, labelCount: map[string]int{}, } @@ -255,10 +255,10 @@ 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.GetSym(fname, p.scope) if !ok { - s = &symbol{used: true} - p.symbols[p.scope+fname] = s + s = &Symbol{Used: true} + p.Symbols[p.scope+fname] = s } p.pushScope(fname) p.funcScope = p.scope @@ -282,8 +282,8 @@ func (p *Parser) parseFunc(in Tokens) (out Tokens, err error) { if err != nil { return out, err } - s.kind = symFunc - s.typ = typ + s.Kind = SymFunc + s.Type = typ p.function = s toks, err := p.Parse(in[len(in)-1].Block()) @@ -479,8 +479,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.typ.Rtype.NumOut() - in[0].End = s.typ.Rtype.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 606752c..3aba4e5 100644 --- a/parser/symbol.go +++ b/parser/symbol.go @@ -8,54 +8,54 @@ import ( "github.com/mvertes/parscan/vm" ) -type symKind int +type SymKind int const ( - symValue symKind = iota // a Go value defined in the runtime - symType // a Go type - symLabel // a label indication a position in the VM code - symConst // a Go constant - symVar // a Go variable, located in the VM memory - symFunc // a Go function, located in the VM code - symPkg // a Go package + 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 +//go:generate stringer -type=SymKind -const unsetAddr = -65535 +const UnsetAddr = -65535 -type symbol struct { - kind symKind - index int // address of symbol in frame - pkgPath string // - typ *vm.Type // - value vm.Value // - cval constant.Value // - local bool // if true address is relative to local frame, otherwise global - used bool // +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 // } -func symtype(s *symbol) *vm.Type { - if s.typ != nil { - return s.typ +func SymbolType(s *Symbol) *vm.Type { + if s.Type != nil { + return s.Type } - return vm.TypeOf(s.value) + return vm.TypeOf(s.Value) } // AddSym add a new named value at memory position i in the parser symbol table. -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 vm.Value) { +// p.addSym(i, name, v, SymValue, nil, false) +// } -func (p *Parser) addSym(i int, name string, v vm.Value, k symKind, t *vm.Type, local bool) { +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, typ: t} + 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) { +// 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 { + if sym, ok = p.Symbols[scope+"/"+name]; ok { return sym, scope, ok } i := strings.LastIndex(scope, "/") @@ -66,23 +66,23 @@ func (p *Parser) getSym(name, scope string) (sym *symbol, sc string, ok bool) { break } } - sym, ok = p.symbols[name] + sym, ok = p.Symbols[name] return sym, scope, ok } -func initUniverse() map[string]*symbol { - return map[string]*symbol{ - "any": {kind: symType, index: unsetAddr, typ: vm.TypeOf((*any)(nil)).Elem()}, - "bool": {kind: symType, index: unsetAddr, typ: vm.TypeOf((*bool)(nil)).Elem()}, - "error": {kind: symType, index: unsetAddr, typ: vm.TypeOf((*error)(nil)).Elem()}, - "int": {kind: symType, index: unsetAddr, typ: vm.TypeOf((*int)(nil)).Elem()}, - "string": {kind: symType, index: unsetAddr, typ: vm.TypeOf((*string)(nil)).Elem()}, +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), typ: vm.TypeOf(true)}, - "false": {index: unsetAddr, value: vm.ValueOf(false), typ: vm.TypeOf(false)}, + "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...) })}, + "println": {Index: UnsetAddr, Value: vm.ValueOf(func(v ...any) { fmt.Println(v...) })}, } } diff --git a/parser/symkind_string.go b/parser/symkind_string.go index a22c994..dc6a33d 100644 --- a/parser/symkind_string.go +++ b/parser/symkind_string.go @@ -1,4 +1,4 @@ -// Code generated by "stringer -type=symKind"; DO NOT EDIT. +// Code generated by "stringer -type=SymKind"; DO NOT EDIT. package parser @@ -8,23 +8,23 @@ 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] + _ = 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" +const _SymKind_name = "SymValueSymTypeSymLabelSymConstSymVarSymFuncSymPkg" -var _symKind_index = [...]uint8{0, 8, 15, 23, 31, 37, 44, 50} +var _SymKind_index = [...]uint8{0, 8, 15, 23, 31, 37, 44, 50} -func (i symKind) String() string { +func (i SymKind) String() string { idx := int(i) - 0 - if i < 0 || idx >= len(_symKind_index)-1 { - return "symKind(" + strconv.FormatInt(int64(i), 10) + ")" + 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]] + return _SymKind_name[_SymKind_index[idx]:_SymKind_index[idx+1]] } diff --git a/parser/type.go b/parser/type.go index b1b25dc..6f75f6f 100644 --- a/parser/type.go +++ b/parser/type.go @@ -100,11 +100,11 @@ 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.GetSym(in[0].Str, p.scope) + if !ok || s.Kind != SymType { return nil, fmt.Errorf("%w: %s", ErrInvalidType, in[0].Str) } - return s.typ, nil + return s.Type, nil case lang.Struct: if len(in) != 2 || in[1].Tok != lang.BraceBlock { @@ -174,16 +174,16 @@ func (p *Parser) addSymVar(index int, name string, typ *vm.Type, flag typeFlag, zv := vm.NewValue(typ) switch flag { case parseTypeIn: - p.addSym(-index-2, name, zv, symVar, typ, true) + p.AddSymbol(-index-2, name, zv, SymVar, typ, true) case parseTypeOut: - p.addSym(p.framelen[p.funcScope], name, zv, symVar, typ, true) + p.AddSymbol(p.framelen[p.funcScope], name, zv, SymVar, typ, true) p.framelen[p.funcScope]++ case parseTypeVar: if !local { - p.addSym(unsetAddr, name, zv, symVar, typ, local) + p.AddSymbol(UnsetAddr, name, zv, SymVar, typ, local) break } - p.addSym(p.framelen[p.funcScope], name, zv, symVar, typ, local) + p.AddSymbol(p.framelen[p.funcScope], name, zv, SymVar, typ, local) p.framelen[p.funcScope]++ } } @@ -193,8 +193,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.GetSym(in[0].Str, p.scope) + return !ok || s.Kind != SymType } // typeStartIndex returns the index of the start of type expression in tokens, or -1. |
