///|
/// A position in a Python source file.
///
/// Three numbers in three units, and keeping them apart is the first thing
/// this port has to get right, because Python itself does not:
///
/// * `line` is 1-based, as everything that reports a Python position is.
/// * `col` counts CODE POINTS from the start of the line, 0-based. This is
/// what the `tokenize` module reports and what a person means by a column.
/// CPython's `ast` nodes carry `col_offset`, which counts UTF-8 BYTES; the
/// reference checker prints that number, so a message in its format is
/// rendered through `Source::byte_col` and nothing else converts.
/// * `offset` counts UTF-16 code units from the start of the source, 0-based.
/// It exists to slice a MoonBit `String` and to hand a span to
/// `error-report`, and it is never reported.
pub(all) struct Pos {
line : Int
col : Int
offset : Int
} derive(Eq, Compare, Debug)
///|
/// The position before the first character.
pub let origin : Pos = { line: 1, col: 0, offset: 0, }
///|
/// `line:col`, in the format the reference's messages use.
pub fn Pos::to_display(self : Pos) -> String {
"\{self.line}:\{self.col}"
}
///|
/// A half-open range of a source file.
pub(all) struct Span {
start : Pos
end : Pos
} derive(Eq, Debug)
///|
/// The empty span at `p`, for something with no extent -- an unexpected end of
/// input, or a token the parser wanted and did not get.
pub fn Span::at(p : Pos) -> Span {
{ start: p, end: p, }
}
///|
/// A span standing for "nowhere": what the builders of `ast` give a node that
/// a code generator made up rather than read.
pub let nowhere : Span = { start: origin, end: origin, }
///|
/// The smallest span covering both.
pub fn Span::merge(self : Span, other : Span) -> Span {
let start = if self.start.offset <= other.start.offset {
self.start
} else {
other.start
}
let end = if self.end.offset >= other.end.offset {
self.end
} else {
other.end
}
{ start, end, }
}
///|
/// Length in UTF-16 code units -- the unit `error-report` spans are in.
pub fn Span::units(self : Span) -> Int {
self.end.offset - self.start.offset
}
///|
/// `l:c-l:c`, for a token dump.
pub fn Span::to_display(self : Span) -> String {
"\{self.start.to_display()}-\{self.end.to_display()}"
}