From ec1ee5f5b623486ed94d10e5186dab38343e1c33 Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Wed, 18 Sep 2019 23:32:04 +0200 Subject: [PATCH] fix: support array operations on array pointers --- _test/copy1.go | 14 ++++++++++++++ _test/ptr_array0.go | 13 +++++++++++++ _test/ptr_array1.go | 19 +++++++++++++++++++ _test/ptr_array2.go | 16 ++++++++++++++++ _test/ptr_array3.go | 11 +++++++++++ interp/cfg.go | 34 ++++++++++++++++++++++++++++++---- interp/run.go | 16 ++++++++-------- interp/value.go | 11 +++++++++++ 8 files changed, 122 insertions(+), 12 deletions(-) create mode 100644 _test/copy1.go create mode 100644 _test/ptr_array0.go create mode 100644 _test/ptr_array1.go create mode 100644 _test/ptr_array2.go create mode 100644 _test/ptr_array3.go diff --git a/_test/copy1.go b/_test/copy1.go new file mode 100644 index 00000000..2944c811 --- /dev/null +++ b/_test/copy1.go @@ -0,0 +1,14 @@ +package main + +import "fmt" + +func main() { + a := []int{10, 20, 30} + b := &[4]int{} + c := b[:] + copy(c, a) + fmt.Println(c) +} + +// Output: +// [10 20 30 0] diff --git a/_test/ptr_array0.go b/_test/ptr_array0.go new file mode 100644 index 00000000..fc324171 --- /dev/null +++ b/_test/ptr_array0.go @@ -0,0 +1,13 @@ +package main + +type T [2]int + +func F0(t *T) int { return t[0] } + +func main() { + t := &T{1, 2} + println(F0(t)) +} + +// Output: +// 1 diff --git a/_test/ptr_array1.go b/_test/ptr_array1.go new file mode 100644 index 00000000..f9bd5bf3 --- /dev/null +++ b/_test/ptr_array1.go @@ -0,0 +1,19 @@ +package main + +type T [3]int + +func F0(t *T) { + for i, v := range t { + println(i, v) + } +} + +func main() { + t := &T{1, 2, 3} + F0(t) +} + +// Output: +// 0 1 +// 1 2 +// 2 3 diff --git a/_test/ptr_array2.go b/_test/ptr_array2.go new file mode 100644 index 00000000..2e52621d --- /dev/null +++ b/_test/ptr_array2.go @@ -0,0 +1,16 @@ +package main + +import "fmt" + +type T [2]int + +func F1(t *T) { t[0] = 1 } + +func main() { + t := &T{} + F1(t) + fmt.Println(t) +} + +// Output: +// &[1 0] diff --git a/_test/ptr_array3.go b/_test/ptr_array3.go new file mode 100644 index 00000000..b65a317e --- /dev/null +++ b/_test/ptr_array3.go @@ -0,0 +1,11 @@ +package main + +import "fmt" + +func main() { + a := &[...]int{1, 2, 3} + fmt.Println(a[:]) +} + +// Output: +// [1 2 3] diff --git a/interp/cfg.go b/interp/cfg.go index 1a255778..26000488 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -86,6 +86,14 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { n.anc.gen = rangeMap ktyp = o.typ.key vtyp = o.typ.val + case ptrT: + ktyp = sc.getType("int") + vtyp = o.typ.val + if vtyp.cat == valueT { + vtyp = &itype{cat: valueT, rtype: vtyp.rtype.Elem()} + } else { + vtyp = vtyp.val + } case stringT: ktyp = sc.getType("int") vtyp = sc.getType("byte") @@ -569,20 +577,34 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { wireChild(n) t := n.child[0].typ switch t.cat { - case valueT: - n.typ = &itype{cat: valueT, rtype: t.rtype.Elem()} + case ptrT: + n.typ = t.val + if t.val.cat == valueT { + n.typ = &itype{cat: valueT, rtype: t.val.rtype.Elem()} + } else { + n.typ = t.val.val + } case stringT: n.typ = sc.getType("byte") + case valueT: + n.typ = &itype{cat: valueT, rtype: t.rtype.Elem()} default: n.typ = t.val } n.findex = sc.add(n.typ) n.recv = &receiver{node: n} - switch k := t.TypeOf().Kind(); k { + typ := t.TypeOf() + switch k := typ.Kind(); k { case reflect.Map: n.gen = getIndexMap case reflect.Array, reflect.Slice, reflect.String: n.gen = getIndexArray + case reflect.Ptr: + if typ2 := typ.Elem(); typ2.Kind() == reflect.Array { + n.gen = getIndexArray + } else { + err = n.cfgErrorf("type %v does not support indexing", typ) + } default: err = n.cfgErrorf("type is not an array, slice, string or map: %v", t.id()) } @@ -1253,7 +1275,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) { case sliceExpr: wireChild(n) - if ctyp := n.child[0].typ; ctyp.size != 0 { + ctyp := n.child[0].typ + if ctyp.cat == ptrT { + ctyp = ctyp.val + } + if ctyp.size != 0 { // Create a slice type from an array type n.typ = &itype{} *n.typ = *ctyp diff --git a/interp/run.go b/interp/run.go index df027bdf..9a81f619 100644 --- a/interp/run.go +++ b/interp/run.go @@ -887,7 +887,7 @@ func getIndexBinPtrMethod(n *node) { // getIndexArray returns array value from index func getIndexArray(n *node) { tnext := getExec(n.tnext) - value0 := genValue(n.child[0]) // array + value0 := genValueArray(n.child[0]) // array if n.child[1].rval.IsValid() { // constant array index ai := int(vInt(n.child[1].rval)) @@ -1505,8 +1505,8 @@ func _range(n *node) { tnext := getExec(n.tnext) if len(n.child) == 4 { - index1 := n.child[1].findex // array value location in frame - value := genValue(n.child[2]) // array + index1 := n.child[1].findex // array value location in frame + value := genValueArray(n.child[2]) // array n.exec = func(f *frame) bltn { a := value(f) v0 := f.data[index0] @@ -1519,7 +1519,7 @@ func _range(n *node) { return tnext } } else { - value := genValue(n.child[1]) // array + value := genValueArray(n.child[1]) // array n.exec = func(f *frame) bltn { a := value(f) v0 := f.data[index0] @@ -1780,7 +1780,7 @@ func _cap(n *node) { func _copy(n *node) { dest := genValue(n) - value0 := genValue(n.child[1]) + value0 := genValueArray(n.child[1]) value1 := genValue(n.child[2]) next := getExec(n.tnext) @@ -2109,8 +2109,8 @@ func _select(n *node) { func slice(n *node) { i := n.findex next := getExec(n.tnext) - value0 := genValue(n.child[0]) // array - value1 := genValue(n.child[1]) // low (if 2 or 3 args) or high (if 1 arg) + value0 := genValueArray(n.child[0]) // array + value1 := genValue(n.child[1]) // low (if 2 or 3 args) or high (if 1 arg) switch len(n.child) { case 2: @@ -2143,7 +2143,7 @@ func slice(n *node) { func slice0(n *node) { i := n.findex next := getExec(n.tnext) - value0 := genValue(n.child[0]) + value0 := genValueArray(n.child[0]) switch len(n.child) { case 1: diff --git a/interp/value.go b/interp/value.go index 88a72294..72fae603 100644 --- a/interp/value.go +++ b/interp/value.go @@ -107,6 +107,17 @@ func genValue(n *node) func(*frame) reflect.Value { } } +func genValueArray(n *node) func(*frame) reflect.Value { + value := genValue(n) + // dereference array pointer, to support array operations on array pointer + if n.typ.TypeOf().Kind() == reflect.Ptr { + return func(f *frame) reflect.Value { + return value(f).Elem() + } + } + return value +} + func genValueInterfacePtr(n *node) func(*frame) reflect.Value { value := genValue(n) it := reflect.TypeOf((*interface{})(nil)).Elem()