stap_lang/
parser.rs

1use std::fmt::Display;
2
3use pest::iterators::Pair;
4use pest_derive::Parser;
5
6pub use pest::Parser;
7
8#[derive(Parser)]
9#[grammar = "stap.pest"]
10pub struct StapParser;
11
12#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct Module {
14    pub values: Vec<Value>,
15}
16
17impl Module {
18    pub fn parse(source: &str) -> Self {
19        let module = StapParser::parse(Rule::module, source)
20            .unwrap_or_else(|e| panic!("Error parsing. {:?}", e))
21            .next()
22            .expect("A module must have content. Did the grammar get mangled?");
23
24        let values = module
25            .into_inner()
26            .filter_map(|pair| match pair.as_rule() {
27                Rule::value => {
28                    let inner = pair.into_inner().next().unwrap();
29                    Some(Value::from(inner))
30                }
31                Rule::EOI => None,
32                rule => unreachable!(
33                    "A module can only contain top-level values. Found: {:?}",
34                    rule
35                ),
36            })
37            .collect();
38
39        Module { values }
40    }
41
42    pub fn parse_line(line: &str) -> (Module, String) {
43        let (balanced, remaining, _) = line.chars().fold(
44            (String::new(), String::new(), 0),
45            |(balanced, mut acc, parens), c| {
46                acc.push(c);
47                match (c, parens) {
48                    ('(', _) => (balanced, acc, parens + 1),
49                    (')', 1) => (balanced + &acc, String::new(), 0),
50                    (')', _) => (balanced, acc, parens - 1),
51                    (_, _) => (balanced, acc, parens),
52                }
53            },
54        );
55
56        (Module::parse(&balanced), remaining)
57    }
58
59    pub fn join(self, other: Module) -> Module {
60        Module {
61            values: [self.values, other.values].concat(),
62        }
63    }
64}
65
66impl Display for Module {
67    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
68        for value in &self.values {
69            writeln!(f, "{}", value)?;
70        }
71        Ok(())
72    }
73}
74
75#[derive(Clone, Debug, PartialEq, Eq)]
76pub enum Value {
77    Function(Vec<Value>),
78    List(Vec<Value>),
79    String(String),
80    Identifier(String),
81}
82
83impl From<Pair<'_, Rule>> for Value {
84    fn from(pair: Pair<'_, Rule>) -> Self {
85        match pair.as_rule() {
86            Rule::function => Self::Function(pair.into_inner().map(Value::from).collect()),
87            Rule::list => Self::List(pair.into_inner().map(Value::from).collect()),
88            Rule::quoted_string => Value::from(pair.into_inner().next().unwrap()),
89            Rule::string => Self::String(pair.as_str().to_owned()),
90            Rule::identifier => Self::Identifier(pair.as_str().to_owned()),
91            Rule::value => Value::from(pair.into_inner().next().unwrap()),
92            _ => unreachable!(
93                "A StapValue must be a function, list, string, or identifier. Found: {:?}",
94                pair
95            ),
96        }
97    }
98}
99
100impl Display for Value {
101    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102        match self {
103            Self::Function(values) => {
104                let terms = values.iter().map(|v| v.to_string()).collect::<Vec<_>>();
105                let terms = terms.join(" ");
106                write!(f, "({})", terms)
107            }
108            Self::List(values) => {
109                let terms = values.iter().map(|v| v.to_string()).collect::<Vec<_>>();
110                let terms = terms.join(" ");
111                write!(f, "[{}]", terms)
112            }
113            Self::String(s) => write!(f, "\"{}\"", s),
114            Self::Identifier(i) => write!(f, "{}", i),
115        }
116    }
117}
118
119/* --- All tests from here --- */
120
121#[test]
122fn parse_a_module_i_guess() {
123    use Value::*;
124
125    let module = Module::parse("(println \"look ma I did it\")");
126
127    assert_eq!(
128        module,
129        Module {
130            values: vec![Function(vec![
131                Identifier("println".into()),
132                String("look ma I did it".into())
133            ])]
134        }
135    );
136}
137
138#[allow(dead_code)]
139fn test_parse(rule: Rule, input: &str) -> Pair<'_, Rule> {
140    StapParser::parse(rule, input)
141        .expect("parse failed")
142        .next()
143        .unwrap()
144}
145
146#[test]
147fn simple_module() {
148    let res = test_parse(Rule::module, "(println (+ 1 2))");
149
150    // I.e. it should have nothing omitted.
151    assert_eq!(res.as_str(), "(println (+ 1 2))");
152}
153
154#[test]
155fn empty_module() {
156    let res = test_parse(Rule::module, "");
157
158    assert_eq!(res.as_str(), "");
159}