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#[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 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}