use alloc::{string::String, vec::Vec};
use core::fmt::Write as _;
use diag_lang::{Diagnostic, Severity};
use syntax_lang::{Element, Node, Span};
use crate::{Language, kind::Kind};
#[derive(Clone, Debug)]
pub struct Parse<'a> {
language: &'a Language,
source: &'a str,
tree: Node<Kind>,
diagnostics: Vec<Diagnostic>,
injections: Vec<Injection<'a>>,
}
impl<'a> Parse<'a> {
pub(crate) fn new(
language: &'a Language,
source: &'a str,
tree: Node<Kind>,
diagnostics: Vec<Diagnostic>,
injections: Vec<Injection<'a>>,
) -> Self {
Self {
language,
source,
tree,
diagnostics,
injections,
}
}
#[must_use]
pub fn injections(&self) -> &[Injection<'a>] {
&self.injections
}
#[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(" ");
}
if let Some(label) = kind.label().and_then(|l| self.language.label_name(l)) {
out.push_str(label);
out.push(':');
}
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
}
}
#[derive(Clone, Debug)]
pub struct Injection<'a> {
id: &'a str,
language: &'a str,
span: Span,
tree: Option<Node<Kind>>,
editor: bool,
}
impl<'a> Injection<'a> {
pub(crate) fn new(
id: &'a str,
language: &'a str,
span: Span,
tree: Option<Node<Kind>>,
editor: bool,
) -> Self {
Self {
id,
language,
span,
tree,
editor,
}
}
#[must_use]
pub fn id(&self) -> &'a str {
self.id
}
#[must_use]
pub fn language(&self) -> &'a str {
self.language
}
#[must_use]
pub fn span(&self) -> Span {
self.span
}
#[must_use]
pub fn tree(&self) -> Option<&Node<Kind>> {
self.tree.as_ref()
}
#[must_use]
pub fn is_editor(&self) -> bool {
self.editor
}
}