-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtokens.go
188 lines (149 loc) · 5.12 KB
/
tokens.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package golex
import (
"fmt"
"iter"
)
// Tokens represents a set of tokens
type Tokens []Token
// TokenCollection represents an iterable collection of tokens
type TokenCollection struct {
tokens Tokens
tokensLength int
cursor int
}
func NewTokenCollection(tokens Tokens) TokenCollection {
return TokenCollection{tokens: tokens, tokensLength: len(tokens), cursor: 0}
}
func (ti *TokenCollection) Iter() iter.Seq2[int, Token] {
return func(yield func(int, Token) bool) {
for ti.cursor = 0; ti.cursor < ti.tokensLength; ti.cursor++ {
if !yield(ti.cursor, ti.tokens[ti.cursor]) {
return
}
}
}
}
// IncrementCursor increments the cursor by the amount
func (t *TokenCollection) IncrementCursor(amount int) {
t.cursor += amount
}
func (t TokenCollection) CursorIsOutOfBounds() bool {
return t.cursor >= t.tokensLength
}
func (t TokenCollection) ReachedEOF() bool {
return t.TokenAtCursor().Type == TypeEof
}
// NextToken increments the cursor position by 1
// and returns the token at that position
func (t *TokenCollection) NextToken() Token {
t.cursor += 1
return t.TokenAtPosition(t.cursor)
}
// TokenAtCursor returns the token at the current cursor position
func (t *TokenCollection) TokenAtCursor() Token {
return t.TokenAtPosition(t.cursor)
}
// TokenAtPosition returns the token at the absolute position
func (t *TokenCollection) TokenAtPosition(pos int) Token {
// TODO: add out of bounds checking
return t.tokens[pos]
}
// TokenAtRelativePosition returns the token at the position relative to the cursor
func (t *TokenCollection) TokenAtRelativePosition(pos int) Token {
// TODO: add out of bounds checking
return t.tokens[t.cursor+pos]
}
// CollectTokensBetweenParentheses collects all the tokens between
// the opening and closing parentheses starting at the offset start
// It assumes that the offset start contains the opening parenthesis.
// Nested parenthesis will be contained in the output tokens until
// the matching closing parenthesis to the start is found.
// In addition it returns the start and end cursor position for the collected portion
func (t *TokenCollection) CollectTokensBetweenParentheses() (Tokens, int, int, error) {
return t.CollectTokensBetween(TypeOpenParen, TypeCloseParen)
}
// CollectTokensBetweenCurlyBraced collects all the tokens between
// the opening and closing curly braces starting at the offset start
// It assumes that the offset start contains the opening curly brace.
// Nested curly braces will be contained in the output tokens until
// the matching closing curly brace to the start is found.
// In addition it returns the start and end cursor position for the collected portion
func (t *TokenCollection) CollectTokensBetweenCurlyBraces() (Tokens, int, int, error) {
return t.CollectTokensBetween(TypeOpenCurly, TypeCloseCurly)
}
// CollectTokensBetween collects all the tokens between the open
// and close type starting at the offset start
// it assumes that the offset start contains the opening token.
// Nested openers and closers will be contained in the output
// tokens until the matching closer is found.
// In addition it returns the start and end cursor position for the collected portion
func (t *TokenCollection) CollectTokensBetween(open TokenType, close TokenType) (Tokens, int, int, error) {
collected := Tokens{}
token := t.TokenAtCursor()
if !token.TypeIs(open) {
return collected, -1, -1, fmt.Errorf("Token at start offset is not of opener type %s", open)
}
start := t.cursor
end := start
level := 1
for !token.TypeIs(TypeEof) {
end = t.cursor
t.cursor += 1
token = t.tokens[t.cursor]
if token.TypeIs(TypeEof) {
return collected, start, end, fmt.Errorf("Unexpected EndOfFile")
}
if token.TypeIs(close) {
level -= 1
if level == 0 {
break
}
}
if token.TypeIs(open) {
level += 1
}
collected = append(collected, token)
}
return collected, start, end, nil
}
func (t *TokenCollection) CollectTokensDelimited(tokenType TokenType, delimiter TokenType) (Tokens, error) {
tokens := Tokens{}
token := t.TokenAtCursor()
for !token.TypeIs(TypeEof) {
if !token.TypeIs(tokenType) {
return tokens, fmt.Errorf("expected %s but found %s", tokenType, token.Type)
}
tokens = append(tokens, token)
if !t.TokenAtRelativePosition(1).TypeIs(delimiter) {
break
}
t.IncrementCursor(2) // Consume the delimiter and get the next token after it
token = t.TokenAtCursor()
}
return tokens, nil
}
func (t *TokenCollection) CollectAnyTokensDelimited(delimiter TokenType) ([]Token, error) {
tokens := []Token{}
token := t.TokenAtCursor()
for !token.TypeIs(TypeEof) {
tokens = append(tokens, token)
if !t.TokenAtRelativePosition(1).TypeIs(delimiter) {
break
}
t.IncrementCursor(2) // Consume the delimiter and get the next token after it
token = t.TokenAtCursor()
}
return tokens, nil
}
func (t *TokenCollection) CollectTokensUntil(delimiter TokenType) ([]Token, error) {
tokens := []Token{}
token := t.TokenAtCursor()
for !token.TypeIs(TypeEof) && !token.TypeIs(delimiter) {
tokens = append(tokens, token)
if !t.TokenAtRelativePosition(1).TypeIs(delimiter) {
break
}
token = t.NextToken()
}
return tokens, nil
}