use rowan::{GreenNode, GreenNodeBuilder, GreenNodeData, GreenTokenData, Language, NodeOrToken}; use std::mem; use crate::lst_parser::syntax_kind::{Lang, SyntaxKind}; use super::{error::SyntaxError, events::Event}; 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 { debug_print_green_node(NodeOrToken::Node(&self.green_node), f, 0) } } fn debug_print_green_node( node: NodeOrToken<&GreenNodeData, &GreenTokenData>, f: &mut std::fmt::Formatter<'_>, lvl: i32, ) -> std::fmt::Result { for _ in 0..lvl { f.write_str(" ")?; } match node { NodeOrToken::Node(n) => { writeln!(f, "{:?} {{", Lang::kind_from_raw(node.kind()))?; for c in n.children() { debug_print_green_node(c, f, lvl + 1)?; } for _ in 0..lvl { f.write_str(" ")?; } f.write_str("}\n") } NodeOrToken::Token(t) => { writeln!(f, "{:?} {:?};", Lang::kind_from_raw(t.kind()), t.text()) } } } impl Output { pub fn from_parser_output( mut raw_toks: Vec<(SyntaxKind, &str)>, (mut events, errs): (Vec, Vec), ) -> Self { let mut builder = GreenNodeBuilder::new(); let mut fw_parents = 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() { if kind != SyntaxKind::TOMBSTONE { builder.start_node(kind.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); }), Event::Error => todo!(), } } Self { green_node: builder.finish(), errors: errs, } } }