Skip to content

Commit fc9b09e

Browse files
committed
feat: update CustomLexerContext to CustomLexerCursor
Signed-off-by: Ian Lewis <ian@ianlewis.org>
1 parent 5da033c commit fc9b09e

File tree

6 files changed

+273
-284
lines changed

6 files changed

+273
-284
lines changed

README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ in addition to the underlying reader's position. When the token has been fully
130130
processed it can be emitted to a channel for further processing by the `Parser`.
131131

132132
Developers implement the token processing portion of the lexer by implementing
133-
`LexState` interface for each relevant lexer state. A `CustomLexerContext` is
133+
`LexState` interface for each relevant lexer state. A `CustomLexerCursor` is
134134
passed to each `LexState` during processing and includes a number of methods
135135
that can be used to advance through the input text.
136136

@@ -211,7 +211,7 @@ type LexState interface {
211211
// Run returns the next state to transition to or an error. If the returned
212212
// next state is nil or the returned error is io.EOF then the Lexer
213213
// finishes processing normally.
214-
Run(*CustomLexerContext) (LexState, error)
214+
Run(context.Context, *CustomLexerCursor) (LexState, error)
215215
}
216216
```
217217

@@ -238,23 +238,23 @@ advancing over the text.
238238

239239
```go
240240
// lexText tokenizes normal text.
241-
func lexText(ctx *lexparse.CustomLexerContext) (lexparse.LexState, error) {
241+
func lexText(ctx context.Context, c *lexparse.CustomLexerCursor) (lexparse.LexState, error) {
242242
for {
243-
p := ctx.PeekN(2)
243+
p := c.PeekN(2)
244244
switch string(p) {
245245
case tokenBlockStart, tokenVarStart:
246-
if ctx.Width() > 0 {
247-
ctx.Emit(lexTypeText)
246+
if c.Width() > 0 {
247+
c.Emit(lexTypeText)
248248
}
249249
return lexparse.LexStateFn(lexCode), nil
250250
default:
251251
}
252252

253253
// Advance the input.
254-
if !ctx.Advance() {
254+
if !c.Advance() {
255255
// End of input. Emit the text up to this point.
256-
if ctx.Width() > 0 {
257-
ctx.Emit(lexTypeText)
256+
if c.Width() > 0 {
257+
c.Emit(lexTypeText)
258258
}
259259
return nil, nil
260260
}

custom.go

Lines changed: 51 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -35,106 +35,113 @@ const EOF rune = -1
3535
type LexState interface {
3636
// Run returns the next state to transition to or an error. If the returned
3737
// error is io.EOF then the Lexer finishes processing normally.
38-
Run(ctx *CustomLexerContext) (LexState, error)
38+
Run(ctx context.Context, cursor *CustomLexerCursor) (LexState, error)
3939
}
4040

4141
type lexFnState struct {
42-
f func(*CustomLexerContext) (LexState, error)
42+
f func(context.Context, *CustomLexerCursor) (LexState, error)
4343
}
4444

4545
// Run implements [LexState.Run].
4646
//
4747
//nolint:ireturn // Returning interface required to satisfy [LexState.Run]
48-
func (s *lexFnState) Run(ctx *CustomLexerContext) (LexState, error) {
49-
return s.f(ctx)
48+
func (s *lexFnState) Run(ctx context.Context, cursor *CustomLexerCursor) (LexState, error) {
49+
return s.f(ctx, cursor)
5050
}
5151

5252
// LexStateFn creates a State from the given Run function.
5353
//
5454
//nolint:ireturn // Returning interface required to satisfy [LexState.Run]
55-
func LexStateFn(f func(*CustomLexerContext) (LexState, error)) LexState {
55+
func LexStateFn(f func(context.Context, *CustomLexerCursor) (LexState, error)) LexState {
5656
return &lexFnState{f}
5757
}
5858

59-
// CustomLexerContext is a context that carries a reference to the current
60-
// CustomLexer. It is passed to [LexState.Run] method to allow the state
61-
// implementation to interact with the lexer.
62-
type CustomLexerContext struct {
63-
//nolint:containedctx // Embedding context required for interface compliance.
64-
context.Context
65-
59+
// CustomLexerCursor is a type that allows for processing the input for the
60+
// CustomLexer. It provides methods to advance the reader, emit tokens, and
61+
// manage the current token being processed. It is designed to be used within
62+
// the [LexState.Run] method to allow the state implementation to interact with
63+
// the lexer without exposing the full CustomLexer implementation.
64+
type CustomLexerCursor struct {
6665
l *CustomLexer
6766
}
6867

68+
// NewCustomLexerCursor creates a new CustomLexerCursor with the given context
69+
// and CustomLexer.
70+
func NewCustomLexerCursor(l *CustomLexer) *CustomLexerCursor {
71+
return &CustomLexerCursor{
72+
l: l,
73+
}
74+
}
75+
6976
// Advance attempts to advance the underlying reader a single rune and returns
7077
// true if actually advanced. The current token cursor position is not updated.
71-
func (ctx *CustomLexerContext) Advance() bool {
72-
return ctx.l.advance(1, false) == 1
78+
func (c *CustomLexerCursor) Advance() bool {
79+
return c.l.advance(1, false) == 1
7380
}
7481

7582
// AdvanceN attempts to advance the underlying reader n runes and returns the
7683
// number actually advanced. The current token cursor position is not updated.
77-
func (ctx *CustomLexerContext) AdvanceN(n int) int {
78-
return ctx.l.advance(n, false)
84+
func (c *CustomLexerCursor) AdvanceN(n int) int {
85+
return c.l.advance(n, false)
7986
}
8087

8188
// Cursor returns the current position of the underlying cursor marking the
8289
// beginning of the current token being processed.
83-
func (ctx *CustomLexerContext) Cursor() Position {
84-
return ctx.l.cursor
90+
func (c *CustomLexerCursor) Cursor() Position {
91+
return c.l.cursor
8592
}
8693

8794
// Discard attempts to discard the next rune, advancing the current token
8895
// cursor, and returns true if actually discarded.
89-
func (ctx *CustomLexerContext) Discard() bool {
90-
return ctx.l.advance(1, true) == 1
96+
func (c *CustomLexerCursor) Discard() bool {
97+
return c.l.advance(1, true) == 1
9198
}
9299

93100
// DiscardN attempts to discard n runes, advancing the current token cursor
94101
// position, and returns the number actually discarded.
95-
func (ctx *CustomLexerContext) DiscardN(n int) int {
96-
return ctx.l.advance(n, true)
102+
func (c *CustomLexerCursor) DiscardN(n int) int {
103+
return c.l.advance(n, true)
97104
}
98105

99106
// DiscardTo searches the input for one of the given search strings, advancing
100107
// the reader, and stopping when one of the strings is found. The token cursor
101108
// is advanced and data prior to the search string is discarded. The string
102109
// found is returned. If no match is found an empty string is returned.
103-
func (ctx *CustomLexerContext) DiscardTo(query []string) string {
104-
return ctx.l.discardTo(query)
110+
func (c *CustomLexerCursor) DiscardTo(query []string) string {
111+
return c.l.discardTo(query)
105112
}
106113

107114
// Emit emits the token between the current cursor position and reader
108115
// position and returns the token. If the lexer is not currently active, this
109116
// is a no-op. This advances the current token cursor.
110-
func (ctx *CustomLexerContext) Emit(typ TokenType) *Token {
111-
return ctx.l.emit(typ)
117+
func (c *CustomLexerCursor) Emit(typ TokenType) *Token {
118+
return c.l.emit(typ)
112119
}
113120

114121
// Find searches the input for one of the given search strings, advancing the
115122
// reader, and stopping when one of the strings is found. The token cursor is
116123
// not advanced. The string found is returned. If no match is found an empty
117124
// string is returned.
118-
func (ctx *CustomLexerContext) Find(query []string) string {
119-
return ctx.l.find(query)
125+
func (c *CustomLexerCursor) Find(query []string) string {
126+
return c.l.find(query)
120127
}
121128

122129
// Ignore ignores the previous input and resets the token start position to
123130
// the current reader position.
124-
func (ctx *CustomLexerContext) Ignore() {
125-
ctx.l.ignore()
131+
func (c *CustomLexerCursor) Ignore() {
132+
c.l.ignore()
126133
}
127134

128135
// NextRune returns the next rune of input, advancing the reader while not
129136
// advancing the token cursor.
130-
func (ctx *CustomLexerContext) NextRune() rune {
131-
return ctx.l.nextRune()
137+
func (c *CustomLexerCursor) NextRune() rune {
138+
return c.l.nextRune()
132139
}
133140

134141
// Peek returns the next rune from the buffer without advancing the reader or
135142
// current token cursor.
136-
func (ctx *CustomLexerContext) Peek() rune {
137-
p := ctx.PeekN(1)
143+
func (c *CustomLexerCursor) Peek() rune {
144+
p := c.PeekN(1)
138145
if len(p) < 1 {
139146
return EOF
140147
}
@@ -145,24 +152,24 @@ func (ctx *CustomLexerContext) Peek() rune {
145152
// PeekN returns the next n runes from the buffer without advancing the reader
146153
// or current token cursor. PeekN may return fewer runes than requested if an
147154
// error occurs or at end of input.
148-
func (ctx *CustomLexerContext) PeekN(n int) []rune {
149-
return ctx.l.peekN(n)
155+
func (c *CustomLexerCursor) PeekN(n int) []rune {
156+
return c.l.peekN(n)
150157
}
151158

152159
// Pos returns the current position of the underlying reader.
153-
func (ctx *CustomLexerContext) Pos() Position {
154-
return ctx.l.pos
160+
func (c *CustomLexerCursor) Pos() Position {
161+
return c.l.pos
155162
}
156163

157164
// Token returns the current token value.
158-
func (ctx *CustomLexerContext) Token() string {
159-
return ctx.l.b.String()
165+
func (c *CustomLexerCursor) Token() string {
166+
return c.l.b.String()
160167
}
161168

162169
// Width returns the current width of the token being processed. It is
163170
// equivalent to l.Pos().Offset - l.Cursor().Offset.
164-
func (ctx *CustomLexerContext) Width() int {
165-
return ctx.l.pos.Offset - ctx.l.cursor.Offset
171+
func (c *CustomLexerCursor) Width() int {
172+
return c.l.pos.Offset - c.l.cursor.Offset
166173
}
167174

168175
// CustomLexer lexically processes a byte stream. It is implemented as a
@@ -240,10 +247,7 @@ func (l *CustomLexer) NextToken(ctx context.Context) *Token {
240247
return l.newToken(TokenTypeEOF)
241248
}
242249

243-
lexerCtx := &CustomLexerContext{
244-
Context: ctx,
245-
l: l,
246-
}
250+
cursor := NewCustomLexerCursor(l)
247251

248252
// If we have no tokens to return, we need to run the current state.
249253
for len(l.buf) == 0 && l.state != nil {
@@ -258,7 +262,7 @@ func (l *CustomLexer) NextToken(ctx context.Context) *Token {
258262

259263
var err error
260264

261-
l.state, err = l.state.Run(lexerCtx)
265+
l.state, err = l.state.Run(ctx, cursor)
262266
l.setErr(err)
263267

264268
if l.err != nil {

0 commit comments

Comments
 (0)