// ParseInput — tracks position within the source string
///|
pub(all) struct ParseInput {
source : String
pos : Int
line : Int
col : Int
} derive(Debug, Eq)
///|
pub fn ParseInput::new(source : String) -> ParseInput {
ParseInput::{ source, pos: 0, line: 1, col: 1 }
}
///|
pub fn ParseInput::current(self : ParseInput) -> String {
if self.pos >= self.source.length() {
""
} else {
self.source.substring(start=self.pos, end=self.pos + 1)
}
}
///|
pub fn ParseInput::advance(self : ParseInput) -> ParseInput {
if self.pos >= self.source.length() {
self
} else {
let ch = self.current()
let new_line = if ch == "\n" { self.line + 1 } else { self.line }
let new_col = if ch == "\n" { 1 } else { self.col + 1 }
ParseInput::{ ..self, pos: self.pos + 1, line: new_line, col: new_col }
}
}
///|
pub fn ParseInput::advance_by(self : ParseInput, n : Int) -> ParseInput {
advance_n(self, n)
}
///|
fn advance_n(input : ParseInput, n : Int) -> ParseInput {
if n <= 0 {
input
} else {
advance_n(input.advance(), n - 1)
}
}
///|
pub fn ParseInput::is_eof(self : ParseInput) -> Bool {
self.pos >= self.source.length()
}
///|
pub fn ParseInput::remaining(self : ParseInput) -> String {
if self.pos >= self.source.length() {
""
} else {
self.source.substring(start=self.pos, end=self.source.length())
}
}
///|
pub fn ParseInput::position(self : ParseInput) -> String {
"line " + self.line.to_string() + ", col " + self.col.to_string()
}
///|
pub fn ParseInput::slice(
self : ParseInput,
start_pos : Int,
end_pos : Int,
) -> String {
if start_pos >= self.source.length() {
return ""
}
let end = if end_pos > self.source.length() {
self.source.length()
} else {
end_pos
}
self.source.substring(start=start_pos, end~)
}
///|
pub fn ParseInput::source_len(self : ParseInput) -> Int {
self.source.length()
}