///|
pub(all) enum TokenKind {
Whitespace
OpenObject
CloseObject
OpenArray
CloseArray
Colon
Comma
StringToken
NumberToken
TrueToken
FalseToken
NullToken
} derive(Eq, Debug)
///|
pub struct Token {
kind : TokenKind
span : Span
text : String
} derive(Debug)
///|
pub fn Token::kind(self : Token) -> TokenKind {
self.kind
}
///|
pub fn Token::span(self : Token) -> Span {
self.span
}
///|
pub fn Token::text(self : Token) -> String {
self.text
}
///|
pub fn CstDocument::slice(self : CstDocument, span : Span) -> String? {
if span.end > self.source.length() {
None
} else {
Some(self.source[span.start:span.end].to_owned())
}
}
///|
/// Tokenize the already-checked source, including every trivia occurrence.
pub fn CstDocument::tokens(self : CstDocument) -> Array[Token] {
let tokens = []
let mut pos = 0
while pos < self.source.length() {
let start = pos
let c = self.source.code_unit_at(pos)
pos += 1
let kind = match c {
123 => OpenObject
125 => CloseObject
91 => OpenArray
93 => CloseArray
58 => Colon
44 => Comma
32 | 9 | 10 | 13 => {
while pos < self.source.length() {
match self.source.code_unit_at(pos) {
32 | 9 | 10 | 13 => pos += 1
_ => break
}
}
Whitespace
}
34 => {
while pos < self.source.length() {
let next = self.source.code_unit_at(pos)
pos += 1
if next == 92 {
pos += 1
} else if next == 34 {
break
}
}
StringToken
}
_ => {
while pos < self.source.length() {
match self.source.code_unit_at(pos) {
32 | 9 | 10 | 13 | 44 | 93 | 125 => break
_ => pos += 1
}
}
match c {
116 => TrueToken
102 => FalseToken
110 => NullToken
_ => NumberToken
}
}
}
tokens.push({
kind,
span: { start, end: pos, },
text: self.source[start:pos].to_owned(),
})
}
tokens
}
///|
pub struct Position {
line : Int32
column : Int32
} derive(Eq, Debug)
///|
pub fn Position::line(self : Position) -> Int32 {
self.line
}
///|
pub fn Position::column(self : Position) -> Int32 {
self.column
}
///|
pub struct Location {
source_id : String?
node_index : Int32
value_span : Span
key_span : Span?
priv node : NodeId
} derive(Debug)
///|
pub fn Location::source_id(self : Location) -> String? {
self.source_id
}
///|
/// Index into the owning CST only. It is not stable across parses or edits.
pub fn Location::node_index(self : Location) -> Int32 {
self.node_index
}
///|
/// The node as a handle that `CstDocument::replace_value` accepts.
pub fn Location::node(self : Location) -> NodeId {
self.node
}
///|
pub fn Location::value_span(self : Location) -> Span {
self.value_span
}
///|
pub fn Location::key_span(self : Location) -> Span? {
self.key_span
}
///|
pub struct SourceMap {
cst : CstDocument
line_starts : Array[Int32]
} derive(Debug)
///|
pub fn CstDocument::source_map(self : CstDocument) -> SourceMap {
let line_starts = [0]
let mut i = 0
while i < self.source.length() {
let c = self.source.code_unit_at(i)
i += 1
if c == 13 {
if i < self.source.length() && self.source.code_unit_at(i) == 10 {
i += 1
}
line_starts.push(i)
} else if c == 10 {
line_starts.push(i)
}
}
{ cst: self, line_starts, }
}
///|
pub fn SourceMap::position(self : SourceMap, offset : Int32) -> Position? {
if offset < 0 || offset > self.cst.source.length() {
return None
}
let mut low = 0
let mut high = self.line_starts.length()
while low + 1 < high {
let mid = low + (high - low) / 2
if self.line_starts[mid] <= offset {
low = mid
} else {
high = mid
}
}
Some({ line: low + 1, column: offset - self.line_starts[low] + 1, })
}
///|
/// Return all occurrences. Duplicate object names have no implicit winner.
pub fn SourceMap::locations(
self : SourceMap,
path : Array[String],
) -> Array[Location] {
let mut indices = [0]
for part in path {
let next = []
for index in indices {
let node = self.cst.nodes[index]
for ordinal, child in node.children {
if self.cst.nodes[child].key.unwrap_or(ordinal.to_string()) == part {
next.push(child)
}
}
}
indices = next
if indices.is_empty() {
break
}
}
indices.map(index => {
let node = self.cst.nodes[index]
{
source_id: self.cst.source_id,
node_index: index,
value_span: node.span,
key_span: node.key_span,
node: { index, source: self.cst.source },
}
})
}
///|
pub extend TokenKind with Eq::{equal, not_equal}
///|
pub extend TokenKind with @debug.Debug::{to_repr}
///|
pub extend Token with @debug.Debug::{to_repr}
///|
pub extend Position with Eq::{equal, not_equal}
///|
pub extend Position with @debug.Debug::{to_repr}
///|
pub extend Location with @debug.Debug::{to_repr}
///|
pub extend SourceMap with @debug.Debug::{to_repr}