Skip to content

Commit

Permalink
interp: fix range expression handling
Browse files Browse the repository at this point in the history
  • Loading branch information
kortschak authored and traefiker committed Sep 30, 2019
1 parent 2c2b471 commit bb2921b
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 6 deletions.
14 changes: 14 additions & 0 deletions _test/range0.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "fmt"

func main() {
v := []int{1, 2, 3}
for i := range v {
v = append(v, i)
}
fmt.Println(v)
}

// Output:
// [1 2 3 0 1 2]
14 changes: 14 additions & 0 deletions _test/range1.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "fmt"

func main() {
a := [...]int{2, 1, 0}
for _, v := range a {
a[v] = v
}
fmt.Println(a)
}

// Output:
// [0 1 2]
14 changes: 14 additions & 0 deletions _test/range2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package main

import "fmt"

func main() {
a := [...]int{2, 1, 0}
for _, v := range &a {
a[v] = v
}
fmt.Println(a)
}

// Output:
// [2 1 2]
4 changes: 4 additions & 0 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
ktyp = &itype{cat: valueT, rtype: typ.Key()}
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
case reflect.String:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case reflect.Array, reflect.Slice:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = &itype{cat: valueT, rtype: typ.Elem()}
}
Expand All @@ -96,9 +98,11 @@ func (interp *Interpreter) cfg(root *node) ([]*node, error) {
vtyp = vtyp.val
}
case stringT:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = sc.getType("rune")
case arrayT, variadicT:
sc.add(sc.getType("int")) // Add a dummy type to store array shallow copy for range
ktyp = sc.getType("int")
vtyp = o.typ.val
}
Expand Down
13 changes: 7 additions & 6 deletions interp/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -1534,6 +1534,7 @@ var rat = reflect.ValueOf((*[]rune)(nil)).Type().Elem() // runes array type

func _range(n *node) {
index0 := n.child[0].findex // array index location in frame
index2 := index0 - 1 // shallow array for range, always just behind index0
fnext := getExec(n.fnext)
tnext := getExec(n.tnext)

Expand All @@ -1544,10 +1545,10 @@ func _range(n *node) {
if isString(an.typ.TypeOf()) {
value = genValueAs(an, rat) // range on string iterates over runes
} else {
value = genValueArray(an)
value = genValueRangeArray(an)
}
n.exec = func(f *frame) bltn {
a := value(f)
a := f.data[index2]
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
i := int(v0.Int())
Expand All @@ -1562,13 +1563,12 @@ func _range(n *node) {
if isString(an.typ.TypeOf()) {
value = genValueAs(an, rat) // range on string iterates over runes
} else {
value = genValueArray(an)
value = genValueRangeArray(an)
}
n.exec = func(f *frame) bltn {
a := value(f)
v0 := f.data[index0]
v0.SetInt(v0.Int() + 1)
if int(v0.Int()) >= a.Len() {
if int(v0.Int()) >= f.data[index2].Len() {
return fnext
}
return tnext
Expand All @@ -1578,7 +1578,8 @@ func _range(n *node) {
// Init sequence
next := n.exec
n.child[0].exec = func(f *frame) bltn {
f.data[index0].SetInt(-1)
f.data[index2] = value(f) // set array shallow copy for range
f.data[index0].SetInt(-1) // assing index value
return next
}
}
Expand Down
16 changes: 16 additions & 0 deletions interp/value.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,22 @@ func genValueArray(n *node) func(*frame) reflect.Value {
return value
}

func genValueRangeArray(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 func(f *frame) reflect.Value {
// This is necessary to prevent changes in the returned
// reflect.Value being reflected back to the value used
// for the range expression.
return reflect.ValueOf(value(f).Interface())
}
}

func genValueInterfacePtr(n *node) func(*frame) reflect.Value {
value := genValue(n)
it := reflect.TypeOf((*interface{})(nil)).Elem()
Expand Down

0 comments on commit bb2921b

Please sign in to comment.