#[derive(Clone, Debug, PartialEq, Eq)]
#[allow(clippy::struct_excessive_bools)]
pub struct GrammarNode {
pub term: &'static str,
pub named: bool,
pub field: Option<&'static str>,
pub start: usize,
pub end: usize,
pub is_error: bool,
pub is_missing: bool,
pub has_error: bool,
pub extra: bool,
pub children: Vec<Self>,
}
impl GrammarNode {
pub const fn node(term: &'static str, start: usize, end: usize, children: Vec<Self>) -> Self {
Self {
term,
named: true,
field: None,
start,
end,
is_error: false,
is_missing: false,
has_error: false,
extra: false,
children,
}
}
pub const fn anonymous(term: &'static str, start: usize, end: usize) -> Self {
let mut token = Self::node(term, start, end, Vec::new());
token.named = false;
token
}
pub const fn extra(term: &'static str, named: bool, start: usize, end: usize) -> Self {
let mut token = Self::node(term, start, end, Vec::new());
token.named = named;
token.extra = true;
token
}
pub const fn missing(term: &'static str, named: bool, at: usize) -> Self {
let mut node = Self::node(term, at, at, Vec::new());
node.named = named;
node.is_missing = true;
node
}
pub const fn error(start: usize, end: usize, children: Vec<Self>) -> Self {
let mut node = Self::node("ERROR", start, end, children);
node.is_error = true;
node
}
pub fn spanning(term: &'static str, children: Vec<Self>) -> Self {
let start = children.first().map_or(0, |child| child.start);
let end = children.last().map_or(0, |child| child.end);
Self::node(term, start, end, children)
}
pub const fn with_field(mut self, field: &'static str) -> Self {
self.field = Some(field);
self
}
pub const fn is_token(&self) -> bool {
self.children.is_empty() && self.start < self.end
}
}
pub fn fill_extras(
mut root: GrammarNode,
lex_gap: &mut impl FnMut(usize, usize) -> Vec<GrammarNode>,
) -> GrammarNode {
fill(&mut root, true, lex_gap);
root
}
fn fill(
parent: &mut GrammarNode,
is_root: bool,
lex_gap: &mut impl FnMut(usize, usize) -> Vec<GrammarNode>,
) {
if !is_root && parent.children.is_empty() {
return;
}
let mut children = Vec::new();
let mut covered = parent.start;
for mut child in std::mem::take(&mut parent.children) {
if child.start > covered {
children.extend(lex_gap(covered, child.start));
}
fill(&mut child, false, lex_gap);
covered = covered.max(child.end);
children.push(child);
}
if parent.end > covered {
children.extend(lex_gap(covered, parent.end));
}
parent.children = children;
}
pub fn propagate_errors(tree: &mut GrammarNode) -> bool {
let mut has_error = tree.is_error || tree.is_missing;
for child in &mut tree.children {
has_error = propagate_errors(child) || has_error;
}
if has_error {
tree.has_error = true;
}
has_error
}