solar_parse/parser/
yul.rs1use super::SeqSep;
2use crate::{PResult, Parser};
3use smallvec::SmallVec;
4use solar_ast::{token::*, yul::*, AstPath, Box, DocComments, LitKind, PathSlice, StrKind, StrLit};
5use solar_interface::{error_code, kw, sym, Ident};
6
7impl<'sess, 'ast> Parser<'sess, 'ast> {
8 #[instrument(level = "debug", skip_all)]
13 pub fn parse_yul_file_object(&mut self) -> PResult<'sess, Object<'ast>> {
14 let docs = self.parse_doc_comments();
15 let object = if self.check_keyword(sym::object) {
16 self.parse_yul_object(docs)
17 } else {
18 let lo = self.token.span;
19 self.parse_yul_block().map(|code| {
20 let span = lo.to(self.prev_token.span);
21 let name = StrLit { span, value: sym::object };
22 let code = CodeBlock { span, code };
23 Object { docs, span, name, code, children: Box::default(), data: Box::default() }
24 })
25 }?;
26 self.expect(TokenKind::Eof)?;
27 Ok(object)
28 }
29
30 pub fn parse_yul_object(&mut self, docs: DocComments<'ast>) -> PResult<'sess, Object<'ast>> {
34 let lo = self.token.span;
35 self.expect_keyword(sym::object)?;
36 let name = self.parse_str_lit()?;
37
38 self.expect(TokenKind::OpenDelim(Delimiter::Brace))?;
39 let code = self.parse_yul_code()?;
40 let mut children = Vec::new();
41 let mut data = Vec::new();
42 loop {
43 let docs = self.parse_doc_comments();
44 if self.check_keyword(sym::object) {
45 children.push(self.parse_yul_object(docs)?);
46 } else if self.check_keyword(sym::data) {
47 data.push(self.parse_yul_data()?);
48 } else {
49 break;
50 }
51 }
52 self.expect(TokenKind::CloseDelim(Delimiter::Brace))?;
53
54 let span = lo.to(self.prev_token.span);
55 let children = self.alloc_vec(children);
56 let data = self.alloc_vec(data);
57 Ok(Object { docs, span, name, code, children, data })
58 }
59
60 fn parse_yul_code(&mut self) -> PResult<'sess, CodeBlock<'ast>> {
62 let lo = self.token.span;
63 self.expect_keyword(sym::code)?;
64 let code = self.parse_yul_block()?;
65 let span = lo.to(self.prev_token.span);
66 Ok(CodeBlock { span, code })
67 }
68
69 fn parse_yul_data(&mut self) -> PResult<'sess, Data<'ast>> {
71 let lo = self.token.span;
72 self.expect_keyword(sym::data)?;
73 let name = self.parse_str_lit()?;
74 let data = self.parse_lit()?;
75 if !matches!(data.kind, LitKind::Str(StrKind::Str | StrKind::Hex, _)) {
76 let msg = "only string and hex string literals are allowed in `data` segments";
77 return Err(self.dcx().err(msg).span(data.span));
78 }
79 let span = lo.to(self.prev_token.span);
80 Ok(Data { span, name, data })
81 }
82
83 pub fn parse_yul_stmt(&mut self) -> PResult<'sess, Stmt<'ast>> {
85 self.in_yul(Self::parse_yul_stmt)
86 }
87
88 pub fn parse_yul_stmt_unchecked(&mut self) -> PResult<'sess, Stmt<'ast>> {
90 let docs = self.parse_doc_comments();
91 self.parse_spanned(Self::parse_yul_stmt_kind).map(|(span, kind)| Stmt { docs, span, kind })
92 }
93
94 pub fn parse_yul_block(&mut self) -> PResult<'sess, Block<'ast>> {
96 self.in_yul(Self::parse_yul_block_unchecked)
97 }
98
99 pub fn parse_yul_block_unchecked(&mut self) -> PResult<'sess, Block<'ast>> {
101 self.parse_delim_seq(Delimiter::Brace, SeqSep::none(), true, Self::parse_yul_stmt_unchecked)
102 }
103
104 fn parse_yul_stmt_kind(&mut self) -> PResult<'sess, StmtKind<'ast>> {
106 if self.eat_keyword(kw::Let) {
107 self.parse_yul_stmt_var_decl()
108 } else if self.eat_keyword(kw::Function) {
109 self.parse_yul_function()
110 } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
111 self.parse_yul_block_unchecked().map(StmtKind::Block)
112 } else if self.eat_keyword(kw::If) {
113 self.parse_yul_stmt_if()
114 } else if self.eat_keyword(kw::Switch) {
115 self.parse_yul_stmt_switch().map(StmtKind::Switch)
116 } else if self.eat_keyword(kw::For) {
117 self.parse_yul_stmt_for()
118 } else if self.eat_keyword(kw::Break) {
119 Ok(StmtKind::Break)
120 } else if self.eat_keyword(kw::Continue) {
121 Ok(StmtKind::Continue)
122 } else if self.eat_keyword(kw::Leave) {
123 Ok(StmtKind::Leave)
124 } else if self.check_ident() {
125 let path = self.parse_path_any()?;
126 if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
127 let name = self.expect_single_ident_path(path);
128 self.parse_yul_expr_call_with(name).map(StmtKind::Expr)
129 } else if self.eat(TokenKind::Walrus) {
130 self.check_valid_path(path);
131 let expr = self.parse_yul_expr()?;
132 Ok(StmtKind::AssignSingle(path, expr))
133 } else if self.check(TokenKind::Comma) {
134 self.check_valid_path(path);
135 let mut paths = SmallVec::<[_; 4]>::new();
136 paths.push(path);
137 while self.eat(TokenKind::Comma) {
138 paths.push(self.parse_path()?);
139 }
140 let paths = self.alloc_smallvec(paths);
141 self.expect(TokenKind::Walrus)?;
142 let expr = self.parse_yul_expr()?;
143 let ExprKind::Call(expr) = expr.kind else {
144 let msg = "only function calls are allowed in multi-assignment";
145 return Err(self.dcx().err(msg).span(expr.span));
146 };
147 Ok(StmtKind::AssignMulti(paths, expr))
148 } else {
149 self.unexpected()
150 }
151 } else {
152 self.unexpected()
153 }
154 }
155
156 fn parse_yul_stmt_var_decl(&mut self) -> PResult<'sess, StmtKind<'ast>> {
158 let mut idents = SmallVec::<[_; 8]>::new();
159 loop {
160 idents.push(self.parse_ident()?);
161 if !self.eat(TokenKind::Comma) {
162 break;
163 }
164 }
165 let idents = self.alloc_smallvec(idents);
166 let expr = if self.eat(TokenKind::Walrus) { Some(self.parse_yul_expr()?) } else { None };
167 Ok(StmtKind::VarDecl(idents, expr))
168 }
169
170 fn parse_yul_function(&mut self) -> PResult<'sess, StmtKind<'ast>> {
172 let name = self.parse_ident()?;
173 let parameters = self.parse_paren_comma_seq(true, Self::parse_ident)?;
174 let returns = if self.eat(TokenKind::Arrow) {
175 self.parse_nodelim_comma_seq(
176 TokenKind::OpenDelim(Delimiter::Brace),
177 false,
178 Self::parse_ident,
179 )?
180 } else {
181 Default::default()
182 };
183 let body = self.parse_yul_block_unchecked()?;
184 Ok(StmtKind::FunctionDef(Function { name, parameters, returns, body }))
185 }
186
187 fn parse_yul_stmt_if(&mut self) -> PResult<'sess, StmtKind<'ast>> {
189 let cond = self.parse_yul_expr()?;
190 let body = self.parse_yul_block_unchecked()?;
191 Ok(StmtKind::If(cond, body))
192 }
193
194 fn parse_yul_stmt_switch(&mut self) -> PResult<'sess, StmtSwitch<'ast>> {
196 let lo = self.prev_token.span;
197 let selector = self.parse_yul_expr()?;
198 let mut branches = Vec::new();
199 while self.eat_keyword(kw::Case) {
200 let constant = self.parse_lit()?;
201 self.expect_no_subdenomination();
202 let body = self.parse_yul_block_unchecked()?;
203 branches.push(StmtSwitchCase { constant, body });
204 }
205 let branches = self.alloc_vec(branches);
206 let default_case = if self.eat_keyword(kw::Default) {
207 Some(self.parse_yul_block_unchecked()?)
208 } else {
209 None
210 };
211 if branches.is_empty() {
212 let span = lo.to(self.prev_token.span);
213 if default_case.is_none() {
214 self.dcx().err("`switch` statement has no cases").span(span).emit();
215 } else {
216 self.dcx()
217 .warn("`switch` statement has only a default case")
218 .span(span)
219 .code(error_code!(9592))
220 .emit();
221 }
222 }
223 Ok(StmtSwitch { selector, branches, default_case })
224 }
225
226 fn parse_yul_stmt_for(&mut self) -> PResult<'sess, StmtKind<'ast>> {
228 let init = self.parse_yul_block_unchecked()?;
229 let cond = self.parse_yul_expr()?;
230 let step = self.parse_yul_block_unchecked()?;
231 let body = self.parse_yul_block_unchecked()?;
232 Ok(StmtKind::For { init, cond, step, body })
233 }
234
235 fn parse_yul_expr(&mut self) -> PResult<'sess, Expr<'ast>> {
237 self.parse_spanned(Self::parse_yul_expr_kind).map(|(span, kind)| Expr { span, kind })
238 }
239
240 fn parse_yul_expr_kind(&mut self) -> PResult<'sess, ExprKind<'ast>> {
242 if self.check_lit() {
243 self.parse_lit().map(ExprKind::Lit)
245 } else if self.check_path() {
246 let path = self.parse_path_any()?;
247 if self.token.is_open_delim(Delimiter::Parenthesis) {
248 let ident = self.expect_single_ident_path(path);
250 self.parse_yul_expr_call_with(ident).map(ExprKind::Call)
251 } else {
252 self.check_valid_path(path);
253 Ok(ExprKind::Path(path))
254 }
255 } else {
256 self.unexpected()
257 }
258 }
259
260 fn parse_yul_expr_call_with(&mut self, name: Ident) -> PResult<'sess, ExprCall<'ast>> {
262 if !name.is_yul_evm_builtin() && name.is_reserved(true) {
263 self.expected_ident_found_other(name.into(), false).unwrap_err().emit();
264 }
265 let arguments = self.parse_paren_comma_seq(true, Self::parse_yul_expr)?;
266 Ok(ExprCall { name, arguments })
267 }
268
269 #[track_caller]
271 fn expect_single_ident_path(&mut self, path: AstPath<'_>) -> Ident {
272 if path.segments().len() > 1 {
273 self.dcx().err("fully-qualified paths aren't allowed here").span(path.span()).emit();
274 }
275 *path.last()
276 }
277
278 #[track_caller]
280 fn check_valid_path(&mut self, path: &PathSlice) {
281 let first = path.first();
282 if first.is_reserved(true) {
283 self.expected_ident_found_other((*first).into(), false).unwrap_err().emit();
284 }
285 for ident in &path.segments()[1..] {
286 if !ident.is_yul_evm_builtin() && ident.is_reserved(true) {
287 self.expected_ident_found_other((*ident).into(), false).unwrap_err().emit();
288 }
289 }
290 }
291}