///|
priv struct Cursor {
source : String
index : Int
}
///|
fn Cursor::new(source : String) -> Cursor {
{ source, index: 0 }
}
///|
fn Cursor::is_end(self : Cursor) -> Bool {
self.index >= self.source.length()
}
///|
fn Cursor::peek(self : Cursor) -> Char? {
guard !self.is_end() else { None }
self.source.get_char(self.index)
}
///|
fn Cursor::code_unit_length(self : Cursor) -> Int {
self.source.length()
}
///|
fn Cursor::unsafe_char_at(self : Cursor, index : Int) -> Char {
self.source.get_char(index).unwrap()
}
///|
fn Cursor::next_char_index(self : Cursor, index : Int) -> Int {
match () {
_ if index >= self.code_unit_length() => index
_ if self.source.code_unit_at(index).is_leading_surrogate() => index + 2
_ => index + 1
}
}
///|
fn Cursor::advance_code_units(self : Cursor, amount : Int) -> Cursor {
{ source: self.source, index: self.index + amount }
}
///|
fn Cursor::with_index(self : Cursor, index : Int) -> Cursor {
{ source: self.source, index }
}
///|
fn Cursor::skip_whitespace(self : Cursor) -> Cursor {
let mut index = self.index
while index < self.code_unit_length() &&
self.unsafe_char_at(index).is_whitespace() {
index = self.next_char_index(index)
}
self.with_index(index)
}
///|
fn Cursor::slice_until(self : Cursor, end : Int) -> String {
self.source.sub(start=self.index, end~).to_owned()
}
///|
fn Cursor::error(self : Cursor, message : String) -> String {
error_at(self.index, message)
}
///|
fn error_at(index : Int, message : String) -> String {
"parse error at offset \{index}: \{message}"
}