summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--comp/compiler.go4
-rw-r--r--interp/interpreter_test.go8
-rw-r--r--parser/README.md6
-rw-r--r--parser/expr.go14
-rw-r--r--parser/type.go18
-rw-r--r--vm/op_string.go39
-rw-r--r--vm/type.go22
-rw-r--r--vm/vm.go11
8 files changed, 89 insertions, 33 deletions
diff --git a/comp/compiler.go b/comp/compiler.go
index 5d55be4..47c4a88 100644
--- a/comp/compiler.go
+++ b/comp/compiler.go
@@ -188,6 +188,8 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) {
if v := ks.Value.Value; v.CanInt() {
emit(t, vm.IndexSet)
}
+ case reflect.Map:
+ emit(t, vm.MapSet)
}
case symbol.Unset:
j := top().Type.FieldIndex(ks.Name)
@@ -260,7 +262,7 @@ func (c *Compiler) Generate(tokens parser.Tokens) (err error) {
if s.Type.Rtype.Kind() == reflect.Slice {
emit(t, vm.Fnew, s.Index, s.SliceLen)
} else {
- emit(t, vm.Fnew, s.Index)
+ emit(t, vm.Fnew, s.Index, 1)
}
} else {
emit(t, vm.Dup, s.Index)
diff --git a/interp/interpreter_test.go b/interp/interpreter_test.go
index c7c3cbc..6c92102 100644
--- a/interp/interpreter_test.go
+++ b/interp/interpreter_test.go
@@ -217,6 +217,12 @@ func TestStruct(t *testing.T) {
})
}
+func TestMap(t *testing.T) {
+ run(t, []etest{
+ {src: `type M map[string]bool; var m M; m`, res: `map[]`}, // #00
+ })
+}
+
func TestType(t *testing.T) {
src0 := `type (
I int
@@ -271,5 +277,7 @@ func TestComposite(t *testing.T) {
{src: `type T struct{N int; S string}; t := T{S: "foo"}; t`, res: `{0 foo}`}, // #05
{src: `a := []int{}`, res: `[]`}, // #06
{src: `a := []int{1, 2, 3}; a`, res: `[1 2 3]`}, // #07
+ {src: `m := map[string]bool{}`, res: `map[]`}, // #08
+ {src: `m := map[string]bool{"hello": true}; m`, res: `map[hello:true]`}, // #09
})
}
diff --git a/parser/README.md b/parser/README.md
index ba2f15c..9f40e77 100644
--- a/parser/README.md
+++ b/parser/README.md
@@ -39,14 +39,14 @@ Go language support:
- [ ] complete numeric types
- [x] function types
- [ ] variadic functions
-- [ ] pointers
+- [x] pointers
- [x] structures
- [ ] embedded structures
- [ ] recursive structures
-- [ ] literal composite objects
+- [x] literal composite objects
- [ ] interfaces
- [x] arrays, slices
-- [ ] maps
+- [x] maps
- [ ] deterministic maps
- [ ] channel types
- [ ] channel operations
diff --git a/parser/expr.go b/parser/expr.go
index e00113f..0a87999 100644
--- a/parser/expr.go
+++ b/parser/expr.go
@@ -155,12 +155,22 @@ func (p *Parser) parseExpr(in Tokens, typeStr string) (out Tokens, err error) {
typeStr = typ.String()
p.Symbols.Add(symbol.UnsetAddr, typ.String(), vm.NewValue(typ), symbol.Type, typ, p.funcScope != "")
out = append(out, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: typeStr})
- i++
+ i++ // FIXME: number of tokens to skip should be computed from type parsing.
+
+ case lang.Map:
+ typ, err := p.parseTypeExpr(in[i:])
+ if err != nil {
+ return out, err
+ }
+ typeStr = typ.String()
+ p.Symbols.Add(symbol.UnsetAddr, typ.String(), vm.NewValue(typ), symbol.Type, typ, p.funcScope != "")
+ out = append(out, scanner.Token{Tok: lang.Ident, Pos: t.Pos, Str: typeStr})
+ i += 2 // FIXME: number of tokens to skip should be computed from type parsing.
case lang.Comment:
default:
- log.Println("unxexpected token:", t)
+ log.Println("unexpected token:", t)
}
}
for len(ops) > 0 {
diff --git a/parser/type.go b/parser/type.go
index 70ed4d1..5e8df02 100644
--- a/parser/type.go
+++ b/parser/type.go
@@ -127,6 +127,24 @@ func (p *Parser) parseTypeExpr(in Tokens) (typ *vm.Type, err error) {
}
return vm.StructOf(fields), nil
+ case lang.Map:
+ if len(in) < 3 || in[1].Tok != lang.BracketBlock {
+ return nil, fmt.Errorf("%w: %s", ErrInvalidType, in[0].Str)
+ }
+ kin, err := p.Scan(in[1].Block(), false)
+ if err != nil {
+ return nil, err
+ }
+ ktyp, err := p.parseTypeExpr(kin) // Key type
+ if err != nil {
+ return nil, err
+ }
+ etyp, err := p.parseTypeExpr(in[2:]) // Element type
+ if err != nil {
+ return nil, err
+ }
+ return vm.MapOf(ktyp, etyp), nil
+
default:
return nil, fmt.Errorf("%w: %v", ErrNotImplemented, in[0].Name())
}
diff --git a/vm/op_string.go b/vm/op_string.go
index a39dcfa..e5a00b6 100644
--- a/vm/op_string.go
+++ b/vm/op_string.go
@@ -31,28 +31,29 @@ func _() {
_ = x[Grow-20]
_ = x[Index-21]
_ = x[IndexSet-22]
- _ = x[Jump-23]
- _ = x[JumpTrue-24]
- _ = x[JumpFalse-25]
- _ = x[JumpSetTrue-26]
- _ = x[JumpSetFalse-27]
- _ = x[Lower-28]
- _ = x[Loweri-29]
- _ = x[Mul-30]
- _ = x[New-31]
- _ = x[Negate-32]
- _ = x[Not-33]
- _ = x[Pop-34]
- _ = x[Push-35]
- _ = x[Return-36]
- _ = x[Sub-37]
- _ = x[Subi-38]
- _ = x[Swap-39]
+ _ = x[MapSet-23]
+ _ = x[Jump-24]
+ _ = x[JumpTrue-25]
+ _ = x[JumpFalse-26]
+ _ = x[JumpSetTrue-27]
+ _ = x[JumpSetFalse-28]
+ _ = x[Lower-29]
+ _ = x[Loweri-30]
+ _ = x[Mul-31]
+ _ = x[New-32]
+ _ = x[Negate-33]
+ _ = x[Not-34]
+ _ = x[Pop-35]
+ _ = x[Push-36]
+ _ = x[Return-37]
+ _ = x[Sub-38]
+ _ = x[Subi-39]
+ _ = x[Swap-40]
}
-const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupFnewEqualEqualSetExitFieldFieldSetFieldFsetGreaterGrowIndexIndexSetJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNegateNotPopPushReturnSubSubiSwap"
+const _Op_name = "NopAddAddrAssignFassignVassignCallCalliCallXDerefDupFdupFnewEqualEqualSetExitFieldFieldSetFieldFsetGreaterGrowIndexIndexSetMapSetJumpJumpTrueJumpFalseJumpSetTrueJumpSetFalseLowerLoweriMulNewNegateNotPopPushReturnSubSubiSwap"
-var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 60, 65, 73, 77, 82, 90, 99, 106, 110, 115, 123, 127, 135, 144, 155, 167, 172, 178, 181, 184, 190, 193, 196, 200, 206, 209, 213, 217}
+var _Op_index = [...]uint8{0, 3, 6, 10, 16, 23, 30, 34, 39, 44, 49, 52, 56, 60, 65, 73, 77, 82, 90, 99, 106, 110, 115, 123, 129, 133, 141, 150, 161, 173, 178, 184, 187, 190, 196, 199, 202, 206, 212, 215, 219, 223}
func (i Op) String() string {
idx := int(i) - 0
diff --git a/vm/type.go b/vm/type.go
index 3a8d901..88e3dc0 100644
--- a/vm/type.go
+++ b/vm/type.go
@@ -38,8 +38,21 @@ type Value struct {
}
// NewValue returns an addressable zero value for the specified type.
-func NewValue(typ *Type) Value {
- if typ.Rtype.Kind() == reflect.Func {
+func NewValue(typ *Type, arg ...int) Value {
+ switch typ.Rtype.Kind() {
+ case reflect.Slice:
+ if len(arg) == 1 {
+ v := reflect.New(typ.Rtype).Elem()
+ v.Set(reflect.MakeSlice(typ.Rtype, arg[0], arg[0]))
+ return Value{Type: typ, Value: v}
+ }
+ case reflect.Map:
+ if len(arg) == 1 {
+ v := reflect.New(typ.Rtype).Elem()
+ v.Set(reflect.MakeMapWithSize(typ.Rtype, arg[0]))
+ return Value{Type: typ, Value: v}
+ }
+ case reflect.Func:
typ = TypeOf(0) // Function value is its index in the code segment.
}
return Value{Type: typ, Value: reflect.New(typ.Rtype).Elem()}
@@ -71,6 +84,11 @@ func SliceOf(t *Type) *Type {
return &Type{Rtype: reflect.SliceOf(t.Rtype)}
}
+// MapOf returns the map type with the given key and element types.
+func MapOf(k, e *Type) *Type {
+ return &Type{Rtype: reflect.MapOf(k.Rtype, e.Rtype)}
+}
+
// FuncOf returns the function type with the given argument and result types.
func FuncOf(arg, ret []*Type, variadic bool) *Type {
a := make([]reflect.Type, len(arg))
diff --git a/vm/vm.go b/vm/vm.go
index b5c6cf5..709b459 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -42,6 +42,7 @@ const (
Grow // -- ; sp += $1
Index // a i -- a[i] ;
IndexSet // a i v -- a; a[i] = v
+ MapSet // a i v -- a; a[i] = v
Jump // -- ; ip += $1
JumpTrue // cond -- ; if cond { ip += $1 }
JumpFalse // cond -- ; if cond { ip += $1 }
@@ -170,11 +171,7 @@ func (m *Machine) Run() (err error) {
case Fdup:
mem = append(mem, mem[c.Arg[0]+fp-1])
case Fnew:
- mem = append(mem, NewValue(mem[c.Arg[0]].Type))
- if len(c.Arg) > 1 {
- mem[len(mem)-1].Grow(c.Arg[1])
- mem[len(mem)-1].SetLen(c.Arg[1])
- }
+ mem = append(mem, NewValue(mem[c.Arg[0]].Type, c.Arg[1:]...))
case Field:
fv := mem[sp-1].FieldByIndex(c.Arg)
if !fv.CanSet() {
@@ -268,9 +265,11 @@ func (m *Machine) Run() (err error) {
mem[sp-2].Value = mem[sp-2].Index(int(mem[sp-1].Int()))
mem = mem[:sp-1]
case IndexSet:
- log.Println("## IndexSet:", sp-3, mem[sp-3].Type)
mem[sp-3].Value.Index(int(mem[sp-2].Int())).Set(mem[sp-1].Value)
mem = mem[:sp-2]
+ case MapSet:
+ mem[sp-3].SetMapIndex(mem[sp-2].Value, mem[sp-1].Value)
+ mem = mem[:sp-2]
case Vassign:
mem[sp-2].Set(mem[sp-1].Value)
mem = mem[:sp-2]