summaryrefslogtreecommitdiff
path: root/parser/symbol.go
blob: 606752cd7ae0a9310d77c5a80742a250b8e757c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package parser

import (
	"fmt"
	"go/constant"
	"strings"

	"github.com/mvertes/parscan/vm"
)

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
)

//go:generate stringer -type=symKind

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           //
}

func symtype(s *symbol) *vm.Type {
	if s.typ != nil {
		return s.typ
	}
	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, 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}
}

// 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, 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()},

		"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)},

		"println": {index: unsetAddr, value: vm.ValueOf(func(v ...any) { fmt.Println(v...) })},
	}
}