iowo/crates/lang/src/lst_parser/output.rs
Schrottkatze 3eee768ce1
lang: work on various things
- work on new world
  - add file db
  - source_file parsing
  - locs
- fix some test stuff
2024-07-06 21:57:42 +02:00

209 lines
6.5 KiB
Rust

use clap::builder;
use owo_colors::{unset_override, OwoColorize};
use rowan::{GreenNode, GreenNodeBuilder, GreenNodeData, GreenTokenData, Language, NodeOrToken};
use std::mem;
use crate::{
lst_parser::{input::MEANINGLESS_TOKS, syntax_kind::SyntaxKind},
Lang, SyntaxNode,
};
use super::{
error::SyntaxError,
events::{Event, NodeKind},
};
pub struct Output {
pub green_node: GreenNode,
pub errors: Vec<SyntaxError>,
}
impl std::fmt::Debug for Output {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut errs: Vec<&SyntaxError> = self.errors.iter().collect();
errs.reverse();
debug_print_green_node(NodeOrToken::Node(&self.green_node), f, 0, &mut errs, false)
}
}
const INDENT_STR: &str = " ";
/// colored argument currently broken
fn debug_print_green_node(
node: NodeOrToken<&GreenNodeData, &GreenTokenData>,
f: &mut dyn std::fmt::Write,
lvl: i32,
errs: &mut Vec<&SyntaxError>,
colored: bool,
) -> std::fmt::Result {
for _ in 0..lvl {
f.write_str(INDENT_STR)?;
}
let r = match node {
NodeOrToken::Node(n) => {
let kind = Lang::kind_from_raw(node.kind());
if kind != SyntaxKind::PARSE_ERR {
writeln!(
f,
"{:?} {}",
Lang::kind_from_raw(node.kind()).bright_yellow().bold(),
"{".yellow()
)?;
} else {
let err = errs
.pop()
.expect("all error syntax nodes should correspond to an error")
.bright_red();
writeln!(
f,
"{:?}{} {err:?} {}",
kind.bright_red().bold(),
":".red(),
"{".bright_red().bold()
)?;
}
for c in n.children() {
debug_print_green_node(c, f, lvl + 1, errs, colored)?;
}
for _ in 0..lvl {
f.write_str(INDENT_STR)?;
}
if kind != SyntaxKind::PARSE_ERR {
write!(f, "{}", "}\n".yellow())
} else {
write!(f, "{}", "}\n".bright_red().bold())
}
}
NodeOrToken::Token(t) => {
let tok = Lang::kind_from_raw(t.kind());
if MEANINGLESS_TOKS.contains(tok) {
writeln!(
f,
"{:?} {:?}{}",
Lang::kind_from_raw(t.kind()).white(),
t.text().white(),
";".white()
)
} else {
writeln!(
f,
"{:?} {:?}{}",
Lang::kind_from_raw(t.kind()).bright_cyan().bold(),
t.text().green(),
";".yellow()
)
}
}
};
r
}
impl Output {
pub fn debug_colored(&self) -> String {
let mut out = String::new();
let mut errs: Vec<&SyntaxError> = self.errors.iter().collect();
errs.reverse();
let _ = debug_print_green_node(
NodeOrToken::Node(&self.green_node),
&mut out,
0,
&mut errs,
true,
);
out
}
pub fn from_parser_output(
mut raw_toks: Vec<(SyntaxKind, &str)>,
mut events: Vec<Event>,
) -> Self {
let mut builder = GreenNodeBuilder::new();
let mut fw_parents = Vec::new();
let mut errors = Vec::new();
raw_toks.reverse();
for i in 0..events.len() {
match mem::replace(&mut events[i], Event::tombstone()) {
Event::Start {
kind,
forward_parent,
} => {
if kind == SyntaxKind::TOMBSTONE && forward_parent.is_none() {
continue;
}
fw_parents.push(kind);
let mut idx = i;
let mut fp = forward_parent;
while let Some(fwd) = fp {
idx += fwd as usize;
fp = match mem::replace(&mut events[idx], Event::tombstone()) {
Event::Start {
kind,
forward_parent,
} => {
fw_parents.push(kind);
forward_parent
}
_ => unreachable!(),
}
}
// remove whitespace bc it's ugly
while let Some((SyntaxKind::WHITESPACE | SyntaxKind::NEWLINE, _)) =
raw_toks.last()
{
match events.iter_mut().find(|ev| matches!(ev, Event::Eat { .. })) {
Some(Event::Eat { count }) => *count -= 1,
_ => unreachable!(),
}
let (tok, text): (SyntaxKind, &str) = raw_toks.pop().unwrap();
builder.token(tok.into(), text);
}
for kind in fw_parents.drain(..).rev() {
match kind {
NodeKind::Syntax(kind) if kind != SyntaxKind::TOMBSTONE => {
builder.start_node(kind.into())
}
NodeKind::Error(err) => {
errors.push(err);
builder.start_node(SyntaxKind::PARSE_ERR.into())
}
_ => {}
}
}
}
Event::Finish => builder.finish_node(),
Event::Eat { count } => (0..count).for_each(|_| {
let (tok, text): (SyntaxKind, &str) = raw_toks.pop().unwrap();
builder.token(tok.into(), text);
}),
}
}
Self {
green_node: builder.finish(),
errors,
}
}
pub fn syntax(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green_node.clone())
}
pub fn errors(&self) -> Vec<SyntaxError> {
self.errors.clone()
}
pub fn dissolve(self) -> (GreenNode, Vec<SyntaxError>) {
let Self { green_node, errors } = self;
(green_node, errors)
}
}