intuicio_frontend_assembler/
parser.rs

1use crate::{
2    AsmEnum, AsmEnumVariant, AsmExpression, AsmFile, AsmFunction, AsmFunctionParameter, AsmLiteral,
3    AsmModule, AsmOperation, AsmStruct, AsmStructField,
4};
5use intuicio_core::Visibility;
6use pest::{Parser, iterators::Pair};
7use pest_derive::Parser;
8use std::{fmt::Debug, str::FromStr};
9
10#[derive(Parser)]
11#[grammar = "grammar.pest"]
12pub struct AsmParser;
13
14pub fn parse(content: &str) -> Result<AsmFile, String> {
15    match AsmParser::parse(Rule::file, content) {
16        Ok(mut pairs) => {
17            let pair = pairs.next().unwrap();
18            match pair.as_rule() {
19                Rule::file => Ok(parse_file(pair)),
20                rule => unreachable!("{:?}", rule),
21            }
22        }
23        Err(error) => Err(format!("{}", error)),
24    }
25}
26
27fn parse_file(pair: Pair<Rule>) -> AsmFile {
28    let mut result = AsmFile::default();
29    for pair in pair.into_inner() {
30        match pair.as_rule() {
31            Rule::file_item => {
32                let pair = pair.into_inner().next().unwrap();
33                match pair.as_rule() {
34                    Rule::import => {
35                        result
36                            .dependencies
37                            .push(parse_string(pair.into_inner().next().unwrap()));
38                    }
39                    Rule::module => {
40                        result.modules.push(parse_module(pair));
41                    }
42                    rule => unreachable!("{:?}", rule),
43                }
44            }
45            Rule::EOI => {}
46            rule => unreachable!("{:?}", rule),
47        }
48    }
49    result
50}
51
52fn parse_module(pair: Pair<Rule>) -> AsmModule {
53    let mut pairs = pair.into_inner();
54    let mut result = AsmModule {
55        name: parse_identifier(pairs.next().unwrap()),
56        structs: vec![],
57        enums: vec![],
58        functions: vec![],
59    };
60    for pair in pairs {
61        let pair = pair.into_inner().next().unwrap();
62        match pair.as_rule() {
63            Rule::function => {
64                result.functions.push(parse_function(pair));
65            }
66            Rule::structure => {
67                result.structs.push(parse_structure(pair));
68            }
69            Rule::enumerator => {
70                result.enums.push(parse_enumerator(pair));
71            }
72            rule => unreachable!("{:?}", rule),
73        }
74    }
75    result
76}
77
78fn parse_structure(pair: Pair<Rule>) -> AsmStruct {
79    let mut pairs = pair.into_inner();
80    let mut result = parse_struct_header(pairs.next().unwrap());
81    result.fields = parse_struct_fields(pairs.next().unwrap());
82    result
83}
84
85fn parse_struct_fields(pair: Pair<Rule>) -> Vec<AsmStructField> {
86    pair.into_inner().map(parse_struct_field).collect()
87}
88
89fn parse_struct_field(pair: Pair<Rule>) -> AsmStructField {
90    let pairs = pair.into_inner();
91    let mut result = AsmStructField {
92        meta: None,
93        name: Default::default(),
94        visibility: Visibility::Public,
95        module_name: None,
96        type_name: Default::default(),
97    };
98    for pair in pairs {
99        match pair.as_rule() {
100            Rule::visibility => {
101                result.visibility = parse_visibility(pair);
102            }
103            Rule::identifier => {
104                result.name = parse_identifier(pair);
105            }
106            Rule::path_module => {
107                result.module_name = Some(parse_path_name(pair));
108            }
109            Rule::path_type => {
110                result.type_name = parse_path_name(pair.into_inner().next().unwrap());
111            }
112            rule => unreachable!("{:?}", rule),
113        }
114    }
115    result
116}
117
118fn parse_struct_header(pair: Pair<Rule>) -> AsmStruct {
119    let pairs = pair.into_inner();
120    let mut result = AsmStruct {
121        meta: None,
122        name: Default::default(),
123        visibility: Visibility::Public,
124        fields: vec![],
125    };
126    for pair in pairs {
127        match pair.as_rule() {
128            Rule::visibility => {
129                result.visibility = parse_visibility(pair);
130            }
131            Rule::path_struct => {
132                result.name = parse_path_name(pair);
133            }
134            rule => unreachable!("{:?}", rule),
135        }
136    }
137    result
138}
139
140fn parse_enumerator(pair: Pair<Rule>) -> AsmEnum {
141    let mut pairs = pair.into_inner();
142    let mut result = parse_enumerator_header(pairs.next().unwrap());
143    result.variants = parse_enumerator_variants(pairs.next().unwrap());
144    result
145}
146
147fn parse_enumerator_variants(pair: Pair<Rule>) -> Vec<AsmEnumVariant> {
148    pair.into_inner().map(parse_enumerator_variant).collect()
149}
150
151fn parse_enumerator_variant(pair: Pair<Rule>) -> AsmEnumVariant {
152    let pairs = pair.into_inner();
153    let mut result = AsmEnumVariant {
154        meta: None,
155        name: Default::default(),
156        fields: vec![],
157        discriminant: None,
158    };
159    for pair in pairs {
160        match pair.as_rule() {
161            Rule::identifier => {
162                result.name = parse_identifier(pair);
163            }
164            Rule::structure_fields => {
165                result.fields = parse_struct_fields(pair);
166            }
167            rule => unreachable!("{:?}", rule),
168        }
169    }
170    result
171}
172
173fn parse_enumerator_header(pair: Pair<Rule>) -> AsmEnum {
174    let pairs = pair.into_inner();
175    let mut result = AsmEnum {
176        meta: None,
177        name: Default::default(),
178        visibility: Visibility::Public,
179        variants: vec![],
180        default_variant: None,
181    };
182    for pair in pairs {
183        match pair.as_rule() {
184            Rule::visibility => {
185                result.visibility = parse_visibility(pair);
186            }
187            Rule::path_enum => {
188                result.name = parse_path_name(pair);
189            }
190            rule => unreachable!("{:?}", rule),
191        }
192    }
193    result
194}
195
196fn parse_function(pair: Pair<Rule>) -> AsmFunction {
197    let mut pairs = pair.into_inner();
198    let mut result = parse_function_header(pairs.next().unwrap());
199    result.inputs = parse_function_parameters(pairs.next().unwrap());
200    result.outputs = parse_function_parameters(pairs.next().unwrap());
201    result.script = parse_scope(pairs.next().unwrap());
202    result
203}
204
205fn parse_scope(pair: Pair<Rule>) -> Vec<AsmOperation> {
206    pair.into_inner().map(parse_operation).collect()
207}
208
209fn parse_operation(pair: Pair<Rule>) -> AsmOperation {
210    let pair = pair.into_inner().next().unwrap();
211    match pair.as_rule() {
212        Rule::push_literal => parse_push_literal(pair),
213        Rule::stack_drop => AsmOperation::Expression(AsmExpression::StackDrop),
214        Rule::make_register => parse_make_register(pair),
215        Rule::drop_register => parse_drop_register(pair),
216        Rule::push_from_register => parse_push_from_register(pair),
217        Rule::pop_to_register => parse_pop_to_register(pair),
218        Rule::call_function => parse_call_function(pair),
219        Rule::branch_scope => parse_branch_scope(pair),
220        Rule::loop_scope => parse_loop_scope(pair),
221        Rule::pop_scope => AsmOperation::PopScope,
222        rule => unreachable!("{:?}", rule),
223    }
224}
225
226fn parse_loop_scope(pair: Pair<Rule>) -> AsmOperation {
227    AsmOperation::LoopScope {
228        script: parse_scope(pair.into_inner().next().unwrap()),
229    }
230}
231
232fn parse_branch_scope(pair: Pair<Rule>) -> AsmOperation {
233    let mut pairs = pair.into_inner();
234    AsmOperation::BranchScope {
235        script_success: parse_scope(pairs.next().unwrap()),
236        script_failure: pairs.next().map(parse_scope),
237    }
238}
239
240fn parse_call_function(pair: Pair<Rule>) -> AsmOperation {
241    let pairs = pair.into_inner();
242    let mut name = Default::default();
243    let mut module_name = None;
244    let mut type_name = None;
245    let mut visibility = None;
246    for pair in pairs {
247        match pair.as_rule() {
248            Rule::visibility => {
249                visibility = Some(parse_visibility(pair));
250            }
251            Rule::path_module => {
252                module_name = Some(parse_path_name(pair));
253            }
254            Rule::path_type => {
255                type_name = Some(parse_path_name(pair.into_inner().next().unwrap()));
256            }
257            Rule::path_function => {
258                name = parse_path_name(pair);
259            }
260            rule => unreachable!("{:?}", rule),
261        }
262    }
263    AsmOperation::CallFunction {
264        name,
265        module_name,
266        type_name,
267        visibility,
268    }
269}
270
271fn parse_pop_to_register(pair: Pair<Rule>) -> AsmOperation {
272    AsmOperation::PopToRegister {
273        index: parse_literal::<usize>(pair),
274    }
275}
276
277fn parse_push_from_register(pair: Pair<Rule>) -> AsmOperation {
278    AsmOperation::PushFromRegister {
279        index: parse_literal::<usize>(pair),
280    }
281}
282
283fn parse_drop_register(pair: Pair<Rule>) -> AsmOperation {
284    AsmOperation::DropRegister {
285        index: parse_literal::<usize>(pair),
286    }
287}
288
289fn parse_make_register(pair: Pair<Rule>) -> AsmOperation {
290    let pairs = pair.into_inner();
291    let mut name = Default::default();
292    let mut module_name = None;
293    for pair in pairs {
294        match pair.as_rule() {
295            Rule::path_module => {
296                module_name = Some(parse_path_name(pair));
297            }
298            Rule::path_type => {
299                name = parse_path_name(pair);
300            }
301            rule => unreachable!("{:?}", rule),
302        }
303    }
304    AsmOperation::MakeRegister { name, module_name }
305}
306
307macro_rules! parse_literal {
308    ($type:ty, $pair:expr) => {{
309        let pair = $pair.into_inner().next().unwrap();
310        match pair.as_rule() {
311            Rule::integer | Rule::index => <$type>::from_str(pair.as_str()).unwrap(),
312            Rule::hex_inner => <$type>::from_str_radix(pair.as_str(), 16).unwrap(),
313            Rule::binary_inner => <$type>::from_str_radix(pair.as_str(), 2).unwrap(),
314            rule => unreachable!("{:?}", rule),
315        }
316    }};
317}
318
319fn parse_push_literal(pair: Pair<Rule>) -> AsmOperation {
320    let pair = pair
321        .into_inner()
322        .next()
323        .unwrap()
324        .into_inner()
325        .next()
326        .unwrap();
327    match pair.as_rule() {
328        Rule::literal_unit => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::Unit)),
329        Rule::literal_bool_false => {
330            AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::Bool(false)))
331        }
332        Rule::literal_bool_true => {
333            AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::Bool(true)))
334        }
335        Rule::literal_i8 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::I8(
336            parse_literal!(i8, pair),
337        ))),
338        Rule::literal_i16 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::I16(
339            parse_literal!(i16, pair),
340        ))),
341        Rule::literal_i32 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::I32(
342            parse_literal!(i32, pair),
343        ))),
344        Rule::literal_i64 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::I64(
345            parse_literal!(i64, pair),
346        ))),
347        Rule::literal_i128 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::I128(
348            parse_literal!(i128, pair),
349        ))),
350        Rule::literal_isize => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::Isize(
351            parse_literal!(isize, pair),
352        ))),
353        Rule::literal_u8 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::U8(
354            parse_literal!(u8, pair),
355        ))),
356        Rule::literal_u16 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::U16(
357            parse_literal!(u16, pair),
358        ))),
359        Rule::literal_u32 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::U32(
360            parse_literal!(u32, pair),
361        ))),
362        Rule::literal_u64 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::U64(
363            parse_literal!(u64, pair),
364        ))),
365        Rule::literal_u128 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::U128(
366            parse_literal!(u128, pair),
367        ))),
368        Rule::literal_usize => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::Usize(
369            parse_literal!(usize, pair),
370        ))),
371        Rule::literal_f32 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::F32(
372            parse_literal::<f32>(pair),
373        ))),
374        Rule::literal_f64 => AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::F64(
375            parse_literal::<f64>(pair),
376        ))),
377        Rule::literal_char => {
378            AsmOperation::Expression(AsmExpression::Literal(AsmLiteral::Char(parse_literal::<
379                char,
380            >(pair))))
381        }
382        Rule::literal_string => AsmOperation::Expression(AsmExpression::Literal(
383            AsmLiteral::String(parse_string(pair)),
384        )),
385        rule => unreachable!("{:?}", rule),
386    }
387}
388
389fn parse_function_parameters(pair: Pair<Rule>) -> Vec<AsmFunctionParameter> {
390    pair.into_inner().map(parse_function_parameter).collect()
391}
392
393fn parse_function_parameter(pair: Pair<Rule>) -> AsmFunctionParameter {
394    let mut pairs = pair.into_inner();
395    let mut result = AsmFunctionParameter {
396        meta: None,
397        name: parse_identifier(pairs.next().unwrap()),
398        module_name: None,
399        type_name: Default::default(),
400    };
401    for pair in pairs {
402        match pair.as_rule() {
403            Rule::path_module => {
404                result.module_name = Some(parse_path_name(pair));
405            }
406            Rule::path_type => {
407                result.type_name = parse_path_name(pair.into_inner().next().unwrap());
408            }
409            rule => unreachable!("{:?}", rule),
410        }
411    }
412    result
413}
414
415fn parse_function_header(pair: Pair<Rule>) -> AsmFunction {
416    let pairs = pair.into_inner();
417    let mut result = AsmFunction {
418        meta: None,
419        name: Default::default(),
420        type_name: None,
421        visibility: Visibility::Public,
422        inputs: vec![],
423        outputs: vec![],
424        script: vec![],
425    };
426    for pair in pairs {
427        match pair.as_rule() {
428            Rule::visibility => {
429                result.visibility = parse_visibility(pair);
430            }
431            Rule::path_type => {
432                result.type_name = Some(parse_path_name(pair.into_inner().next().unwrap()));
433            }
434            Rule::path_function => {
435                result.name = parse_path_name(pair);
436            }
437            rule => unreachable!("{:?}", rule),
438        }
439    }
440    result
441}
442
443fn parse_path_name(pair: Pair<Rule>) -> String {
444    parse_identifier(pair.into_inner().next().unwrap())
445}
446
447fn parse_visibility(pair: Pair<Rule>) -> Visibility {
448    match pair.into_inner().next().unwrap().as_rule() {
449        Rule::visibility_public => Visibility::Public,
450        Rule::visibility_internal => Visibility::Module,
451        Rule::visibility_private => Visibility::Private,
452        rule => unreachable!("{:?}", rule),
453    }
454}
455
456fn parse_literal<T>(pair: Pair<Rule>) -> T
457where
458    T: FromStr,
459    <T as FromStr>::Err: Debug,
460{
461    pair.into_inner()
462        .next()
463        .unwrap()
464        .as_str()
465        .parse::<T>()
466        .unwrap()
467}
468
469fn parse_string(pair: Pair<Rule>) -> String {
470    snailquote::unescape(pair.as_str()).unwrap()
471}
472
473fn parse_identifier(pair: Pair<Rule>) -> String {
474    pair.as_str().to_owned()
475}