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, } 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, ) -> 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 { self.errors.clone() } pub fn dissolve(self) -> (GreenNode, Vec) { let Self { green_node, errors } = self; (green_node, errors) } }