emitComment bool // emit itemComment tokens.
pos Pos // current position in the input
start Pos // start position of this item
- width Pos // width of last rune read from input
+ atEOF bool // we have hit the end of input and returned eof
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.
func (l *lexer) next() rune {
if int(l.pos) >= len(l.input) {
- l.width = 0
+ l.atEOF = true
return eof
}
r, w := utf8.DecodeRuneInString(l.input[l.pos:])
- l.width = Pos(w)
- l.pos += l.width
+ l.pos += Pos(w)
if r == '\n' {
l.line++
}
return r
}
-// backup steps back one rune. Can only be called once per call of next.
+// backup steps back one rune.
func (l *lexer) backup() {
- l.pos -= l.width
- // Correct newline count.
- if l.width == 1 && l.input[l.pos] == '\n' {
- l.line--
+ if !l.atEOF && l.pos > 0 {
+ r, w := utf8.DecodeLastRuneInString(l.input[:l.pos])
+ l.pos -= Pos(w)
+ // Correct newline count.
+ if r == '\n' {
+ l.line--
+ }
}
}
// lexText scans until an opening action delimiter, "{{".
func lexText(l *lexer) stateFn {
- l.width = 0
if x := strings.Index(l.input[l.pos:], l.leftDelim); x >= 0 {
ldn := Pos(len(l.leftDelim))
l.pos += Pos(x)
case eof, '.', ',', '|', ':', ')', '(':
return true
}
- // Are we at a right delimiter? TODO: This is harder than it should be
- // because lookahead is only one rune.
- rightDelim := l.rightDelim
- defer func(pos Pos, line int) {
- l.pos = pos
- l.line = line
- }(l.pos, l.line)
- for len(rightDelim) > 0 {
- rNext := l.next()
- if rNext == eof {
- return false
- }
- rDelim, size := utf8.DecodeRuneInString(rightDelim)
- if rNext != rDelim {
- return false
- }
- rightDelim = rightDelim[size:]
- }
- return true
+ return strings.HasPrefix(l.input[l.pos:], l.rightDelim)
}
// lexChar scans a character constant. The initial quote is already