aboutsummaryrefslogtreecommitdiff
path: root/src/text/template/exec.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/text/template/exec.go')
-rw-r--r--src/text/template/exec.go84
1 files changed, 24 insertions, 60 deletions
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index 87cf1e9b1c..83c38cdf13 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -25,12 +25,11 @@ const maxExecDepth = 100000
// template so that multiple executions of the same template
// can execute in parallel.
type state struct {
- tmpl *Template
- wr io.Writer
- node parse.Node // current node, for errors.
- vars []variable // push-down stack of variable values.
- depth int // the height of the stack of executing templates.
- rangeDepth int // nesting level of range loops.
+ tmpl *Template
+ wr io.Writer
+ node parse.Node // current node, for errors
+ vars []variable // push-down stack of variable values.
+ depth int // the height of the stack of executing templates.
}
// variable holds the dynamic value of a variable such as $, $x etc.
@@ -221,17 +220,9 @@ func (t *Template) DefinedTemplates() string {
return s
}
-type rangeControl int8
-
-const (
- rangeNone rangeControl = iota // no action.
- rangeBreak // break out of range.
- rangeContinue // continues next range iteration.
-)
-
// Walk functions step through the major pieces of the template structure,
// generating output as they go.
-func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl {
+func (s *state) walk(dot reflect.Value, node parse.Node) {
s.at(node)
switch node := node.(type) {
case *parse.ActionNode:
@@ -242,15 +233,13 @@ func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl {
s.printValue(node, val)
}
case *parse.IfNode:
- return s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
+ s.walkIfOrWith(parse.NodeIf, dot, node.Pipe, node.List, node.ElseList)
case *parse.ListNode:
for _, node := range node.Nodes {
- if c := s.walk(dot, node); c != rangeNone {
- return c
- }
+ s.walk(dot, node)
}
case *parse.RangeNode:
- return s.walkRange(dot, node)
+ s.walkRange(dot, node)
case *parse.TemplateNode:
s.walkTemplate(dot, node)
case *parse.TextNode:
@@ -258,26 +247,15 @@ func (s *state) walk(dot reflect.Value, node parse.Node) rangeControl {
s.writeError(err)
}
case *parse.WithNode:
- return s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
- case *parse.BreakNode:
- if s.rangeDepth == 0 {
- s.errorf("invalid break outside of range")
- }
- return rangeBreak
- case *parse.ContinueNode:
- if s.rangeDepth == 0 {
- s.errorf("invalid continue outside of range")
- }
- return rangeContinue
+ s.walkIfOrWith(parse.NodeWith, dot, node.Pipe, node.List, node.ElseList)
default:
s.errorf("unknown node: %s", node)
}
- return rangeNone
}
// walkIfOrWith walks an 'if' or 'with' node. The two control structures
// are identical in behavior except that 'with' sets dot.
-func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) rangeControl {
+func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.PipeNode, list, elseList *parse.ListNode) {
defer s.pop(s.mark())
val := s.evalPipeline(dot, pipe)
truth, ok := isTrue(val)
@@ -286,14 +264,13 @@ func (s *state) walkIfOrWith(typ parse.NodeType, dot reflect.Value, pipe *parse.
}
if truth {
if typ == parse.NodeWith {
- return s.walk(val, list)
+ s.walk(val, list)
} else {
- return s.walk(dot, list)
+ s.walk(dot, list)
}
} else if elseList != nil {
- return s.walk(dot, elseList)
+ s.walk(dot, elseList)
}
- return rangeNone
}
// IsTrue reports whether the value is 'true', in the sense of not the zero of its type,
@@ -331,14 +308,13 @@ func isTrue(val reflect.Value) (truth, ok bool) {
return truth, true
}
-func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
+func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
s.at(r)
defer s.pop(s.mark())
val, _ := indirect(s.evalPipeline(dot, r.Pipe))
// mark top of stack before any variables in the body are pushed.
mark := s.mark()
- s.rangeDepth++
- oneIteration := func(index, elem reflect.Value) rangeControl {
+ 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)
@@ -347,9 +323,8 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
if len(r.Pipe.Decl) > 1 {
s.setVar(2, index)
}
- ctrl := s.walk(elem, r.List)
+ s.walk(elem, r.List)
s.pop(mark)
- return ctrl
}
switch val.Kind() {
case reflect.Array, reflect.Slice:
@@ -357,23 +332,17 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
break
}
for i := 0; i < val.Len(); i++ {
- if ctrl := oneIteration(reflect.ValueOf(i), val.Index(i)); ctrl == rangeBreak {
- break
- }
+ oneIteration(reflect.ValueOf(i), val.Index(i))
}
- s.rangeDepth--
- return rangeNone
+ return
case reflect.Map:
if val.Len() == 0 {
break
}
for _, key := range sortKeys(val.MapKeys()) {
- if ctrl := oneIteration(key, val.MapIndex(key)); ctrl == rangeBreak {
- break
- }
+ oneIteration(key, val.MapIndex(key))
}
- s.rangeDepth--
- return rangeNone
+ return
case reflect.Chan:
if val.IsNil() {
break
@@ -384,25 +353,20 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) rangeControl {
if !ok {
break
}
- if ctrl := oneIteration(reflect.ValueOf(i), elem); ctrl == rangeBreak {
- break
- }
+ oneIteration(reflect.ValueOf(i), elem)
}
if i == 0 {
break
}
- s.rangeDepth--
- return rangeNone
+ return
case reflect.Invalid:
break // An invalid value is likely a nil map, etc. and acts like an empty map.
default:
s.errorf("range can't iterate over %v", val)
}
- s.rangeDepth--
if r.ElseList != nil {
- return s.walk(dot, r.ElseList)
+ s.walk(dot, r.ElseList)
}
- return rangeNone
}
func (s *state) walkTemplate(dot reflect.Value, t *parse.TemplateNode) {