1use super::item::VarFlags;
2use crate::{PResult, Parser, parser::SeqSep};
3use smallvec::SmallVec;
4use solar_ast::{token::*, *};
5use solar_data_structures::BumpExt;
6use solar_interface::{Ident, Span, kw, sym};
7
8impl<'sess, 'ast> Parser<'sess, 'ast> {
9 #[instrument(level = "trace", skip_all)]
11 pub fn parse_stmt(&mut self) -> PResult<'sess, Stmt<'ast>> {
12 let docs = self.parse_doc_comments();
13 self.parse_spanned(Self::parse_stmt_kind).map(|(span, kind)| Stmt { docs, kind, span })
14 }
15
16 pub fn parse_stmt_boxed(&mut self) -> PResult<'sess, Box<'ast, Stmt<'ast>>> {
18 self.parse_stmt().map(|stmt| self.alloc(stmt))
19 }
20
21 fn parse_stmt_kind(&mut self) -> PResult<'sess, StmtKind<'ast>> {
23 let mut semi = true;
24 let kind = if self.eat_keyword(kw::If) {
25 semi = false;
26 self.parse_stmt_if()
27 } else if self.eat_keyword(kw::While) {
28 semi = false;
29 self.parse_stmt_while()
30 } else if self.eat_keyword(kw::Do) {
31 self.parse_stmt_do_while()
32 } else if self.eat_keyword(kw::For) {
33 semi = false;
34 self.parse_stmt_for()
35 } else if self.eat_keyword(kw::Unchecked) {
36 semi = false;
37 self.parse_block().map(StmtKind::UncheckedBlock)
38 } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
39 semi = false;
40 self.parse_block().map(StmtKind::Block)
41 } else if self.eat_keyword(kw::Continue) {
42 Ok(StmtKind::Continue)
43 } else if self.eat_keyword(kw::Break) {
44 Ok(StmtKind::Break)
45 } else if self.eat_keyword(kw::Return) {
46 let expr = if self.check(TokenKind::Semi) { None } else { Some(self.parse_expr()?) };
47 Ok(StmtKind::Return(expr))
48 } else if self.eat_keyword(kw::Throw) {
49 let msg = "`throw` statements have been removed; use `revert`, `require`, or `assert` instead";
50 Err(self.dcx().err(msg).span(self.prev_token.span))
51 } else if self.eat_keyword(kw::Try) {
52 semi = false;
53 self.parse_stmt_try().map(|stmt| StmtKind::Try(self.alloc(stmt)))
54 } else if self.eat_keyword(kw::Assembly) {
55 semi = false;
56 self.parse_stmt_assembly().map(StmtKind::Assembly)
57 } else if self.eat_keyword(kw::Emit) {
58 self.parse_path_call().map(|(path, params)| StmtKind::Emit(path, params))
59 } else if self.check_keyword(kw::Revert) && self.look_ahead(1).is_ident() {
60 self.bump(); self.parse_path_call().map(|(path, params)| StmtKind::Revert(path, params))
62 } else if self.check_keyword(sym::underscore) && self.look_ahead(1).kind == TokenKind::Semi
63 {
64 self.bump(); Ok(StmtKind::Placeholder)
66 } else {
67 self.parse_simple_stmt_kind()
68 };
69 if semi && kind.is_ok() {
70 self.expect_semi()?;
71 }
72 kind
73 }
74
75 pub(super) fn parse_block(&mut self) -> PResult<'sess, Block<'ast>> {
77 let lo = self.token.span;
78 self.parse_delim_seq(Delimiter::Brace, SeqSep::none(), true, Self::parse_stmt)
79 .map(|stmts| Block { span: lo.to(self.prev_token.span), stmts })
80 }
81
82 fn parse_stmt_if(&mut self) -> PResult<'sess, StmtKind<'ast>> {
84 self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
85 let expr = self.parse_expr()?;
86 self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
87 let true_stmt = self.parse_stmt()?;
88 let else_stmt =
89 if self.eat_keyword(kw::Else) { Some(self.parse_stmt_boxed()?) } else { None };
90 Ok(StmtKind::If(expr, self.alloc(true_stmt), else_stmt))
91 }
92
93 fn parse_stmt_while(&mut self) -> PResult<'sess, StmtKind<'ast>> {
95 self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
96 let expr = self.parse_expr()?;
97 self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
98 let stmt = self.parse_stmt()?;
99 Ok(StmtKind::While(expr, self.alloc(stmt)))
100 }
101
102 fn parse_stmt_do_while(&mut self) -> PResult<'sess, StmtKind<'ast>> {
104 let stmt = self.parse_stmt()?;
105 let stmt = self.alloc(stmt);
106 self.expect_keyword(kw::While)?;
107 self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
108 let expr = self.parse_expr()?;
109 self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
110 Ok(StmtKind::DoWhile(stmt, expr))
111 }
112
113 fn parse_stmt_for(&mut self) -> PResult<'sess, StmtKind<'ast>> {
115 self.expect(TokenKind::OpenDelim(Delimiter::Parenthesis))?;
116
117 let init = if self.check(TokenKind::Semi) { None } else { Some(self.parse_simple_stmt()?) };
118 self.expect(TokenKind::Semi)?;
119
120 let cond = if self.check(TokenKind::Semi) { None } else { Some(self.parse_expr()?) };
121 self.expect_semi()?;
122
123 let next = if self.check_noexpect(TokenKind::CloseDelim(Delimiter::Parenthesis)) {
124 None
125 } else {
126 Some(self.parse_expr()?)
127 };
128 self.expect(TokenKind::CloseDelim(Delimiter::Parenthesis))?;
129 let body = self.parse_stmt_boxed()?;
130 Ok(StmtKind::For { init: init.map(|init| self.alloc(init)), cond, next, body })
131 }
132
133 fn parse_stmt_try(&mut self) -> PResult<'sess, StmtTry<'ast>> {
135 let expr = self.parse_expr()?;
136 let mut clauses = SmallVec::<[_; 4]>::new();
137
138 let mut lo = self.token.span;
139 let returns = if self.eat_keyword(kw::Returns) {
140 self.parse_parameter_list(false, VarFlags::FUNCTION)?
141 } else {
142 Default::default()
143 };
144 let block = self.parse_block()?;
145 let span = lo.to(self.prev_token.span);
146 clauses.push(TryCatchClause { name: None, args: returns, block, span });
147
148 lo = self.token.span;
149 self.expect_keyword(kw::Catch)?;
150 loop {
151 let name = self.parse_ident_opt()?;
152 let args = if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
153 self.parse_parameter_list(false, VarFlags::FUNCTION)?
154 } else {
155 Default::default()
156 };
157 let block = self.parse_block()?;
158 let span = lo.to(self.prev_token.span);
159 clauses.push(TryCatchClause { name, args, block, span });
160 lo = self.token.span;
161 if !self.eat_keyword(kw::Catch) {
162 break;
163 }
164 }
165
166 let clauses = self.alloc_smallvec(clauses);
167 Ok(StmtTry { expr, clauses })
168 }
169
170 fn parse_stmt_assembly(&mut self) -> PResult<'sess, StmtAssembly<'ast>> {
172 let dialect = self.parse_str_lit_opt();
173 let flags = if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
174 self.parse_paren_comma_seq(false, Self::parse_str_lit)?
175 } else {
176 Default::default()
177 };
178 let block = self.parse_yul_block()?;
179 Ok(StmtAssembly { dialect, flags, block })
180 }
181
182 fn parse_simple_stmt(&mut self) -> PResult<'sess, Stmt<'ast>> {
184 let docs = self.parse_doc_comments();
185 self.parse_spanned(Self::parse_simple_stmt_kind).map(|(span, kind)| Stmt {
186 docs,
187 kind,
188 span,
189 })
190 }
191
192 fn parse_simple_stmt_kind(&mut self) -> PResult<'sess, StmtKind<'ast>> {
196 let lo = self.token.span;
197 if self.eat(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
198 let mut empty_components = 0usize;
199 while self.eat(TokenKind::Comma) {
200 empty_components += 1;
201 }
202
203 let (statement_type, iap) = self.try_parse_iap()?;
204 match statement_type {
205 LookAheadInfo::VariableDeclaration => {
206 let mut variables = smallvec_repeat_none(empty_components);
207 let ty = iap.into_ty(self);
208 variables
209 .push(Some(self.parse_variable_definition_with(VarFlags::FUNCTION, ty)?));
210 self.parse_optional_items_seq_required(
211 Delimiter::Parenthesis,
212 &mut variables,
213 |this| this.parse_variable_definition(VarFlags::FUNCTION),
214 )?;
215 self.expect(TokenKind::Eq)?;
216 let expr = self.parse_expr()?;
217 Ok(StmtKind::DeclMulti(self.alloc_smallvec(variables), expr))
218 }
219 LookAheadInfo::Expression => {
220 let mut components = smallvec_repeat_none(empty_components);
221 let expr = iap.into_expr(self);
222 components.push(Some(self.parse_expr_with(expr)?));
223 self.parse_optional_items_seq_required(
224 Delimiter::Parenthesis,
225 &mut components,
226 Self::parse_expr,
227 )?;
228 let partially_parsed = Expr {
229 span: lo.to(self.prev_token.span),
230 kind: ExprKind::Tuple(self.alloc_smallvec(components)),
231 };
232 self.parse_expr_with(Some(self.alloc(partially_parsed))).map(StmtKind::Expr)
233 }
234 LookAheadInfo::IndexAccessStructure => unreachable!(),
235 }
236 } else {
237 let (statement_type, iap) = self.try_parse_iap()?;
238 match statement_type {
239 LookAheadInfo::VariableDeclaration => {
240 let ty = iap.into_ty(self);
241 self.parse_variable_definition_with(VarFlags::VAR, ty)
242 .map(|var| StmtKind::DeclSingle(self.alloc(var)))
243 }
244 LookAheadInfo::Expression => {
245 let expr = iap.into_expr(self);
246 self.parse_expr_with(expr).map(StmtKind::Expr)
247 }
248 LookAheadInfo::IndexAccessStructure => unreachable!(),
249 }
250 }
251 }
252
253 pub(super) fn parse_optional_items_seq<T>(
256 &mut self,
257 delim: Delimiter,
258 mut f: impl FnMut(&mut Self) -> PResult<'sess, T>,
259 ) -> PResult<'sess, Box<'ast, [Option<T>]>> {
260 self.expect(TokenKind::OpenDelim(delim))?;
261 let mut out = SmallVec::<[_; 8]>::new();
262 while self.eat(TokenKind::Comma) {
263 out.push(None);
264 }
265 if !self.check(TokenKind::CloseDelim(delim)) {
266 out.push(Some(f(self)?));
267 }
268 self.parse_optional_items_seq_required(delim, &mut out, f)
269 .map(|()| self.alloc_smallvec(out))
270 }
271
272 fn parse_optional_items_seq_required<T>(
273 &mut self,
274 delim: Delimiter,
275 out: &mut SmallVec<[Option<T>; 8]>,
276 mut f: impl FnMut(&mut Self) -> PResult<'sess, T>,
277 ) -> PResult<'sess, ()> {
278 let close = TokenKind::CloseDelim(delim);
279 while !self.eat(close) {
280 self.expect(TokenKind::Comma)?;
281 if self.check(TokenKind::Comma) || self.check(close) {
282 out.push(None);
283 } else {
284 out.push(Some(f(self)?));
285 }
286 }
287 Ok(())
288 }
289
290 fn parse_path_call(&mut self) -> PResult<'sess, (AstPath<'ast>, CallArgs<'ast>)> {
292 let path = self.parse_path()?;
293 let params = self.parse_call_args()?;
294 Ok((path, params))
295 }
296
297 fn try_parse_iap(&mut self) -> PResult<'sess, (LookAheadInfo, IndexAccessedPath<'ast>)> {
299 if let ty @ (LookAheadInfo::VariableDeclaration | LookAheadInfo::Expression) =
301 self.peek_statement_type()
302 {
303 return Ok((ty, IndexAccessedPath::default()));
304 }
305
306 let iap = self.parse_iap()?;
307 let ty = if self.token.is_non_reserved_ident(self.in_yul)
308 || self.token.is_location_specifier()
309 {
310 LookAheadInfo::VariableDeclaration
312 } else {
313 LookAheadInfo::Expression
314 };
315 Ok((ty, iap))
316 }
317
318 fn peek_statement_type(&mut self) -> LookAheadInfo {
319 if self.token.is_keyword_any(&[kw::Mapping, kw::Function]) {
321 return LookAheadInfo::VariableDeclaration;
322 }
323
324 if self.check_nr_ident() || self.check_elementary_type() {
325 let next = self.look_ahead(1);
326 if self.token.is_elementary_type() && next.is_ident_where(|id| id.name == kw::Payable) {
327 return LookAheadInfo::VariableDeclaration;
328 }
329 if next.is_non_reserved_ident(self.in_yul)
330 || next.is_location_specifier()
331 || next.is_mutability_specifier()
333 || next.is_visibility_specifier()
334 {
335 return LookAheadInfo::VariableDeclaration;
336 }
337 if matches!(next.kind, TokenKind::OpenDelim(Delimiter::Bracket) | TokenKind::Dot) {
338 return LookAheadInfo::IndexAccessStructure;
339 }
340 }
341 LookAheadInfo::Expression
342 }
343
344 fn parse_iap(&mut self) -> PResult<'sess, IndexAccessedPath<'ast>> {
345 let mut path = SmallVec::<[_; 4]>::new();
347 if self.check_nr_ident() {
348 path.push(IapKind::Member(self.parse_ident()?));
349 while self.eat(TokenKind::Dot) {
350 let id = self.ident_or_err(true)?;
351 if id.name != kw::Address && id.is_reserved(self.in_yul) {
352 self.expected_ident_found_err().emit();
353 }
354 self.bump(); path.push(IapKind::Member(id));
356 }
357 } else if self.check_elementary_type() {
358 let (span, kind) = self.parse_spanned(Self::parse_elementary_type)?;
359 path.push(IapKind::MemberTy(span, kind));
360 } else {
361 return self.unexpected();
362 }
363 let n_idents = path.len();
364
365 while self.check(TokenKind::OpenDelim(Delimiter::Bracket)) {
366 let (span, kind) = self.parse_spanned(Self::parse_expr_index_kind)?;
367 path.push(IapKind::Index(span, kind));
368 }
369
370 Ok(IndexAccessedPath { path, n_idents })
371 }
372}
373
374#[derive(Debug)]
375enum LookAheadInfo {
376 IndexAccessStructure,
378 VariableDeclaration,
379 Expression,
380}
381
382#[derive(Debug)]
383enum IapKind<'ast> {
384 Index(Span, IndexKind<'ast>),
386 Member(Ident),
388 MemberTy(Span, ElementaryType),
390}
391
392#[derive(Debug, Default)]
393struct IndexAccessedPath<'ast> {
394 path: SmallVec<[IapKind<'ast>; 4]>,
395 n_idents: usize,
397}
398
399impl<'ast> IndexAccessedPath<'ast> {
400 fn into_ty(self, parser: &mut Parser<'_, 'ast>) -> Option<Type<'ast>> {
401 let mut path = self.path.into_iter();
403 let first = path.next()?;
404
405 let mut ty = if let IapKind::MemberTy(span, kind) = first {
406 debug_assert_eq!(self.n_idents, 1);
407 Type { span, kind: TypeKind::Elementary(kind) }
408 } else {
409 debug_assert!(self.n_idents >= 1);
410 let first = std::iter::once(&first);
411 let path = first
412 .chain(path.as_slice())
413 .map(|x| match x {
414 IapKind::Member(id) => *id,
415 kind => unreachable!("{kind:?}"),
416 })
417 .take(self.n_idents);
418 let path = PathSlice::from_mut_slice(parser.arena.alloc_from_iter(path));
419 Type { span: path.span(), kind: TypeKind::Custom(path) }
420 };
421
422 for index in path.skip(self.n_idents - 1) {
423 let IapKind::Index(span, kind) = index else { panic!("parsed too much") };
424 let size = match kind {
425 IndexKind::Index(expr) => expr,
426 IndexKind::Range(l, r) => {
427 let msg = "expected array length, got range expression";
428 parser.dcx().err(msg).span(span).emit();
429 l.or(r)
430 }
431 };
432 let span = ty.span.to(span);
433 ty =
434 Type { span, kind: TypeKind::Array(parser.alloc(TypeArray { element: ty, size })) };
435 }
436
437 Some(ty)
438 }
439
440 fn into_expr(self, parser: &mut Parser<'_, 'ast>) -> Option<Box<'ast, Expr<'ast>>> {
441 let mut path = self.path.into_iter();
443
444 let mut expr = parser.alloc(match path.next()? {
445 IapKind::Member(ident) => Expr::from_ident(ident),
446 IapKind::MemberTy(span, kind) => {
447 Expr { span, kind: ExprKind::Type(Type { span, kind: TypeKind::Elementary(kind) }) }
448 }
449 IapKind::Index(..) => panic!("should not happen"),
450 });
451 for index in path {
452 expr = parser.alloc(match index {
453 IapKind::Member(ident) => {
454 Expr { span: expr.span.to(ident.span), kind: ExprKind::Member(expr, ident) }
455 }
456 IapKind::MemberTy(..) => panic!("should not happen"),
457 IapKind::Index(span, kind) => {
458 Expr { span: expr.span.to(span), kind: ExprKind::Index(expr, kind) }
459 }
460 });
461 }
462 Some(expr)
463 }
464}
465
466fn smallvec_repeat_none<T>(n: usize) -> SmallVec<[Option<T>; 8]> {
468 let mut v = SmallVec::with_capacity(n);
469 v.extend(std::iter::repeat_with(|| None).take(n));
470 v
471}
472
473#[cfg(test)]
474mod tests {
475 use super::*;
476 use solar_interface::{Result, Session, source_map::FileName};
477
478 #[test]
479 fn optional_items_seq() {
480 fn check(tests: &[(&str, &[Option<&str>])]) {
481 solar_interface::enter(|| -> Result {
482 let sess = Session::builder().with_test_emitter().build();
483 for (i, &(s, results)) in tests.iter().enumerate() {
484 let name = i.to_string();
485 let arena = Arena::new();
486 let mut parser =
487 Parser::from_source_code(&sess, &arena, FileName::Custom(name), s)?;
488
489 let list = parser
490 .parse_optional_items_seq(Delimiter::Parenthesis, Parser::parse_ident)
491 .map_err(|e| e.emit())
492 .unwrap_or_else(|_| panic!("src: {s:?}"));
493 sess.dcx.has_errors().unwrap();
494 let formatted: Vec<_> =
495 list.iter().map(|o| o.as_ref().map(|i| i.as_str())).collect();
496 assert_eq!(formatted.as_slice(), results, "{s:?}");
497 }
498 Ok(())
499 })
500 .unwrap();
501 }
502
503 check(&[
504 ("()", &[]),
505 ("(a)", &[Some("a")]),
506 ("(a,)", &[Some("a"), None]),
508 ("(,b)", &[None, Some("b")]),
509 ("(a,b)", &[Some("a"), Some("b")]),
510 ("(a,b,)", &[Some("a"), Some("b"), None]),
511 ("(a,,)", &[Some("a"), None, None]),
513 ("(a,b,)", &[Some("a"), Some("b"), None]),
514 ("(a,b,c)", &[Some("a"), Some("b"), Some("c")]),
515 ("(,b,c)", &[None, Some("b"), Some("c")]),
516 ("(,,c)", &[None, None, Some("c")]),
517 ("(a,,c)", &[Some("a"), None, Some("c")]),
518 ]);
519 }
520}