///|
/// Intermediate nodes encode one prefix of a production, not an AST node.
pub(all) enum NodeKind {
TokenLeaf(Int32)
SymbolNode(String)
Intermediate(Int32, Int32)
} derive(Eq, Debug)
///|
pub extend NodeKind with Eq::{equal, not_equal}
///|
pub extend NodeKind with @moonbitlang/core/debug.Debug::{to_repr}
///|
/// A family is an AND-edge; a node's families are OR-alternatives.
pub(all) struct Family {
rule : Int32
children : Array[Int32]
} derive(Eq, Debug)
///|
pub extend Family with Eq::{equal, not_equal}
///|
pub extend Family with @moonbitlang/core/debug.Debug::{to_repr}
///|
/// Read-only snapshot view. Mutating its arrays cannot mutate the forest.
pub(all) struct NodeInfo {
kind : NodeKind
start : Int32
end : Int32
alternatives : Array[Family]
} derive(Eq, Debug)
///|
pub extend NodeInfo with Eq::{equal, not_equal}
///|
pub extend NodeInfo with @moonbitlang/core/debug.Debug::{to_repr}
///|
struct Node {
kind : NodeKind
start : Int32
end : Int32
families : Array[Family]
}
///|
/// Forest IDs are local to this snapshot; spans here are token-index intervals.
pub struct Forest {
nodes : Array[Node]
tokens : Array[Token]
rules : Array[Rule]
root : Int32?
}
///|
fn copy_family(f : Family) -> Family {
{ rule: f.rule, children: f.children.copy(), }
}
///|
fn copy_rule(r : Rule) -> Rule {
{ lhs: r.lhs, rhs: r.rhs.copy(), label: r.label, }
}
///|
pub fn Forest::root(self : Forest) -> Int32? {
self.root
}
///|
pub fn Forest::node_count(self : Forest) -> Int32 {
self.nodes.length()
}
///|
pub fn Forest::node(self : Forest, id : Int32) -> Result[NodeInfo, Problem] {
if id < 0 || id >= self.nodes.length() {
return Err(InvalidNode(id))
}
let n = self.nodes[id]
Ok({
kind: n.kind,
start: n.start,
end: n.end,
alternatives: n.families.map(copy_family),
})
}
///|
pub fn Forest::token_at(self : Forest, id : Int32) -> Result[Token, Problem] {
if id < 0 || id >= self.tokens.length() {
Err(InvalidToken(id, "index outside forest token snapshot"))
} else {
Ok(self.tokens[id])
}
}
///|
pub fn Forest::rule_at(self : Forest, id : Int32) -> Result[Rule, Problem] {
if id < 0 || id >= self.rules.length() {
Err(InvalidGrammar("rule index outside forest snapshot"))
} else {
Ok(copy_rule(self.rules[id]))
}
}