From 98fd66808fafb6496caeb3e848ae277b734f8ed9 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Daniel=20Mart=C3=AD?= Date: Thu, 30 Aug 2018 11:02:41 -0600 Subject: [PATCH] text/template: simplify line tracking in the lexer MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit First, move the strings.Count logic out of emit, since only itemText requires that. Use it in those call sites. itemLeftDelim and itemRightDelim cannot contain newlines, as they're the "{{" and "}}" tokens. Secondly, introduce a startLine lexer field so that we don't have to keep track of it elsewhere. That's also a requirement to move the strings.Count out of emit, as emit modifies the start position field. Change-Id: I69175f403487607a8e5b561b3f1916ee9dc3c0c6 Reviewed-on: https://go-review.googlesource.com/132275 Run-TryBot: Daniel Martí TryBot-Result: Gobot Gobot Reviewed-by: Rob Pike --- src/text/template/parse/lex.go | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go index c0843af6ed..94a676c579 100644 --- a/src/text/template/parse/lex.go +++ b/src/text/template/parse/lex.go @@ -117,6 +117,7 @@ type lexer struct { items chan item // channel of scanned items parenDepth int // nesting depth of ( ) exprs line int // 1+number of newlines seen + startLine int // start line of this item } // next returns the next rune in the input. @@ -152,19 +153,16 @@ func (l *lexer) backup() { // emit passes an item back to the client. func (l *lexer) emit(t itemType) { - l.items <- item{t, l.start, l.input[l.start:l.pos], l.line} - // Some items contain text internally. If so, count their newlines. - switch t { - case itemText, itemLeftDelim, itemRightDelim: - l.line += strings.Count(l.input[l.start:l.pos], "\n") - } + l.items <- item{t, l.start, l.input[l.start:l.pos], l.startLine} l.start = l.pos + l.startLine = l.line } // ignore skips over the pending input before this point. func (l *lexer) ignore() { l.line += strings.Count(l.input[l.start:l.pos], "\n") l.start = l.pos + l.startLine = l.line } // accept consumes the next rune if it's from the valid set. @@ -186,7 +184,7 @@ func (l *lexer) acceptRun(valid string) { // errorf returns an error token and terminates the scan by passing // back a nil pointer that will be the next state, terminating l.nextItem. func (l *lexer) errorf(format string, args ...interface{}) stateFn { - l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.line} + l.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.startLine} return nil } @@ -218,6 +216,7 @@ func lex(name, input, left, right string) *lexer { rightDelim: right, items: make(chan item), line: 1, + startLine: 1, } go l.run() return l @@ -252,16 +251,17 @@ func lexText(l *lexer) stateFn { } l.pos -= trimLength if l.pos > l.start { + l.line += strings.Count(l.input[l.start:l.pos], "\n") l.emit(itemText) } l.pos += trimLength l.ignore() return lexLeftDelim - } else { - l.pos = Pos(len(l.input)) } + l.pos = Pos(len(l.input)) // Correctly reached EOF. if l.pos > l.start { + l.line += strings.Count(l.input[l.start:l.pos], "\n") l.emit(itemText) } l.emit(itemEOF) @@ -609,14 +609,10 @@ Loop: // lexRawQuote scans a raw quoted string. func lexRawQuote(l *lexer) stateFn { - startLine := l.line Loop: for { switch l.next() { case eof: - // Restore line number to location of opening quote. - // We will error out so it's ok just to overwrite the field. - l.line = startLine return l.errorf("unterminated raw quoted string") case '`': break Loop -- 2.50.0