use alloc::{string::String, vec::Vec};
use core::fmt::Write as _;
use diag_lang::{Diagnostic, Severity};
use syntax_lang::{Element, Node};
use crate::{Language, kind::Kind};
#[derive(Clone, Debug)]
pub struct Parse<'a> {
language: &'a Language,
source: &'a str,
tree: Node<Kind>,
diagnostics: Vec<Diagnostic>,
}
impl<'a> Parse<'a> {
pub(crate) fn new(
language: &'a Language,
source: &'a str,
tree: Node<Kind>,
diagnostics: Vec<Diagnostic>,
) -> Self {
Self {
language,
source,
tree,
diagnostics,
}
}
#[inline]
#[must_use]
pub fn tree(&self) -> &Node<Kind> {
&self.tree
}
#[inline]
#[must_use]
pub fn source(&self) -> &'a str {
self.source
}
#[inline]
#[must_use]
pub fn language(&self) -> &'a Language {
self.language
}
#[inline]
#[must_use]
pub fn diagnostics(&self) -> &[Diagnostic] {
&self.diagnostics
}
#[must_use]
pub fn has_errors(&self) -> bool {
self.diagnostics
.iter()
.any(|d| d.severity() == Severity::Error)
}
pub fn report(&mut self, diagnostic: Diagnostic) {
self.diagnostics.push(diagnostic);
}
#[inline]
#[must_use]
pub fn into_tree(self) -> Node<Kind> {
self.tree
}
#[must_use]
pub fn dump(&self) -> String {
let mut out = String::new();
let mut stack: Vec<(&Element<Kind>, usize)> = Vec::new();
let line = |out: &mut String, depth: usize, kind: Kind, start: u32, end: u32| {
for _ in 0..depth {
out.push_str(" ");
}
let _ = write!(out, "{}@{start}..{end}", self.language.kind_name(kind));
};
let span = self.tree.span();
line(
&mut out,
0,
*self.tree.kind(),
span.start().to_u32(),
span.end().to_u32(),
);
out.push('\n');
stack.extend(self.tree.children().map(|c| (c, 1)));
stack.reverse();
while let Some((element, depth)) = stack.pop() {
let span = element.span();
line(
&mut out,
depth,
*element.kind(),
span.start().to_u32(),
span.end().to_u32(),
);
match element {
Element::Node(node) => {
let from = stack.len();
stack.extend(node.children().map(|c| (c, depth + 1)));
stack[from..].reverse();
}
Element::Token(_) => {
let text = &self.source[span.start().to_usize()..span.end().to_usize()];
let _ = write!(out, " {text:?}");
}
}
out.push('\n');
}
out
}
}