///|
pub struct Position {
priv offset : Int
priv line : Int
priv column : Int
}
///|
pub fn Position::offset(self : Position) -> Int {
self.offset
}
///|
pub fn Position::line(self : Position) -> Int {
self.line
}
///|
pub fn Position::column(self : Position) -> Int {
self.column
}
///|
pub struct Span {
priv start : Position
priv end : Position
}
///|
pub fn Span::start(self : Span) -> Position {
self.start
}
///|
pub fn Span::end(self : Span) -> Position {
self.end
}
///|
pub fn Span::length(self : Span) -> Int {
self.end.offset() - self.start.offset()
}
///|
pub struct Located[T] {
priv value : T
priv span : Span
}
///|
pub fn[T] Located::new(value : T, span : Span) -> Located[T] {
{ value, span, }
}
///|
pub fn[T] Located::value(self : Located[T]) -> T {
self.value
}
///|
pub fn[T] Located::span(self : Located[T]) -> Span {
self.span
}
///|
pub fn[T, U] Located::map(
self : Located[T],
transform : (T) -> U,
) -> Located[U] {
{ value: transform(self.value), span: self.span, }
}
///|
pub struct Source {
priv text : String
priv length : Int
priv line_starts : Array[Int]
}
///|
pub fn Source::new(text : String) -> Source {
let line_starts = [0]
let mut length = 0
for char in text {
length = length + 1
if char == '\n' {
line_starts.push(length)
}
}
{ text, length, line_starts, }
}
///|
pub fn Source::text(self : Source) -> String {
self.text
}
///|
pub fn Source::length(self : Source) -> Int {
self.length
}
///|
pub fn Source::line_count(self : Source) -> Int {
self.line_starts.length()
}
///|
pub fn Source::position_at(self : Source, offset : Int) -> Position? {
if offset < 0 || offset > self.length {
None
} else {
let mut line_index = 0
for index = 1; index < self.line_starts.length(); index = index + 1 {
if self.line_starts[index] > offset {
break
}
line_index = index
}
let line_start = self.line_starts[line_index]
Some({ offset, line: line_index + 1, column: offset - line_start + 1, })
}
}
///|
pub fn Source::span(self : Source, start : Int, end : Int) -> Span? {
if end < start {
None
} else {
match (self.position_at(start), self.position_at(end)) {
(Some(start), Some(end)) => Some({ start, end, })
_ => None
}
}
}
///|
pub fn Source::error_position(
self : Source,
error : @parsec.ParseError,
) -> Position? {
self.position_at(error.offset())
}