diff options
| author | Rob Pike <r@golang.org> | 2016-11-08 15:43:20 -0800 |
|---|---|---|
| committer | Rob Pike <r@golang.org> | 2016-11-14 18:42:48 +0000 |
| commit | 794fb71d9c1018c4beae1657baca5229e6a02ad0 (patch) | |
| tree | ed42cf89824429507619862f76f8fa42f77b72ed /src/text/template/parse/parse.go | |
| parent | 2f76c1985fa8bbb0fb09af6600445b5c7d4d5cb4 (diff) | |
| download | go-794fb71d9c1018c4beae1657baca5229e6a02ad0.tar.xz | |
text/template: efficient reporting of line numbers
Instead of scanning the text to count newlines, which is n², keep track as we go
and store the line number in the token.
benchmark old ns/op new ns/op delta
BenchmarkParseLarge-4 1589721293 38783310 -97.56%
Fixes #17851
Change-Id: Ieaf89a35e371b405ad92e38baa1e3fa98d18cfb4
Reviewed-on: https://go-review.googlesource.com/32923
Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/text/template/parse/parse.go')
| -rw-r--r-- | src/text/template/parse/parse.go | 22 |
1 files changed, 12 insertions, 10 deletions
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go index 893564b983..5d5c017ba9 100644 --- a/src/text/template/parse/parse.go +++ b/src/text/template/parse/parse.go @@ -157,7 +157,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{}) { t.Root = nil - format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.lineNumber(), format) + format = fmt.Sprintf("template: %s:%d: %s", t.ParseName, t.lex.line, format) panic(fmt.Errorf(format, args...)) } @@ -376,15 +376,17 @@ func (t *Tree) action() (n Node) { return t.withControl() } t.backup() + token := t.peek() // Do not pop variables; they persist until "end". - return t.newAction(t.peek().pos, t.lex.lineNumber(), t.pipeline("command")) + return t.newAction(token.pos, token.line, t.pipeline("command")) } // Pipeline: // declarations? command ('|' command)* func (t *Tree) pipeline(context string) (pipe *PipeNode) { var decl []*VariableNode - pos := t.peekNonSpace().pos + token := t.peekNonSpace() + pos := token.pos // Are there declarations? for { if v := t.peekNonSpace(); v.typ == itemVariable { @@ -413,7 +415,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) { } break } - pipe = t.newPipeline(pos, t.lex.lineNumber(), decl) + pipe = t.newPipeline(pos, token.line, decl) for { switch token := t.nextNonSpace(); token.typ { case itemRightDelim, itemRightParen: @@ -450,7 +452,6 @@ 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)) - line = t.lex.lineNumber() pipe = t.pipeline(context) var next Node list, next = t.itemList() @@ -479,7 +480,7 @@ func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int t.errorf("expected end; found %s", next) } } - return pipe.Position(), line, pipe, list, elseList + return pipe.Position(), pipe.Line, pipe, list, elseList } // If: @@ -521,9 +522,10 @@ func (t *Tree) elseControl() Node { peek := t.peekNonSpace() if peek.typ == itemIf { // We see "{{else if ... " but in effect rewrite it to {{else}}{{if ... ". - return t.newElse(peek.pos, t.lex.lineNumber()) + return t.newElse(peek.pos, peek.line) } - return t.newElse(t.expect(itemRightDelim, "else").pos, t.lex.lineNumber()) + token := t.expect(itemRightDelim, "else") + return t.newElse(token.pos, token.line) } // Block: @@ -550,7 +552,7 @@ func (t *Tree) blockControl() Node { block.add() block.stopParse() - return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) + return t.newTemplate(token.pos, token.line, name, pipe) } // Template: @@ -567,7 +569,7 @@ func (t *Tree) templateControl() Node { // Do not pop variables; they persist until "end". pipe = t.pipeline(context) } - return t.newTemplate(token.pos, t.lex.lineNumber(), name, pipe) + return t.newTemplate(token.pos, token.line, name, pipe) } func (t *Tree) parseTemplateName(token item, context string) (name string) { |
