summaryrefslogtreecommitdiff
path: root/libgo/go/text/template/parse/lex.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/text/template/parse/lex.go')
-rw-r--r--libgo/go/text/template/parse/lex.go81
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