///|
pub(all) struct Span {
start : Int
end : Int
} derive(Eq, Debug)
///|
pub fn Span::new(start : Int, end : Int) -> Span {
if start <= end {
{ start, end }
} else {
{ start: end, end: start }
}
}
///|
pub fn Span::length(self : Span) -> Int {
self.end - self.start
}
///|
pub fn Span::is_empty(self : Span) -> Bool {
self.start == self.end
}
///|
pub(all) struct SourceFile {
file_name : String
text : String
}
///|
pub fn SourceFile::new(file_name : String, text : String) -> SourceFile {
{ file_name, text }
}
///|
pub fn SourceFile::name(self : SourceFile) -> String {
self.file_name
}
///|
pub fn SourceFile::text(self : SourceFile) -> String {
self.text
}
///|
fn line_col_from(
chars : Array[Char],
limit : Int,
index : Int,
line : Int,
column : Int,
) -> (Int, Int) {
if index >= limit {
(line, column)
} else if chars[index] == '\n' {
line_col_from(chars, limit, index + 1, line + 1, 0)
} else {
line_col_from(chars, limit, index + 1, line, column + 1)
}
}
///|
pub fn SourceFile::line_col(self : SourceFile, offset : Int) -> (Int, Int) {
let chars = self.text.to_array()
let limit = if offset < 0 {
0
} else if offset > chars.length() {
chars.length()
} else {
offset
}
line_col_from(chars, limit, 0, 0, 0)
}
///|
pub fn SourceFile::slice(self : SourceFile, span : Span) -> String {
let start = if span.start < 0 { 0 } else { span.start }
let end = if span.end > self.text.length() {
self.text.length()
} else {
span.end
}
if start >= end {
""
} else {
self.text.sub(start~, end~).to_owned()
}
}