summaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
Diffstat (limited to 'parser')
-rw-r--r--parser/compiler.go106
-rw-r--r--parser/decl.go20
-rw-r--r--parser/interpreter_test.go7
-rw-r--r--parser/symbol.go26
-rw-r--r--parser/type.go7
5 files changed, 105 insertions, 61 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 {
diff --git a/parser/decl.go b/parser/decl.go
index 782b57a..54a2989 100644
--- a/parser/decl.go
+++ b/parser/decl.go
@@ -4,12 +4,15 @@ import (
"errors"
"go/constant"
"go/token"
+ "reflect"
"strings"
"github.com/gnolang/parscan/lang"
"github.com/gnolang/parscan/scanner"
)
+var nilValue = reflect.ValueOf(nil)
+
func (p *Parser) ParseConst(in Tokens) (out Tokens, err error) {
if len(in) < 2 {
return out, errors.New("missing expression")
@@ -51,8 +54,8 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) {
if errors.Is(err, MissingTypeErr) {
for _, lt := range decl.Split(lang.Comma) {
vars = append(vars, lt[0].Str)
- // TODO: compute type from rhs
- p.addSym(unsetAddr, strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/"), nil, symConst, nil, false)
+ name := strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/")
+ p.addSym(unsetAddr, name, nilValue, symConst, nil, false)
}
} else {
return out, err
@@ -75,7 +78,7 @@ func (p *Parser) parseConstLine(in Tokens) (out Tokens, err error) {
kind: symConst,
index: unsetAddr,
cval: cval,
- value: constValue(cval),
+ value: reflect.ValueOf(constValue(cval)),
local: p.funcScope != "",
used: true,
}
@@ -222,7 +225,7 @@ func (p *Parser) parseTypeLine(in Tokens) (out Tokens, err error) {
if err != nil {
return out, err
}
- p.addSym(unsetAddr, in[0].Str, nil, symType, typ, p.funcScope != "")
+ p.addSym(unsetAddr, in[0].Str, reflect.New(typ).Elem(), symType, typ, p.funcScope != "")
return out, err
}
@@ -257,8 +260,13 @@ func (p *Parser) parseVarLine(in Tokens) (out Tokens, err error) {
if errors.Is(err, MissingTypeErr) {
for _, lt := range decl.Split(lang.Comma) {
vars = append(vars, lt[0].Str)
- // TODO: compute type from rhs
- p.addSym(unsetAddr, strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/"), nil, symVar, nil, false)
+ name := strings.TrimPrefix(p.scope+"/"+lt[0].Str, "/")
+ if p.funcScope == "" {
+ p.addSym(unsetAddr, name, nilValue, symVar, nil, false)
+ continue
+ }
+ p.addSym(p.framelen[p.funcScope], name, nilValue, symVar, nil, false)
+ p.framelen[p.funcScope]++
}
} else {
return out, err
diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go
index 9555475..9110e3c 100644
--- a/parser/interpreter_test.go
+++ b/parser/interpreter_test.go
@@ -52,7 +52,7 @@ func run(t *testing.T, tests []etest) {
func TestExpr(t *testing.T) {
run(t, []etest{
- {src: "", res: "<nil>"},
+ {src: "", res: "<invalid reflect.Value>"},
{src: "1+2", res: "3"},
{src: "1+", err: "block not terminated"},
{src: "a := 1 + 2; b := 0; a + 1", res: "4"},
@@ -92,7 +92,7 @@ func TestFunc(t *testing.T) {
{src: "func f() int {return 2}; a := f(); a", res: "2"},
{src: "func f() int {return 2}; f()", res: "2"},
{src: "func f(a int) int {return a+2}; f(3)", res: "5"},
- {src: "func f(a int) int {if a < 4 {a = 5}; return a }; f(3)", res: "5"},
+ {src: "func f(a int) int {if a < 4 {a = 5}; return a}; f(3)", res: "5"},
{src: "func f(a int) int {return a+2}; 7 - f(3)", res: "2"},
{src: "func f(a int) int {return a+2}; f(5) - f(3)", res: "2"},
{src: "func f(a int) int {return a+2}; f(3) - 2", res: "3"},
@@ -195,7 +195,8 @@ func TestArray(t *testing.T) {
func TestPointer(t *testing.T) {
run(t, []etest{
{src: "var a *int; a", res: "<nil>"},
- //{src: "var a int = 2; var b *int = &a; b", res: "2"},
+ {src: "var a int; var b *int = &a; *b", res: "0"},
+ {src: "var a int = 2; var b *int = &a; *b", res: "2"},
})
}
diff --git a/parser/symbol.go b/parser/symbol.go
index 7edcef3..6c5ab9b 100644
--- a/parser/symbol.go
+++ b/parser/symbol.go
@@ -22,12 +22,12 @@ const unsetAddr = -65535
type symbol struct {
kind symKind
- index int // address of symbol in frame
- value any
- cval constant.Value
- Type reflect.Type
- local bool // if true address is relative to local frame, otherwise global
- used bool
+ index int // address of symbol in frame
+ value reflect.Value //
+ cval constant.Value //
+ Type reflect.Type //
+ local bool // if true address is relative to local frame, otherwise global
+ used bool //
}
func symtype(s *symbol) reflect.Type {
@@ -37,11 +37,13 @@ func symtype(s *symbol) reflect.Type {
return reflect.TypeOf(s.value)
}
-func (p *Parser) AddSym(i int, name string, v any) { p.addSym(i, name, v, symValue, nil, false) }
+func (p *Parser) AddSym(i int, name string, v reflect.Value) {
+ p.addSym(i, name, v, symValue, nil, false)
+}
-func (p *Parser) addSym(i int, name string, v any, k symKind, t reflect.Type, local bool) {
+func (p *Parser) addSym(i int, name string, v reflect.Value, k symKind, t reflect.Type, local bool) {
name = strings.TrimPrefix(name, "/")
- p.symbols[name] = &symbol{kind: k, index: i, local: local, value: v, Type: t, used: true}
+ 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.
@@ -72,9 +74,9 @@ func initUniverse() map[string]*symbol {
"nil": {index: unsetAddr},
"iota": {kind: symConst, index: unsetAddr},
- "true": {index: unsetAddr, value: true, Type: reflect.TypeOf(true)},
- "false": {index: unsetAddr, value: false, Type: reflect.TypeOf(false)},
+ "true": {index: unsetAddr, value: reflect.ValueOf(true), Type: reflect.TypeOf(true)},
+ "false": {index: unsetAddr, value: reflect.ValueOf(false), Type: reflect.TypeOf(false)},
- "println": {index: unsetAddr, value: func(v ...any) { fmt.Println(v...) }},
+ "println": {index: unsetAddr, value: reflect.ValueOf(func(v ...any) { fmt.Println(v...) })},
}
}
diff --git a/parser/type.go b/parser/type.go
index 31af1e3..ff16e4f 100644
--- a/parser/type.go
+++ b/parser/type.go
@@ -170,12 +170,7 @@ func (p *Parser) parseParamTypes(in Tokens, flag typeFlag) (types []reflect.Type
}
func (p *Parser) addSymVar(index int, name string, typ reflect.Type, flag typeFlag, local bool) {
- var zv any = reflect.New(typ).Elem()
- switch typ.Kind() {
- case reflect.Struct, reflect.Array, reflect.Slice, reflect.Pointer:
- default:
- zv = zv.(reflect.Value).Interface()
- }
+ zv := reflect.New(typ).Elem()
switch flag {
case parseTypeIn:
p.addSym(-index-2, name, zv, symVar, typ, true)