lopal_core 0.1.0

Lossless Parser Library. Parses to rowan LSTs.
Documentation
use std::marker::PhantomData;

use rowan::{GreenNode, GreenNodeData, GreenTokenData, NodeOrToken};

use crate::{SyntaxElement, SyntaxError};

pub struct ParserOutput<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError> {
    pub green_node: GreenNode,
    pub errors: Vec<SyntaxErr>,
    pub(super) _syntax_kind: PhantomData<SyntaxKind>,
}

impl<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError> std::fmt::Debug
    for ParserOutput<SyntaxKind, SyntaxErr>
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut errs: Vec<&SyntaxErr> = self.errors.iter().collect();
        errs.reverse();
        debug_print_output::<SyntaxKind, SyntaxErr>(
            NodeOrToken::Node(&self.green_node),
            f,
            0,
            &mut errs,
        )
    }
}

fn debug_print_output<SyntaxKind: SyntaxElement, SyntaxErr: SyntaxError>(
    node: NodeOrToken<&GreenNodeData, &GreenTokenData>,
    f: &mut std::fmt::Formatter<'_>,
    lvl: i32,
    errs: &mut Vec<&SyntaxErr>,
) -> std::fmt::Result {
    if f.alternate() {
        for _ in 0..lvl {
            f.write_str("    ")?;
        }
    }
    let maybe_newline = if f.alternate() { "\n" } else { " " };

    match node {
        NodeOrToken::Node(n) => {
            let kind: SyntaxKind = node.kind().into();
            if kind == SyntaxKind::SYNTAX_ERROR {
                let err = errs
                    .pop()
                    .expect("all error syntax nodes should correspond to an error");

                write!(f, "{kind:?}: {err:?} {{{maybe_newline}")?;
            } else {
                write!(f, "{kind:?} {{{maybe_newline}")?;
            }
            for c in n.children() {
                debug_print_output::<SyntaxKind, SyntaxErr>(c, f, lvl + 1, errs)?;
            }

            if f.alternate() {
                for _ in 0..lvl {
                    f.write_str("    ")?;
                }
            }
            write!(f, "}}{maybe_newline}")
        }
        NodeOrToken::Token(t) => {
            write!(
                f,
                "{:?} {:?};{maybe_newline}",
                Into::<SyntaxKind>::into(t.kind()),
                t.text()
            )
        }
    }
}