lelwel 0.10.4

Resilient LL(1) parser generator
Documentation
use crate::{Cst, NodeRef, SemanticData};

use super::ast::*;

macro_rules! member {
    ($id: ident) => {
        format!(
            concat!("\x1b[90m", stringify!($id), "=\x1b[32m{:?}\x1b[0m"),
            $id
        )
    };
    ($id: literal) => {
        concat!("\x1b[90m", $id, "\x1b[0m")
    };
}
macro_rules! set {
    ($id: ident) => {
        format!(
            concat!("\x1b[90m", stringify!($id), "=\x1b[36m{}\x1b[0m"),
            $id
        )
    };
}
macro_rules! pos {
    ($id: expr) => {
        format!("\x1b[34m<{:?}>\x1b[0m", $id)
    };
}
macro_rules! syntax {
    ($e: expr) => {
        format!("\x1b[33m[{:?}]\x1b[0m", $e)
    };
    ($name: literal, $e: expr) => {
        if let Some(syntax) = $e {
            format!("\x1b[90m{}=\x1b[32m[{:?}]\x1b[0m", $name, syntax.0)
        } else {
            "\x1b[33m[]\x1b[0m".to_string()
        }
    };
}

#[derive(Default)]
pub struct DebugPrinter {
    active: Vec<bool>,
}
impl DebugPrinter {
    pub fn new() -> DebugPrinter {
        Self::default()
    }
    fn indent(&self) {
        for a in self.active.iter() {
            if *a {
                print!("");
            } else {
                print!("   ");
            }
        }
    }
    fn branch<Visit: Fn(&mut Self)>(&mut self, last: bool, visit: Visit) {
        self.indent();
        if last {
            print!("└─ ");
        } else {
            print!("├─ ");
        }
        self.active.push(!last);
        visit(self);
        self.active.pop();
    }
    pub fn run(&mut self, cst: &Cst<'_>, sema: &SemanticData<'_>) {
        if let Some(file) = File::cast(cst, NodeRef::ROOT) {
            println!("File {}", syntax!(file.syntax().0));
            self.branch(false, |s| {
                println!("{}", member!("start_decls"));
                let mut it = file.start_decls(cst).peekable();
                while let Some(decl) = it.next() {
                    s.branch(it.peek().is_none(), |s| s.print_start_decl(cst, decl));
                }
            });
            self.branch(false, |s| {
                println!("{}", member!("right_decls"));
                let mut it = file.right_decls(cst).peekable();
                while let Some(decl) = it.next() {
                    s.branch(it.peek().is_none(), |s| s.print_right_decl(cst, decl));
                }
            });
            self.branch(false, |s| {
                println!("{}", member!("skip_decls"));
                let mut it = file.skip_decls(cst).peekable();
                while let Some(decl) = it.next() {
                    s.branch(it.peek().is_none(), |s| s.print_skip_decl(cst, decl));
                }
            });
            self.branch(false, |s| {
                println!("{}", member!("part_decls"));
                let mut it = file.part_decls(cst).peekable();
                while let Some(decl) = it.next() {
                    s.branch(it.peek().is_none(), |s| s.print_part_decl(cst, decl));
                }
            });
            self.branch(false, |s| {
                println!("{}", member!("token_decls"));
                let mut it = file.token_decls(cst).peekable();
                while let Some(decl) = it.next() {
                    s.branch(it.peek().is_none(), |s| s.print_token_decl(cst, decl));
                }
            });
            self.branch(true, |s| {
                println!("{}", member!("rule_decls"));
                let mut it = file.rule_decls(cst).peekable();
                while let Some(decl) = it.next() {
                    s.branch(it.peek().is_none(), |s| s.print_rule_decl(cst, sema, decl));
                }
            });
        }
    }
    fn print_token_decl(&mut self, cst: &Cst<'_>, decl: TokenDecl) {
        let name = decl.name(cst).map_or("", |(val, _)| val);
        let symbol = decl.symbol(cst).map_or("", |(val, _)| val);
        println!(
            "Token {} {} {} {}",
            member!(name),
            member!(symbol),
            pos!(decl.span(cst)),
            syntax!(decl.syntax().0),
        );
    }
    fn print_rule_decl(&mut self, cst: &Cst<'_>, sema: &SemanticData<'_>, decl: RuleDecl) {
        let name = decl.name(cst).map_or("", |(val, _)| val);
        println!(
            "Rule {} {} {}",
            member!(name),
            pos!(decl.span(cst)),
            syntax!(decl.syntax().0),
        );
        decl.regex(cst)
            .inspect(|r| self.branch(true, |s| s.print_regex(cst, sema, *r)));
    }
    fn print_start_decl(&mut self, cst: &Cst<'_>, decl: StartDecl) {
        let rule_name = decl.rule_name(cst).map_or("", |(val, _)| val);
        println!(
            "Start {} {} {}",
            member!(rule_name),
            pos!(decl.span(cst)),
            syntax!(decl.syntax().0),
        );
    }
    fn print_right_decl(&mut self, cst: &Cst<'_>, decl: RightDecl) {
        let mut token_names = vec![];
        decl.token_names(cst, |(val, _)| token_names.push(val));
        println!(
            "Right {} {} {}",
            member!(token_names),
            pos!(decl.span(cst)),
            syntax!(decl.syntax().0),
        );
    }
    fn print_skip_decl(&mut self, cst: &Cst<'_>, decl: SkipDecl) {
        let mut token_names = vec![];
        decl.token_names(cst, |(val, _)| token_names.push(val));
        println!(
            "Skip {} {} {}",
            member!(token_names),
            pos!(decl.span(cst)),
            syntax!(decl.syntax().0),
        );
    }
    fn print_part_decl(&mut self, cst: &Cst<'_>, decl: PartDecl) {
        let mut rule_names = vec![];
        decl.rule_names(cst, |(val, _)| rule_names.push(val));
        println!(
            "Part {} {} {}",
            member!(rule_names),
            pos!(decl.span(cst)),
            syntax!(decl.syntax().0),
        );
    }
    fn print_regex(&mut self, cst: &Cst<'_>, sema: &SemanticData<'_>, regex: Regex) {
        let first = &sema
            .first_sets
            .get(&regex.syntax())
            .map_or("{}".to_string(), |set| format!("{set:?}"));
        let follow = &sema
            .follow_sets
            .get(&regex.syntax())
            .map_or("{}".to_string(), |set| format!("{set:?}"));
        let recovery = &sema
            .recovery_sets
            .get(&regex.syntax())
            .map_or("{}".to_string(), |set| format!("{set:?}"));
        match regex {
            Regex::OrderedChoice(choice) => {
                println!(
                    "OrderedChoice {} {} {} {}",
                    set!(first),
                    set!(follow),
                    pos!(choice.span(cst)),
                    syntax!(choice.syntax().0),
                );
                let mut it = choice.operands(cst).peekable();
                while let Some(op) = it.next() {
                    self.branch(it.peek().is_none(), |s| s.print_regex(cst, sema, op));
                }
            }
            Regex::Alternation(alt) => {
                println!(
                    "Alternation {} {} {} {}",
                    set!(first),
                    set!(follow),
                    pos!(alt.span(cst)),
                    syntax!(alt.syntax().0),
                );
                let mut it = alt.operands(cst).peekable();
                while let Some(op) = it.next() {
                    self.branch(it.peek().is_none(), |s| s.print_regex(cst, sema, op));
                }
            }
            Regex::Concat(concat) => {
                println!(
                    "Concat {} {} {} {}",
                    set!(first),
                    set!(follow),
                    pos!(concat.span(cst)),
                    syntax!(concat.syntax().0),
                );
                let mut it = concat.operands(cst).peekable();
                while let Some(op) = it.next() {
                    self.branch(it.peek().is_none(), |s| s.print_regex(cst, sema, op));
                }
            }
            Regex::Paren(paren) => {
                println!(
                    "Paren {} {} {} {}",
                    set!(first),
                    set!(follow),
                    pos!(paren.span(cst)),
                    syntax!(paren.syntax().0),
                );
                paren
                    .inner(cst)
                    .inspect(|r| self.branch(true, |s| s.print_regex(cst, sema, *r)));
            }
            Regex::Optional(opt) => {
                println!(
                    "Optional {} {} {} {} {}",
                    set!(first),
                    set!(follow),
                    set!(recovery),
                    pos!(opt.span(cst)),
                    syntax!(opt.syntax().0),
                );
                opt.operand(cst)
                    .inspect(|r| self.branch(true, |s| s.print_regex(cst, sema, *r)));
            }
            Regex::Star(star) => {
                println!(
                    "Star {} {} {} {} {}",
                    set!(first),
                    set!(follow),
                    set!(recovery),
                    pos!(star.span(cst)),
                    syntax!(star.syntax().0),
                );
                star.operand(cst)
                    .inspect(|r| self.branch(true, |s| s.print_regex(cst, sema, *r)));
            }
            Regex::Plus(plus) => {
                println!(
                    "Plus {} {} {} {} {}",
                    set!(first),
                    set!(follow),
                    set!(recovery),
                    pos!(plus.span(cst)),
                    syntax!(plus.syntax().0),
                );
                plus.operand(cst)
                    .inspect(|r| self.branch(true, |s| s.print_regex(cst, sema, *r)));
            }
            Regex::Name(name) => {
                let value = name.value(cst).map_or("", |(val, _)| val);
                let binding = sema.decl_bindings.get(&name.syntax());
                println!(
                    "Name {} {} {} {} {} {}",
                    member!(value),
                    syntax!("binding", binding),
                    set!(first),
                    set!(follow),
                    pos!(name.span(cst)),
                    syntax!(name.syntax().0),
                );
            }
            Regex::Symbol(symbol) => {
                let value = symbol.value(cst).map_or("", |(val, _)| val);
                let binding = sema.decl_bindings.get(&symbol.syntax());
                println!(
                    "Symbol {} {} {} {} {} {}",
                    member!(value),
                    syntax!("binding", binding),
                    set!(first),
                    set!(follow),
                    pos!(symbol.span(cst)),
                    syntax!(symbol.syntax().0),
                );
            }
            Regex::Predicate(pred) => {
                let value = pred.value(cst).map_or("", |(val, _)| val);
                println!(
                    "Predicate {} {} {} {} {}",
                    member!(value),
                    set!(first),
                    set!(follow),
                    pos!(pred.span(cst)),
                    syntax!(pred.syntax().0),
                );
            }
            Regex::Action(action) => {
                let value = action.value(cst).map_or("", |(val, _)| val);
                println!(
                    "Action {} {} {} {} {}",
                    member!(value),
                    set!(first),
                    set!(follow),
                    pos!(action.span(cst)),
                    syntax!(action.syntax().0),
                );
            }
            Regex::Assertion(assertion) => {
                let value = assertion.value(cst).map_or("", |(val, _)| val);
                println!(
                    "Assertion {} {} {} {} {}",
                    member!(value),
                    set!(first),
                    set!(follow),
                    pos!(assertion.span(cst)),
                    syntax!(assertion.syntax().0),
                );
            }
            Regex::NodeRename(rename) => {
                let value = rename.value(cst).map_or("", |(val, _)| val);
                println!(
                    "NodeRename {} {} {} {} {}",
                    member!(value),
                    set!(first),
                    set!(follow),
                    pos!(rename.span(cst)),
                    syntax!(rename.syntax().0),
                );
            }
            Regex::NodeElision(elision) => {
                println!(
                    "NodeElision {} {} {} {} {}",
                    set!(first),
                    set!(follow),
                    set!(recovery),
                    pos!(elision.span(cst)),
                    syntax!(elision.syntax().0),
                );
            }
            Regex::NodeMarker(marker) => {
                let value = marker.value(cst).map_or("", |(val, _)| val);
                println!(
                    "NodeMarker {} {} {} {} {}",
                    member!(value),
                    set!(first),
                    set!(follow),
                    pos!(marker.span(cst)),
                    syntax!(marker.syntax().0),
                );
            }
            Regex::NodeCreation(creation) => {
                let value = creation.value(cst).map_or("", |(val, _)| val);
                println!(
                    "NodeCreation {} {} {} {} {}",
                    member!(value),
                    set!(first),
                    set!(follow),
                    pos!(creation.span(cst)),
                    syntax!(creation.syntax().0),
                );
            }
            Regex::Commit(commit) => {
                println!(
                    "Commit {} {} {} {}",
                    set!(first),
                    set!(follow),
                    pos!(commit.span(cst)),
                    syntax!(commit.syntax().0),
                );
            }
            Regex::Return(commit) => {
                println!(
                    "Return {} {} {} {}",
                    set!(first),
                    set!(follow),
                    pos!(commit.span(cst)),
                    syntax!(commit.syntax().0),
                );
            }
        }
    }
}