summaryrefslogtreecommitdiff
path: root/parser/compiler.go
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2024-03-22 16:59:25 +0100
committerGitHub <noreply@github.com>2024-03-22 16:59:25 +0100
commit362f7c9c45598b429c92e67756f41b690043e0c4 (patch)
tree59dd897446880912b4a2ca4a3a8d8c49e3553211 /parser/compiler.go
parentbf2d6438e95c60946c64a6692e3dae1d836364a6 (diff)
feat: add initial support for import, provide minimal fmt (#6)
The `import` statement is now parsed. It only provides minimal support for the `fmt` package (only `Println` symbol is defined). This should be sufficient to pass a few tests. Full support of package namespaces, source and binary imports will be supported later, based on this work.
Diffstat (limited to 'parser/compiler.go')
-rw-r--r--parser/compiler.go59
1 files changed, 47 insertions, 12 deletions
diff --git a/parser/compiler.go b/parser/compiler.go
index fb79720..57e176f 100644
--- a/parser/compiler.go
+++ b/parser/compiler.go
@@ -86,7 +86,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
emit(int64(t.Pos), vm.Not)
case lang.Plus:
- // Nothing to do.
+ // Unary '+' is idempotent. Nothing to do.
case lang.Addr:
push(&symbol{Type: vm.PointerTo(pop().Type)})
@@ -109,16 +109,22 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
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.Rtype.NumOut(); i++ {
- push(&symbol{Type: typ.Out(i)})
+ s := pop()
+ if s.kind != symValue {
+ typ := s.Type
+ // TODO: pop input types (careful with variadic function).
+ for i := 0; i < typ.Rtype.NumOut(); i++ {
+ push(&symbol{Type: typ.Out(i)})
+ }
+ emit(int64(t.Pos), vm.Call)
+ break
}
- emit(int64(t.Pos), vm.Call)
+ push(s)
+ fallthrough // A symValue must be called through callX.
case lang.CallX:
rtyp := pop().value.Data.Type()
- // TODO: pop input types (careful with variadic function)
+ // TODO: pop input types (careful with variadic function).
for i := 0; i < rtyp.NumOut(); i++ {
push(&symbol{Type: &vm.Type{Rtype: rtyp.Out(i)}})
}
@@ -128,7 +134,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
emit(int64(t.Pos), vm.Grow, int64(t.Beg))
case lang.Define:
- // TODO: support assignment to local, composite objects
+ // TODO: support assignment to local, composite objects.
st := tokens[i-1]
l := len(c.Data)
typ := pop().Type
@@ -186,6 +192,9 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
return fmt.Errorf("symbol not found: %s", t.Str)
}
push(s)
+ if s.kind == symPkg {
+ break
+ }
if s.local {
emit(int64(t.Pos), vm.Fdup, int64(s.index))
} else {
@@ -256,11 +265,37 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
emit(int64(t.Pos), vm.Jump, i)
case lang.Period:
- if f, ok := pop().Type.Rtype.FieldByName("X" + t.Str[1:]); ok {
- emit(append([]int64{int64(t.Pos), vm.Field}, slint64(f.Index)...)...)
- break
+ s := pop()
+ switch s.kind {
+ case symPkg:
+ p, ok := packages[s.pkgPath]
+ if !ok {
+ 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:])
+ }
+ name := s.pkgPath + t.Str
+ var l int
+ sym, _, ok := c.getSym(name, "")
+ if ok {
+ 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]
+ }
+ push(sym)
+ emit(int64(t.Pos), vm.Dup, int64(l))
+ default:
+ if f, ok := s.Type.Rtype.FieldByName("X" + t.Str[1:]); ok {
+ emit(append([]int64{int64(t.Pos), vm.Field}, slint64(f.Index)...)...)
+ break
+ }
+ return fmt.Errorf("field or method not found: %s", t.Str[1:])
}
- return fmt.Errorf("field or method not found: %s", t.Str[1:])
case lang.Return:
emit(int64(t.Pos), vm.Return, int64(t.Beg), int64(t.End))