Skip to main content

mist_parser/parser/common/
expr.rs

1use crate::{
2    Rule,
3    ast::*,
4    ast_ensure, ast_expr,
5    error::{AstError, AstResult, GetLength, IntoErr, collect_recovered, collect_recovered_map},
6    parser::consume_rule,
7};
8use pest::pratt_parser::PrattParser;
9use std::sync::OnceLock;
10
11impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Expression {
12    type Error = AstError<'a, Self>;
13
14    fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
15        let rule = pair.as_rule();
16        let mut inner = pair.clone().into_inner();
17
18        match rule {
19            Rule::expr => {
20                static PRATT_PARSER: OnceLock<PrattParser<Rule>> = OnceLock::new();
21                let pratt = PRATT_PARSER.get_or_init(|| {
22                    use pest::pratt_parser::{Assoc::*, Op};
23
24                    PrattParser::new().op(Op::infix(Rule::bin_op, Left))
25                });
26
27                pratt
28                    .map_primary(|primary_pair| Expression::try_from(primary_pair))
29                    .map_infix(|expr, op, rhs| {
30                        ast_expr!(Expression::Binary {
31                            lhs: expr.map(Box::new).get_map(Box::new),
32                            op: Ok(op.as_str().to_string()) as AstResult<'_, String>,
33                            rhs: rhs.map(Box::new).get_map(Box::new),
34                        })
35                    })
36                    .parse(inner)
37            }
38
39            Rule::term => {
40                let mut prefix_pairs = Vec::new();
41                let mut primary_pair = None;
42                let mut postfix_pairs = Vec::new();
43
44                for p in inner {
45                    match p.as_rule() {
46                        Rule::prefix => prefix_pairs.push(p),
47                        Rule::primary => primary_pair = Some(p),
48                        Rule::postfix => postfix_pairs.push(p),
49                        _ => {}
50                    }
51                }
52
53                let prefixes = collect_recovered::<Prefix, Prefix>(prefix_pairs.into_iter());
54                let exp = Expression::try_from(
55                    primary_pair.expect("Term must contain a primary expression"),
56                );
57                let postfixes = collect_recovered::<Postfix, Postfix>(postfix_pairs.into_iter());
58
59                if postfixes.len() > 0 || prefixes.len() > 0 {
60                    ast_expr!(Expression::Fix {
61                        initial: exp.map(Box::new),
62                        prefixes: prefixes,
63                        postfixes: postfixes,
64                    })
65                } else {
66                    ast_expr!(use exp?, prefixes, postfixes)
67                }
68            }
69
70            Rule::tuple => {
71                ast_expr!(Expression::Literal(
72                    collect_recovered(pair.into_inner())
73                        .map(Literal::Tuple)
74                        .get_map(Literal::Tuple)
75                ))
76            }
77
78            Rule::primary => pair.into_inner().next().unwrap().try_into(),
79            Rule::static_path => ast_expr!(Expression::Path(pair.try_into())),
80            Rule::literal => ast_expr!(Expression::Literal(pair.try_into())),
81            Rule::expr_path => ast_expr!(Expression::Path(pair.try_into())),
82            Rule::statement_wrapper => {
83                let i = inner.next().unwrap();
84                match i.as_rule() {
85                    Rule::expr => i.try_into(),
86                    _ => ast_expr!(Expression::Statement(
87                        i.try_into().get_map(Box::new).map(Box::new)
88                    )),
89                }
90            }
91            Rule::statement | Rule::basic_stmt | Rule::control_flow => ast_expr!(
92                Expression::Statement(pair.try_into().get_map(Box::new).map(Box::new))
93            ),
94
95            _ => AstError::bug_unimplemented(pair),
96        }
97    }
98}
99
100impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Prefix {
101    type Error = AstError<'a, Self>;
102
103    fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
104        Ok(match pair.as_rule() {
105            Rule::prefix => Self::try_from(pair.into_inner().next().unwrap())?,
106            Rule::deref_px => Self::Deref,
107            Rule::mut_ref_px => Self::RefMut,
108            Rule::ref_px => Self::Ref,
109            Rule::not_px => Self::Not,
110            Rule::neg_px => Self::Neg,
111            Rule::closure => {
112                let mut inner = pair.into_inner();
113
114                return ast_expr!(Self::Closure(
115                    consume_rule(&mut inner, Rule::type_expr)
116                        .map(TypeExpr::try_from)
117                        .transpose(),
118                    collect_recovered(inner.next().unwrap().into_inner())
119                ));
120            }
121
122            _ => return AstError::bug_unimplemented(pair),
123        })
124    }
125}
126
127impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for Postfix {
128    type Error = AstError<'a, Self>;
129
130    fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
131        let rule = pair.as_rule();
132        let mut inner = pair.clone().into_inner();
133
134        match rule {
135            Rule::postfix => Postfix::try_from(inner.next().unwrap()),
136
137            Rule::field_px => {
138                ast_expr!(Postfix::FieldAccess(
139                    inner.next().unwrap().try_into(),
140                    inner.next().map(Generics::try_from).transpose()
141                ))
142            }
143
144            Rule::call_px => ast_expr!(Postfix::Call(collect_recovered(inner))),
145
146            Rule::struct_px => ast_expr!(Postfix::StructCall(collect_recovered_map(inner, |p| {
147                let mut pi = p.into_inner();
148                Ok((
149                    Identifier::try_from(pi.next().unwrap())?,
150                    Expression::try_from(pi.next().unwrap()).get()?,
151                ))
152            }))),
153
154            Rule::index_px => {
155                ast_expr!(Postfix::Index(Expression::try_from(inner.next().unwrap())))
156            }
157
158            Rule::macro_call_paren => Ok(Postfix::MacroCall {
159                inner: inner.as_str().to_string(),
160                delimiter: MacroDelimiter::Paren,
161            }),
162            Rule::macro_call_bracket => Ok(Postfix::MacroCall {
163                inner: inner.as_str().to_string(),
164                delimiter: MacroDelimiter::Bracket,
165            }),
166            Rule::macro_call_brace => Ok(Postfix::MacroCall {
167                inner: inner.as_str().to_string(),
168                delimiter: MacroDelimiter::Brace,
169            }),
170
171            Rule::as_px => {
172                ast_expr!(Postfix::As(inner.next().unwrap().try_into()))
173            }
174
175            Rule::try_px => Ok(Postfix::Try),
176
177            Rule::increment => Ok(Postfix::Increment),
178            Rule::decrement => Ok(Postfix::Decrement),
179
180            _ => AstError::bug_unimplemented(pair),
181        }
182    }
183}
184
185impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ExprPath {
186    type Error = AstError<'a, Self>;
187
188    fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
189        ast_ensure!(pair, Rule::expr_path => {
190            ast_expr!(ExprPath(collect_recovered(pair.into_inner())))
191        })
192    }
193}
194
195impl<'a> TryFrom<pest::iterators::Pair<'a, Rule>> for ExprPathSegment {
196    type Error = AstError<'a, Self>;
197
198    fn try_from(pair: pest::iterators::Pair<'a, Rule>) -> Result<Self, Self::Error> {
199        let mut inner = pair.clone().into_inner();
200
201        ast_ensure!(pair, Rule::expr_path_segment => {
202            ast_expr!(ExprPathSegment {
203                ident: Identifier::try_from(inner.next().unwrap()),
204                generics: inner.next().map(Generics::try_from).transpose(),
205            })
206        })
207    }
208}