aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ccl.go13
-rw-r--r--ccl_test.go7
-rw-r--r--lexer.go112
3 files changed, 54 insertions, 78 deletions
diff --git a/ccl.go b/ccl.go
index 3a444c1..6d97152 100644
--- a/ccl.go
+++ b/ccl.go
@@ -164,7 +164,6 @@ import (
"encoding/base64"
"errors"
"fmt"
- "iter"
"math"
"reflect"
"strconv"
@@ -243,7 +242,7 @@ func fieldMap(out map[structField]int, types map[reflect.Type]bool, s reflect.Ty
}
type parser struct {
- nextTok func() (token, error, bool)
+ nextTok func() (token, error)
tok []byte
err error
data []byte
@@ -261,11 +260,7 @@ func (p *parser) peek() ([]byte, error) {
if p.err != nil || p.tok != nil {
return p.tok, p.err
}
- tok, err, ok := p.nextTok()
- if !ok {
- p.err = errEOF
- return nil, p.err
- }
+ tok, err := p.nextTok()
if err != nil {
p.err = err
return nil, p.err
@@ -747,7 +742,5 @@ func Unmarshal(data []byte, v any) error {
if err := fieldMap(fields, make(map[reflect.Type]bool), val.Type().Elem()); err != nil {
return err
}
- nextToken, stop := iter.Pull2(tokens(data))
- defer stop()
- return (&parser{nextTok: nextToken, data: data, fieldMap: fields}).parse(val.Elem())
+ return (&parser{nextTok: newLexer(data).next, data: data, fieldMap: fields}).parse(val.Elem())
}
diff --git a/ccl_test.go b/ccl_test.go
index ab4833f..53b2a24 100644
--- a/ccl_test.go
+++ b/ccl_test.go
@@ -684,8 +684,13 @@ func BenchmarkLex(b *testing.B) {
repeated: [5, 6]
`)
for b.Loop() {
- for _, err := range tokens(msg) {
+ l := newLexer(msg)
+ for {
+ _, err := l.next()
if err != nil {
+ if err == errEOF {
+ break
+ }
b.Fatal(err)
}
}
diff --git a/lexer.go b/lexer.go
index c7c0631..6561e38 100644
--- a/lexer.go
+++ b/lexer.go
@@ -2,7 +2,6 @@ package ccl
import (
"bytes"
- "iter"
"unicode"
"unicode/utf8"
)
@@ -13,21 +12,18 @@ type token struct {
}
type lexer struct {
- data []byte
- i int
- yieldTok func(token, error) bool
+ data []byte
+ i int
}
-func (l *lexer) error(reason string, args ...any) {
- l.yieldTok(token{}, newSyntaxError(l.data, l.i, reason, args...))
+func (l *lexer) error(reason string, args ...any) error {
+ return newSyntaxError(l.data, l.i, reason, args...)
}
-func (l *lexer) yield(n int) bool {
- if !l.yieldTok(token{l.i, l.data[l.i : l.i+n]}, nil) {
- return false
- }
+func (l *lexer) yield(n int) token {
+ t := token{l.i, l.data[l.i : l.i+n]}
l.i += n
- return true
+ return t
}
func (l *lexer) skipSpace() {
@@ -75,67 +71,49 @@ func fieldTailByte(b byte) bool {
'0' <= b && b <= '9'
}
-func (l *lexer) tokens() {
- for l.i = 0; ; {
- l.skipSpace()
- if l.i == len(l.data) {
- break
- }
- switch l.data[l.i] {
- case
- '{',
- '}',
- '[',
- ']',
- ':',
- ',':
+func (l *lexer) next() (token, error) {
+ l.skipSpace()
+ if l.i == len(l.data) {
+ return token{}, errEOF
+ }
+ switch l.data[l.i] {
+ case
+ '{',
+ '}',
+ '[',
+ ']',
+ ':',
+ ',':
- if !l.yield(1) {
- return
- }
- continue
- case '\'', '"':
- q := l.data[l.i]
- i := l.i + 1
- for ; i < len(l.data) && l.data[i] != q; i++ {
- if l.data[i] == '\\' {
- i++
- }
+ return l.yield(1), nil
+ case '\'', '"':
+ q := l.data[l.i]
+ i := l.i + 1
+ for ; i < len(l.data) && l.data[i] != q; i++ {
+ if l.data[i] == '\\' {
+ i++
}
- if i >= len(l.data) {
- l.error("unterminated string")
- return
- }
- if !l.yield(i + 1 - l.i) {
- return
- }
- continue
}
- switch b := l.data[l.i]; {
- case numFirstByte(b):
- i := l.i + 1
- for ; i < len(l.data) && numTailByte(l.data[i]); i++ {
- }
- if !l.yield(i - l.i) {
- return
- }
- continue
- case fieldFirstByte(b):
- i := l.i + 1
- for ; i < len(l.data) && fieldTailByte(l.data[i]); i++ {
- }
- if !l.yield(i - l.i) {
- return
- }
- continue
+ if i >= len(l.data) {
+ return token{}, l.error("unterminated string")
}
- l.error("invalid lexeme")
- return
+ return l.yield(i + 1 - l.i), nil
}
+ switch b := l.data[l.i]; {
+ case numFirstByte(b):
+ i := l.i + 1
+ for ; i < len(l.data) && numTailByte(l.data[i]); i++ {
+ }
+ return l.yield(i - l.i), nil
+ case fieldFirstByte(b):
+ i := l.i + 1
+ for ; i < len(l.data) && fieldTailByte(l.data[i]); i++ {
+ }
+ return l.yield(i - l.i), nil
+ }
+ return token{}, l.error("invalid lexeme")
}
-func tokens(data []byte) iter.Seq2[token, error] {
- return func(yield func(token, error) bool) {
- (&lexer{data: data, yieldTok: yield}).tokens()
- }
+func newLexer(data []byte) *lexer {
+ return &lexer{data: data}
}