summaryrefslogtreecommitdiff
path: root/parser/compiler.go
diff options
context:
space:
mode:
Diffstat (limited to 'parser/compiler.go')
-rw-r--r--parser/compiler.go106
1 files changed, 72 insertions, 34 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 {