diff options
author | Cherry Zhang <cherryyz@google.com> | 2020-10-28 09:12:20 -0400 |
---|---|---|
committer | Cherry Zhang <cherryyz@google.com> | 2020-10-28 09:12:20 -0400 |
commit | a16e30d162c1c7408db7821e7b9513cefa09c6ca (patch) | |
tree | af752ba9ba44c547df39bb0af9bff79f610ba9d5 /src/text/template/parse/parse.go | |
parent | 91e4d2d57bc341dd82c98247117114c851380aef (diff) | |
parent | cf6cfba4d5358404dd890f6025e573a4b2156543 (diff) | |
download | go-git-dev.link.tar.gz |
[dev.link] all: merge branch 'master' into dev.linkdev.link
Clean merge.
Change-Id: Ia7b2808bc649790198d34c226a61d9e569084dc5
Diffstat (limited to 'src/text/template/parse/parse.go')
-rw-r--r-- | src/text/template/parse/parse.go | 59 |
1 files changed, 33 insertions, 26 deletions
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go index 496d8bfa1d..5e6e512eb4 100644 --- a/src/text/template/parse/parse.go +++ b/src/text/template/parse/parse.go @@ -24,13 +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{} - lex *lexer - token [3]item // three-token lookahead for parser. - peekCount int - vars []string // variables defined at the moment. - treeSet map[string]*Tree - mode Mode + funcs []map[string]interface{} + 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 } // A mode value is a set of flags (or 0). Modes control parser behavior. @@ -187,6 +188,16 @@ func (t *Tree) expectOneOf(expected1, expected2 itemType, context string) item { // unexpected complains about the token and terminates processing. func (t *Tree) unexpected(token item, context string) { + if token.typ == itemError { + extra := "" + if t.actionLine != 0 && t.actionLine != token.line { + extra = fmt.Sprintf(" in action started at %s:%d", t.ParseName, t.actionLine) + if strings.HasSuffix(token.val, " action") { + extra = extra[len(" in action"):] // avoid "action in action" + } + } + t.errorf("%s%s", token, extra) + } t.errorf("unexpected %s in %s", token, context) } @@ -350,6 +361,8 @@ func (t *Tree) textOrAction() Node { case itemText: return t.newText(token.pos, token.val) case itemLeftDelim: + t.actionLine = token.line + defer t.clearActionLine() return t.action() case itemComment: return t.newComment(token.pos, token.val) @@ -359,6 +372,10 @@ func (t *Tree) textOrAction() Node { return nil } +func (t *Tree) clearActionLine() { + t.actionLine = 0 +} + // Action: // control // command ("|" command)* @@ -384,12 +401,12 @@ func (t *Tree) action() (n Node) { t.backup() token := t.peek() // Do not pop variables; they persist until "end". - return t.newAction(token.pos, token.line, t.pipeline("command")) + return t.newAction(token.pos, token.line, t.pipeline("command", itemRightDelim)) } // Pipeline: // declarations? command ('|' command)* -func (t *Tree) pipeline(context string) (pipe *PipeNode) { +func (t *Tree) pipeline(context string, end itemType) (pipe *PipeNode) { token := t.peekNonSpace() pipe = t.newPipeline(token.pos, token.line, nil) // Are there declarations or assignments? @@ -430,12 +447,9 @@ decls: } for { switch token := t.nextNonSpace(); token.typ { - case itemRightDelim, itemRightParen: + case end: // At this point, the pipeline is complete t.checkPipeline(pipe, context) - if token.typ == itemRightParen { - t.backup() - } return case itemBool, itemCharConstant, itemComplex, itemDot, itemField, itemIdentifier, itemNumber, itemNil, itemRawString, itemString, itemVariable, itemLeftParen: @@ -464,7 +478,7 @@ 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) + pipe = t.pipeline(context, itemRightDelim) var next Node list, next = t.itemList() switch next.Type() { @@ -550,7 +564,7 @@ func (t *Tree) blockControl() Node { token := t.nextNonSpace() name := t.parseTemplateName(token, context) - pipe := t.pipeline(context) + pipe := t.pipeline(context, itemRightDelim) block := New(name) // name will be updated once we know it. block.text = t.text @@ -580,7 +594,7 @@ func (t *Tree) templateControl() Node { if t.nextNonSpace().typ != itemRightDelim { t.backup() // Do not pop variables; they persist until "end". - pipe = t.pipeline(context) + pipe = t.pipeline(context, itemRightDelim) } return t.newTemplate(token.pos, token.line, name, pipe) } @@ -614,13 +628,12 @@ func (t *Tree) command() *CommandNode { switch token := t.next(); token.typ { case itemSpace: continue - case itemError: - t.errorf("%s", token.val) case itemRightDelim, itemRightParen: t.backup() case itemPipe: + // nothing here; break loop below default: - t.errorf("unexpected %s in operand", token) + t.unexpected(token, "operand") } break } @@ -675,8 +688,6 @@ func (t *Tree) operand() Node { // A nil return means the next item is not a term. func (t *Tree) term() Node { switch token := t.nextNonSpace(); token.typ { - case itemError: - t.errorf("%s", token.val) case itemIdentifier: if !t.hasFunction(token.val) { t.errorf("function %q not defined", token.val) @@ -699,11 +710,7 @@ func (t *Tree) term() Node { } return number case itemLeftParen: - pipe := t.pipeline("parenthesized pipeline") - if token := t.next(); token.typ != itemRightParen { - t.errorf("unclosed right paren: unexpected %s", token) - } - return pipe + return t.pipeline("parenthesized pipeline", itemRightParen) case itemString, itemRawString: s, err := strconv.Unquote(token.val) if err != nil { |