Skip to content

Commit 2f4437c

Browse files
committed
make parser use the new iterator API in lexer
1 parent 152f67d commit 2f4437c

File tree

3 files changed

+44
-35
lines changed

3 files changed

+44
-35
lines changed

file/error.go

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ var tabReplacer = strings.NewReplacer("\t", " ")
2323
func (e *Error) Bind(source Source) *Error {
2424
src := source.String()
2525

26+
var runeCount, lineStart int
2627
e.Line = 1
27-
var runeCount, lineStart, lineOffset int
28+
e.Column = 0
2829
for i, r := range src {
2930
if runeCount == e.From {
3031
break
@@ -33,12 +34,9 @@ func (e *Error) Bind(source Source) *Error {
3334
lineStart = i
3435
e.Line++
3536
e.Column = 0
36-
lineOffset = 0
37-
} else {
38-
e.Column++
3937
}
4038
runeCount++
41-
lineOffset++
39+
e.Column++
4240
}
4341

4442
lineEnd := lineStart + strings.IndexByte(src[lineStart:], '\n')
@@ -52,11 +50,11 @@ func (e *Error) Bind(source Source) *Error {
5250
const prefix = "\n | "
5351
line := src[lineStart:lineEnd]
5452
snippet := new(strings.Builder)
55-
snippet.Grow(2*len(prefix) + len(line) + lineOffset + 1)
53+
snippet.Grow(2*len(prefix) + len(line) + e.Column + 1)
5654
snippet.WriteString(prefix)
5755
tabReplacer.WriteString(snippet, line)
5856
snippet.WriteString(prefix)
59-
for i := 0; i < lineOffset; i++ {
57+
for i := 0; i < e.Column; i++ {
6058
snippet.WriteByte('.')
6159
}
6260
snippet.WriteByte('^')

parser/lexer/lexer.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,6 @@ func (l *Lexer) Next() (Token, error) {
6767
return Token{}, io.EOF
6868
}
6969

70-
func (l *Lexer) Cap() int {
71-
return l.tokens.Cap()
72-
}
73-
7470
const eof rune = -1
7571

7672
func (l *Lexer) commit() {

parser/parser.go

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package parser
22

33
import (
4+
"errors"
45
"fmt"
6+
"io"
57
"math"
68
"strconv"
79
"strings"
@@ -10,6 +12,7 @@ import (
1012
"github.com/expr-lang/expr/builtin"
1113
"github.com/expr-lang/expr/conf"
1214
"github.com/expr-lang/expr/file"
15+
"github.com/expr-lang/expr/parser/lexer"
1316
. "github.com/expr-lang/expr/parser/lexer"
1417
"github.com/expr-lang/expr/parser/operator"
1518
"github.com/expr-lang/expr/parser/utils"
@@ -45,13 +48,13 @@ var predicates = map[string]struct {
4548
}
4649

4750
type parser struct {
48-
tokens []Token
49-
current Token
50-
pos int
51-
err *file.Error
52-
config *conf.Config
53-
depth int // predicate call depth
54-
nodeCount uint // tracks number of AST nodes created
51+
lexer *lexer.Lexer
52+
current, stashed Token
53+
hasStash bool
54+
err *file.Error
55+
config *conf.Config
56+
depth int // predicate call depth
57+
nodeCount uint // tracks number of AST nodes created
5558
}
5659

5760
func (p *parser) checkNodeLimit() error {
@@ -102,19 +105,14 @@ func Parse(input string) (*Tree, error) {
102105
}
103106

104107
func ParseWithConfig(input string, config *conf.Config) (*Tree, error) {
105-
source := file.NewSource(input)
106-
107-
tokens, err := Lex(source)
108-
if err != nil {
109-
return nil, err
110-
}
111-
112108
p := &parser{
113-
tokens: tokens,
114-
current: tokens[0],
115-
config: config,
109+
lexer: lexer.New(),
110+
config: config,
116111
}
117112

113+
source := file.NewSource(input)
114+
p.lexer.Reset(source)
115+
p.next()
118116
node := p.parseSequenceExpression()
119117

120118
if !p.current.Is(EOF) {
@@ -147,12 +145,28 @@ func (p *parser) errorAt(token Token, format string, args ...any) {
147145
}
148146

149147
func (p *parser) next() {
150-
p.pos++
151-
if p.pos >= len(p.tokens) {
152-
p.error("unexpected end of expression")
148+
if p.hasStash {
149+
p.current = p.stashed
150+
p.hasStash = false
153151
return
154152
}
155-
p.current = p.tokens[p.pos]
153+
154+
token, err := p.lexer.Next()
155+
var e *file.Error
156+
switch {
157+
case err == nil:
158+
p.current = token
159+
case errors.Is(err, io.EOF):
160+
p.error("unexpected end of expression")
161+
case errors.As(err, &e):
162+
p.err = e
163+
default:
164+
p.err = &file.Error{
165+
Location: p.current.Location,
166+
Message: "unknown lexing error",
167+
Prev: err,
168+
}
169+
}
156170
}
157171

158172
func (p *parser) expect(kind Kind, values ...string) {
@@ -209,15 +223,16 @@ func (p *parser) parseExpression(precedence int) Node {
209223

210224
// Handle "not *" operator, like "not in" or "not contains".
211225
if negate {
212-
currentPos := p.pos
226+
tokenBackup := p.current
213227
p.next()
214228
if operator.AllowedNegateSuffix(p.current.Value) {
215229
if op, ok := operator.Binary[p.current.Value]; ok && op.Precedence >= precedence {
216230
notToken = p.current
217231
opToken = p.current
218232
} else {
219-
p.pos = currentPos
220-
p.current = opToken
233+
p.hasStash = true
234+
p.stashed = p.current
235+
p.current = tokenBackup
221236
break
222237
}
223238
} else {

0 commit comments

Comments
 (0)