diff options
| author | Marc Vertes <mvertes@free.fr> | 2023-11-20 11:00:51 +0100 |
|---|---|---|
| committer | Marc Vertes <mvertes@free.fr> | 2023-11-20 11:00:51 +0100 |
| commit | 001ca51323a1a54c9b3db377f0783c330666c480 (patch) | |
| tree | 7779e6b0c453f9f38bd5a24201011475f2b1f53a | |
| parent | ee21c324ce8c41b589e5a39e5715223ffd154315 (diff) | |
parser: add support for slices and arrays, parse index expressions
| -rw-r--r-- | lang/token.go | 1 | ||||
| -rw-r--r-- | parser/README.md | 4 | ||||
| -rw-r--r-- | parser/compiler.go | 5 | ||||
| -rw-r--r-- | parser/expr.go | 4 | ||||
| -rw-r--r-- | parser/interpreter_test.go | 8 | ||||
| -rw-r--r-- | parser/type.go | 27 | ||||
| -rw-r--r-- | vm/vm.go | 5 |
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 { @@ -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] |
