summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--comp/compiler.go85
-rw-r--r--interp/interpreter_test.go2
-rw-r--r--parser/decl.go23
-rw-r--r--parser/expr.go5
-rw-r--r--parser/parse.go17
-rw-r--r--parser/symbol.go89
-rw-r--r--parser/symkind_string.go30
-rw-r--r--parser/type.go17
-rw-r--r--symbol/kind_string.go30
-rw-r--r--symbol/symbol.go92
-rw-r--r--vm/type.go4
-rw-r--r--vm/vm.go4
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...) })}
+}
diff --git a/vm/type.go b/vm/type.go
index 782aa28..644c106 100644
--- a/vm/type.go
+++ b/vm/type.go
@@ -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
diff --git a/vm/vm.go b/vm/vm.go
index d035226..6472156 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -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 {