strings.textscanner: add .current/0, .peek_back/0, .peek_back_n/1 and .goto_end/1 methods
parent
ce3681ee8f
commit
a21ee1abd4
|
@ -35,6 +35,7 @@ pub fn (ss &TextScanner) remaining() int {
|
||||||
|
|
||||||
// next returns the next character code from the input text.
|
// next returns the next character code from the input text.
|
||||||
// next returns `-1` if it can't reach the next character.
|
// next returns `-1` if it can't reach the next character.
|
||||||
|
// next advances the scanner position.
|
||||||
[direct_array_access; inline]
|
[direct_array_access; inline]
|
||||||
pub fn (mut ss TextScanner) next() int {
|
pub fn (mut ss TextScanner) next() int {
|
||||||
if ss.pos < ss.ilen {
|
if ss.pos < ss.ilen {
|
||||||
|
@ -76,6 +77,8 @@ pub fn (ss &TextScanner) peek() int {
|
||||||
|
|
||||||
// peek_n returns the character code from the input text at position + `n`.
|
// 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.
|
// 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]
|
[direct_array_access; inline]
|
||||||
pub fn (ss &TextScanner) peek_n(n int) int {
|
pub fn (ss &TextScanner) peek_n(n int) int {
|
||||||
if ss.pos + n < ss.ilen {
|
if ss.pos + n < ss.ilen {
|
||||||
|
@ -103,7 +106,49 @@ pub fn (mut ss TextScanner) back_n(n int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reset resets the internal state of the scanner.
|
// 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() {
|
pub fn (mut ss TextScanner) reset() {
|
||||||
ss.pos = 0
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -89,6 +89,36 @@ fn test_back_n() {
|
||||||
assert s.next() == `b`
|
assert s.next() == `b`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_peek_back() {
|
||||||
|
mut s := textscanner.new('abc')
|
||||||
|
assert s.next() == `a`
|
||||||
|
assert s.next() == `b`
|
||||||
|
// check that calling .peek_back() multiple times
|
||||||
|
// does not change the state:
|
||||||
|
assert s.peek_back() == `a`
|
||||||
|
assert s.peek_back() == `a`
|
||||||
|
assert s.peek_back() == `a`
|
||||||
|
// advance, then peek_back again:
|
||||||
|
assert s.next() == `c`
|
||||||
|
assert s.peek_back() == `b`
|
||||||
|
// peeking before the start:
|
||||||
|
s.reset()
|
||||||
|
assert s.peek_back() == -1
|
||||||
|
// peeking right at the end:
|
||||||
|
s.goto_end()
|
||||||
|
assert s.peek_back() == `b`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_peek_back_n() {
|
||||||
|
mut s := textscanner.new('abc')
|
||||||
|
s.goto_end()
|
||||||
|
assert s.peek_back_n(0) == `c`
|
||||||
|
assert s.peek_back_n(1) == `b`
|
||||||
|
assert s.peek_back_n(2) == `a`
|
||||||
|
assert s.peek_back_n(3) == -1
|
||||||
|
assert s.peek_back_n(4) == -1
|
||||||
|
}
|
||||||
|
|
||||||
fn test_reset() {
|
fn test_reset() {
|
||||||
mut s := textscanner.new('abc')
|
mut s := textscanner.new('abc')
|
||||||
assert s.next() == `a`
|
assert s.next() == `a`
|
||||||
|
@ -98,3 +128,32 @@ fn test_reset() {
|
||||||
s.reset()
|
s.reset()
|
||||||
assert s.next() == `a`
|
assert s.next() == `a`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_current() {
|
||||||
|
mut s := textscanner.new('abc')
|
||||||
|
assert s.current() == -1
|
||||||
|
assert s.next() == `a`
|
||||||
|
assert s.current() == `a`
|
||||||
|
assert s.current() == `a`
|
||||||
|
assert s.peek_back() == -1
|
||||||
|
assert s.next() == `b`
|
||||||
|
assert s.current() == `b`
|
||||||
|
assert s.current() == `b`
|
||||||
|
assert s.peek_back() == `a`
|
||||||
|
assert s.next() == `c`
|
||||||
|
assert s.current() == `c`
|
||||||
|
assert s.next() == -1
|
||||||
|
assert s.current() == `c`
|
||||||
|
assert s.next() == -1
|
||||||
|
assert s.current() == `c`
|
||||||
|
s.reset()
|
||||||
|
assert s.current() == -1
|
||||||
|
assert s.next() == `a`
|
||||||
|
assert s.current() == `a`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_goto_end() {
|
||||||
|
mut s := textscanner.new('abc')
|
||||||
|
s.goto_end()
|
||||||
|
assert s.current() == `c`
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue