solar_parse/parser/
yul.rs1use super::SeqSep;
2use crate::{PResult, Parser};
3use smallvec::SmallVec;
4use solar_ast::{AstPath, Box, DocComments, LitKind, PathSlice, StrKind, StrLit, token::*, yul::*};
5use solar_interface::{Ident, error_code, kw, sym};
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 let lo = self.token.span;
102 self.parse_delim_seq(Delimiter::Brace, SeqSep::none(), true, Self::parse_yul_stmt_unchecked)
103 .map(|stmts| {
104 let span = lo.to(self.prev_token.span);
105 Block { span, stmts }
106 })
107 }
108
109 fn parse_yul_stmt_kind(&mut self) -> PResult<'sess, StmtKind<'ast>> {
111 if self.eat_keyword(kw::Let) {
112 self.parse_yul_stmt_var_decl()
113 } else if self.eat_keyword(kw::Function) {
114 self.parse_yul_function()
115 } else if self.check(TokenKind::OpenDelim(Delimiter::Brace)) {
116 self.parse_yul_block_unchecked().map(StmtKind::Block)
117 } else if self.eat_keyword(kw::If) {
118 self.parse_yul_stmt_if()
119 } else if self.eat_keyword(kw::Switch) {
120 self.parse_yul_stmt_switch().map(StmtKind::Switch)
121 } else if self.eat_keyword(kw::For) {
122 self.parse_yul_stmt_for()
123 } else if self.eat_keyword(kw::Break) {
124 Ok(StmtKind::Break)
125 } else if self.eat_keyword(kw::Continue) {
126 Ok(StmtKind::Continue)
127 } else if self.eat_keyword(kw::Leave) {
128 Ok(StmtKind::Leave)
129 } else if self.check_ident() {
130 let path = self.parse_path_any()?;
131 if self.check(TokenKind::OpenDelim(Delimiter::Parenthesis)) {
132 let name = self.expect_single_ident_path(path);
133 self.parse_yul_expr_call_with(name).map(StmtKind::Expr)
134 } else if self.eat(TokenKind::Walrus) {
135 self.check_valid_path(path);
136 let expr = self.parse_yul_expr()?;
137 Ok(StmtKind::AssignSingle(path, expr))
138 } else if self.check(TokenKind::Comma) {
139 self.check_valid_path(path);
140 let mut paths = SmallVec::<[_; 4]>::new();
141 paths.push(path);
142 while self.eat(TokenKind::Comma) {
143 paths.push(self.parse_yul_path()?);
144 }
145 let paths = self.alloc_smallvec(paths);
146 self.expect(TokenKind::Walrus)?;
147 let expr = self.parse_yul_expr()?;
148 let ExprKind::Call(expr) = expr.kind else {
149 let msg = "only function calls are allowed in multi-assignment";
150 return Err(self.dcx().err(msg).span(expr.span));
151 };
152 Ok(StmtKind::AssignMulti(paths, expr))
153 } else {
154 self.unexpected()
155 }
156 } else {
157 self.unexpected()
158 }
159 }
160
161 fn parse_yul_stmt_var_decl(&mut self) -> PResult<'sess, StmtKind<'ast>> {
163 let mut idents = SmallVec::<[_; 8]>::new();
164 loop {
165 idents.push(self.parse_ident()?);
166 if !self.eat(TokenKind::Comma) {
167 break;
168 }
169 }
170 let idents = self.alloc_smallvec(idents);
171 let expr = if self.eat(TokenKind::Walrus) { Some(self.parse_yul_expr()?) } else { None };
172 Ok(StmtKind::VarDecl(idents, expr))
173 }
174
175 fn parse_yul_function(&mut self) -> PResult<'sess, StmtKind<'ast>> {
177 let name = self.parse_ident()?;
178 let parameters = self.parse_paren_comma_seq(true, Self::parse_ident)?;
179 let returns = if self.eat(TokenKind::Arrow) {
180 self.parse_nodelim_comma_seq(
181 TokenKind::OpenDelim(Delimiter::Brace),
182 false,
183 Self::parse_ident,
184 )?
185 } else {
186 Default::default()
187 };
188 let body = self.parse_yul_block_unchecked()?;
189 Ok(StmtKind::FunctionDef(Function { name, parameters, returns, body }))
190 }
191
192 fn parse_yul_stmt_if(&mut self) -> PResult<'sess, StmtKind<'ast>> {
194 let cond = self.parse_yul_expr()?;
195 let body = self.parse_yul_block_unchecked()?;
196 Ok(StmtKind::If(cond, body))
197 }
198
199 fn parse_yul_stmt_switch(&mut self) -> PResult<'sess, StmtSwitch<'ast>> {
201 let lo = self.prev_token.span;
202 let selector = self.parse_yul_expr()?;
203 let mut branches = Vec::new();
204 while self.eat_keyword(kw::Case) {
205 let constant = self.parse_lit()?;
206 self.expect_no_subdenomination();
207 let body = self.parse_yul_block_unchecked()?;
208 branches.push(StmtSwitchCase { constant, body });
209 }
210 let branches = self.alloc_vec(branches);
211 let default_case = if self.eat_keyword(kw::Default) {
212 Some(self.parse_yul_block_unchecked()?)
213 } else {
214 None
215 };
216 if branches.is_empty() {
217 let span = lo.to(self.prev_token.span);
218 if default_case.is_none() {
219 self.dcx().err("`switch` statement has no cases").span(span).emit();
220 } else {
221 self.dcx()
222 .warn("`switch` statement has only a default case")
223 .span(span)
224 .code(error_code!(9592))
225 .emit();
226 }
227 }
228 Ok(StmtSwitch { selector, branches, default_case })
229 }
230
231 fn parse_yul_stmt_for(&mut self) -> PResult<'sess, StmtKind<'ast>> {
233 let init = self.parse_yul_block_unchecked()?;
234 let cond = self.parse_yul_expr()?;
235 let step = self.parse_yul_block_unchecked()?;
236 let body = self.parse_yul_block_unchecked()?;
237 Ok(StmtKind::For { init, cond, step, body })
238 }
239
240 fn parse_yul_expr(&mut self) -> PResult<'sess, Expr<'ast>> {
242 self.parse_spanned(Self::parse_yul_expr_kind).map(|(span, kind)| Expr { span, kind })
243 }
244
245 fn parse_yul_expr_kind(&mut self) -> PResult<'sess, ExprKind<'ast>> {
247 if self.check_lit() {
248 self.parse_lit().map(ExprKind::Lit)
250 } else if self.check_path() {
251 let path = self.parse_path_any()?;
252 if self.token.is_open_delim(Delimiter::Parenthesis) {
253 let ident = self.expect_single_ident_path(path);
255 self.parse_yul_expr_call_with(ident).map(ExprKind::Call)
256 } else {
257 self.check_valid_path(path);
258 Ok(ExprKind::Path(path))
259 }
260 } else {
261 self.unexpected()
262 }
263 }
264
265 fn parse_yul_expr_call_with(&mut self, name: Ident) -> PResult<'sess, ExprCall<'ast>> {
267 if !name.is_yul_evm_builtin() && name.is_reserved(true) {
268 self.expected_ident_found_other(name.into(), false).unwrap_err().emit();
269 }
270 let arguments = self.parse_paren_comma_seq(true, Self::parse_yul_expr)?;
271 Ok(ExprCall { name, arguments })
272 }
273
274 #[track_caller]
276 fn expect_single_ident_path(&mut self, path: AstPath<'_>) -> Ident {
277 if path.segments().len() > 1 {
278 self.dcx().err("fully-qualified paths aren't allowed here").span(path.span()).emit();
279 }
280 *path.last()
281 }
282
283 fn parse_yul_path(&mut self) -> PResult<'sess, AstPath<'ast>> {
284 let path = self.parse_path_any()?;
285 self.check_valid_path(path);
286 Ok(path)
287 }
288
289 #[track_caller]
291 fn check_valid_path(&mut self, path: &PathSlice) {
292 let first = *path.first();
295 if first.is_yul_keyword() || (path.segments().len() == 1 && first.is_yul_evm_builtin()) {
296 self.expected_ident_found_other(first.into(), false).unwrap_err().emit();
297 }
298 for &ident in &path.segments()[1..] {
299 if ident.is_yul_keyword() {
300 self.expected_ident_found_other(ident.into(), false).unwrap_err().emit();
301 }
302 }
303 }
304}