Skip to main content

solar_parse/parser/
expr.rs

1use crate::{PResult, Parser};
2use smallvec::SmallVec;
3use solar_ast::{token::*, *};
4
5use solar_interface::{Ident, Symbol, kw};
6
7impl<'sess, 'ast, 'cb> Parser<'sess, 'ast, 'cb> {
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::StarStar {
53                    precedence
54                } else {
55                    precedence + 1
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().emit_err(self.prev_token.span, "unary plus is not supported");
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                let dot_span = self.prev_token.span;
145                // expr.member
146                match self.parse_ident_any() {
147                    Ok(member) => ExprKind::Member(expr, member),
148                    Err(err) => {
149                        err.emit();
150                        let member = Ident::new(Symbol::DUMMY, dot_span.shrink_to_hi());
151                        ExprKind::Member(expr, member)
152                    }
153                }
154            } else if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
155                // expr(args)
156                let args = self.parse_call_args()?;
157                ExprKind::Call(expr, args)
158            } else if self.check(TokenKind::OpenDelim(Delimiter::Bracket)) {
159                let kind = self.parse_expr_index_kind()?;
160                ExprKind::Index(expr, kind)
161            } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
162                // This may be `try` statement block.
163                if !self.look_ahead(1).is_ident() || self.look_ahead(2).kind != TokenKind::Colon {
164                    break;
165                }
166
167                // expr{args}
168                let args = self.parse_named_args(false)?;
169                ExprKind::CallOptions(expr, args)
170            } else {
171                break;
172            };
173            let span = lo.to(self.prev_token.span);
174            expr = self.alloc(Expr { span, kind });
175        }
176        Ok(expr)
177    }
178
179    /// Parses a primary expression.
180    fn parse_primary_expr(&mut self) -> PResult<'sess, Box<'ast, Expr<'ast>>> {
181        let lo = self.token.span;
182        let kind = if self.check_lit() {
183            let (lit, sub) = self.parse_lit(true)?;
184            ExprKind::Lit(self.alloc(lit), sub)
185        } else if self.eat_keyword(kw::Type) {
186            self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
187            let ty = self.parse_type()?;
188            self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
189            ExprKind::TypeCall(ty)
190        } else if self.check_elementary_type() {
191            let mut ty = self.parse_type()?;
192            if let TypeKind::Elementary(ElementaryType::Address(payable)) = &mut ty.kind
193                && *payable
194            {
195                let msg = "`address payable` cannot be used in an expression";
196                self.dcx().emit_err(ty.span, msg);
197                *payable = false;
198            }
199            ExprKind::Type(ty)
200        } else if self.check_nr_ident() {
201            let ident = self.parse_ident()?;
202            ExprKind::Ident(ident)
203        } else if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis))
204            || self.check(TokenKind::OpenDelim(Delimiter::Bracket))
205        {
206            // Array or tuple expression.
207            let TokenKind::OpenDelim(close_delim) = self.token.kind else { unreachable!() };
208            let is_array = close_delim == Delimiter::Bracket;
209            let list = self.parse_optional_items_seq(close_delim, Self::parse_expr)?;
210            if is_array {
211                let list = list
212                    .into_iter()
213                    .map(|item| match item.into() {
214                        Some(expr) => Ok(Some(expr)),
215                        None => {
216                            let msg = "array expression components cannot be empty";
217                            let span = lo.to(self.prev_token.span);
218                            Err(self.dcx().err(msg).span(span))
219                        }
220                    })
221                    .collect::<Result<SmallVec<[Option<_>; 8]>, _>>()?;
222
223                // SAFETY: All elements are checked to be `Some` above.
224                ExprKind::Array(unsafe { option_boxes_unwrap_unchecked(self.alloc_smallvec(list)) })
225            } else {
226                ExprKind::Tuple(self.alloc_smallvec(list))
227            }
228        } else {
229            return self.unexpected();
230        };
231        let span = lo.to(self.prev_token.span);
232        Ok(self.alloc(Expr { span, kind }))
233    }
234
235    /// Parses a list of function call arguments.
236    #[track_caller]
237    pub(super) fn parse_call_args(&mut self) -> PResult<'sess, CallArgs<'ast>> {
238        self.parse_spanned(Self::parse_call_args_kind).map(|(span, kind)| CallArgs { span, kind })
239    }
240
241    #[track_caller]
242    fn parse_call_args_kind(&mut self) -> PResult<'sess, CallArgsKind<'ast>> {
243        if self.look_ahead(1).kind == TokenKind::OpenDelim(Delimiter::Brace) {
244            self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
245            let args = self.parse_named_args(true).map(CallArgsKind::Named)?;
246            self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
247            Ok(args)
248        } else {
249            self.parse_unnamed_args().map(CallArgsKind::Unnamed)
250        }
251    }
252
253    /// Parses a `[]` indexing expression.
254    pub(super) fn parse_expr_index_kind(&mut self) -> PResult<'sess, IndexKind<'ast>> {
255        self.expect(TokenKind::OpenDelim(Delimiter::Bracket))?;
256        let kind = if self.check(TokenKind::CloseDelim(Delimiter::Bracket)) {
257            // expr[]
258            IndexKind::Index(None)
259        } else {
260            let start = if self.check(TokenKind::Colon) { None } else { Some(self.parse_expr()?) };
261            if self.eat_noexpect(TokenKind::Colon) {
262                // expr[start?:end?]
263                let end = if self.check(TokenKind::CloseDelim(Delimiter::Bracket)) {
264                    None
265                } else {
266                    Some(self.parse_expr()?)
267                };
268                IndexKind::Range(start, end)
269            } else {
270                // expr[start?]
271                IndexKind::Index(start)
272            }
273        };
274        self.expect(TokenKind::CloseDelim(Delimiter::Bracket))?;
275        Ok(kind)
276    }
277
278    /// Parses a list of named arguments: `{a: b, c: d, ...}`
279    #[track_caller]
280    fn parse_named_args(&mut self, allow_empty: bool) -> PResult<'sess, NamedArgList<'ast>> {
281        self.parse_delim_comma_seq(Delimiter::Brace, allow_empty, Self::parse_named_arg)
282    }
283
284    /// Parses a single named argument: `a: b`.
285    #[track_caller]
286    fn parse_named_arg(&mut self) -> PResult<'sess, NamedArg<'ast>> {
287        let name = self.parse_ident()?;
288        self.expect(TokenKind::Colon)?;
289        let value = self.parse_expr()?;
290        Ok(NamedArg { name, value })
291    }
292
293    /// Parses a list of expressions: `(a, b, c, ...)`.
294    #[allow(clippy::vec_box)]
295    #[track_caller]
296    fn parse_unnamed_args(&mut self) -> PResult<'sess, BoxSlice<'ast, Box<'ast, Expr<'ast>>>> {
297        self.parse_paren_comma_seq(true, Self::parse_expr)
298    }
299}
300
301fn token_precedence(t: Token) -> usize {
302    // https://github.com/argotorg/solidity/blob/78ec8dd6f93bf5a5b4ca7582f9d491a4f66c3610/liblangutil/Token.h#L68
303    use BinOpToken::*;
304    use TokenKind::*;
305    match t.kind {
306        Question => 3,
307        Eq => 2,
308        BinOpEq(_) => 2,
309        Comma => 1,
310        OrOr => 4,
311        AndAnd => 5,
312        BinOp(Or) => 8,
313        BinOp(Caret) => 9,
314        BinOp(And) => 10,
315        BinOp(Shl) => 11,
316        BinOp(Sar) => 11,
317        BinOp(Shr) => 11,
318        BinOp(Plus) => 12,
319        BinOp(Minus) => 12,
320        BinOp(Star) => 13,
321        BinOp(Slash) => 13,
322        BinOp(Percent) => 13,
323        StarStar => 14,
324        EqEq => 6,
325        Ne => 6,
326        Lt => 7,
327        Gt => 7,
328        Le => 7,
329        Ge => 7,
330        Walrus => 2,
331        _ => 0,
332    }
333}
334
335/// Converts a list of `SpannedOption<Box<'ast, T>>` into a list of `Box<'ast, T>`.
336///
337/// This only works because `Option<Box<'ast, T>>` is guaranteed to be a valid `Box<'ast, T>` when
338/// `Some` when `T: Sized`.
339///
340/// # Safety
341///
342/// All elements of the list must be `Some`.
343#[inline]
344unsafe fn option_boxes_unwrap_unchecked<'a, 'b, T>(
345    list: BoxSlice<'a, Option<Box<'b, T>>>,
346) -> BoxSlice<'a, Box<'b, T>> {
347    debug_assert!(list.iter().all(Option::is_some));
348    // SAFETY: Caller must ensure that all elements are `Some`.
349    unsafe { std::mem::transmute(list) }
350}