abackus/
treeficator.rs

1#![deny(warnings)]
2
3use crate::ebnf::ParserBuilder;
4use earlgrey::{EarleyParser, EarleyForest};
5use std::fmt::Debug;
6
7#[derive(Clone,Debug)]
8pub enum Sexpr {
9    Atom(String),
10    List(Vec<Sexpr>),
11}
12
13#[derive(Debug,Clone,PartialEq)]
14pub enum Tree {
15    // 1st element of each option is the matched rule
16    // ("[+-]", "+")
17    Leaf(String, String),
18    // ("E -> E [+-] E", [...])
19    Node(String, Vec<Tree>),
20}
21
22impl Sexpr {
23    pub fn print(&self) -> String {
24        let mut out = String::new();
25        self.print_helper("", &mut out);
26        out
27    }
28
29    fn print_helper(&self, indent: &str, out: &mut String) {
30        match *self {
31            Sexpr::Atom(ref lexeme) =>
32                *out += &format!("\u{2500} {}\n", lexeme),
33            Sexpr::List(ref subn) => {
34                let (first, rest) = subn.split_first().unwrap();
35                let (last, rest) = rest.split_last().unwrap();
36                *out += &format!("\u{252c}");
37                first.print_helper(&format!("{}\u{2502}", indent), out);
38                for mid in rest {
39                    *out += &format!("{}\u{251c}", indent);
40                    mid.print_helper(&format!("{}\u{2502}", indent), out);
41                }
42                *out += &format!("{}\u{2570}", indent);
43                last.print_helper(&format!("{} ", indent), out);
44            }
45        }
46    }
47}
48
49impl ParserBuilder {
50    pub fn treeficator<SI>(self, grammar: &str, start: &str)
51        -> impl Fn(SI) -> Result<Vec<Tree>, String>
52        where SI: Iterator, SI::Item: AsRef<str> + Debug
53    {
54        // User may pre-plug grammar (self.0) with terminals
55        // 1. build a parser for user's grammar
56        let grammar = ParserBuilder::parse_grammar(self.0, grammar)
57            .unwrap_or_else(|e| panic!("treeficator error: {:?}", e))
58            .into_grammar(start)
59            .unwrap_or_else(|e| panic!("treeficator error: {:?}", e));
60        // 2. build evaler that builds trees when executing semantic actions
61        let mut tree_builder = EarleyForest::new(
62            |sym, tok| Tree::Leaf(sym.to_string(), tok.to_string()));
63        for rule in grammar.rules.iter().map(|r| r.to_string()) {
64            tree_builder.action(
65                &rule.clone(), move |nodes| Tree::Node(rule.clone(), nodes));
66        }
67        // 3. make function that parses strings into trees
68        let parser = EarleyParser::new(grammar);
69        move |tokenizer| tree_builder.eval_all(&parser.parse(tokenizer)?)
70    }
71
72    pub fn sexprificator<SI>(self, grammar: &str, start: &str)
73        -> impl Fn(SI) -> Result<Vec<Sexpr>, String>
74        where SI: Iterator, SI::Item: AsRef<str> + Debug
75    {
76        // User may pre-plug grammar (self.0) with terminals
77        // 1. build a parser for user's grammar
78        let grammar = ParserBuilder::parse_grammar(self.0, grammar)
79            .unwrap_or_else(|e| panic!("treeficator error: {:?}", e))
80            .into_grammar(start)
81            .unwrap_or_else(|e| panic!("treeficator error: {:?}", e));
82        // 2. build evaler that builds trees when executing semantic actions
83        let mut tree_builder = EarleyForest::new(
84            |_, tok| Sexpr::Atom(tok.to_string()));
85        for rule in &grammar.rules {
86            tree_builder.action(&rule.to_string(),
87                move |mut nodes| match nodes.len() {
88                    1 => nodes.swap_remove(0),
89                    _ => Sexpr::List(nodes),
90                });
91        }
92        // 3. make function that parses strings into trees
93        let parser = EarleyParser::new(grammar);
94        move |tokenizer| tree_builder.eval_all(&parser.parse(tokenizer)?)
95    }
96}