diff options
Diffstat (limited to 'src/text/template/exec.go')
| -rw-r--r-- | src/text/template/exec.go | 84 |
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) { |
