solar_parse/parser/
expr.rs

1use crate::{PResult, Parser};
2use smallvec::SmallVec;
3use solar_ast::{token::*, *};
4
5use solar_interface::kw;
6
7impl<'sess, 'ast> Parser<'sess, 'ast> {
8    /// Parses an expression.
9    #[inline]
10    pub fn parse_expr(&mut self) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
11        self.with_recursion_limit("expression", |this| this.parse_expr_with(None))
12    }
13
14    #[instrument(name = "parse_expr", level = "trace", skip_all)]
15    pub(super) fn parse_expr_with(
16        &mut self,
17        with: Option<Box<'ast, Expr<'ast>>>,
18    ) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
19        let expr = self.parse_binary_expr(4, with)?;
20        if self.eat(TokenKind::Question) {
21            let then = self.parse_expr()?;
22            self.expect(TokenKind::Colon)?;
23            let else_ = self.parse_expr()?;
24            let span = expr.span.to(self.prev_token.span);
25            Ok(self.alloc(Expr { span, kind: ExprKind::Ternary(expr, then, else_) }))
26        } else {
27            let kind = if let Some(binop_eq) = self.token.as_binop_eq() {
28                Some(binop_eq)
29            } else if self.token.kind == TokenKind::Eq {
30                None
31            } else {
32                return Ok(expr);
33            };
34            self.bump(); // binop token
35            let rhs = self.parse_expr()?;
36            let span = expr.span.to(self.prev_token.span);
37            Ok(self.alloc(Expr { span, kind: ExprKind::Assign(expr, kind, rhs) }))
38        }
39    }
40
41    /// Parses a binary expression.
42    fn parse_binary_expr(
43        &mut self,
44        min_precedence: usize,
45        with: Option<Box<'ast, Expr<'ast>>>,
46    ) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
47        let mut expr = self.parse_unary_expr(with)?;
48        let mut precedence = token_precedence(self.token);
49        while precedence >= min_precedence {
50            while token_precedence(self.token) == precedence {
51                // Parse a**b**c as a**(b**c)
52                let next_precedence = if self.token.kind == TokenKind::BinOp(BinOpToken::Star) {
53                    precedence + 1
54                } else {
55                    precedence
56                };
57
58                let token = self.token;
59                self.bump(); // binop token
60
61                let rhs = self.parse_binary_expr(next_precedence, None)?;
62
63                let span = expr.span.to(self.prev_token.span);
64
65                let kind = if let Some(binop) = token.as_binop() {
66                    ExprKind::Binary(expr, binop, rhs)
67                } else if let Some(binop_eq) = token.as_binop_eq() {
68                    ExprKind::Assign(expr, Some(binop_eq), rhs)
69                } else if token.kind == TokenKind::Eq {
70                    ExprKind::Assign(expr, None, rhs)
71                } else {
72                    let msg = format!("unknown binop token: {token:?}");
73                    self.dcx().bug(msg).span(span).emit();
74                };
75                expr = self.alloc(Expr { span, kind });
76            }
77            precedence -= 1;
78        }
79        Ok(expr)
80    }
81
82    /// Parses a unary expression.
83    fn parse_unary_expr(
84        &mut self,
85        with: Option<Box<'ast, Expr<'ast>>>,
86    ) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
87        if with.is_none() && self.eat(TokenKind::BinOp(BinOpToken::Plus)) {
88            self.dcx().err("unary plus is not supported").span(self.prev_token.span).emit();
89        }
90
91        let lo = with.as_ref().map(|e| e.span).unwrap_or(self.token.span);
92        let parse_lhs = |this: &mut Self, with| {
93            this.parse_lhs_expr(with, lo).map(|expr| {
94                if let Some(unop) = this.token.as_unop(true) {
95                    this.bump(); // unop
96                    let span = lo.to(this.prev_token.span);
97                    this.alloc(Expr { span, kind: ExprKind::Unary(unop, expr) })
98                } else {
99                    expr
100                }
101            })
102        };
103        if let Some(with) = with {
104            parse_lhs(self, Some(with))
105        } else if self.eat_keyword(kw::Delete) {
106            self.parse_unary_expr(None).map(|expr| {
107                let span = lo.to(self.prev_token.span);
108                self.alloc(Expr { span, kind: ExprKind::Delete(expr) })
109            })
110        } else if let Some(unop) = self.token.as_unop(false) {
111            self.bump(); // unop
112            self.parse_unary_expr(None).map(|expr| {
113                let span = lo.to(self.prev_token.span);
114                self.alloc(Expr { span, kind: ExprKind::Unary(unop, expr) })
115            })
116        } else {
117            parse_lhs(self, None)
118        }
119    }
120
121    /// Parses a primary left-hand-side expression.
122    fn parse_lhs_expr(
123        &mut self,
124        with: Option<Box<'ast, Expr<'ast>>>,
125        lo: Span,
126    ) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
127        let mut expr = if let Some(with) = with {
128            Ok(with)
129        } else if self.eat_keyword(kw::New) {
130            self.parse_type().map(|ty| {
131                let span = lo.to(self.prev_token.span);
132                self.alloc(Expr { span, kind: ExprKind::New(ty) })
133            })
134        } else if self.eat_keyword(kw::Payable) {
135            self.parse_call_args().map(|args| {
136                let span = lo.to(self.prev_token.span);
137                self.alloc(Expr { span, kind: ExprKind::Payable(args) })
138            })
139        } else {
140            self.parse_primary_expr()
141        }?;
142        loop {
143            let kind = if self.eat(TokenKind::Dot) {
144                // expr.member
145                let member = self.parse_ident_any()?;
146                ExprKind::Member(expr, member)
147            } else if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
148                // expr(args)
149                let args = self.parse_call_args()?;
150                ExprKind::Call(expr, args)
151            } else if self.check(TokenKind::OpenDelim(Delimiter::Bracket)) {
152                let kind = self.parse_expr_index_kind()?;
153                ExprKind::Index(expr, kind)
154            } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
155                // This may be `try` statement block.
156                if !self.look_ahead(1).is_ident() || self.look_ahead(2).kind != TokenKind::Colon {
157                    break;
158                }
159
160                // expr{args}
161                let args = self.parse_named_args(false)?;
162                ExprKind::CallOptions(expr, args)
163            } else {
164                break;
165            };
166            let span = lo.to(self.prev_token.span);
167            expr = self.alloc(Expr { span, kind });
168        }
169        Ok(expr)
170    }
171
172    /// Parses a primary expression.
173    fn parse_primary_expr(&mut self) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
174        let lo = self.token.span;
175        let kind = if self.check_lit() {
176            let (lit, sub) = self.parse_lit(true)?;
177            ExprKind::Lit(self.alloc(lit), sub)
178        } else if self.eat_keyword(kw::Type) {
179            self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
180            let ty = self.parse_type()?;
181            self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
182            ExprKind::TypeCall(ty)
183        } else if self.check_elementary_type() {
184            let mut ty = self.parse_type()?;
185            if let TypeKind::Elementary(ElementaryType::Address(payable)) = &mut ty.kind
186                && *payable
187            {
188                let msg = "`address payable` cannot be used in an expression";
189                self.dcx().err(msg).span(ty.span).emit();
190                *payable = false;
191            }
192            ExprKind::Type(ty)
193        } else if self.check_nr_ident() {
194            let ident = self.parse_ident()?;
195            ExprKind::Ident(ident)
196        } else if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis))
197            || self.check(TokenKind::OpenDelim(Delimiter::Bracket))
198        {
199            // Array or tuple expression.
200            let TokenKind::OpenDelim(close_delim) = self.token.kind else { unreachable!() };
201            let is_array = close_delim == Delimiter::Bracket;
202            let list = self.parse_optional_items_seq(close_delim, Self::parse_expr)?;
203            if is_array {
204                let list = list
205                    .into_iter()
206                    .map(|item| match item.into() {
207                        Some(expr) => Ok(Some(expr)),
208                        None => {
209                            let msg = "array expression components cannot be empty";
210                            let span = lo.to(self.prev_token.span);
211                            Err(self.dcx().err(msg).span(span))
212                        }
213                    })
214                    .collect::<Result<SmallVec<[Option<_>; 8]>, _>>()?;
215
216                // SAFETY: All elements are checked to be `Some` above.
217                ExprKind::Array(unsafe { option_boxes_unwrap_unchecked(self.alloc_smallvec(list)) })
218            } else {
219                ExprKind::Tuple(self.alloc_smallvec(list))
220            }
221        } else {
222            return self.unexpected();
223        };
224        let span = lo.to(self.prev_token.span);
225        Ok(self.alloc(Expr { span, kind }))
226    }
227
228    /// Parses a list of function call arguments.
229    #[track_caller]
230    pub(super) fn parse_call_args(&mut self) -> PResult<'sess, CallArgs<'ast>> {
231        self.parse_spanned(Self::parse_call_args_kind).map(|(span, kind)| CallArgs { span, kind })
232    }
233
234    #[track_caller]
235    fn parse_call_args_kind(&mut self) -> PResult<'sess, CallArgsKind<'ast>> {
236        if self.look_ahead(1).kind == TokenKind::OpenDelim(Delimiter::Brace) {
237            self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
238            let args = self.parse_named_args(true).map(CallArgsKind::Named)?;
239            self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
240            Ok(args)
241        } else {
242            self.parse_unnamed_args().map(CallArgsKind::Unnamed)
243        }
244    }
245
246    /// Parses a `[]` indexing expression.
247    pub(super) fn parse_expr_index_kind(&mut self) -> PResult<'sess, IndexKind<'ast>> {
248        self.expect(TokenKind::OpenDelim(Delimiter::Bracket))?;
249        let kind = if self.check(TokenKind::CloseDelim(Delimiter::Bracket)) {
250            // expr[]
251            IndexKind::Index(None)
252        } else {
253            let start = if self.check(TokenKind::Colon) { None } else { Some(self.parse_expr()?) };
254            if self.eat_noexpect(TokenKind::Colon) {
255                // expr[start?:end?]
256                let end = if self.check(TokenKind::CloseDelim(Delimiter::Bracket)) {
257                    None
258                } else {
259                    Some(self.parse_expr()?)
260                };
261                IndexKind::Range(start, end)
262            } else {
263                // expr[start?]
264                IndexKind::Index(start)
265            }
266        };
267        self.expect(TokenKind::CloseDelim(Delimiter::Bracket))?;
268        Ok(kind)
269    }
270
271    /// Parses a list of named arguments: `{a: b, c: d, ...}`
272    #[track_caller]
273    fn parse_named_args(&mut self, allow_empty: bool) -> PResult<'sess, NamedArgList<'ast>> {
274        self.parse_delim_comma_seq(Delimiter::Brace, allow_empty, Self::parse_named_arg)
275    }
276
277    /// Parses a single named argument: `a: b`.
278    #[track_caller]
279    fn parse_named_arg(&mut self) -> PResult<'sess, NamedArg<'ast>> {
280        let name = self.parse_ident()?;
281        self.expect(TokenKind::Colon)?;
282        let value = self.parse_expr()?;
283        Ok(NamedArg { name, value })
284    }
285
286    /// Parses a list of expressions: `(a, b, c, ...)`.
287    #[allow(clippy::vec_box)]
288    #[track_caller]
289    fn parse_unnamed_args(&mut self) -> PResult<'sess, BoxSlice<'ast, Box<'ast, Expr<'ast>>>> {
290        self.parse_paren_comma_seq(true, Self::parse_expr)
291    }
292}
293
294fn token_precedence(t: Token) -> usize {
295    // https://github.com/argotorg/solidity/blob/78ec8dd6f93bf5a5b4ca7582f9d491a4f66c3610/liblangutil/Token.h#L68
296    use BinOpToken::*;
297    use TokenKind::*;
298    match t.kind {
299        Question => 3,
300        Eq => 2,
301        BinOpEq(_) => 2,
302        Comma => 1,
303        OrOr => 4,
304        AndAnd => 5,
305        BinOp(Or) => 8,
306        BinOp(Caret) => 9,
307        BinOp(And) => 10,
308        BinOp(Shl) => 11,
309        BinOp(Sar) => 11,
310        BinOp(Shr) => 11,
311        BinOp(Plus) => 12,
312        BinOp(Minus) => 12,
313        BinOp(Star) => 13,
314        BinOp(Slash) => 13,
315        BinOp(Percent) => 13,
316        StarStar => 14,
317        EqEq => 6,
318        Ne => 6,
319        Lt => 7,
320        Gt => 7,
321        Le => 7,
322        Ge => 7,
323        Walrus => 2,
324        _ => 0,
325    }
326}
327
328/// Converts a list of `SpannedOption<Box<'ast, T>>` into a list of `Box<'ast, T>`.
329///
330/// This only works because `Option<Box<'ast, T>>` is guaranteed to be a valid `Box<'ast, T>` when
331/// `Some` when `T: Sized`.
332///
333/// # Safety
334///
335/// All elements of the list must be `Some`.
336#[inline]
337unsafe fn option_boxes_unwrap_unchecked<'a, 'b, T>(
338    list: BoxSlice<'a, Option<Box<'b, T>>>,
339) -> BoxSlice<'a, Box<'b, T>> {
340    debug_assert!(list.iter().all(Option::is_some));
341    // SAFETY: Caller must ensure that all elements are `Some`.
342    unsafe { std::mem::transmute(list) }
343}