mirror of
https://github.com/golang/go
synced 2024-11-22 08:34:40 -07:00
template/parse: add a Walk method to Tree.
R=golang-dev, dsymonds, r CC=golang-dev, mikesamuel https://golang.org/cl/4918041
This commit is contained in:
parent
fd80efee10
commit
82189f654d
@ -10,5 +10,6 @@ GOFILES=\
|
|||||||
node.go\
|
node.go\
|
||||||
parse.go\
|
parse.go\
|
||||||
set.go\
|
set.go\
|
||||||
|
walk.go\
|
||||||
|
|
||||||
include ../../../Make.pkg
|
include ../../../Make.pkg
|
||||||
|
@ -7,6 +7,7 @@ package parse
|
|||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -257,3 +258,129 @@ func TestParse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func before(n Node) string {
|
||||||
|
t := ""
|
||||||
|
switch n := n.(type) {
|
||||||
|
case nil:
|
||||||
|
t = "<nil>"
|
||||||
|
case *ActionNode:
|
||||||
|
t = "("
|
||||||
|
case *BoolNode:
|
||||||
|
t = fmt.Sprintf("(%t)", n.True)
|
||||||
|
case *CommandNode:
|
||||||
|
t = "<"
|
||||||
|
case *DotNode:
|
||||||
|
t = "."
|
||||||
|
case *FieldNode:
|
||||||
|
t = "F"
|
||||||
|
case *IdentifierNode:
|
||||||
|
t = fmt.Sprintf("(%s)", n.Ident)
|
||||||
|
case *IfNode:
|
||||||
|
t = "if{"
|
||||||
|
case *ListNode:
|
||||||
|
t = "["
|
||||||
|
case *NumberNode:
|
||||||
|
t = fmt.Sprintf("(%s)", n.Text)
|
||||||
|
case *PipeNode:
|
||||||
|
t = "{"
|
||||||
|
case *RangeNode:
|
||||||
|
t = "range{"
|
||||||
|
case *StringNode:
|
||||||
|
t = fmt.Sprintf("(%q)", n.Text)
|
||||||
|
case *TemplateNode:
|
||||||
|
t = fmt.Sprintf("{template %q", n.Name)
|
||||||
|
case *TextNode:
|
||||||
|
t = fmt.Sprintf("%q", n.Text)
|
||||||
|
case *VariableNode:
|
||||||
|
t = fmt.Sprintf("%q", n.Ident)
|
||||||
|
case *WithNode:
|
||||||
|
t = "with{"
|
||||||
|
default:
|
||||||
|
t = "???"
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func after(n Node) string {
|
||||||
|
t := ""
|
||||||
|
switch n := n.(type) {
|
||||||
|
case nil:
|
||||||
|
t = "<nil>"
|
||||||
|
case *ActionNode:
|
||||||
|
t = ")"
|
||||||
|
case *BoolNode:
|
||||||
|
case *CommandNode:
|
||||||
|
t = ">"
|
||||||
|
case *DotNode:
|
||||||
|
case *FieldNode:
|
||||||
|
case *IdentifierNode:
|
||||||
|
case *IfNode:
|
||||||
|
t = "}"
|
||||||
|
case *ListNode:
|
||||||
|
t = "]"
|
||||||
|
case *NumberNode:
|
||||||
|
case *PipeNode:
|
||||||
|
t = "}"
|
||||||
|
case *RangeNode:
|
||||||
|
t = "}"
|
||||||
|
case *StringNode:
|
||||||
|
case *TemplateNode:
|
||||||
|
t = "}"
|
||||||
|
case *TextNode:
|
||||||
|
case *VariableNode:
|
||||||
|
case *WithNode:
|
||||||
|
t = "}"
|
||||||
|
default:
|
||||||
|
t = "???"
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
// A silly template with lots of pieces to test walking using the before and after functions.
|
||||||
|
const walkText = `
|
||||||
|
{{range $u, $v := 3}}
|
||||||
|
{{if .}}
|
||||||
|
{{printf "hi" 3 true 1.2i $u }}
|
||||||
|
{{end}}
|
||||||
|
{{else}}
|
||||||
|
{{with .}}
|
||||||
|
{{printf $ | printf}}
|
||||||
|
{{else}}
|
||||||
|
{{template "x"}}
|
||||||
|
{{end}}
|
||||||
|
{{end}}`
|
||||||
|
|
||||||
|
const walkResult = `
|
||||||
|
["\n"range{
|
||||||
|
{["$u"]["$v"]<(3)>}
|
||||||
|
["\n\t"if{
|
||||||
|
{<.>}
|
||||||
|
["\n\t"({<(printf)("hi")(3)(true)(1.2i)["$u"]>})"\n\t"]
|
||||||
|
}"\n"]
|
||||||
|
["\n\t"with{
|
||||||
|
{<.>}
|
||||||
|
["\n\t"({<(printf)["$"]><(printf)>})"\n\t"]
|
||||||
|
["\n\t"{template "x"}"\n\t"]
|
||||||
|
}"\n"]}
|
||||||
|
]`
|
||||||
|
|
||||||
|
// Use before and after to walk the template and generate a messy but complete print of the template.
|
||||||
|
func TestWalk(t *testing.T) {
|
||||||
|
tree, err := New("walk").Parse(walkText, builtins)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
s := ""
|
||||||
|
tree.Walk(func(n Node) { s += before(n) }, func(n Node) { s += after(n) })
|
||||||
|
stripSpace := func(r int) int {
|
||||||
|
if r == '\t' || r == '\n' {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
expect := strings.Map(stripSpace, walkResult)
|
||||||
|
if s != expect {
|
||||||
|
t.Fatalf("expected\n\t%s\ngot\n\t%s", expect, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
89
src/pkg/template/parse/walk.go
Normal file
89
src/pkg/template/parse/walk.go
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package parse
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
// Walk walks the parse tree, calling before for each node, then
|
||||||
|
// recurring for any non-nil child nodes that node may have, and
|
||||||
|
// then calling after. The before and after functions can be nil.
|
||||||
|
func (t *Tree) Walk(before, after func(n Node)) {
|
||||||
|
walk(t.Root, before, after)
|
||||||
|
}
|
||||||
|
|
||||||
|
func walk(n Node, before, after func(n Node)) {
|
||||||
|
if before != nil {
|
||||||
|
before(n)
|
||||||
|
}
|
||||||
|
switch n := n.(type) {
|
||||||
|
case nil:
|
||||||
|
case *ActionNode:
|
||||||
|
if n.Pipe != nil {
|
||||||
|
walk(n.Pipe, before, after)
|
||||||
|
}
|
||||||
|
case *BoolNode:
|
||||||
|
case *CommandNode:
|
||||||
|
for _, arg := range n.Args {
|
||||||
|
walk(arg, before, after)
|
||||||
|
}
|
||||||
|
case *DotNode:
|
||||||
|
case *FieldNode:
|
||||||
|
case *IdentifierNode:
|
||||||
|
case *IfNode:
|
||||||
|
if n.Pipe != nil {
|
||||||
|
walk(n.Pipe, before, after)
|
||||||
|
}
|
||||||
|
if n.List != nil {
|
||||||
|
walk(n.List, before, after)
|
||||||
|
}
|
||||||
|
if n.ElseList != nil {
|
||||||
|
walk(n.ElseList, before, after)
|
||||||
|
}
|
||||||
|
case *ListNode:
|
||||||
|
for _, node := range n.Nodes {
|
||||||
|
walk(node, before, after)
|
||||||
|
}
|
||||||
|
case *NumberNode:
|
||||||
|
case *PipeNode:
|
||||||
|
for _, decl := range n.Decl {
|
||||||
|
walk(decl, before, after)
|
||||||
|
}
|
||||||
|
for _, cmd := range n.Cmds {
|
||||||
|
walk(cmd, before, after)
|
||||||
|
}
|
||||||
|
case *RangeNode:
|
||||||
|
if n.Pipe != nil {
|
||||||
|
walk(n.Pipe, before, after)
|
||||||
|
}
|
||||||
|
if n.List != nil {
|
||||||
|
walk(n.List, before, after)
|
||||||
|
}
|
||||||
|
if n.ElseList != nil {
|
||||||
|
walk(n.ElseList, before, after)
|
||||||
|
}
|
||||||
|
case *StringNode:
|
||||||
|
case *TemplateNode:
|
||||||
|
if n.Pipe != nil {
|
||||||
|
walk(n.Pipe, before, after)
|
||||||
|
}
|
||||||
|
case *TextNode:
|
||||||
|
case *VariableNode:
|
||||||
|
case *WithNode:
|
||||||
|
if n.Pipe != nil {
|
||||||
|
walk(n.Pipe, before, after)
|
||||||
|
}
|
||||||
|
if n.List != nil {
|
||||||
|
walk(n.List, before, after)
|
||||||
|
}
|
||||||
|
if n.ElseList != nil {
|
||||||
|
walk(n.ElseList, before, after)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
panic("unknown node of type " + fmt.Sprintf("%T", n))
|
||||||
|
}
|
||||||
|
if after != nil {
|
||||||
|
after(n)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user