Skip to content

Commit fcb7d02

Browse files
text/template: support range-over-func
Fixes #66107 Change-Id: If3e503efca200aa86463c9d27d06986b03c0d638
1 parent ad77cef commit fcb7d02

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

src/text/template/exec.go

+33
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,25 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
394394
}()
395395
s.walk(elem, r.List)
396396
}
397+
398+
rangeone := func(elem reflect.Value) {
399+
if len(r.Pipe.Decl) > 0 {
400+
s.setVar(r.Pipe.Decl[0].Ident[0], elem)
401+
}
402+
if len(r.Pipe.Decl) > 1 {
403+
s.errorf("can't use %v iterate over two variables", val)
404+
return
405+
}
406+
defer s.pop(mark)
407+
defer func() {
408+
// Consume panic(walkContinue)
409+
if r := recover(); r != nil && r != walkContinue {
410+
panic(r)
411+
}
412+
}()
413+
s.walk(elem, r.List)
414+
}
415+
397416
switch val.Kind() {
398417
case reflect.Array, reflect.Slice:
399418
if val.Len() == 0 {
@@ -434,6 +453,20 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
434453
return
435454
case reflect.Invalid:
436455
break // An invalid value is likely a nil map, etc. and acts like an empty map.
456+
case reflect.Func:
457+
if val.Type().CanSeq() {
458+
for v := range val.Seq() {
459+
rangeone(v)
460+
}
461+
return
462+
}
463+
if val.Type().CanSeq2() {
464+
for i, v := range val.Seq2() {
465+
oneIteration(reflect.ValueOf(i), v)
466+
}
467+
return
468+
}
469+
fallthrough
437470
default:
438471
s.errorf("range can't iterate over %v", val)
439472
}

src/text/template/exec_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,27 @@ var execTests = []execTest{
601601
{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
602602
{"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
603603
{"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
604+
{"range iter.Seq[int]", `{{range $i := .}}{{$i}}{{end}}`, "01", func(yield func(int) bool) {
605+
for i := range 2 {
606+
if !yield(i) {
607+
break
608+
}
609+
}
610+
}, true},
611+
{"range iter.Seq[int]", `{{range $i, $c := .}}{{$c}}{{end}}`, "", func(yield func(int) bool) {
612+
for i := range 2 {
613+
if !yield(i) {
614+
break
615+
}
616+
}
617+
}, false},
618+
{"range iter.Seq[int,int]", `{{range $i, $c := .}}{{$i}}{{$c}}{{end}}`, "0112", func(yield func(int, int) bool) {
619+
for i := range 2 {
620+
if !yield(i, i+1) {
621+
break
622+
}
623+
}
624+
}, true},
604625

605626
// Cute examples.
606627
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},

0 commit comments

Comments
 (0)