1
0
mirror of https://github.com/golang/go synced 2024-11-13 19:20:31 -07:00

text/template: simplify line tracking in the lexer

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í <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rob Pike <r@golang.org>
This commit is contained in:
Daniel Martí 2018-08-30 11:02:41 -06:00
parent 2524ed1994
commit 98fd66808f

View File

@ -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