tpl: Sync go_templates for Go 1.18

Using Go tag go1.18 4aa1efed4853ea067d665a952eee77c52faac774

Updates #9677
This commit is contained in:
Bjørn Erik Pedersen
2022-03-16 08:48:16 +01:00
parent 4d6d1d08da
commit 65a78cae1e
48 changed files with 697 additions and 223 deletions

View File

@@ -24,14 +24,14 @@ type Tree struct {
Mode Mode // parsing mode.
text string // text parsed to create the template (or its parent)
// Parsing only; cleared after parse.
funcs []map[string]interface{}
funcs []map[string]any
lex *lexer
token [3]item // three-token lookahead for parser.
peekCount int
vars []string // variables defined at the moment.
treeSet map[string]*Tree
actionLine int // line of left delim starting action
mode Mode
rangeDepth int
}
// A mode value is a set of flags (or 0). Modes control parser behavior.
@@ -39,6 +39,7 @@ type Mode uint
const (
ParseComments Mode = 1 << iota // parse comments and add them to AST
SkipFuncCheck // do not check that functions are defined
)
// Copy returns a copy of the Tree. Any parsing state is discarded.
@@ -58,7 +59,7 @@ func (t *Tree) Copy() *Tree {
// templates described in the argument string. The top-level template will be
// given the specified name. If an error is encountered, parsing stops and an
// empty map is returned with the error.
func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]interface{}) (map[string]*Tree, error) {
func Parse(name, text, leftDelim, rightDelim string, funcs ...map[string]any) (map[string]*Tree, error) {
treeSet := make(map[string]*Tree)
t := New(name)
t.text = text
@@ -127,7 +128,7 @@ func (t *Tree) peekNonSpace() item {
// Parsing.
// New allocates a new parse tree with the given name.
func New(name string, funcs ...map[string]interface{}) *Tree {
func New(name string, funcs ...map[string]any) *Tree {
return &Tree{
Name: name,
funcs: funcs,
@@ -157,7 +158,7 @@ func (t *Tree) ErrorContext(n Node) (location, context string) {
}
// errorf formats the error and terminates processing.
func (t *Tree) errorf(format string, args ...interface{}) {
func (t *Tree) errorf(format string, args ...any) {
t.Root = nil
format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.token[0].line, format)
panic(fmt.Errorf(format, args...))
@@ -217,12 +218,14 @@ func (t *Tree) recover(errp *error) {
}
// startParse initializes the parser, using the lexer.
func (t *Tree) startParse(funcs []map[string]interface{}, lex *lexer, treeSet map[string]*Tree) {
func (t *Tree) startParse(funcs []map[string]any, lex *lexer, treeSet map[string]*Tree) {
t.Root = nil
t.lex = lex
t.vars = []string{"$"}
t.funcs = funcs
t.treeSet = treeSet
lex.breakOK = !t.hasFunction("break")
lex.continueOK = !t.hasFunction("continue")
}
// stopParse terminates parsing.
@@ -237,7 +240,7 @@ func (t *Tree) stopParse() {
// the template for execution. If either action delimiter string is empty, the
// default ("{{" or "}}") is used. Embedded template definitions are added to
// the treeSet map.
func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]interface{}) (tree *Tree, err error) {
func (t *Tree) Parse(text, leftDelim, rightDelim string, treeSet map[string]*Tree, funcs ...map[string]any) (tree *Tree, err error) {
defer t.recover(&err)
t.ParseName = t.Name
emitComment := t.Mode&ParseComments != 0
@@ -385,6 +388,10 @@ func (t *Tree) action() (n Node) {
switch token := t.nextNonSpace(); token.typ {
case itemBlock:
return t.blockControl()
case itemBreak:
return t.breakControl(token.pos, token.line)
case itemContinue:
return t.continueControl(token.pos, token.line)
case itemElse:
return t.elseControl()
case itemEnd:
@@ -404,6 +411,32 @@ func (t *Tree) action() (n Node) {
return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim))
}
// Break:
// {{break}}
// Break keyword is past.
func (t *Tree) breakControl(pos Pos, line int) Node {
if token := t.next(); token.typ != itemRightDelim {
t.unexpected(token, "in {{break}}")
}
if t.rangeDepth == 0 {
t.errorf("{{break}} outside {{range}}")
}
return t.newBreak(pos, line)
}
// Continue:
// {{continue}}
// Continue keyword is past.
func (t *Tree) continueControl(pos Pos, line int) Node {
if token := t.next(); token.typ != itemRightDelim {
t.unexpected(token, "in {{continue}}")
}
if t.rangeDepth == 0 {
t.errorf("{{continue}} outside {{range}}")
}
return t.newContinue(pos, line)
}
// Pipeline:
// declarations? command ('|' command)*
func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) {
@@ -479,8 +512,14 @@ func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
defer t.popVars(len(t.vars))
pipe = t.pipeline(context, itemRightDelim)
if context == "range" {
t.rangeDepth++
}
var next Node
list, next = t.itemList()
if context == "range" {
t.rangeDepth--
}
switch next.Type() {
case nodeEnd: //done
case nodeElse:
@@ -522,7 +561,8 @@ func (t *Tree) ifControl() Node {
// {{range pipeline}} itemList {{else}} itemList {{end}}
// Range keyword is past.
func (t *Tree) rangeControl() Node {
return t.newRange(t.parseControl(false, "range"))
r := t.newRange(t.parseControl(false, "range"))
return r
}
// With:
@@ -689,7 +729,8 @@ func (t *Tree) operand() Node {
func (t *Tree) term() Node {
switch token := t.nextNonSpace(); token.typ {
case itemIdentifier:
if !t.hasFunction(token.val) {
checkFunc := t.Mode&SkipFuncCheck == 0
if checkFunc && !t.hasFunction(token.val) {
t.errorf("function %q not defined", token.val)
}
return NewIdentifier(token.val).SetTree(t).SetPos(token.pos)