///|
/// Line parser state and basic helpers.
///|
priv struct LineParser {
lines : Array[String]
mut index : Int32
offsets : Array[Int32]
mut func_depth : Int32
mut async_depth : Int32
mut block_depth : Int32
mut last_dedent_from : Int32?
}
///|
fn LineParser::new(source : String) -> LineParser {
let lines : Array[String] = []
for line in source.split("\n") {
lines.push(line.to_owned())
}
let offsets : Array[Int32] = []
let mut offset = 0
for line in lines {
offsets.push(offset)
offset += line.length() + 1
}
LineParser::{
lines,
index: 0,
offsets,
func_depth: 0,
async_depth: 0,
block_depth: 0,
last_dedent_from: None,
}
}
///|
fn LineParser::invalid_syntax_at_line(
self : LineParser,
line : Int32,
) -> ParseError {
let line_index = if line <= 0 { 0 } else { line - 1 }
let base = self.offsets[line_index]
make_parse_error(ParseErrorKind::Syntax, "invalid syntax".to_string(), {
kind: Eof,
start: base,
end: base + 1,
line,
column: 1,
})
}
///|
fn LineParser::peek_next_indent(self : LineParser) -> Int32 {
let mut idx = self.index
while idx < self.lines.length() {
let line = self.lines[idx]
let trimmed = line.trim(chars=" \t").to_owned()
if trimmed.length() == 0 || trimmed.has_prefix("#") {
idx += 1
continue
}
return count_indent(line)
}
0
}
///|
fn LineParser::peek_next_significant_index(self : LineParser) -> Int32? {
let mut idx = self.index
while idx < self.lines.length() {
let line = self.lines[idx]
let trimmed = line.trim(chars=" \t").to_owned()
if trimmed.length() == 0 || trimmed.has_prefix("#") {
idx += 1
continue
}
return Some(idx)
}
None
}
///|
fn LineParser::clamp_line_index(self : LineParser, idx : Int32) -> Int32 {
if idx < 0 {
return 0
}
if idx >= self.lines.length() {
if self.lines.length() == 0 {
return 0
}
return self.lines.length() - 1
}
idx
}