summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Vertes <mvertes@free.fr>2023-11-20 11:00:51 +0100
committerMarc Vertes <mvertes@free.fr>2023-11-20 11:00:51 +0100
commit001ca51323a1a54c9b3db377f0783c330666c480 (patch)
tree7779e6b0c453f9f38bd5a24201011475f2b1f53a
parentee21c324ce8c41b589e5a39e5715223ffd154315 (diff)
parser: add support for slices and arrays, parse index expressions
-rw-r--r--lang/token.go1
-rw-r--r--parser/README.md4
-rw-r--r--parser/compiler.go5
-rw-r--r--parser/expr.go4
-rw-r--r--parser/interpreter_test.go8
-rw-r--r--parser/type.go27
-rw-r--r--vm/vm.go5
7 files changed, 49 insertions, 5 deletions
diff --git a/lang/token.go b/lang/token.go
index 37ac557..a894c98 100644
--- a/lang/token.go
+++ b/lang/token.go
@@ -108,6 +108,7 @@ const (
Call
CallX
Grow
+ Index
Label
JumpFalse
JumpSetFalse
diff --git a/parser/README.md b/parser/README.md
index 6a1a0e0..eb65dcf 100644
--- a/parser/README.md
+++ b/parser/README.md
@@ -44,7 +44,7 @@ Go language support:
- [ ] embedded structures
- [ ] recursive structures
- [ ] interfaces
-- [ ] arrays, slices
+- [x] arrays, slices
- [ ] maps
- [ ] deterministic maps
- [ ] channel types
@@ -76,7 +76,7 @@ Go language support:
- [x] operator precedence rules
- [x] parenthesis expressions
- [x] call expressions
-- [ ] index expressions
+- [x] index expressions
- [x] selector expressions
- [ ] type convertions
- [ ] type assertions
diff --git a/parser/compiler.go b/parser/compiler.go
index 36fc9d4..41448b7 100644
--- a/parser/compiler.go
+++ b/parser/compiler.go
@@ -77,6 +77,9 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
push(&symbol{Type: arithmeticOpType(pop(), pop())})
emit(int64(t.Pos), vm.Sub)
+ case lang.Index:
+ emit(int64(t.Pos), vm.Index)
+
case lang.Greater:
emit(int64(t.Pos), vm.Greater)
@@ -103,7 +106,7 @@ func (c *Compiler) Codegen(tokens Tokens) (err error) {
case lang.Assign:
st := tokens[i-1]
- if st.Id == lang.Period {
+ if st.Id == lang.Period || st.Id == lang.Index {
emit(int64(t.Pos), vm.Vassign)
break
}
diff --git a/parser/expr.go b/parser/expr.go
index c2d5eeb..fa8afa4 100644
--- a/parser/expr.go
+++ b/parser/expr.go
@@ -71,6 +71,10 @@ func (p *Parser) ParseExpr(in Tokens) (out Tokens, err error) {
}
}
ops = append(ops, scanner.Token{Str: "call", Id: lang.Call, Pos: t.Pos})
+ case lang.BracketBlock:
+ out = append(out, t)
+ vl++
+ ops = append(ops, scanner.Token{Str: "index", Id: lang.Index, Pos: t.Pos})
}
if len(selectors) > 0 {
out = append(out, selectors...)
diff --git a/parser/interpreter_test.go b/parser/interpreter_test.go
index 255f7c5..308474c 100644
--- a/parser/interpreter_test.go
+++ b/parser/interpreter_test.go
@@ -180,6 +180,14 @@ func TestConst(t *testing.T) {
})
}
+func TestArray(t *testing.T) {
+ run(t, []etest{
+ {src: "type T []int; var t T; t", res: "[]"},
+ {src: "type T [3]int; var t T; t", res: "[0 0 0]"},
+ {src: "type T [3]int; var t T; t[1] = 2; t", res: "[0 2 0]"},
+ })
+}
+
func TestStruct(t *testing.T) {
run(t, []etest{
{src: "type T struct {a string; b, c int}; var t T; t", res: "{ 0 0}"},
diff --git a/parser/type.go b/parser/type.go
index f1a2642..573ae6f 100644
--- a/parser/type.go
+++ b/parser/type.go
@@ -29,6 +29,28 @@ var (
// the corresponding runtime type or an error.
func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) {
switch in[0].Id {
+ case lang.BracketBlock:
+ typ, err := p.ParseTypeExpr(in[1:])
+ if err != nil {
+ return nil, err
+ }
+ if b := in[0].Block(); len(b) > 0 {
+ x, err := p.Scan(b, false)
+ if err != nil {
+ return nil, err
+ }
+ cval, _, err := p.evalConstExpr(x)
+ if err != nil {
+ return nil, err
+ }
+ size, ok := constValue(cval).(int)
+ if !ok {
+ return nil, fmt.Errorf("invalid size")
+ }
+ return reflect.ArrayOf(size, typ), nil
+ }
+ return reflect.SliceOf(typ), nil
+
case lang.Func:
// Get argument and return token positions depending on function pattern:
// method with receiver, named function or anonymous closure.
@@ -99,7 +121,6 @@ func (p *Parser) ParseTypeExpr(in Tokens) (typ reflect.Type, err error) {
default:
return nil, fmt.Errorf("%w: %v", TypeNotImplementedErr, in[0].Name())
}
- return typ, err
}
// parseParamTypes parses a list of comma separated typed parameters and returns a list of
@@ -143,7 +164,9 @@ 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()
- if typ.Kind() != reflect.Struct {
+ switch typ.Kind() {
+ case reflect.Struct, reflect.Array, reflect.Slice:
+ default:
zv = zv.(reflect.Value).Interface()
}
switch flag {
diff --git a/vm/vm.go b/vm/vm.go
index f6adf18..fa31ff0 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -28,6 +28,7 @@ const (
Field // s -- f ; f = s.FieldIndex($1, ...)
Greater // n1 n2 -- cond; cond = n1 > n2
Grow // -- ; sp += $1
+ Index // a i -- a[i] ;
Jump // -- ; ip += $1
JumpTrue // cond -- ; if cond { ip += $1 }
JumpFalse // cond -- ; if cond { ip += $1 }
@@ -59,6 +60,7 @@ var strop = [...]string{ // for VM tracing.
Field: "Field",
Greater: "Greater",
Grow: "Grow",
+ Index: "Index",
Jump: "Jump",
JumpTrue: "JumpTrue",
JumpFalse: "JumpFalse",
@@ -225,6 +227,9 @@ func (m *Machine) Run() (err error) {
mem = mem[:sp-1]
case Subi:
mem[sp-1] = mem[sp-1].(int) - int(op[2])
+ case Index:
+ mem[sp-2] = mem[sp-1].(reflect.Value).Index(mem[sp-2].(int))
+ mem = mem[:sp-1]
case Vassign:
mem[sp-1].(reflect.Value).Set(reflect.ValueOf(mem[sp-2]))
mem = mem[:sp-2]