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