Skip to main content

chrobry_core/
parser.rs

1use crate::ast::*;
2use pest::{iterators::Pair, Parser};
3use std::collections::HashMap;
4
5pub fn parse(content: &str) -> Result<Ast, String> {
6    let program = match AstParser::parse(Rule::program, content) {
7        Ok(mut pairs) => pairs.next().unwrap(),
8        Err(error) => return Err(format!("{:#?}", error)),
9    };
10    let mut ast = Ast::default();
11    for pair in program.into_inner() {
12        match pair.as_rule() {
13            Rule::import_elm => ast.imports.push(parse_import(pair)),
14            Rule::inject_elm => ast.injects.push(parse_inject(pair)),
15            Rule::replace_elm => ast.replacements.push(parse_replace(pair)),
16            Rule::extern_elm => ast.externs.push(parse_extern(pair)),
17            Rule::struct_elm => ast.structs.push(parse_struct(pair)),
18            Rule::enum_elm => ast.enums.push(parse_enum(pair)),
19            Rule::impl_elm => ast.implementations.push(parse_implementation(pair)),
20            Rule::EOI => {}
21            _ => panic!("{:?}", pair.as_rule()),
22        }
23    }
24    Ok(ast)
25}
26
27fn parse_import(pair: Pair<Rule>) -> String {
28    parse_string(pair.into_inner().next().unwrap())
29}
30
31fn parse_inject(pair: Pair<Rule>) -> AstCode {
32    parse_code(pair.into_inner().next().unwrap())
33}
34
35fn parse_replace(pair: Pair<Rule>) -> AstReplace {
36    let mut pairs = pair.into_inner();
37    let pattern = parse_string(pairs.next().unwrap()).replace("\\\\", "\\");
38    let template = parse_code(pairs.next().unwrap());
39    AstReplace { pattern, template }
40}
41
42fn parse_extern(pair: Pair<Rule>) -> AstExtern {
43    let mut pairs = pair.into_inner();
44    let types = parse_extern_types(pairs.next().unwrap());
45    let implementations = parse_extern_implementations(pairs.next().unwrap());
46    AstExtern {
47        types,
48        implementations,
49    }
50}
51
52fn parse_extern_types(pair: Pair<Rule>) -> Vec<String> {
53    pair.into_inner().map(parse_string).collect::<Vec<_>>()
54}
55
56fn parse_extern_implementations(pair: Pair<Rule>) -> Vec<(String, AstCode)> {
57    pair.into_inner()
58        .map(parse_extern_implementation)
59        .collect::<Vec<_>>()
60}
61
62fn parse_extern_implementation(pair: Pair<Rule>) -> (String, AstCode) {
63    let mut pairs = pair.into_inner();
64    let identifier = parse_identifier(pairs.next().unwrap());
65    let code = parse_code(pairs.next().unwrap());
66    (identifier, code)
67}
68
69fn parse_struct(pair: Pair<Rule>) -> AstStruct {
70    let mut result = AstStruct::default();
71    for pair in pair.into_inner() {
72        match pair.as_rule() {
73            Rule::tags => result.tags = parse_tags(pair),
74            Rule::identifier => result.name = parse_identifier(pair),
75            Rule::fields => result.fields = parse_struct_fields(pair),
76            _ => panic!("{:?}", pair.as_rule()),
77        }
78    }
79    result
80}
81
82fn parse_struct_fields(pair: Pair<Rule>) -> Vec<(String, AstType)> {
83    pair.into_inner()
84        .map(parse_struct_field)
85        .collect::<Vec<_>>()
86}
87
88fn parse_struct_field(pair: Pair<Rule>) -> (String, AstType) {
89    let mut pairs = pair.into_inner();
90    let identifier = parse_identifier(pairs.next().unwrap());
91    let type_ = parse_type(pairs.next().unwrap());
92    (identifier, type_)
93}
94
95fn parse_enum(pair: Pair<Rule>) -> AstEnum {
96    let mut result = AstEnum::default();
97    for pair in pair.into_inner() {
98        match pair.as_rule() {
99            Rule::tags => result.tags = parse_tags(pair),
100            Rule::identifier => result.name = parse_identifier(pair),
101            Rule::enum_fields => result.fields = parse_enum_fields(pair),
102            _ => panic!("{:?}", pair.as_rule()),
103        }
104    }
105    result
106}
107
108fn parse_enum_fields(pair: Pair<Rule>) -> Vec<String> {
109    pair.into_inner().map(parse_identifier).collect::<Vec<_>>()
110}
111
112fn parse_implementation(pair: Pair<Rule>) -> AstImplementation {
113    let mut result = AstImplementation::default();
114    for pair in pair.into_inner() {
115        match pair.as_rule() {
116            Rule::impl_target => result.target = parse_implementation_target(pair),
117            Rule::identifier => result.name = parse_identifier(pair),
118            Rule::where_rules => result.where_rules = parse_where_rules(pair),
119            Rule::code => result.code = parse_code(pair),
120            _ => panic!("{:?}", pair.as_rule()),
121        }
122    }
123    result
124}
125
126fn parse_implementation_target(pair: Pair<Rule>) -> AstImplementationTarget {
127    let pair = pair.into_inner().next().unwrap();
128    match pair.as_rule() {
129        Rule::impl_target_struct => AstImplementationTarget::Struct,
130        Rule::impl_target_enum => AstImplementationTarget::Enum,
131        _ => panic!("{:?}", pair.as_rule()),
132    }
133}
134
135fn parse_type(pair: Pair<Rule>) -> AstType {
136    let pair = pair.into_inner().next().unwrap();
137    match pair.as_rule() {
138        Rule::string => AstType::Extern(parse_string(pair)),
139        Rule::identifier => AstType::Local(parse_identifier(pair)),
140        _ => panic!("{:?}", pair.as_rule()),
141    }
142}
143
144fn parse_tags(pair: Pair<Rule>) -> Vec<(String, HashMap<String, String>)> {
145    pair.into_inner().map(parse_tag).collect::<Vec<_>>()
146}
147
148fn parse_tag(pair: Pair<Rule>) -> (String, HashMap<String, String>) {
149    let mut pairs = pair.into_inner();
150    let identifier = parse_identifier(pairs.next().unwrap());
151    let parameters = if let Some(pair) = pairs.next() {
152        pair.into_inner()
153            .map(parse_tag_parameter)
154            .collect::<HashMap<_, _>>()
155    } else {
156        Default::default()
157    };
158    (identifier, parameters)
159}
160
161fn parse_tag_parameter(pair: Pair<Rule>) -> (String, String) {
162    let mut pairs = pair.into_inner();
163    let identifier = parse_identifier(pairs.next().unwrap());
164    let value = if let Some(pair) = pairs.next() {
165        parse_string(pair)
166    } else {
167        Default::default()
168    };
169    (identifier, value)
170}
171
172fn parse_code(pair: Pair<Rule>) -> AstCode {
173    let pair = pair.into_inner().next().unwrap();
174    let mut code = AstCode::default();
175    for pair in pair.into_inner() {
176        match pair.as_rule() {
177            Rule::code_chars => {
178                code.0.push(AstCodeChunk::Content(pair.as_str().to_owned()));
179            }
180            Rule::code_op => {
181                let pair = pair.into_inner().next().unwrap();
182                match pair.as_rule() {
183                    Rule::variable => {
184                        code.0.push(AstCodeChunk::Variable(parse_variable(pair)));
185                    }
186                    Rule::code_op_for => {
187                        code.0.push(AstCodeChunk::For(parse_code_for(pair)));
188                    }
189                    _ => panic!("{:?}", pair.as_rule()),
190                }
191            }
192            _ => panic!("{:?}", pair.as_rule()),
193        }
194    }
195    code
196}
197
198fn parse_code_for(pair: Pair<Rule>) -> AstCodeFor {
199    let mut result = AstCodeFor::default();
200    for pair in pair.into_inner() {
201        match pair.as_rule() {
202            Rule::vars => result.variables = parse_variables(pair),
203            Rule::code_op_in => result.container = parse_in(pair),
204            Rule::where_rules => result.where_rules = parse_where_rules(pair),
205            Rule::code => result.code = parse_code(pair),
206            _ => panic!("{:?}", pair.as_rule()),
207        }
208    }
209    result
210}
211
212fn parse_in(pair: Pair<Rule>) -> AstIn {
213    let pair = pair.into_inner().next().unwrap();
214    match pair.as_rule() {
215        Rule::variable => AstIn::Variable(parse_variable(pair)),
216        Rule::code_op_in_fields => AstIn::Fields,
217        _ => panic!("{:?}", pair.as_rule()),
218    }
219}
220
221fn parse_where_rules(pair: Pair<Rule>) -> Vec<AstWhereRule> {
222    pair.into_inner().map(parse_where_rule).collect::<Vec<_>>()
223}
224
225fn parse_where_rule(pair: Pair<Rule>) -> AstWhereRule {
226    let pair = pair.into_inner().next().unwrap();
227    match pair.as_rule() {
228        Rule::where_rule_exists => {
229            AstWhereRule::Exists(parse_variable(pair.into_inner().next().unwrap()))
230        }
231        Rule::where_rule_is => AstWhereRule::Is(parse_where_rule_is(pair)),
232        Rule::where_rule_impl => AstWhereRule::Impl(parse_where_rule_impl(pair)),
233        _ => panic!("{:?}", pair.as_rule()),
234    }
235}
236
237fn parse_where_rule_is(pair: Pair<Rule>) -> AstWhereRuleIs {
238    let mut pairs = pair.into_inner();
239    let variable = parse_variable(pairs.next().unwrap());
240    let value = parse_string(pairs.next().unwrap());
241    AstWhereRuleIs { variable, value }
242}
243
244fn parse_where_rule_impl(pair: Pair<Rule>) -> AstWhereRuleImpl {
245    let mut pairs = pair.into_inner();
246    let container = parse_in(pairs.next().unwrap());
247    let implements = pairs
248        .next()
249        .unwrap()
250        .into_inner()
251        .map(parse_identifier)
252        .collect::<Vec<_>>();
253    AstWhereRuleImpl {
254        container,
255        implements,
256    }
257}
258
259fn parse_variables(pair: Pair<Rule>) -> Vec<String> {
260    pair.into_inner().map(parse_variable).collect::<Vec<_>>()
261}
262
263fn parse_string(pair: Pair<Rule>) -> String {
264    pair.into_inner().next().unwrap().as_str().to_owned()
265}
266
267fn parse_identifier(pair: Pair<Rule>) -> String {
268    pair.as_str().to_owned()
269}
270
271fn parse_variable(pair: Pair<Rule>) -> String {
272    pair.into_inner().next().unwrap().as_str().to_owned()
273}