summaryrefslogtreecommitdiff
path: root/parser
diff options
context:
space:
mode:
Diffstat (limited to 'parser')
-rw-r--r--parser/compiler.go25
-rw-r--r--parser/expr.go2
-rw-r--r--parser/interpreter_test.go2
-rw-r--r--parser/parse.go25
-rw-r--r--parser/type.go16
5 files changed, 46 insertions, 24 deletions
diff --git a/parser/compiler.go b/parser/compiler.go
index 3b9a32d..05462eb 100644
--- a/parser/compiler.go
+++ b/parser/compiler.go
@@ -61,13 +61,14 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
case lang.String:
s := t.Block()
+ v := vm.Value{Data: reflect.ValueOf(s), Type: vm.TypeOf(s)}
i, ok := c.strings[s]
if !ok {
i = len(c.Data)
- c.Data = append(c.Data, vm.ValueOf(s))
+ c.Data = append(c.Data, v)
c.strings[s] = i
}
- push(&symbol{kind: symConst, value: vm.ValueOf(s)})
+ push(&symbol{kind: symConst, value: v})
emit(int64(t.Pos), vm.Dup, int64(i))
case lang.Add:
@@ -144,7 +145,11 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
// TODO: support assignment to local, composite objects.
st := tokens[i-1]
l := len(c.Data)
- typ := pop().Type
+ d := pop()
+ typ := d.Type
+ if typ == nil {
+ typ = d.value.Type
+ }
v := vm.NewValue(typ)
c.addSym(l, st.Str, v, symVar, typ, false)
c.Data = append(c.Data, v)
@@ -160,7 +165,11 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
if !ok {
return fmt.Errorf("symbol not found: %s", st.Str)
}
- typ := pop().Type
+ d := pop()
+ typ := d.Type
+ if typ == nil {
+ typ = d.value.Type
+ }
if s.Type == nil {
s.Type = typ
s.value = vm.NewValue(typ)
@@ -259,7 +268,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
} else {
i = s.value.Data.Int() - int64(len(c.Code))
}
- emit(int64(t.Pos), vm.JumpSetTrue, int64(i))
+ emit(int64(t.Pos), vm.JumpSetTrue, i)
case lang.Goto:
var i int64
@@ -431,17 +440,17 @@ type DumpValue struct {
// This design choice allows the Virtual Machine (VM) to evolve its memory management strategies
// without compromising backward compatibility with dumps generated by previous versions.
func (c *Compiler) Dump() *Dump {
- var dv []*DumpValue
dict := c.symbolsByIndex()
+ dv := make([]*DumpValue, len(c.Data))
for i, d := range c.Data {
e := dict[i]
- dv = append(dv, &DumpValue{
+ dv[i] = &DumpValue{
Index: e.index,
Name: e.name,
Kind: int(e.kind),
Type: e.Type.Name,
Value: d.Data.Interface(),
- })
+ }
}
return &Dump{Values: dv}
diff --git a/parser/expr.go b/parser/expr.go
index cf6ee74..1efb45e 100644
--- a/parser/expr.go
+++ b/parser/expr.go
@@ -110,7 +110,7 @@ func (p *Parser) parseExpr(in Tokens) (out Tokens, err error) {
case lang.Comment:
return out, nil
default:
- return nil, fmt.Errorf("expression not supported yet: %v: %q", t.Tok, t.Str)
+ return nil, fmt.Errorf("invalid expression: %v: %q", t.Tok, t.Str)
}
if len(selectors) > 0 {
out = append(out, selectors...)
diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go
index a6ad246..314f35b 100644
--- a/parser/interpreter_test.go
+++ b/parser/interpreter_test.go
@@ -69,6 +69,7 @@ func TestExpr(t *testing.T) {
{src: "-2 + 5", res: "3"},
{src: "5 + -2", res: "3"},
{src: "!false", res: "true"},
+ {src: `a := "hello"`, res: "hello"},
})
}
@@ -233,6 +234,7 @@ func TestVar(t *testing.T) {
{src: "var a, b int = 2, 5; a+b", res: "7"},
{src: "var x = 5; x", res: "5"},
{src: "var a = 1; func f() int { var a, b int = 3, 4; return a+b}; a+f()", res: "8"},
+ {src: `var a = "hello"; a`, res: "hello"},
{src: `var (
a, b int = 4+1, 3
c = 8
diff --git a/parser/parse.go b/parser/parse.go
index add1600..537b68e 100644
--- a/parser/parse.go
+++ b/parser/parse.go
@@ -29,6 +29,15 @@ type Parser struct {
clonum int // closure instance number
}
+// Parser errors.
+var (
+ ErrBody = errors.New("missign body")
+ ErrBreak = errors.New("invalid break statement")
+ ErrContinue = errors.New("invalid continue statement")
+ ErrFor = errors.New("invalid for statement")
+ ErrGoto = errors.New("invalid goto statement")
+)
+
// Scan performs lexical analysis on s and returns Tokens or an error.
func (p *Parser) Scan(s string, endSemi bool) (Tokens, error) {
return p.Scanner.Scan(s, endSemi)
@@ -36,11 +45,11 @@ func (p *Parser) Scan(s string, endSemi bool) (Tokens, error) {
// Parse performs syntax analysis on s and return Tokens or an error.
func (p *Parser) Parse(src string) (out Tokens, err error) {
- log.Printf("Parse src: %#v\n", src)
in, err := p.Scan(src, true)
if err != nil {
return out, err
}
+ log.Printf("Parse src: %#v\n", src)
return p.parseStmts(in)
}
@@ -122,12 +131,12 @@ func (p *Parser) parseBreak(in Tokens) (out Tokens, err error) {
label = p.breakLabel
case 2:
if in[1].Tok != lang.Ident {
- return nil, fmt.Errorf("invalid break statement")
+ return nil, ErrBreak
}
// TODO: check validity of user provided label
label = in[1].Str
default:
- return nil, fmt.Errorf("invalid break statement")
+ return nil, ErrBreak
}
out = Tokens{{Tok: lang.Goto, Str: label}}
return out, err
@@ -140,12 +149,12 @@ func (p *Parser) parseContinue(in Tokens) (out Tokens, err error) {
label = p.continueLabel
case 2:
if in[1].Tok != lang.Ident {
- return nil, fmt.Errorf("invalid continue statement")
+ return nil, ErrContinue
}
// TODO: check validity of user provided label
label = in[1].Str
default:
- return nil, fmt.Errorf("invalid continue statement")
+ return nil, ErrContinue
}
out = Tokens{{Tok: lang.Goto, Str: label}}
return out, err
@@ -153,7 +162,7 @@ func (p *Parser) parseContinue(in Tokens) (out Tokens, err error) {
func (p *Parser) parseGoto(in Tokens) (out Tokens, err error) {
if len(in) != 2 || in[1].Tok != lang.Ident {
- return nil, fmt.Errorf("invalid goto statement")
+ return nil, ErrGoto
}
// TODO: check validity of user provided label
return Tokens{{Tok: lang.Goto, Str: p.funcScope + "/" + in[1].Str}}, nil
@@ -171,7 +180,7 @@ func (p *Parser) parseFor(in Tokens) (out Tokens, err error) {
case 3:
init, cond, post = pre[0], pre[1], pre[2]
default:
- return nil, fmt.Errorf("invalild for statement")
+ return nil, ErrFor
}
breakLabel, continueLabel := p.breakLabel, p.continueLabel
p.pushScope("for" + fc)
@@ -247,7 +256,7 @@ func (p *Parser) parseFunc(in Tokens) (out Tokens, err error) {
bi := in.Index(lang.BraceBlock)
if bi < 0 {
- return out, fmt.Errorf("no function body")
+ return out, ErrBody
}
typ, err := p.parseTypeExpr(in[:bi])
if err != nil {
diff --git a/parser/type.go b/parser/type.go
index ba60e8f..e25431a 100644
--- a/parser/type.go
+++ b/parser/type.go
@@ -20,10 +20,12 @@ const (
// Type parsing error definitions.
var (
- ErrInvalidType = errors.New("invalid type")
- ErrMissingType = errors.New("missing type")
- ErrSyntax = errors.New("syntax error")
- ErrTypeNotImplemented = errors.New("not implemented")
+ ErrFuncType = errors.New("invalid function type")
+ ErrInvalidType = errors.New("invalid type")
+ ErrMissingType = errors.New("missing type")
+ ErrSize = errors.New("invalid size")
+ ErrSyntax = errors.New("syntax error")
+ ErrNotImplemented = errors.New("not implemented")
)
func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) {
@@ -44,7 +46,7 @@ func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) {
}
size, ok := constValue(cval).(int)
if !ok {
- return nil, fmt.Errorf("invalid size")
+ return nil, ErrSize
}
return vm.ArrayOf(size, typ), nil
}
@@ -71,7 +73,7 @@ func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) {
case l >= 2 && in1.Tok == lang.ParenBlock:
indexArgs, out = 1, in[2:]
default:
- return nil, fmt.Errorf("invalid func signature")
+ return nil, ErrFuncType
}
// We can now parse function input and output parameter types.
@@ -125,7 +127,7 @@ func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) {
return vm.StructOf(fields), nil
default:
- return nil, fmt.Errorf("%w: %v", ErrTypeNotImplemented, in[0].Name())
+ return nil, fmt.Errorf("%w: %v", ErrNotImplemented, in[0].Name())
}
}