blob: 55251373b41f3700da943a259e37a3185c8c19ba (
plain)
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
|
module textscanner
// TextScanner simplifies writing small scanners/parsers
// by providing safe methods to scan texts character by
// character, peek for the next characters, go back, etc.
pub struct TextScanner {
pub:
input string
ilen int
mut:
pos int // current position; pos is *always* kept in [0,ilen]
}
// new returns a stack allocated instance of TextScanner.
pub fn new(input string) TextScanner {
return TextScanner{
input: input
ilen: input.len
}
}
// free frees all allocated resources.
[unsafe]
pub fn (mut ss TextScanner) free() {
unsafe {
ss.input.free()
}
}
// remaining returns how many characters remain from current position.
[inline]
pub fn (ss &TextScanner) remaining() int {
return ss.ilen - ss.pos
}
// next returns the next character code from the input text.
// next returns `-1` if it can't reach the next character.
// next advances the scanner position.
[direct_array_access; inline]
pub fn (mut ss TextScanner) next() int {
if ss.pos < ss.ilen {
opos := ss.pos
ss.pos++
return ss.input[opos]
}
return -1
}
// skip skips one character ahead; `skip()` is slightly faster than `.next()`.
// `skip()` does not return a result.
[inline]
pub fn (mut ss TextScanner) skip() {
if ss.pos + 1 < ss.ilen {
ss.pos++
}
}
// skip_n skips ahead `n` characters, stopping at the end of the input.
[inline]
pub fn (mut ss TextScanner) skip_n(n int) {
ss.pos += n
if ss.pos > ss.ilen {
ss.pos = ss.ilen
}
}
// peek returns the *next* character code from the input text.
// peek returns `-1` if it can't peek the next character.
// unlike `next()`, `peek()` does not change the state of the scanner.
[direct_array_access; inline]
pub fn (ss &TextScanner) peek() int {
if ss.pos < ss.ilen {
return ss.input[ss.pos]
}
return -1
}
// peek_n returns the character code from the input text at position + `n`.
// peek_n returns `-1` if it can't peek `n` characters ahead.
// ts.peek_n(0) == ts.current() .
// ts.peek_n(1) == ts.peek() .
[direct_array_access; inline]
pub fn (ss &TextScanner) peek_n(n int) int {
if ss.pos + n < ss.ilen {
return ss.input[ss.pos + n]
}
return -1
}
// back goes back one character from the current scanner position.
[inline]
pub fn (mut ss TextScanner) back() {
if ss.pos > 0 {
ss.pos--
}
}
// back_n goes back `n` characters from the current scanner position.
pub fn (mut ss TextScanner) back_n(n int) {
ss.pos -= n
if ss.pos < 0 {
ss.pos = 0
}
if ss.pos > ss.ilen {
ss.pos = ss.ilen
}
}
// peek_back returns the *previous* character code from the input text.
// peek_back returns `-1` if it can't peek the previous character.
// unlike `back()`, `peek_back()` does not change the state of the scanner.
[direct_array_access; inline]
pub fn (ss &TextScanner) peek_back() int {
return ss.peek_back_n(1)
}
// peek_back_n returns the character code from the input text at position - `n`.
// peek_back_n returns `-1` if it can't peek `n` characters back.
// ts.peek_back_n(0) == ts.current()
// ts.peek_back_n(1) == ts.peek_back()
[direct_array_access; inline]
pub fn (ss &TextScanner) peek_back_n(n int) int {
offset := n + 1
if ss.pos >= offset {
return ss.input[ss.pos - offset]
}
return -1
}
// current returns the current character code from the input text.
// current returns `-1` at the start of the input text.
// NB: after `c := ts.next()`, `ts.current()` will also return `c`.
[direct_array_access; inline]
pub fn (mut ss TextScanner) current() int {
if ss.pos > 0 {
return ss.input[ss.pos - 1]
}
return -1
}
// reset resets the internal state of the scanner
// After calling .reset(), .next() will start reading
// again from the start of the input text.
pub fn (mut ss TextScanner) reset() {
ss.pos = 0
}
// goto_end has the same effect as `for ts.next() != -1 {}`
// i.e. after calling .goto_end(), the scanner will be at
// the end of the input text. Further .next() calls will
// return -1, unless you go back.
pub fn (mut ss TextScanner) goto_end() {
ss.pos = ss.ilen
}
|