coroc: support for range loops over strings
chriso opened this issue · comments
Chris O'Hara commented
The desugaring pass should be updated to desugar for range loops over strings:
var s string
for range string { ... }
for index := range string { ... }
for index, rune := range string { ... }
At first glance it should simply be a matter of adding *types.Basic
(with .Kind() == types.String
) to the case where we handle *types.Array
and *types.Slice
here, however range loops are a bit different when strings are involved. When indexing a string you get back a byte
. When using a for range loop with a string you get a rune
along with an index representing its offset in the string. More info in https://go.dev/blog/strings.
The desugaring pass should use utf.DecodeRuneInString
to parse runes from strings iteratively.
Chris O'Hara commented
Test case:
diff --git i/compiler/coroutine_test.go w/compiler/coroutine_test.go
index 85fa53b..ca9be36 100644
--- i/compiler/coroutine_test.go
+++ w/compiler/coroutine_test.go
@@ -243,6 +243,16 @@ func TestCoroutineYield(t *testing.T) {
coro: func() { IdentityGenericStructClosureInt(11) },
yields: []int{11, 100, 23, 12, 101, 45},
},
+
+ {
+ name: "range over string",
+ coro: func() { RangeOverString("foo") },
+ yields: []int{
+ 0, 0, 0,
+ 0, 1, 2,
+ 0, 'f', 1, 'o', 2, 'o',
+ },
+ },
}
// This emulates the installation of function type information by the
diff --git i/compiler/testdata/coroutine.go w/compiler/testdata/coroutine.go
index 36b42ff..1a11938 100644
--- i/compiler/testdata/coroutine.go
+++ w/compiler/testdata/coroutine.go
@@ -636,3 +636,16 @@ func IdentityGenericStructClosureInt(n int) {
fn(23)
fn(45)
}
+
+func RangeOverString(s string) {
+ for range s {
+ coroutine.Yield[int, any](0)
+ }
+ for i := range s {
+ coroutine.Yield[int, any](i)
+ }
+ for i, c := range s {
+ coroutine.Yield[int, any](i)
+ coroutine.Yield[int, any](int(c))
+ }
+}