v/vlib/strings/textscanner/textscanner.v

108 lines
2.2 KiB
V

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]
}
pub fn new(input string) TextScanner {
return TextScanner{
input: input
ilen: input.len
}
}
[unsafe]
pub fn (mut ss TextScanner) free() {
unsafe {
ss.input.free()
}
}
// remaining - return how many characters remain in the input
[inline]
pub fn (ss &TextScanner) remaining() int {
return ss.ilen - ss.pos
}
// next - safely get a character from the input text
[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 - skip one character; skip() is slightly faster than .next()
// and ignoring the result.
[inline]
pub fn (mut ss TextScanner) skip() {
if ss.pos + 1 < ss.ilen {
ss.pos++
}
}
// skip_n - skip the next `n` characters
[inline]
pub fn (mut ss TextScanner) skip_n(n int) {
ss.pos += n
if ss.pos > ss.ilen {
ss.pos = ss.ilen
}
}
// peek - safely get the *next* character from the input text
// if the character exists. NB: unlike next(), peek() *will 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 - safely get the *next* character from the input text at the current
// position + `n`, if the character exists, or else it returns -1.
// NB: .peek() and .peek_offset(0) are equivalent.
[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 - go back a character
[inline]
pub fn (mut ss TextScanner) back() {
if ss.pos > 0 {
ss.pos--
}
}
// back_n - go back `n` characters
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
}
}
// reset - go back to the start of the input
pub fn (mut ss TextScanner) reset() {
ss.pos = 0
}