1use crate::ast::abi::{Argument, EventDefinition, FunctionDefinition};
2use crate::ast::span::AstSpan;
3use crate::builtin_eval::{PadDirection, eval_builtin_bytes, eval_builtin_pad_simple, eval_event_hash, eval_function_signature};
4use crate::{
5 bytecode::*,
6 bytes_util::*,
7 error::{CodegenError, CodegenErrorKind},
8 evm_version::EVMVersion,
9 opcodes::{OPCODES_MAP, Opcode},
10 prelude::{MacroArg::Ident, Span, TokenKind},
11 push_value::PushValue,
12};
13use alloy_primitives::U256;
14use indexmap::IndexMap;
15use std::collections::HashSet;
16use std::{
17 collections::BTreeMap,
18 fmt::{Display, Formatter},
19 path::PathBuf,
20 sync::{Arc, Mutex},
21};
22
23pub type Literal = [u8; 32];
25
26pub const RUNTIME_CODESIZE_ARG: &str = "RUNTIME";
29
30pub type FilePath = PathBuf;
34
35#[derive(Debug, Default, Clone)]
42pub struct Contract {
43 pub macros: IndexMap<String, MacroDefinition>,
47 pub invocations: Vec<MacroInvocation>,
49 pub imports: Vec<FilePath>,
51 pub constants: Arc<Mutex<Vec<ConstantDefinition>>>,
53 pub errors: Vec<ErrorDefinition>,
55 pub functions: Vec<FunctionDefinition>,
57 pub events: Vec<EventDefinition>,
59 pub tables: Vec<TableDefinition>,
61 pub labels: HashSet<String>,
63 pub flattened_source: Option<String>,
65 pub source_files: Vec<(String, String)>,
68 pub source_map: Vec<(usize, usize, usize)>, pub runtime_size: Option<usize>,
73}
74
75pub fn is_runtime_codesize(bf: &BuiltinFunctionCall) -> bool {
77 matches!(bf.kind, BuiltinFunctionKind::Codesize)
78 && matches!(bf.args.as_slice(), [BuiltinFunctionArg::Identifier(name, _)] if name == RUNTIME_CODESIZE_ARG)
79}
80
81impl Contract {
82 pub fn map_flattened_position_to_source(&self, flattened_start: usize, flattened_end: usize) -> (u32, usize, usize) {
85 let mut file_id = 0u32;
87 let mut original_start = flattened_start;
88 let mut original_end = flattened_end;
89
90 for (idx, (file_start_in_flattened, fid, _)) in self.source_map.iter().enumerate() {
92 let file_end = if idx + 1 < self.source_map.len() {
94 self.source_map[idx + 1].0
95 } else {
96 usize::MAX
98 };
99
100 if *file_start_in_flattened <= flattened_start && flattened_start < file_end {
102 file_id = *fid as u32;
103 original_start = flattened_start - file_start_in_flattened;
105 original_end = flattened_end - file_start_in_flattened;
106 break;
107 }
108 }
109
110 (file_id, original_start, original_end)
111 }
112
113 pub fn map_original_span_to_flattened(&self, span: &crate::prelude::Span) -> Option<(usize, usize)> {
116 if let Some(file) = &span.file {
117 let file_id = self.source_files.iter().enumerate().find(|(_, (path, _))| path == &file.path).map(|(id, _)| id)?;
119
120 let file_start_in_flattened = self.source_map.iter().find(|(_, fid, _)| *fid == file_id).map(|(start, _, _)| *start)?;
122
123 let flattened_start = file_start_in_flattened + span.start;
125 let flattened_end = file_start_in_flattened + span.end;
126
127 Some((flattened_start, flattened_end))
128 } else {
129 None
130 }
131 }
132
133 pub fn find_macro_by_name(&self, name: &str) -> Option<&MacroDefinition> {
135 self.macros.get(name).or_else(|| {
136 tracing::warn!("Failed to find macro \"{}\" in contract", name);
137 None
138 })
139 }
140
141 pub fn find_table_by_name(&self, name: &str) -> Option<TableDefinition> {
143 if let Some(t) = self.tables.iter().find(|t| t.name == name) {
144 Some(t.clone())
145 } else {
146 tracing::warn!("Failed to find table \"{}\" in contract", name);
147 None
148 }
149 }
150
151 pub fn derive_storage_pointers(&mut self) {
156 let mut storage_pointers: Vec<(String, [u8; 32])> = Vec::new();
157 let mut last_assigned_free_pointer = 0;
158
159 match self.find_macro_by_name("CONSTRUCTOR") {
161 Some(m) => self.recurse_ast_constants(m, &mut storage_pointers, &mut last_assigned_free_pointer, false),
162 None => {
163 tracing::warn!(target: "ast", "'CONSTRUCTOR' MACRO NOT FOUND WHILE DERIVING STORAGE POINTERS!")
165 }
166 }
167
168 match self.find_macro_by_name("MAIN") {
170 Some(m) => self.recurse_ast_constants(m, &mut storage_pointers, &mut last_assigned_free_pointer, false),
171 None => {
172 tracing::error!(target: "ast", "'MAIN' MACRO NOT FOUND WHILE DERIVING STORAGE POINTERS!")
173 }
174 }
175
176 for test in self.macros.values().filter(|m| m.test) {
179 self.recurse_ast_constants(test, &mut storage_pointers, &mut last_assigned_free_pointer, false);
180 let decorator_constants =
181 test.decorator.iter().flat_map(|d| &d.flags).flat_map(|f| &f.args).filter_map(|arg| match &arg.value {
182 DecoratorValue::Constant(name) => Some(name),
183 _ => None,
184 });
185 for name in decorator_constants {
186 self.assign_free_storage_pointers(name, &test.name, &mut storage_pointers, &mut last_assigned_free_pointer);
187 }
188 }
189
190 tracing::debug!(target: "ast", "Generate Storage pointers: {:?}", storage_pointers);
191 tracing::debug!(target: "ast", "ALL AST CONSTANTS: {:?}", storage_pointers);
192
193 for c in self.constants.lock().unwrap().iter_mut() {
195 match storage_pointers.iter().filter(|pointer| pointer.0.eq(&c.name)).collect::<Vec<&(String, [u8; 32])>>().first() {
196 Some(p) => {
197 *c = ConstantDefinition { name: c.name.to_string(), value: ConstVal::StoragePointer(p.1), span: c.span.clone() };
198 }
199 None => {
200 tracing::warn!(target: "ast", "SET STORAGE POINTER BUT FAILED TO SET DERIVED CONSTANT VALUE FOR \"{}\"", c.name)
201 }
202 }
203 }
204 }
205
206 pub fn recurse_ast_constants(
218 &self,
219 macro_def: &MacroDefinition,
220 storage_pointers: &mut Vec<(String, [u8; 32])>,
221 last_p: &mut i32,
222 checking_constructor: bool,
223 ) {
224 let mut visited = std::collections::HashSet::new();
225 self.recurse_ast_constants_inner(macro_def, storage_pointers, last_p, checking_constructor, &mut visited)
226 }
227
228 fn recurse_ast_constants_inner(
229 &self,
230 macro_def: &MacroDefinition,
231 storage_pointers: &mut Vec<(String, [u8; 32])>,
232 last_p: &mut i32,
233 checking_constructor: bool,
234 visited: &mut std::collections::HashSet<String>,
235 ) {
236 if visited.contains(¯o_def.name) {
238 tracing::warn!(target: "ast", "Circular macro invocation detected: '{}' is already being processed. Skipping to prevent infinite recursion.", macro_def.name);
239 return;
240 }
241
242 visited.insert(macro_def.name.clone());
244 let mut statements = macro_def.statements.clone();
245
246 let mut i = 0;
247 loop {
248 if i >= statements.len() {
249 break;
250 }
251 match &statements[i].clone().ty {
252 StatementType::Constant(const_name) => {
253 self.assign_free_storage_pointers(const_name, ¯o_def.name, storage_pointers, last_p);
254 }
255 StatementType::MacroInvocation(mi) => {
256 tracing::debug!(target: "ast", "Found macro invocation: \"{}\" in macro def: \"{}\"!", mi.macro_name, macro_def.name);
257
258 let mut constant_args: Vec<String> = Vec::new();
260 for arg in &mi.args {
261 if let Ident(name) = arg {
263 self.constants.lock().unwrap().iter().for_each(|constant| {
264 if name == &constant.name {
265 tracing::debug!(target: "ast", "CONSTANT FOUND AS MACRO PARAMETER {}", name);
266 constant_args.push(name.to_string());
267 }
268 })
269 }
270 }
271 for constant_arg in constant_args {
273 self.assign_free_storage_pointers(&constant_arg, ¯o_def.name, storage_pointers, last_p);
274 }
275
276 match self.macros.get(&mi.macro_name) {
277 Some(md) => {
278 if md.name.eq("CONSTRUCTOR") {
279 if !checking_constructor {
280 self.recurse_ast_constants_inner(md, storage_pointers, last_p, true, visited);
281 }
282 } else {
283 self.recurse_ast_constants_inner(md, storage_pointers, last_p, checking_constructor, visited);
284 }
285 }
286 None => {
287 tracing::warn!(target: "ast", "MACRO \"{}\" INVOKED BUT NOT FOUND IN AST!", mi.macro_name)
288 }
289 }
290 }
291 StatementType::BuiltinFunctionCall(bfc) => {
292 tracing::debug!(target: "ast", "Deriving Storage Pointers: Found builtin function {:?}", bfc.kind);
293 for builtin_fn_arg in &bfc.args {
294 let BuiltinFunctionArg::Identifier(name, _) = builtin_fn_arg else { continue };
295 match self.macros.get(name) {
296 Some(md) => {
297 if md.name.eq("CONSTRUCTOR") {
298 if !checking_constructor {
299 self.recurse_ast_constants_inner(md, storage_pointers, last_p, true, visited);
300 }
301 } else {
302 self.recurse_ast_constants_inner(md, storage_pointers, last_p, checking_constructor, visited);
303 }
304 }
305 None => {
306 tracing::warn!(target: "ast", "BUILTIN HAS ARG NAME \"{}\" BUT NOT FOUND IN AST!", name)
307 }
308 }
309 }
310 }
311 StatementType::Label(l) => {
312 for state in l.inner.iter().rev() {
313 statements.insert(i + 1, state.clone());
314 }
315 }
316 _ => {}
317 }
318 i += 1;
319 }
320
321 visited.remove(¯o_def.name);
323
324 }
330
331 fn assign_free_storage_pointers(
332 &self,
333 const_name: &String,
334 macro_name: &String,
335 storage_pointers: &mut Vec<(String, [u8; 32])>,
336 last_p: &mut i32,
337 ) {
338 tracing::debug!(target: "ast", "Found constant \"{}\" in macro def \"{}\" statements!", const_name, macro_name);
339 if storage_pointers.iter().filter(|pointer| pointer.0.eq(const_name)).collect::<Vec<&(String, [u8; 32])>>().is_empty() {
340 tracing::debug!(target: "ast", "No storage pointer already set for \"{}\"!", const_name);
341 match self.constants.lock().unwrap().iter().filter(|c| c.name.eq(const_name)).collect::<Vec<&ConstantDefinition>>().first() {
343 Some(c) => {
344 match c.value {
345 ConstVal::FreeStoragePointer(_) => {
346 let old_p = *last_p;
347 *last_p += 1;
348 let new_value = str_to_bytes32(&format!("{old_p}"));
349 storage_pointers.push((const_name.to_string(), new_value));
350 }
351 ConstVal::Bytes(_)
352 | ConstVal::String(_)
353 | ConstVal::BuiltinFunctionCall(_)
354 | ConstVal::Expression(_)
355 | ConstVal::Noop => {
356 }
358 _ => panic!("Invalid Constant Value"),
360 };
361 }
362 None => {
363 tracing::warn!(target: "ast", "CONSTANT \"{}\" NOT FOUND IN AST CONSTANTS", const_name)
364 }
365 }
366 }
367 }
368
369 pub fn add_override_constants(&self, override_constants: &Option<BTreeMap<&str, Bytes>>) {
376 if let Some(override_constants) = override_constants {
377 for (name, value) in override_constants {
378 let mut constants = self.constants.lock().unwrap();
379 if let Some(c) = constants.iter_mut().find(|c| c.name.as_str().eq(*name)) {
380 c.value = ConstVal::Bytes(value.clone());
381 } else {
382 constants.push(ConstantDefinition {
383 name: name.to_string(),
384 value: ConstVal::Bytes(value.clone()),
385 span: AstSpan::default(),
386 });
387 }
388 }
389 }
390 }
391
392 pub fn validate_opcodes(&self, evm_version: &EVMVersion) -> Result<(), CodegenError> {
394 for macro_def in self.macros.values() {
395 Self::validate_statements_opcodes(¯o_def.statements, evm_version)?;
396 }
397
398 for table in &self.tables {
399 Self::validate_statements_opcodes(&table.statements, evm_version)?;
400 }
401
402 Ok(())
403 }
404
405 fn validate_statements_opcodes(statements: &[Statement], evm_version: &EVMVersion) -> Result<(), CodegenError> {
407 for statement in statements {
408 match &statement.ty {
409 StatementType::Opcode(opcode) | StatementType::ImmediateOpcode { opcode, .. } => {
410 if let Some(required_version) = opcode.requires_evm_version()
411 && evm_version.version() < &required_version
412 {
413 return Err(CodegenError {
414 kind: CodegenErrorKind::InvalidOpcodeForEVMVersion(
415 opcode.as_ref().to_string(),
416 required_version.to_string(),
417 evm_version.to_string(),
418 ),
419 span: statement.span.clone_box(),
420 token: Some(TokenKind::Opcode(*opcode)),
421 });
422 }
423 }
424 StatementType::Label(label) => {
425 Self::validate_statements_opcodes(&label.inner, evm_version)?;
427 }
428 StatementType::ForLoop { body, .. } => {
429 Self::validate_statements_opcodes(body, evm_version)?;
430 }
431 StatementType::IfStatement { then_branch, else_if_branches, else_branch, .. } => {
432 Self::validate_statements_opcodes(then_branch, evm_version)?;
433 for (_, branch) in else_if_branches {
434 Self::validate_statements_opcodes(branch, evm_version)?;
435 }
436 if let Some(branch) = else_branch {
437 Self::validate_statements_opcodes(branch, evm_version)?;
438 }
439 }
440 StatementType::MacroInvocation(invocation) => {
441 Self::validate_macro_invocation_args(&invocation.args, evm_version, &statement.span)?;
443 }
444 StatementType::ArgMacroInvocation(_, _, args) => {
445 Self::validate_macro_invocation_args(args, evm_version, &statement.span)?;
447 }
448 _ => {
449 }
451 }
452 }
453 Ok(())
454 }
455
456 fn validate_macro_invocation_args(args: &[MacroArg], evm_version: &EVMVersion, invocation_span: &AstSpan) -> Result<(), CodegenError> {
458 for arg in args {
459 match arg {
460 MacroArg::Ident(name) => {
461 if let Some(&opcode) = OPCODES_MAP.get(name.as_str()) {
463 if let Some(required_version) = opcode.requires_evm_version()
465 && evm_version.version() < &required_version
466 {
467 return Err(CodegenError {
468 kind: CodegenErrorKind::InvalidOpcodeForEVMVersion(
469 opcode.as_ref().to_string(),
470 required_version.to_string(),
471 evm_version.to_string(),
472 ),
473 span: invocation_span.clone_box(),
474 token: Some(TokenKind::Opcode(opcode)),
475 });
476 }
477 }
478 }
479 MacroArg::MacroCall(invocation) => {
480 Self::validate_macro_invocation_args(&invocation.args, evm_version, &invocation.span)?;
482 }
483 MacroArg::ArgCallMacroInvocation(_, nested_args) => {
484 Self::validate_macro_invocation_args(nested_args, evm_version, invocation_span)?;
487 }
488 _ => {
489 }
491 }
492 }
493 Ok(())
494 }
495
496 pub fn evaluate_constant_expression(&self, expr: &Expression) -> Result<Literal, CodegenError> {
500 let mut evaluating = std::collections::HashSet::new();
502 self.evaluate_constant_expression_internal(expr, &mut evaluating)
503 }
504
505 fn evaluate_constant_expression_internal(
507 &self,
508 expr: &Expression,
509 evaluating: &mut std::collections::HashSet<String>,
510 ) -> Result<Literal, CodegenError> {
511 match expr {
512 Expression::Literal { value, .. } => {
513 Ok(*value)
515 }
516
517 Expression::Constant { name, span } => {
518 if evaluating.contains(name) {
520 return Err(CodegenError {
521 kind: CodegenErrorKind::CircularConstantDependency(name.clone()),
522 span: span.clone_box(),
523 token: None,
524 });
525 }
526
527 evaluating.insert(name.clone());
529
530 let const_value = {
533 let constants = self.constants.lock().unwrap();
534 let const_def = constants.iter().find(|c| c.name == *name).ok_or_else(|| CodegenError {
535 kind: CodegenErrorKind::UndefinedConstant(name.clone()),
536 span: span.clone_box(),
537 token: None,
538 })?;
539 const_def.value.clone()
540 };
541
542 let result = match &const_value {
544 ConstVal::Bytes(bytes) => {
545 Ok(str_to_bytes32(&bytes.as_str()))
547 }
548 ConstVal::Expression(e) => {
549 self.evaluate_constant_expression_internal(e, evaluating)
551 }
552 ConstVal::StoragePointer(lit) => {
553 Ok(*lit)
555 }
556 ConstVal::BuiltinFunctionCall(bf) => {
557 let push_value = match bf.kind {
559 BuiltinFunctionKind::FunctionSignature => eval_function_signature(self, bf)?,
560 BuiltinFunctionKind::EventHash => eval_event_hash(self, bf)?,
561 BuiltinFunctionKind::Bytes => eval_builtin_bytes(bf)?,
562 BuiltinFunctionKind::RightPad => eval_builtin_pad_simple(bf, PadDirection::Right)?,
563 BuiltinFunctionKind::LeftPad => eval_builtin_pad_simple(bf, PadDirection::Left)?,
564 _ if is_runtime_codesize(bf) => {
567 let size = self.runtime_size.ok_or_else(|| CodegenError {
568 kind: CodegenErrorKind::RuntimeSizeNotComputed,
569 span: span.clone_box(),
570 token: None,
571 })?;
572 PushValue::from(U256::from(size).to_be_bytes::<32>())
573 }
574 _ => {
575 return Err(CodegenError {
576 kind: CodegenErrorKind::UnsupportedBuiltinFunction(format!("{}", bf.kind)),
577 span: span.clone_box(),
578 token: None,
579 });
580 }
581 };
582 Ok(push_value.value.0)
584 }
585 _ => Err(CodegenError { kind: CodegenErrorKind::InvalidConstantExpression, span: span.clone_box(), token: None }),
586 };
587
588 evaluating.remove(name);
590
591 result
592 }
593
594 Expression::Binary { left, op, right, span } => {
595 let left_val = self.evaluate_constant_expression_internal(left, evaluating)?;
597 let right_val = self.evaluate_constant_expression_internal(right, evaluating)?;
598
599 let l = U256::from_be_bytes(left_val);
601 let r = U256::from_be_bytes(right_val);
602
603 let result = match op {
605 BinaryOp::Add => l.checked_add(r).ok_or_else(|| CodegenError {
606 kind: CodegenErrorKind::ArithmeticOverflow,
607 span: span.clone_box(),
608 token: None,
609 })?,
610 BinaryOp::Sub => l.checked_sub(r).ok_or_else(|| CodegenError {
611 kind: CodegenErrorKind::ArithmeticUnderflow,
612 span: span.clone_box(),
613 token: None,
614 })?,
615 BinaryOp::Mul => l.checked_mul(r).ok_or_else(|| CodegenError {
616 kind: CodegenErrorKind::ArithmeticOverflow,
617 span: span.clone_box(),
618 token: None,
619 })?,
620 BinaryOp::Div => {
621 if r.is_zero() {
622 return Err(CodegenError { kind: CodegenErrorKind::DivisionByZero, span: span.clone_box(), token: None });
623 }
624 l / r
625 }
626 BinaryOp::Mod => {
627 if r.is_zero() {
628 return Err(CodegenError { kind: CodegenErrorKind::DivisionByZero, span: span.clone_box(), token: None });
629 }
630 l % r
631 }
632 BinaryOp::Eq => {
634 if l == r {
635 U256::from(1u64)
636 } else {
637 U256::ZERO
638 }
639 }
640 BinaryOp::NotEq => {
641 if l != r {
642 U256::from(1u64)
643 } else {
644 U256::ZERO
645 }
646 }
647 BinaryOp::Lt => {
648 if l < r {
649 U256::from(1u64)
650 } else {
651 U256::ZERO
652 }
653 }
654 BinaryOp::Gt => {
655 if l > r {
656 U256::from(1u64)
657 } else {
658 U256::ZERO
659 }
660 }
661 BinaryOp::LtEq => {
662 if l <= r {
663 U256::from(1u64)
664 } else {
665 U256::ZERO
666 }
667 }
668 BinaryOp::GtEq => {
669 if l >= r {
670 U256::from(1u64)
671 } else {
672 U256::ZERO
673 }
674 }
675 };
676
677 Ok(result.to_be_bytes())
678 }
679
680 Expression::Unary { op, expr, .. } => {
681 let val = self.evaluate_constant_expression_internal(expr, evaluating)?;
683 let v = U256::from_be_bytes(val);
684
685 let result = match op {
687 UnaryOp::Neg => {
688 U256::ZERO.wrapping_sub(v)
690 }
691 UnaryOp::Not => {
692 if v.is_zero() { U256::from(1u64) } else { U256::ZERO }
694 }
695 };
696
697 Ok(result.to_be_bytes())
698 }
699
700 Expression::Grouped { expr, .. } => {
701 self.evaluate_constant_expression_internal(expr, evaluating)
703 }
704
705 Expression::ArgCall { name, span, .. } => {
706 Err(CodegenError { kind: CodegenErrorKind::ArgCallInConstantExpression(name.clone()), span: span.clone_box(), token: None })
710 }
711 }
712 }
713}
714
715#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
717pub struct TableDefinition {
718 pub name: String,
720 pub kind: TableKind,
722 pub statements: Vec<Statement>,
724 pub size: Option<Literal>,
726 pub span: AstSpan,
728}
729
730impl TableDefinition {
731 pub fn new(name: String, kind: TableKind, statements: Vec<Statement>, size: Option<Literal>, span: AstSpan) -> Self {
733 TableDefinition { name, kind, statements, size, span }
734 }
735}
736
737#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
739pub enum TableKind {
740 JumpTable,
742 JumpTablePacked,
744 CodeTable,
746}
747
748impl From<TokenKind> for TableKind {
749 fn from(token_kind: TokenKind) -> Self {
751 match token_kind {
752 TokenKind::JumpTable => TableKind::JumpTable,
753 TokenKind::JumpTablePacked => TableKind::JumpTablePacked,
754 TokenKind::CodeTable => TableKind::CodeTable,
755 _ => panic!("Invalid Token Kind"), }
757 }
758}
759
760#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
762pub struct MacroDefinition {
763 pub name: String,
765 pub decorator: Option<Decorator>,
767 pub parameters: Vec<Argument>,
769 pub statements: Vec<Statement>,
771 pub takes: usize,
773 pub returns: usize,
775 pub span: AstSpan,
777 pub outlined: bool,
779 pub test: bool,
781}
782
783impl ToIRBytecode<CodegenError> for MacroDefinition {
784 fn to_irbytecode(&self, evm_version: &EVMVersion) -> Result<IRBytecode<'_>, CodegenError> {
785 let inner_irbytes: Vec<IRBytes> = MacroDefinition::to_irbytes(evm_version, &self.statements);
786 Ok(IRBytecode(inner_irbytes))
787 }
788}
789
790impl MacroDefinition {
791 #[allow(clippy::too_many_arguments)]
793 pub fn new(
794 name: String,
795 decorator: Option<Decorator>,
796 parameters: Vec<Argument>,
797 statements: Vec<Statement>,
798 takes: usize,
799 returns: usize,
800 spans: Vec<Span>,
801 outlined: bool,
802 test: bool,
803 ) -> Self {
804 MacroDefinition { name, decorator, parameters, statements, takes, returns, span: AstSpan(spans), outlined, test }
805 }
806
807 pub fn to_irbytes<'a>(evm_version: &EVMVersion, statements: &'a [Statement]) -> Vec<IRBytes<'a>> {
809 let mut inner_irbytes: Vec<IRBytes> = vec![];
810
811 let mut statement_iter = statements.iter();
812 while let Some(statement) = statement_iter.next() {
813 match &statement.ty {
814 StatementType::Literal(l) => {
815 let push_bytes = literal_gen(evm_version, l);
816 inner_irbytes.push(IRBytes { ty: IRByteType::Bytes(Bytes::Raw(push_bytes)), span: &statement.span });
817 }
818 StatementType::Opcode(o) => {
819 let opcode_str = o.string();
820 inner_irbytes.push(IRBytes { ty: IRByteType::Bytes(Bytes::Raw(opcode_str)), span: &statement.span });
821 if o.is_value_push() {
824 match statement_iter.next() {
825 Some(Statement { ty: StatementType::Literal(l), span: _ }) => {
826 let hex_literal: String = bytes32_to_hex_string(l, false);
827 let prefixed_hex_literal = o.prefix_push_literal(&hex_literal);
828 inner_irbytes
829 .push(IRBytes { ty: IRByteType::Bytes(Bytes::Raw(prefixed_hex_literal)), span: &statement.span });
830 }
831 _ => {
832 panic!("Invalid push statement");
835 }
836 }
837 }
838 }
839 StatementType::Code(c) => {
840 inner_irbytes.push(IRBytes { ty: IRByteType::Bytes(Bytes::Raw(c.to_owned())), span: &statement.span });
841 }
842 StatementType::MacroInvocation(mi) => {
843 inner_irbytes.push(IRBytes {
844 ty: IRByteType::Statement(Box::new(Statement {
845 ty: StatementType::MacroInvocation(mi.clone()),
846 span: statement.span.clone(),
847 })),
848 span: &statement.span,
849 });
850 }
851 StatementType::Constant(name) => {
852 inner_irbytes.push(IRBytes { ty: IRByteType::Constant(name.to_owned()), span: &statement.span });
854 }
855 StatementType::ArgCall(parent_macro_name, arg_name) => {
856 inner_irbytes.push(IRBytes {
858 ty: IRByteType::ArgCall(parent_macro_name.to_owned(), arg_name.to_owned()),
859 span: &statement.span,
860 });
861 }
862 StatementType::ArgMacroInvocation(parent_macro_name, arg_name, args) => {
863 inner_irbytes.push(IRBytes {
865 ty: IRByteType::Statement(Box::new(Statement {
866 ty: StatementType::ArgMacroInvocation(parent_macro_name.clone(), arg_name.clone(), args.clone()),
867 span: statement.span.clone(),
868 })),
869 span: &statement.span,
870 });
871 }
872 StatementType::LabelCall(jump_to) => {
873 inner_irbytes.push(IRBytes {
875 ty: IRByteType::Statement(Box::new(Statement {
876 ty: StatementType::LabelCall(jump_to.to_string()),
877 span: statement.span.clone(),
878 })),
879 span: &statement.span,
880 });
881 }
882 StatementType::Label(l) => {
883 inner_irbytes.push(IRBytes {
885 ty: IRByteType::Statement(Box::new(Statement {
886 ty: StatementType::Label(l.clone()),
887 span: statement.span.clone(),
888 })),
889 span: &statement.span,
890 });
891
892 inner_irbytes.append(&mut MacroDefinition::to_irbytes(evm_version, &l.inner));
894 }
895 StatementType::BuiltinFunctionCall(builtin) => {
896 inner_irbytes.push(IRBytes {
897 ty: IRByteType::Statement(Box::new(Statement {
898 ty: StatementType::BuiltinFunctionCall(builtin.clone()),
899 span: statement.span.clone(),
900 })),
901 span: &statement.span,
902 });
903 }
904 StatementType::ImmediateOpcode { .. } => {
905 inner_irbytes.push(IRBytes { ty: IRByteType::Statement(Box::new(statement.clone())), span: &statement.span });
908 }
909 StatementType::ForLoop { .. } => {
910 inner_irbytes.push(IRBytes { ty: IRByteType::Statement(Box::new(statement.clone())), span: &statement.span });
912 }
913 StatementType::IfStatement { .. } => {
914 inner_irbytes.push(IRBytes { ty: IRByteType::Statement(Box::new(statement.clone())), span: &statement.span });
916 }
917 }
918 }
919
920 inner_irbytes
921 }
922}
923
924#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
926pub struct MacroInvocation {
927 pub macro_name: String,
929 pub args: Vec<MacroArg>,
931 pub span: AstSpan,
933}
934
935#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
937pub enum MacroArg {
938 HexLiteral(Literal),
942 Ident(String),
946 ArgCall(ArgCall),
950 ArgCallMacroInvocation(String, Vec<MacroArg>),
954 MacroCall(MacroInvocation),
958 Opcode(Opcode),
962 BuiltinFunctionCall(BuiltinFunctionCall),
966 Noop,
970}
971
972#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
974pub struct ArgCall {
975 pub macro_name: String,
977 pub name: String,
979 pub span: AstSpan,
981}
982
983#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
985pub struct FreeStoragePointer;
986
987#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
989pub enum Expression {
990 Literal {
992 value: Literal,
994 span: AstSpan,
996 },
997 Constant {
999 name: String,
1001 span: AstSpan,
1003 },
1004 Binary {
1006 left: Box<Expression>,
1008 op: BinaryOp,
1010 right: Box<Expression>,
1012 span: AstSpan,
1014 },
1015 Unary {
1017 op: UnaryOp,
1019 expr: Box<Expression>,
1021 span: AstSpan,
1023 },
1024 Grouped {
1026 expr: Box<Expression>,
1028 span: AstSpan,
1030 },
1031 ArgCall {
1033 macro_name: String,
1035 name: String,
1037 span: AstSpan,
1039 },
1040}
1041
1042impl Expression {
1043 pub fn span(&self) -> &AstSpan {
1045 match self {
1046 Expression::Literal { span, .. } => span,
1047 Expression::Constant { span, .. } => span,
1048 Expression::Binary { span, .. } => span,
1049 Expression::Unary { span, .. } => span,
1050 Expression::Grouped { span, .. } => span,
1051 Expression::ArgCall { span, .. } => span,
1052 }
1053 }
1054}
1055
1056#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1058pub enum BinaryOp {
1059 Add,
1061 Sub,
1063 Mul,
1065 Div,
1067 Mod,
1069 Eq,
1071 NotEq,
1073 Lt,
1075 Gt,
1077 LtEq,
1079 GtEq,
1081}
1082
1083#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1085pub enum UnaryOp {
1086 Neg,
1088 Not,
1090}
1091
1092#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1094pub enum ConstVal {
1095 Bytes(Bytes),
1097 String(String),
1099 FreeStoragePointer(FreeStoragePointer),
1101 StoragePointer(Literal),
1103 BuiltinFunctionCall(BuiltinFunctionCall),
1105 Expression(Expression),
1107 Noop,
1109}
1110
1111#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1113pub struct ConstantDefinition {
1114 pub name: String,
1116 pub value: ConstVal,
1118 pub span: AstSpan,
1120}
1121
1122#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1124pub struct ErrorDefinition {
1125 pub name: String,
1127 pub selector: [u8; 4],
1129 pub parameters: Vec<Argument>,
1131 pub span: AstSpan,
1133}
1134
1135#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1137pub struct Label {
1138 pub name: String,
1140 pub inner: Vec<Statement>,
1142 pub span: AstSpan,
1144}
1145
1146#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1148pub enum BuiltinFunctionArg {
1149 StringLiteral(String, AstSpan),
1151 Identifier(String, AstSpan),
1153 HexLiteral(String, AstSpan),
1155 BuiltinFunctionCall(BuiltinFunctionCall),
1157 Constant(String, AstSpan),
1159 Expression(Expression),
1161}
1162
1163impl BuiltinFunctionArg {
1164 pub fn span(&self) -> AstSpan {
1166 match self {
1167 BuiltinFunctionArg::StringLiteral(_, span) => span.clone(),
1168 BuiltinFunctionArg::Identifier(_, span) => span.clone(),
1169 BuiltinFunctionArg::HexLiteral(_, span) => span.clone(),
1170 BuiltinFunctionArg::BuiltinFunctionCall(b) => b.span.clone(),
1171 BuiltinFunctionArg::Constant(_, span) => span.clone(),
1172 BuiltinFunctionArg::Expression(expr) => expr.span().clone(),
1173 }
1174 }
1175}
1176
1177#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1179pub struct BuiltinFunctionCall {
1180 pub kind: BuiltinFunctionKind,
1182 pub args: Vec<BuiltinFunctionArg>,
1187 pub span: AstSpan,
1189}
1190
1191#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1193pub enum BuiltinFunctionKind {
1194 Tablesize,
1196 Codesize,
1198 Tablestart,
1200 EmbedTable,
1202 FunctionSignature,
1204 EventHash,
1206 Error,
1208 RightPad,
1210 LeftPad,
1212 ArgsStart,
1214 Verbatim,
1216 Bytes,
1218 AssertPc,
1220}
1221
1222impl From<String> for BuiltinFunctionKind {
1223 fn from(value: String) -> Self {
1224 match value.as_str() {
1225 "__tablesize" => BuiltinFunctionKind::Tablesize,
1226 "__codesize" => BuiltinFunctionKind::Codesize,
1227 "__tablestart" => BuiltinFunctionKind::Tablestart,
1228 "__EMBED_TABLE" => BuiltinFunctionKind::EmbedTable,
1229 "__FUNC_SIG" => BuiltinFunctionKind::FunctionSignature,
1230 "__EVENT_HASH" => BuiltinFunctionKind::EventHash,
1231 "__ERROR" => BuiltinFunctionKind::Error,
1232 "__RIGHTPAD" => BuiltinFunctionKind::RightPad,
1233 "__LEFTPAD" => BuiltinFunctionKind::LeftPad,
1234 "__argsstart" => BuiltinFunctionKind::ArgsStart,
1235 "__VERBATIM" => BuiltinFunctionKind::Verbatim,
1236 "__BYTES" => BuiltinFunctionKind::Bytes,
1237 "__ASSERT_PC" => BuiltinFunctionKind::AssertPc,
1238 _ => panic!("Invalid Builtin Function Kind"), }
1242 }
1243}
1244
1245impl TryFrom<&String> for BuiltinFunctionKind {
1246 type Error = ();
1247
1248 fn try_from(value: &String) -> Result<Self, <BuiltinFunctionKind as TryFrom<&String>>::Error> {
1249 match value.as_str() {
1250 "__tablesize" => Ok(BuiltinFunctionKind::Tablesize),
1251 "__codesize" => Ok(BuiltinFunctionKind::Codesize),
1252 "__tablestart" => Ok(BuiltinFunctionKind::Tablestart),
1253 "__EMBED_TABLE" => Ok(BuiltinFunctionKind::EmbedTable),
1254 "__FUNC_SIG" => Ok(BuiltinFunctionKind::FunctionSignature),
1255 "__EVENT_HASH" => Ok(BuiltinFunctionKind::EventHash),
1256 "__ERROR" => Ok(BuiltinFunctionKind::Error),
1257 "__RIGHTPAD" => Ok(BuiltinFunctionKind::RightPad),
1258 "__LEFTPAD" => Ok(BuiltinFunctionKind::LeftPad),
1259 "__argsstart" => Ok(BuiltinFunctionKind::ArgsStart),
1260 "__VERBATIM" => Ok(BuiltinFunctionKind::Verbatim),
1261 "__BYTES" => Ok(BuiltinFunctionKind::Bytes),
1262 "__ASSERT_PC" => Ok(BuiltinFunctionKind::AssertPc),
1263 _ => Err(()),
1264 }
1265 }
1266}
1267
1268impl Display for BuiltinFunctionKind {
1269 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1270 match self {
1271 BuiltinFunctionKind::Tablesize => write!(f, "__tablesize"),
1272 BuiltinFunctionKind::Codesize => write!(f, "__codesize"),
1273 BuiltinFunctionKind::Tablestart => write!(f, "__tablestart"),
1274 BuiltinFunctionKind::EmbedTable => write!(f, "__EMBED_TABLE"),
1275 BuiltinFunctionKind::FunctionSignature => write!(f, "__FUNC_SIG"),
1276 BuiltinFunctionKind::EventHash => write!(f, "__EVENT_HASH"),
1277 BuiltinFunctionKind::Error => write!(f, "__ERROR"),
1278 BuiltinFunctionKind::RightPad => write!(f, "__RIGHTPAD"),
1279 BuiltinFunctionKind::LeftPad => write!(f, "__LEFTPAD"),
1280 BuiltinFunctionKind::ArgsStart => write!(f, "__argsstart"),
1281 BuiltinFunctionKind::Verbatim => write!(f, "__VERBATIM"),
1282 BuiltinFunctionKind::Bytes => write!(f, "__BYTES"),
1283 BuiltinFunctionKind::AssertPc => write!(f, "__ASSERT_PC"),
1284 }
1285 }
1286}
1287
1288impl BuiltinFunctionKind {
1289 pub fn is_reserved_name(name: &str) -> bool {
1291 matches!(
1292 name,
1293 "__tablesize"
1294 | "__codesize"
1295 | "__tablestart"
1296 | "__EMBED_TABLE"
1297 | "__FUNC_SIG"
1298 | "__EVENT_HASH"
1299 | "__ERROR"
1300 | "__RIGHTPAD"
1301 | "__LEFTPAD"
1302 | "__argsstart"
1303 | "__VERBATIM"
1304 | "__BYTES"
1305 | "__ASSERT_PC"
1306 | "__NOOP"
1307 )
1308 }
1309}
1310
1311#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1313pub struct Statement {
1314 pub ty: StatementType,
1316 pub span: AstSpan,
1318}
1319
1320#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1322pub enum StatementType {
1323 Literal(Literal),
1327 Opcode(Opcode),
1331 ImmediateOpcode {
1336 opcode: Opcode,
1338 operands: Vec<Expression>,
1340 },
1341 Code(String),
1345 MacroInvocation(MacroInvocation),
1349 Constant(String),
1353 ArgCall(String, String),
1359 ArgMacroInvocation(String, String, Vec<MacroArg>),
1365 Label(Label),
1369 LabelCall(String),
1373 BuiltinFunctionCall(BuiltinFunctionCall),
1377 ForLoop {
1381 variable: String,
1383 start: Expression,
1385 end: Expression,
1387 step: Option<Expression>,
1389 body: Vec<Statement>,
1391 },
1392 IfStatement {
1396 condition: Expression,
1398 then_branch: Vec<Statement>,
1400 else_if_branches: Vec<(Expression, Vec<Statement>)>,
1402 else_branch: Option<Vec<Statement>>,
1404 },
1405}
1406
1407impl Display for StatementType {
1408 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1409 match self {
1410 StatementType::Literal(l) => write!(f, "LITERAL: {}", bytes32_to_hex_string(l, true)),
1411 StatementType::Opcode(o) => write!(f, "OPCODE: {o}"),
1412 StatementType::ImmediateOpcode { opcode, operands } => {
1413 write!(f, "IMMEDIATE OPCODE: {opcode:?} with {} operands", operands.len())
1414 }
1415 StatementType::Code(s) => write!(f, "CODE: {s}"),
1416 StatementType::MacroInvocation(m) => {
1417 write!(f, "MACRO INVOCATION: {}", m.macro_name)
1418 }
1419 StatementType::Constant(c) => write!(f, "CONSTANT: {c}"),
1420 StatementType::ArgCall(m, c) => write!(f, "ARG CALL in {m}: {c}"),
1421 StatementType::ArgMacroInvocation(parent_macro, arg_name, args) => {
1422 write!(f, "ARG MACRO INVOCATION: <{}>({:?}) in {}", arg_name, args, parent_macro)
1423 }
1424 StatementType::Label(l) => write!(f, "LABEL: {}", l.name),
1425 StatementType::LabelCall(l) => write!(f, "LABEL CALL: {l}"),
1426 StatementType::BuiltinFunctionCall(b) => {
1427 write!(f, "BUILTIN FUNCTION CALL: {:?}", b.kind)
1428 }
1429 StatementType::ForLoop { variable, start: _, end: _, step, body } => {
1430 write!(f, "FOR LOOP: {} in ... step {:?}, {} statements", variable, step, body.len())
1431 }
1432 StatementType::IfStatement { condition: _, then_branch, else_if_branches, else_branch } => {
1433 write!(
1434 f,
1435 "IF STATEMENT: then {} statements, {} else if branches, else branch: {}",
1436 then_branch.len(),
1437 else_if_branches.len(),
1438 else_branch.is_some()
1439 )
1440 }
1441 }
1442 }
1443}
1444
1445#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1450pub struct Decorator {
1451 pub flags: Vec<DecoratorFlag>,
1453}
1454
1455#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1459pub struct DecoratorFlag {
1460 pub name: String,
1462 pub args: Vec<DecoratorArg>,
1464 pub span: AstSpan,
1466}
1467
1468#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1470pub struct DecoratorArg {
1471 pub key: Option<String>,
1473 pub value: DecoratorValue,
1475 pub span: AstSpan,
1477}
1478
1479#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
1481pub enum DecoratorValue {
1482 Hex(String),
1484 Int(usize),
1486 Str(String),
1488 Bool(bool),
1490 Constant(String),
1492 Builtin(BuiltinFunctionCall),
1494 Ident(String),
1496}