diff options
Diffstat (limited to 'libgo/go/text/template/parse/lex.go')
-rw-r--r-- | libgo/go/text/template/parse/lex.go | 81 |
1 files changed, 41 insertions, 40 deletions
diff --git a/libgo/go/text/template/parse/lex.go b/libgo/go/text/template/parse/lex.go index ea93e05142..6fbf36d7a4 100644 --- a/libgo/go/text/template/parse/lex.go +++ b/libgo/go/text/template/parse/lex.go @@ -13,9 +13,10 @@ import ( // item represents a token or text string returned from the scanner. type item struct { - typ itemType // The type of this item. - pos Pos // The starting position, in bytes, of this item in the input string. - val string // The value of this item. + typ itemType // The type of this item. + pos Pos // The starting position, in bytes, of this item in the input string. + val string // The value of this item. + line int // The line number at the start of this item. } func (i item) String() string { @@ -116,6 +117,7 @@ type lexer struct { lastPos Pos // position of most recent item returned by nextItem items chan item // channel of scanned items parenDepth int // nesting depth of ( ) exprs + line int // 1+number of newlines seen } // next returns the next rune in the input. @@ -127,6 +129,9 @@ func (l *lexer) next() rune { r, w := utf8.DecodeRuneInString(l.input[l.pos:]) l.width = Pos(w) l.pos += l.width + if r == '\n' { + l.line++ + } return r } @@ -140,11 +145,20 @@ func (l *lexer) peek() rune { // backup steps back one rune. Can only be called once per call of next. func (l *lexer) backup() { l.pos -= l.width + // Correct newline count. + if l.width == 1 && l.input[l.pos] == '\n' { + l.line-- + } } // 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.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, itemRawString, itemLeftDelim, itemRightDelim: + l.line += strings.Count(l.input[l.start:l.pos], "\n") + } l.start = l.pos } @@ -155,7 +169,7 @@ func (l *lexer) ignore() { // accept consumes the next rune if it's from the valid set. func (l *lexer) accept(valid string) bool { - if strings.IndexRune(valid, l.next()) >= 0 { + if strings.ContainsRune(valid, l.next()) { return true } l.backup() @@ -164,22 +178,15 @@ func (l *lexer) accept(valid string) bool { // acceptRun consumes a run of runes from the valid set. func (l *lexer) acceptRun(valid string) { - for strings.IndexRune(valid, l.next()) >= 0 { + for strings.ContainsRune(valid, l.next()) { } l.backup() } -// lineNumber reports which line we're on, based on the position of -// the previous item returned by nextItem. Doing it this way -// means we don't have to worry about peek double counting. -func (l *lexer) lineNumber() int { - return 1 + strings.Count(l.input[:l.lastPos], "\n") -} - // 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.items <- item{itemError, l.start, fmt.Sprintf(format, args...), l.line} return nil } @@ -212,6 +219,7 @@ func lex(name, input, left, right string) *lexer { leftDelim: left, rightDelim: right, items: make(chan item), + line: 1, } go l.run() return l @@ -236,24 +244,23 @@ const ( // lexText scans until an opening action delimiter, "{{". func lexText(l *lexer) stateFn { - for { - delim, trimSpace := l.atLeftDelim() - if delim { - trimLength := Pos(0) - if trimSpace { - trimLength = rightTrimLength(l.input[l.start:l.pos]) - } - l.pos -= trimLength - if l.pos > l.start { - l.emit(itemText) - } - l.pos += trimLength - l.ignore() - return lexLeftDelim + l.width = 0 + if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 { + ldn := Pos(len(l.leftDelim)) + l.pos += Pos(x) + trimLength := Pos(0) + if strings.HasPrefix(l.input[l.pos+ldn:], leftTrimMarker) { + trimLength = rightTrimLength(l.input[l.start:l.pos]) } - if l.next() == eof { - break + l.pos -= trimLength + if l.pos > l.start { + l.emit(itemText) } + l.pos += trimLength + l.ignore() + return lexLeftDelim + } else { + l.pos = Pos(len(l.input)) } // Correctly reached EOF. if l.pos > l.start { @@ -263,16 +270,6 @@ func lexText(l *lexer) stateFn { return nil } -// atLeftDelim reports whether the lexer is at a left delimiter, possibly followed by a trim marker. -func (l *lexer) atLeftDelim() (delim, trimSpaces bool) { - if !strings.HasPrefix(l.input[l.pos:], l.leftDelim) { - return false, false - } - // The left delim might have the marker afterwards. - trimSpaces = strings.HasPrefix(l.input[l.pos+Pos(len(l.leftDelim)):], leftTrimMarker) - return true, trimSpaces -} - // rightTrimLength returns the length of the spaces at the end of the string. func rightTrimLength(s string) Pos { return Pos(len(s) - len(strings.TrimRight(s, spaceChars))) @@ -613,10 +610,14 @@ 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 |