mirror of
https://github.com/golang/go
synced 2024-11-24 22:00:09 -07:00
template: range over channel
R=golang-dev, dsymonds CC=golang-dev https://golang.org/cl/4951046
This commit is contained in:
parent
77f0bdce07
commit
361c5ace05
@ -196,23 +196,25 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
|
|||||||
val, _ := indirect(s.evalPipeline(dot, r.Pipe))
|
val, _ := indirect(s.evalPipeline(dot, r.Pipe))
|
||||||
// mark top of stack before any variables in the body are pushed.
|
// mark top of stack before any variables in the body are pushed.
|
||||||
mark := s.mark()
|
mark := s.mark()
|
||||||
|
oneIteration := func(index, elem reflect.Value) {
|
||||||
|
// Set top var (lexically the second if there are two) to the element.
|
||||||
|
if len(r.Pipe.Decl) > 0 {
|
||||||
|
s.setVar(1, elem)
|
||||||
|
}
|
||||||
|
// Set next var (lexically the first if there are two) to the index.
|
||||||
|
if len(r.Pipe.Decl) > 1 {
|
||||||
|
s.setVar(2, index)
|
||||||
|
}
|
||||||
|
s.walk(elem, r.List)
|
||||||
|
s.pop(mark)
|
||||||
|
}
|
||||||
switch val.Kind() {
|
switch val.Kind() {
|
||||||
case reflect.Array, reflect.Slice:
|
case reflect.Array, reflect.Slice:
|
||||||
if val.Len() == 0 {
|
if val.Len() == 0 {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for i := 0; i < val.Len(); i++ {
|
for i := 0; i < val.Len(); i++ {
|
||||||
elem := val.Index(i)
|
oneIteration(reflect.ValueOf(i), val.Index(i))
|
||||||
// Set top var (lexically the second if there are two) to the element.
|
|
||||||
if len(r.Pipe.Decl) > 0 {
|
|
||||||
s.setVar(1, elem)
|
|
||||||
}
|
|
||||||
// Set next var (lexically the first if there are two) to the index.
|
|
||||||
if len(r.Pipe.Decl) > 1 {
|
|
||||||
s.setVar(2, reflect.ValueOf(i))
|
|
||||||
}
|
|
||||||
s.walk(elem, r.List)
|
|
||||||
s.pop(mark)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
@ -220,17 +222,23 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
for _, key := range val.MapKeys() {
|
for _, key := range val.MapKeys() {
|
||||||
elem := val.MapIndex(key)
|
oneIteration(key, val.MapIndex(key))
|
||||||
// Set top var (lexically the second if there are two) to the element.
|
}
|
||||||
if len(r.Pipe.Decl) > 0 {
|
return
|
||||||
s.setVar(1, elem)
|
case reflect.Chan:
|
||||||
|
if val.IsNil() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i := 0
|
||||||
|
for ; ; i++ {
|
||||||
|
elem, ok := val.Recv()
|
||||||
|
if !ok {
|
||||||
|
break
|
||||||
}
|
}
|
||||||
// Set next var (lexically the first if there are two) to the key.
|
oneIteration(reflect.ValueOf(i), elem)
|
||||||
if len(r.Pipe.Decl) > 1 {
|
}
|
||||||
s.setVar(2, key)
|
if i == 0 {
|
||||||
}
|
break
|
||||||
s.walk(elem, r.List)
|
|
||||||
s.pop(mark)
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
case reflect.Invalid:
|
case reflect.Invalid:
|
||||||
|
@ -391,6 +391,8 @@ var execTests = []execTest{
|
|||||||
{"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
|
{"range $x $y MSIone", "{{range $x, $y := .MSIone}}<{{$x}}={{$y}}>{{end}}", "<one=1>", tVal, true},
|
||||||
{"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
|
{"range $x PSI", "{{range $x := .PSI}}<{{$x}}>{{end}}", "<21><22><23>", tVal, true},
|
||||||
{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
|
{"declare in range", "{{range $x := .PSI}}<{{$foo:=$x}}{{$x}}>{{end}}", "<21><22><23>", tVal, true},
|
||||||
|
{"range count", `{{range $i, $x := count 5}}[{{$i}}]{{$x}}{{end}}`, "[0]a[1]b[2]c[3]d[4]e", tVal, true},
|
||||||
|
{"range nil count", `{{range $i, $x := count 0}}{{else}}empty{{end}}`, "empty", tVal, true},
|
||||||
|
|
||||||
// Cute examples.
|
// Cute examples.
|
||||||
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
|
{"or as if true", `{{or .SI "slice is empty"}}`, "[3 4 5]", tVal, true},
|
||||||
@ -424,9 +426,29 @@ func oneArg(a string) string {
|
|||||||
return "oneArg=" + a
|
return "oneArg=" + a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// count returns a channel that will deliver n sequential 1-letter strings starting at "a"
|
||||||
|
func count(n int) chan string {
|
||||||
|
if n == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
c := make(chan string)
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
c <- "abcdefghijklmnop"[i : i+1]
|
||||||
|
}
|
||||||
|
close(c)
|
||||||
|
}()
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
func testExecute(execTests []execTest, set *Set, t *testing.T) {
|
func testExecute(execTests []execTest, set *Set, t *testing.T) {
|
||||||
b := new(bytes.Buffer)
|
b := new(bytes.Buffer)
|
||||||
funcs := FuncMap{"zeroArgs": zeroArgs, "oneArg": oneArg, "typeOf": typeOf}
|
funcs := FuncMap{
|
||||||
|
"count": count,
|
||||||
|
"oneArg": oneArg,
|
||||||
|
"typeOf": typeOf,
|
||||||
|
"zeroArgs": zeroArgs,
|
||||||
|
}
|
||||||
for _, test := range execTests {
|
for _, test := range execTests {
|
||||||
tmpl := New(test.name).Funcs(funcs)
|
tmpl := New(test.name).Funcs(funcs)
|
||||||
_, err := tmpl.ParseInSet(test.input, set)
|
_, err := tmpl.ParseInSet(test.input, set)
|
||||||
|
Loading…
Reference in New Issue
Block a user