strings.textscanner, examples: add TextScanner .skip_whitespace/0, .peek_u8/0, .peek_n_u8/0, add examples/mini_calculator_recursive_descent.v (#23001)

This commit is contained in:
Delyan Angelov 2024-11-28 21:17:24 +02:00 committed by GitHub
parent acad4c2810
commit c7ee45fc64
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 167 additions and 1 deletions

View file

@ -7,7 +7,7 @@ pub struct TextScanner {
pub:
input string
ilen int
mut:
pub mut:
pos int // current position; pos is *always* kept in [0,ilen]
}
@ -75,6 +75,19 @@ pub fn (ss &TextScanner) peek() int {
return -1
}
// peek_u8 returns the *next* character code from the input text, as a byte/u8.
// unlike `next()`, `peek_u8()` does not change the state of the scanner.
// Note: peek_u8 returns `0`, if it can't peek the next character.
// Note: use `peek()`, instead of `peek_u8()`, if your input itself can
// legitimately contain bytes with value `0`.
@[direct_array_access; inline]
pub fn (ss &TextScanner) peek_u8() u8 {
if ss.pos < ss.ilen {
return ss.input[ss.pos]
}
return 0
}
// 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() .
@ -87,6 +100,19 @@ pub fn (ss &TextScanner) peek_n(n int) int {
return -1
}
// peek_n_u8 returns the character code from the input text, at position + `n`,
// as a byte/u8.
// Note: peek_n_u8 returns `0`, if it can't peek the next character.
// Note: use `peek_n()`, instead of `peek_n_u8()`, if your input itself can
// legitimately contain bytes with value `0`.
@[direct_array_access; inline]
pub fn (ss &TextScanner) peek_n_u8(n int) u8 {
if ss.pos + n < ss.ilen {
return ss.input[ss.pos + n]
}
return 0
}
// back goes back one character from the current scanner position.
@[inline]
pub fn (mut ss TextScanner) back() {
@ -152,3 +178,10 @@ pub fn (mut ss TextScanner) reset() {
pub fn (mut ss TextScanner) goto_end() {
ss.pos = ss.ilen
}
// skip_whitespace advances the scanner pass any space characters in the input.
pub fn (mut ss TextScanner) skip_whitespace() {
for ss.ilen - ss.pos > 0 && ss.peek_u8().is_space() {
ss.next()
}
}

View file

@ -183,3 +183,34 @@ fn test_goto_end() {
s.goto_end()
assert s.current() == `c`
}
fn test_skip_whitespace() {
mut s := textscanner.new('abc d \n xyz')
assert s.current() == -1
assert s.next() == `a`
assert s.next() == `b`
assert s.next() == `c`
s.skip_whitespace()
assert s.next() == `d`
s.skip_whitespace()
assert s.next() == `x`
assert s.next() == `y`
assert s.next() == `z`
}
fn test_peek_u8() {
mut s := textscanner.new('abc')
assert s.peek_u8() == `a`
assert !s.peek_u8().is_digit()
assert s.next() == `a`
assert s.peek_u8() == `b`
}
fn test_peek_n_u8() {
mut s := textscanner.new('abc')
assert s.peek_n_u8(0) == `a`
assert s.peek_n_u8(1) == `b`
assert s.peek_n_u8(2) == `c`
assert s.peek_n_u8(3) == 0
assert s.peek_n_u8(4) == 0
}