]> Cypherpunks repositories - gostls13.git/commitdiff
text/template: support range-over-int
authorqiulaidongfeng <2645477756@qq.com>
Wed, 25 Sep 2024 12:20:06 +0000 (20:20 +0800)
committerGopher Robot <gobot@golang.org>
Thu, 26 Sep 2024 20:17:24 +0000 (20:17 +0000)
Fixes #66107

Change-Id: I19b466e3fb17557cf4f198b7fd8c13e774d854b1
Reviewed-on: https://go-review.googlesource.com/c/go/+/615095
Auto-Submit: Ian Lance Taylor <iant@golang.org>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
Commit-Queue: Ian Lance Taylor <iant@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
doc/next/6-stdlib/99-minor/text/template/66107.md
src/text/template/doc.go
src/text/template/exec.go
src/text/template/exec_test.go

index 109c96e0214649be919185d243a30aff439682c6..03e1a1f21c8878c1d638458e9b2c11ea6813e9dc 100644 (file)
@@ -1 +1 @@
-Templates now support range-over-func.
+Templates now support range-over-func and range-over-int.
index 847f96b72508f3cf9760cea14f507881033879bb..7b63bb76ae4c5d0fa99a72490416d38fbdf730cd 100644 (file)
@@ -99,7 +99,7 @@ data, defined in detail in the corresponding sections that follow.
 
        {{range pipeline}} T1 {{end}}
                The value of the pipeline must be an array, slice, map, iter.Seq,
-               iter.Seq2 or channel.
+               iter.Seq2, integer or channel.
                If the value of the pipeline has length zero, nothing is output;
                otherwise, dot is set to the successive elements of the array,
                slice, or map and T1 is executed. If the value is a map and the
@@ -108,7 +108,7 @@ data, defined in detail in the corresponding sections that follow.
 
        {{range pipeline}} T1 {{else}} T0 {{end}}
                The value of the pipeline must be an array, slice, map, iter.Seq,
-               iter.Seq2 or channel.
+               iter.Seq2, integer or channel.
                If the value of the pipeline has length zero, dot is unaffected and
                T0 is executed; otherwise, dot is set to the successive elements
                of the array, slice, or map and T1 is executed.
index 96d2f50ef87ffc3c7c6ef942cf5a1d9a2d3011a4..a70d383566d726bdcd57cd6ba96840f2af21ab8b 100644 (file)
@@ -395,6 +395,22 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
                s.walk(elem, r.List)
        }
        switch val.Kind() {
+       case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+               reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
+               if len(r.Pipe.Decl) > 1 {
+                       s.errorf("can't use %s to iterate over more than one variable", val)
+                       break
+               }
+               run := false
+               for v := range val.Seq() {
+                       run = true
+                       // Pass element as second value, as we do for channels.
+                       oneIteration(reflect.Value{}, v)
+               }
+               if !run {
+                       break
+               }
+               return
        case reflect.Array, reflect.Slice:
                if val.Len() == 0 {
                        break
index b84e278c12bd2e070d339951289c7520a63ebbcc..cca53f4d72302ccfa39ac788e0f18359a1e78bdc 100644 (file)
@@ -613,6 +613,19 @@ var execTests = []execTest{
        {"i,x range iter.Seq[int]", `{{$i := 0}}{{$x := 0}}{{range $i = .}}{{$i}}{{end}}`, "01", fVal1(2), true},
        {"range iter.Seq[int] else", `{{range $i := .}}{{$i}}{{else}}empty{{end}}`, "empty", fVal1(0), true},
        {"range iter.Seq2[int,int] else", `{{range $i := .}}{{$i}}{{else}}empty{{end}}`, "empty", fVal2(0), true},
+       {"range int8", rangeTestInt, rangeTestData[int8](), int8(5), true},
+       {"range int16", rangeTestInt, rangeTestData[int16](), int16(5), true},
+       {"range int32", rangeTestInt, rangeTestData[int32](), int32(5), true},
+       {"range int64", rangeTestInt, rangeTestData[int64](), int64(5), true},
+       {"range int", rangeTestInt, rangeTestData[int](), int(5), true},
+       {"range uint8", rangeTestInt, rangeTestData[uint8](), uint8(5), true},
+       {"range uint16", rangeTestInt, rangeTestData[uint16](), uint16(5), true},
+       {"range uint32", rangeTestInt, rangeTestData[uint32](), uint32(5), true},
+       {"range uint64", rangeTestInt, rangeTestData[uint64](), uint64(5), true},
+       {"range uint", rangeTestInt, rangeTestData[uint](), uint(5), true},
+       {"range uintptr", rangeTestInt, rangeTestData[uintptr](), uintptr(5), true},
+       {"range uintptr(0)", `{{range $v := .}}{{print $v}}{{else}}empty{{end}}`, "empty", uintptr(0), true},
+       {"range 5", `{{range $v := 5}}{{printf "%T%d" $v $v}}{{end}}`, rangeTestData[int](), nil, true},
 
        // Cute examples.
        {"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
@@ -737,6 +750,17 @@ func fVal2(i int) iter.Seq2[int, int] {
        }
 }
 
+const rangeTestInt = `{{range $v := .}}{{printf "%T%d" $v $v}}{{end}}`
+
+func rangeTestData[T int | int8 | int16 | int32 | int64 | uint | uint8 | uint16 | uint32 | uint64 | uintptr]() string {
+       I := T(5)
+       var buf strings.Builder
+       for i := T(0); i < I; i++ {
+               fmt.Fprintf(&buf, "%T%d", i, i)
+       }
+       return buf.String()
+}
+
 func zeroArgs() string {
        return "zeroArgs"
 }