Skip to main content

huff_neo_parser/
lib.rs

1#![doc = include_str!("../README.md")]
2#![warn(missing_docs)]
3#![warn(unused_extern_crates)]
4#![forbid(unsafe_code)]
5
6use alloy_primitives::{U256, hex, keccak256};
7use huff_neo_utils::ast::abi::{Argument, ArgumentLocation, EventDefinition, FunctionDefinition, FunctionType};
8use huff_neo_utils::ast::huff::*;
9use huff_neo_utils::ast::span::AstSpan;
10use huff_neo_utils::bytecode::Bytes;
11use huff_neo_utils::file::remapper;
12use huff_neo_utils::{
13    error::*,
14    opcodes::Opcode,
15    prelude::{Span, str_to_bytes32},
16    token::{Token, TokenKind},
17    types::*,
18};
19
20/// The Parser
21#[derive(Debug, Clone)]
22pub struct Parser {
23    /// Vector of the tokens
24    pub tokens: Vec<Token>,
25    /// Current position
26    pub cursor: usize,
27    /// Current token
28    pub current_token: Token,
29    /// Current base path for resolving imports
30    pub base: Option<String>,
31    /// A collection of current spans
32    pub spans: Vec<Span>,
33    /// Our remapper
34    pub remapper: remapper::Remapper,
35    /// Stack of active for loop variable names (for nested loops)
36    loop_variables: Vec<String>,
37}
38
39impl Parser {
40    /// Public associated function that instantiates a Parser.
41    pub fn new(tokens: Vec<Token>, base: Option<String>) -> Self {
42        let initial_token = tokens.first().unwrap().clone();
43        let remapper = remapper::Remapper::new("./");
44        Self { tokens, cursor: 0, current_token: initial_token, base, spans: vec![], remapper, loop_variables: vec![] }
45    }
46
47    /// Resets the current token and cursor to the first token in the parser's token vec
48    ///
49    /// PANICS if the tokens vec is empty!
50    pub fn reset(&mut self) {
51        self.current_token = self.tokens.first().unwrap().clone();
52        self.cursor = 0;
53    }
54
55    /// Parse
56    pub fn parse(&mut self) -> Result<Contract, ParserError> {
57        // Remove all whitespaces, newlines, and comments first
58        self.tokens.retain(|token| !matches!(token.kind, TokenKind::Whitespace | TokenKind::Comment(_)));
59
60        // Reset the initial token
61        self.reset();
62
63        // Initialize an empty Contract
64        let mut contract = Contract::default();
65
66        // Iterate over tokens and construct the Contract aka AST
67        while !self.check(TokenKind::Eof) {
68            // Reset our spans
69            self.spans = vec![];
70
71            // Check for imports with the "#include" keyword
72            if self.check(TokenKind::Include) {
73                contract.imports.push(self.parse_imports()?);
74            }
75            // Check for a decorator above a test macro
76            else if self.check(TokenKind::Pound) {
77                let m = self.parse_macro(&mut contract)?;
78                tracing::info!(target: "parser", "SUCCESSFULLY PARSED MACRO {}", m.name);
79                contract.macros.insert(m.name.clone(), m);
80            }
81            // Check for a definition with the "#define" keyword
82            else if self.check(TokenKind::Define) {
83                // Consume the definition token
84                self.match_kind(TokenKind::Define)?;
85
86                // match to function, constant, macro, or event
87                match self.current_token.kind {
88                    TokenKind::Function => {
89                        let func = self.parse_function()?;
90                        tracing::info!(target: "parser", "SUCCESSFULLY PARSED FUNCTION {}", func.name);
91                        contract.functions.push(func);
92                    }
93                    TokenKind::Event => {
94                        let ev = self.parse_event()?;
95                        tracing::info!(target: "parser", "SUCCESSFULLY PARSED EVENT {}", ev.name);
96                        contract.events.push(ev);
97                    }
98                    TokenKind::Constant => {
99                        let c = self.parse_constant()?;
100                        tracing::info!(target: "parser", "SUCCESSFULLY PARSED CONSTANT {}", c.name);
101                        contract.constants.lock().unwrap().push(c);
102                    }
103                    TokenKind::Error => {
104                        let e = self.parse_custom_error()?;
105                        tracing::info!(target: "parser", "SUCCESSFULLY PARSED ERROR {}", e.name);
106                        contract.errors.push(e);
107                    }
108                    TokenKind::Macro | TokenKind::Fn => {
109                        let m = self.parse_macro(&mut contract)?;
110                        tracing::info!(target: "parser", "SUCCESSFULLY PARSED MACRO {}", m.name);
111                        contract.macros.insert(m.name.clone(), m);
112                    }
113                    TokenKind::Test => {
114                        let m = self.parse_macro(&mut contract)?;
115                        tracing::info!(target: "parser", "SUCCESSFULLY PARSED TEST {}", m.name);
116                        contract.macros.insert(m.name.clone(), m);
117                    }
118                    TokenKind::JumpTable | TokenKind::JumpTablePacked | TokenKind::CodeTable => {
119                        contract.tables.push(self.parse_table()?);
120                    }
121                    _ => {
122                        tracing::error!(
123                            target: "parser",
124                            "Invalid definition. Must be a function, event, constant, error, or macro. Got: {}",
125                            self.current_token.kind
126                        );
127                        return Err(ParserError {
128                            kind: ParserErrorKind::InvalidDefinition(self.current_token.kind.clone()),
129                            hint: Some(
130                                "Definition must be one of: `function`, `event`, `constant`, `error`, `macro`, `fn`, or `test`."
131                                    .to_string(),
132                            ),
133                            spans: AstSpan(vec![self.current_token.span.clone()]),
134                            cursor: self.cursor,
135                        });
136                    }
137                };
138            } else {
139                // If we don't have an "#include" or "#define" keyword, we have an invalid token
140                return Err(ParserError {
141                    kind: ParserErrorKind::UnexpectedType(self.current_token.kind.clone()),
142                    hint: Some(format!("Expected either \"{}\" or \"{}\"", TokenKind::Define, TokenKind::Include)),
143                    spans: AstSpan(vec![self.current_token.span.clone()]),
144                    cursor: self.cursor,
145                });
146            }
147        }
148
149        Ok(contract)
150    }
151
152    /// Parses Contract Imports
153    pub fn parse_imports(&mut self) -> Result<FilePath, ParserError> {
154        // First token should be keyword "#include"
155        self.match_kind(TokenKind::Include)?;
156
157        // Then let's grab and validate the file path
158        self.match_kind(TokenKind::Str("x".to_string()))?;
159        let tok = self.peek_behind().unwrap().kind;
160        let p = match tok {
161            TokenKind::Str(file_path) => file_path,
162            _ => {
163                tracing::error!(target: "parser", "INVALID IMPORT PATH: {}", tok);
164                let new_spans = self.spans.clone();
165                self.spans = vec![];
166                return Err(ParserError {
167                    kind: ParserErrorKind::InvalidName(tok.clone()),
168                    hint: Some(format!("Expected import string. Got: \"{tok}\"")),
169                    spans: AstSpan(new_spans),
170                    cursor: self.cursor,
171                });
172            }
173        };
174
175        Ok(std::path::PathBuf::from(p))
176    }
177
178    /// Match current token to a type.
179    pub fn match_kind(&mut self, kind: TokenKind) -> Result<TokenKind, ParserError> {
180        if std::mem::discriminant(&self.current_token.kind) == std::mem::discriminant(&kind) {
181            let curr_kind: TokenKind = self.current_token.kind.clone();
182            self.consume();
183            Ok(curr_kind)
184        } else {
185            tracing::error!(target: "parser", "TOKEN MISMATCH - EXPECTED: {}, GOT: {}", kind, self.current_token.kind);
186            Err(ParserError {
187                kind: ParserErrorKind::UnexpectedType(self.current_token.kind.clone()),
188                hint: Some(format!("Expected: \"{kind}\"")),
189                spans: AstSpan(self.spans.clone()),
190                cursor: self.cursor,
191            })
192        }
193    }
194
195    /// Check the current token's type against the given type.
196    pub fn check(&mut self, kind: TokenKind) -> bool {
197        std::mem::discriminant(&self.current_token.kind) == std::mem::discriminant(&kind)
198    }
199
200    /// Checks whether the input label is unique in a macro.
201    fn check_duplicate_label(&self, contract: &mut Contract, macro_name: &str, label: String, span: Span) -> Result<(), ParserError> {
202        let key = format!("{}{macro_name}{label}", span.clone().file.map(|f| f.path.clone()).unwrap_or_default());
203
204        if contract.labels.contains(&key) {
205            tracing::error!(target: "parser", "DUPLICATED LABEL NAME: {}", label);
206            Err(ParserError {
207                kind: ParserErrorKind::DuplicateLabel(label.clone()),
208                hint: Some(format!("Duplicated label name: \"{label}\" in macro: \"{macro_name}\"")),
209                spans: AstSpan(vec![span]),
210                cursor: self.cursor,
211            })
212        } else {
213            contract.labels.insert(key);
214            Ok(())
215        }
216    }
217
218    /// Consumes the next token.
219    pub fn consume(&mut self) {
220        self.spans.push(self.current_token.span.clone());
221        self.current_token = self.peek().unwrap();
222        self.cursor += 1;
223    }
224
225    /// Consumes following tokens until not contained in the kinds vec of TokenKinds.
226    pub fn consume_all(&mut self, kinds: Vec<TokenKind>) {
227        loop {
228            let token = self.peek().unwrap();
229            if !kinds.contains(&token.kind) {
230                break;
231            }
232            self.current_token = token;
233            self.cursor += 1;
234        }
235    }
236
237    /// Take a look at next token without consuming.
238    pub fn peek(&mut self) -> Option<Token> {
239        if self.cursor >= self.tokens.len() { None } else { Some(self.tokens.get(self.cursor + 1).unwrap().clone()) }
240    }
241
242    /// Take a look at the previous token.
243    pub fn peek_behind(&self) -> Option<Token> {
244        if self.cursor == 0 || self.cursor > self.tokens.len() { None } else { Some(self.tokens.get(self.cursor - 1).unwrap().clone()) }
245    }
246
247    /// Parses a function.
248    /// Adheres to <https://github.com/huff-language/huffc/blob/master/src/parser/high-level.ts#L87-L111>
249    pub fn parse_function(&mut self) -> Result<FunctionDefinition, ParserError> {
250        // the first token should be of `TokenKind::Function`
251        self.match_kind(TokenKind::Function)?;
252        // function name should be next
253        self.match_kind(TokenKind::Ident("x".to_string()))?;
254        let tok = self.peek_behind().unwrap().kind;
255        let name = match tok {
256            TokenKind::Ident(fn_name) => fn_name,
257            _ => {
258                tracing::error!(target: "parser", "TOKEN MISMATCH - EXPECTED IDENT, GOT: {}", tok);
259                return Err(ParserError {
260                    kind: ParserErrorKind::InvalidName(tok.clone()),
261                    hint: Some(format!("Expected function name, found: \"{tok}\"")),
262                    spans: AstSpan(self.spans.clone()),
263                    cursor: self.cursor,
264                });
265            }
266        };
267
268        // function inputs should be next
269        let inputs = self.parse_args(true, true, false)?;
270        // function type should be next
271        let fn_type = match self.current_token.kind.clone() {
272            TokenKind::View => FunctionType::View,
273            TokenKind::Pure => FunctionType::Pure,
274            TokenKind::Payable => FunctionType::Payable,
275            TokenKind::NonPayable => FunctionType::NonPayable,
276            tok => {
277                return Err(ParserError {
278                    kind: ParserErrorKind::UnexpectedType(tok),
279                    hint: Some("Expected one of: `view`, `pure`, `payable`, `nonpayable`.".to_string()),
280                    spans: AstSpan(vec![self.current_token.span.clone()]),
281                    cursor: self.cursor,
282                });
283            }
284        };
285        // consume the function type
286        self.consume();
287
288        // next token should be of `TokenKind::Returns`
289        self.match_kind(TokenKind::Returns)?;
290        // function outputs should be next
291        let outputs = self.parse_args(true, true, false)?;
292
293        let input_types = inputs.iter().map(|i| i.arg_type.as_ref().unwrap().clone()).collect::<Vec<_>>();
294        let method_signature = format!("{name}({})", input_types.join(","));
295        let selector = keccak256(method_signature)[..4].try_into().unwrap();
296
297        Ok(FunctionDefinition { name, signature: selector, inputs, fn_type, outputs, span: AstSpan(self.spans.clone()) })
298    }
299
300    /// Parse an event.
301    pub fn parse_event(&mut self) -> Result<EventDefinition, ParserError> {
302        // The event should start with `TokenKind::Event`
303        self.match_kind(TokenKind::Event)?;
304
305        // Parse the event name
306        self.match_kind(TokenKind::Ident("x".to_string()))?;
307        let tok = self.peek_behind().unwrap().kind;
308
309        let name = match tok {
310            TokenKind::Ident(event_name) => event_name,
311            _ => {
312                tracing::error!(target: "parser", "TOKEN MISMATCH - EXPECTED IDENT, GOT: {}", tok);
313                return Err(ParserError {
314                    kind: ParserErrorKind::InvalidName(tok.clone()),
315                    hint: Some(format!("Expected event name, found: \"{tok}\"")),
316                    spans: AstSpan(self.spans.clone()),
317                    cursor: self.cursor,
318                });
319            }
320        };
321
322        // Parse the event's parameters
323        let parameters = self.parse_args(true, true, true)?;
324
325        let input_types = parameters.iter().map(|i| i.arg_type.as_ref().unwrap().clone()).collect::<Vec<_>>();
326        let event_signature = format!("{name}({})", input_types.join(","));
327        let event_selector = keccak256(event_signature).0;
328
329        Ok(EventDefinition { name, parameters, span: AstSpan(self.spans.clone()), hash: event_selector })
330    }
331
332    /// Parse a constant.
333    pub fn parse_constant(&mut self) -> Result<ConstantDefinition, ParserError> {
334        // Constant Identifier
335        self.match_kind(TokenKind::Constant)?;
336
337        // Parse the constant name
338        // Check for reserved constant names first (before match_kind)
339        if matches!(self.current_token.kind, TokenKind::Noop) {
340            tracing::error!(target: "parser", "RESERVED CONSTANT NAME: __NOOP");
341            return Err(ParserError {
342                kind: ParserErrorKind::InvalidConstantName,
343                hint: Some("__NOOP is a reserved built-in constant and cannot be used as a constant name.".to_string()),
344                spans: AstSpan(self.spans.clone()),
345                cursor: self.cursor,
346            });
347        }
348
349        self.match_kind(TokenKind::Ident("x".to_string()))?;
350        let tok = self.peek_behind().unwrap().kind;
351        let name = match tok {
352            TokenKind::Ident(const_name) => const_name,
353            _ => {
354                tracing::error!(target: "parser", "TOKEN MISMATCH - EXPECTED IDENT, GOT: {}", tok);
355                return Err(ParserError {
356                    kind: ParserErrorKind::UnexpectedType(tok),
357                    hint: Some("Expected constant name.".to_string()),
358                    spans: AstSpan(self.spans.clone()),
359                    cursor: self.cursor,
360                });
361            }
362        };
363
364        // We must assign a value to the constant
365        self.match_kind(TokenKind::Assign)?;
366
367        let value: ConstVal = match self.current_token.kind.clone() {
368            TokenKind::FreeStoragePointer => {
369                self.consume();
370                ConstVal::FreeStoragePointer(FreeStoragePointer {})
371            }
372            TokenKind::Noop => {
373                self.consume();
374                ConstVal::Noop
375            }
376            TokenKind::Str(s) => {
377                self.consume();
378                ConstVal::String(s)
379            }
380            TokenKind::BuiltinFunction(f) => {
381                let curr_spans = vec![self.current_token.span.clone()];
382                self.match_kind(TokenKind::BuiltinFunction(String::default()))?;
383                let args = self.parse_builtin_args()?;
384                ConstVal::BuiltinFunctionCall(BuiltinFunctionCall { kind: BuiltinFunctionKind::from(f), args, span: AstSpan(curr_spans) })
385            }
386            // Simple hex literal without any operators - preserve original byte length
387            TokenKind::HexLiteral(hex_str) if !self.is_expression_context() => {
388                self.consume();
389                ConstVal::Bytes(Bytes::Raw(hex_str))
390            }
391            // Handle arithmetic expressions (including hex literals that are part of expressions,
392            // and decimal literals, which are always evaluated as expressions)
393            TokenKind::HexLiteral(_)
394            | TokenKind::Integer(_)
395            | TokenKind::OpenParen
396            | TokenKind::Sub
397            | TokenKind::Not
398            | TokenKind::OpenBracket => {
399                let expr = self.parse_constant_expression()?;
400                ConstVal::Expression(expr)
401            }
402            kind => {
403                tracing::error!(target: "parser", "TOKEN MISMATCH - EXPECTED FreeStoragePointer OR Hex, GOT: {}", self.current_token.kind);
404                return Err(ParserError {
405                    kind: ParserErrorKind::InvalidConstantValue(kind),
406                    hint: Some(
407                        "Expected constant value to be Hex, decimal, arithmetic expression, or `FREE_STORAGE_POINTER()`".to_string(),
408                    ),
409                    spans: AstSpan(vec![self.current_token.span.clone()]),
410                    cursor: self.cursor,
411                });
412            }
413        };
414
415        // Clone spans and set to nothing
416        let new_spans = self.spans.clone();
417        self.spans = vec![];
418
419        // Return the Constant Definition
420        Ok(ConstantDefinition { name, value, span: AstSpan(new_spans) })
421    }
422
423    /// Parse a custom error definition.
424    pub fn parse_custom_error(&mut self) -> Result<ErrorDefinition, ParserError> {
425        // Error Identifier
426        self.match_kind(TokenKind::Error)?;
427
428        // Parse the error name
429        self.match_kind(TokenKind::Ident("x".to_string()))?;
430        let tok = self.peek_behind().unwrap().kind;
431        let name = match tok {
432            TokenKind::Ident(err_name) => err_name,
433            _ => {
434                tracing::error!(target: "parser", "TOKEN MISMATCH - EXPECTED IDENT, GOT: {}", tok);
435                return Err(ParserError {
436                    kind: ParserErrorKind::UnexpectedType(tok),
437                    hint: Some("Expected error name.".to_string()),
438                    spans: AstSpan(self.spans.clone()),
439                    cursor: self.cursor,
440                });
441            }
442        };
443
444        // Get arguments for signature
445        let parameters = self.parse_args(true, true, false)?;
446
447        let input_types = parameters.iter().map(|i| i.arg_type.as_ref().unwrap().clone()).collect::<Vec<_>>();
448        let method_signature = format!("{name}({})", input_types.join(","));
449        let selector = keccak256(method_signature)[..4].try_into().unwrap();
450
451        // Clone spans and set to nothing
452        let new_spans = self.spans.clone();
453        self.spans = vec![];
454
455        Ok(ErrorDefinition { name, selector, parameters, span: AstSpan(new_spans) })
456    }
457
458    /// Parses the decorator blocks above a macro definition.
459    ///
460    /// Several `#[...]` blocks may be stacked; their flags are merged in source order. Flag names
461    /// and arguments are only checked for syntax here, the test runner decides what they mean.
462    pub fn parse_decorator(&mut self) -> Result<Decorator, ParserError> {
463        let mut flags: Vec<DecoratorFlag> = Vec::default();
464
465        while self.check(TokenKind::Pound) {
466            self.match_kind(TokenKind::Pound)?;
467            self.match_kind(TokenKind::OpenBracket)?;
468
469            while !self.check(TokenKind::CloseBracket) {
470                flags.push(self.parse_decorator_flag()?);
471
472                // Flags are comma separated and a trailing comma is allowed. The comma is optional
473                // to stay compatible with sources written for earlier versions.
474                if self.check(TokenKind::Comma) {
475                    self.consume();
476                }
477            }
478
479            self.match_kind(TokenKind::CloseBracket)?;
480        }
481
482        Ok(Decorator { flags })
483    }
484
485    /// Parses a single decorator flag: `name` or `name(arg, key = arg, ...)`.
486    fn parse_decorator_flag(&mut self) -> Result<DecoratorFlag, ParserError> {
487        let TokenKind::Ident(name) = self.current_token.kind.clone() else {
488            return Err(self.decorator_error(String::from("Expected a decorator flag name")));
489        };
490        let span = AstSpan(vec![self.current_token.span.clone()]);
491        self.consume();
492
493        let mut args: Vec<DecoratorArg> = Vec::new();
494        if self.check(TokenKind::OpenParen) {
495            self.consume();
496            while !self.check(TokenKind::CloseParen) {
497                args.push(self.parse_decorator_arg(&name)?);
498
499                if self.check(TokenKind::Comma) {
500                    self.consume();
501                } else if !self.check(TokenKind::CloseParen) {
502                    return Err(self.decorator_error(format!("Expected `,` or `)` in the arguments of decorator flag: {name}")));
503                }
504            }
505            self.match_kind(TokenKind::CloseParen)?;
506        }
507
508        Ok(DecoratorFlag { name, args, span })
509    }
510
511    /// Parses a decorator flag argument, optionally prefixed with `key =`.
512    fn parse_decorator_arg(&mut self, flag: &str) -> Result<DecoratorArg, ParserError> {
513        let start_span = self.current_token.span.clone();
514
515        let mut key = None;
516        if let TokenKind::Ident(ident) = self.current_token.kind.clone()
517            && self.peek().is_some_and(|t| t.kind == TokenKind::Assign)
518        {
519            key = Some(ident);
520            self.consume();
521            self.match_kind(TokenKind::Assign)?;
522        }
523
524        let value_span = self.current_token.span.clone();
525        let value = match self.current_token.kind.clone() {
526            TokenKind::HexLiteral(hex) => {
527                self.consume();
528                DecoratorValue::Hex(hex)
529            }
530            TokenKind::Integer(int) => {
531                self.consume();
532                DecoratorValue::Int(int)
533            }
534            TokenKind::Str(s) => {
535                self.consume();
536                DecoratorValue::Str(s)
537            }
538            TokenKind::Ident(ident) => {
539                self.consume();
540                match ident.as_str() {
541                    "true" => DecoratorValue::Bool(true),
542                    "false" => DecoratorValue::Bool(false),
543                    _ => DecoratorValue::Ident(ident),
544                }
545            }
546            TokenKind::OpenBracket => {
547                let (constant, _) = self.parse_constant_push()?;
548                DecoratorValue::Constant(constant)
549            }
550            TokenKind::BuiltinFunction(f) => {
551                self.consume();
552                let args = self.parse_builtin_args()?;
553                DecoratorValue::Builtin(BuiltinFunctionCall {
554                    kind: BuiltinFunctionKind::from(f),
555                    args,
556                    span: AstSpan(vec![value_span.clone()]),
557                })
558            }
559            kind => {
560                return Err(ParserError {
561                    kind: ParserErrorKind::InvalidDecoratorFlagArg(kind),
562                    hint: Some(format!(
563                        "Expected a hex or decimal literal, string, boolean, identifier, [CONSTANT] or builtin call for decorator flag: {flag}"
564                    )),
565                    spans: AstSpan(vec![value_span]),
566                    cursor: self.cursor,
567                });
568            }
569        };
570
571        Ok(DecoratorArg { key, value, span: AstSpan(vec![self.span_from(&start_span)]) })
572    }
573
574    /// The source range from `start` through the last consumed token.
575    fn span_from(&self, start: &Span) -> Span {
576        let end = self.peek_behind().map_or(start.end, |t| t.span.end);
577        Span { start: start.start, end, file: start.file.clone() }
578    }
579
580    /// Builds a decorator syntax error at the current token.
581    fn decorator_error(&self, hint: String) -> ParserError {
582        ParserError {
583            kind: ParserErrorKind::InvalidDecoratorFlag(self.current_token.kind.to_string()),
584            hint: Some(hint),
585            spans: AstSpan(vec![self.current_token.span.clone()]),
586            cursor: self.cursor,
587        }
588    }
589
590    /// Parses a macro.
591    ///
592    /// It should parse the following : macro MACRO_NAME(args...) = takes (x) returns (n) {...}
593    pub fn parse_macro(&mut self, contract: &mut Contract) -> Result<MacroDefinition, ParserError> {
594        let mut decorator: Option<Decorator> = None;
595        let mut decorator_span = None;
596        if self.check(TokenKind::Pound) {
597            let start = self.current_token.span.clone();
598            decorator = Some(self.parse_decorator()?);
599            decorator_span = Some(self.span_from(&start));
600
601            // Consume the `#define` keyword
602            self.consume();
603        }
604
605        let outlined = self.check(TokenKind::Fn);
606        let test = self.check(TokenKind::Test);
607        if !test && let Some(span) = decorator_span {
608            let name = self.peek().map(|t| t.kind.to_string()).unwrap_or_default();
609            return Err(ParserError {
610                kind: ParserErrorKind::DecoratorOnNonTest(name),
611                hint: Some(String::from("Decorators only apply to `#define test` definitions")),
612                spans: AstSpan(vec![span]),
613                cursor: self.cursor,
614            });
615        }
616
617        self.match_kind(if outlined {
618            TokenKind::Fn
619        } else if test {
620            TokenKind::Test
621        } else {
622            TokenKind::Macro
623        })?;
624
625        let macro_name: String = self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?.to_string();
626
627        // Macros, fns and tests, decorated or not, share their names, so a second one would replace the first
628        if contract.macros.contains_key(&macro_name) {
629            tracing::error!(target: "parser", "DUPLICATE MACRO NAME FOUND: {}", macro_name);
630            return Err(ParserError {
631                kind: ParserErrorKind::DuplicateMacro(macro_name),
632                hint: Some("Macros, fns and tests share their names, which must be unique".to_string()),
633                spans: AstSpan(self.peek_behind().map(|token| token.span).into_iter().collect()),
634                cursor: self.cursor,
635            });
636        }
637
638        // Check for reserved builtin function names
639        if BuiltinFunctionKind::is_reserved_name(&macro_name) {
640            tracing::error!(target: "parser", "RESERVED MACRO NAME: {}", macro_name);
641            return Err(ParserError {
642                kind: ParserErrorKind::InvalidMacroName,
643                hint: Some(format!("{} is a reserved built-in function name and cannot be used as a macro name.", macro_name)),
644                spans: AstSpan(self.spans.clone()),
645                cursor: self.cursor,
646            });
647        }
648
649        // RUNTIME is reserved as the magic argument to __codesize(RUNTIME).
650        if macro_name == RUNTIME_CODESIZE_ARG {
651            tracing::error!(target: "parser", "RESERVED MACRO NAME: {RUNTIME_CODESIZE_ARG}");
652            return Err(ParserError {
653                kind: ParserErrorKind::InvalidMacroName,
654                hint: Some(format!(
655                    "{RUNTIME_CODESIZE_ARG} is reserved (used by __codesize({RUNTIME_CODESIZE_ARG})) and cannot be used as a macro name."
656                )),
657                spans: AstSpan(self.spans.clone()),
658                cursor: self.cursor,
659            });
660        }
661
662        tracing::info!(target: "parser", "PARSING MACRO: \"{}\"", macro_name);
663
664        let macro_arguments = self.parse_args(true, false, false)?;
665        self.match_kind(TokenKind::Assign)?;
666
667        let macro_takes = self.match_kind(TokenKind::Takes).map_or(Ok(0), |_| self.parse_single_arg())?;
668        let macro_returns = self.match_kind(TokenKind::Returns).map_or(Ok(0), |_| self.parse_single_arg())?;
669
670        let macro_statements: Vec<Statement> = self.parse_body(&macro_name, contract)?;
671
672        Ok(MacroDefinition::new(
673            macro_name,
674            decorator,
675            macro_arguments,
676            macro_statements,
677            macro_takes,
678            macro_returns,
679            self.spans.clone(),
680            outlined,
681            test,
682        ))
683    }
684
685    /// Returns true if the current token can start an opcode operand.
686    fn at_opcode_operand(&self) -> bool {
687        matches!(
688            self.current_token.kind,
689            TokenKind::Integer(_) | TokenKind::HexLiteral(_) | TokenKind::OpenBracket | TokenKind::LeftAngle | TokenKind::OpenParen
690        )
691    }
692
693    /// Returns true if the opcode just consumed is followed by operands resolved at compile time,
694    /// e.g. `dupn 17` or `push2 [SIZE]`. A push followed by a hex literal keeps the plain form.
695    fn takes_opcode_operands(&self, o: Opcode) -> bool {
696        o.has_stack_immediate() || (o.is_value_push() && !matches!(self.current_token.kind, TokenKind::HexLiteral(_)))
697    }
698
699    /// Parses the operands of an opcode that carries immediate data.
700    ///
701    /// Covers DUPN, SWAPN and EXCHANGE (`dupn 17`, `exchange 1 2`) as well as PUSH1..PUSH32 with a
702    /// non-literal value (`push2 [SIZE]`). Each operand is a compile-time expression: a decimal or
703    /// hex literal, `[CONSTANT]`, `<arg>`, a loop variable, or a parenthesized expression.
704    /// Literal operands are validated immediately; all others once resolved during codegen.
705    fn parse_opcode_operands(&mut self, o: Opcode, opcode_span: Span) -> Result<Statement, ParserError> {
706        let (operand_count, kind, hint) = if o.is_value_push() {
707            (1, ParserErrorKind::InvalidPush(o), format!("\"{o:?}\" takes one value: a literal, [CONSTANT], <arg>, or (expression)"))
708        } else {
709            (o.stack_immediate_operands(), ParserErrorKind::InvalidStackImmediate(o), o.stack_immediate_hint())
710        };
711
712        let mut operands = Vec::with_capacity(operand_count);
713        let mut spans = vec![opcode_span];
714        for _ in 0..operand_count {
715            if !self.at_opcode_operand() {
716                // Opcode tokens display as their byte value; show the mnemonic instead
717                let found = match &self.current_token.kind {
718                    TokenKind::Opcode(op) => op.as_ref().to_string(),
719                    other => other.to_string(),
720                };
721                return Err(ParserError {
722                    kind,
723                    hint: Some(format!("{hint}, found \"{found}\"")),
724                    spans: AstSpan(vec![self.current_token.span.clone()]),
725                    cursor: self.cursor,
726                });
727            }
728            let operand = self.parse_primary_expression()?;
729            spans.extend_from_slice(operand.span().inner_ref());
730            operands.push(operand);
731        }
732
733        // Validate operands that are already known
734        let literals: Option<Vec<U256>> = operands
735            .iter()
736            .map(|e| if let Expression::Literal { value, .. } = e { Some(U256::from_be_bytes(*value)) } else { None })
737            .collect();
738        if let Some(values) = literals
739            && let Err(hint) = o.encode_immediate(&values)
740        {
741            return Err(ParserError { kind, hint: Some(hint), spans: AstSpan(spans[1..].to_vec()), cursor: self.cursor });
742        }
743
744        tracing::info!(target: "parser", "PARSED OPCODE OPERANDS: [{:?} with {} operands]", o, operands.len());
745        Ok(Statement { ty: StatementType::ImmediateOpcode { opcode: o, operands }, span: AstSpan(spans) })
746    }
747
748    /// Parse the body of a macro.
749    ///
750    /// Only HEX, OPCODES, labels, builtins, and MACRO calls should be authorized.
751    pub fn parse_body(&mut self, macro_name: &str, contract: &mut Contract) -> Result<Vec<Statement>, ParserError> {
752        let mut statements: Vec<Statement> = Vec::new();
753        self.match_kind(TokenKind::OpenBrace)?;
754        tracing::info!(target: "parser", "PARSING MACRO BODY");
755        while !self.check(TokenKind::CloseBrace) {
756            match self.current_token.kind.clone() {
757                TokenKind::HexLiteral(hex_str) => {
758                    let curr_spans = vec![self.current_token.span.clone()];
759                    let val = str_to_bytes32(&hex_str);
760                    tracing::info!(target: "parser", "PARSING MACRO BODY: [HEX LITERAL: {}]", hex::encode(val));
761                    self.consume();
762                    statements.push(Statement { ty: StatementType::Literal(val), span: AstSpan(curr_spans) });
763                }
764                TokenKind::Opcode(o) => {
765                    let curr_spans = vec![self.current_token.span.clone()];
766                    tracing::info!(target: "parser", "PARSING MACRO BODY: [OPCODE: {}]", o);
767                    self.consume();
768                    if self.takes_opcode_operands(o) {
769                        statements.push(self.parse_opcode_operands(o, curr_spans[0].clone())?);
770                        continue;
771                    }
772                    statements.push(Statement { ty: StatementType::Opcode(o), span: AstSpan(curr_spans) });
773                    // If the opcode is a push that takes a literal value, we need to parse the next
774                    // literal
775                    if o.is_value_push() {
776                        match self.current_token.kind.clone() {
777                            TokenKind::HexLiteral(hex_str) => {
778                                let curr_spans = vec![self.current_token.span.clone()];
779                                let val = str_to_bytes32(&hex_str);
780                                tracing::info!(target: "parser", "PARSING MACRO BODY: [HEX LITERAL: {}]", hex::encode(val));
781
782                                // Check that the literal does not overflow the push size
783                                if o.push_overflows(&hex_str) {
784                                    return Err(ParserError {
785                                        kind: ParserErrorKind::InvalidPush(o),
786                                        hint: Some(format!("Literal {hex_str:?} contains too many bytes for opcode \"{o:?}\"")),
787                                        spans: AstSpan(curr_spans),
788                                        cursor: self.cursor,
789                                    });
790                                }
791
792                                self.consume();
793                                // Otherwise we can push the literal
794                                statements.push(Statement { ty: StatementType::Literal(val), span: AstSpan(curr_spans) });
795                            }
796                            _ => {
797                                return Err(ParserError {
798                                    kind: ParserErrorKind::InvalidPush(o),
799                                    hint: Some(format!("Expected literal following \"{:?}\", found \"{:?}\"", o, self.current_token.kind)),
800                                    spans: AstSpan(vec![self.current_token.span.clone()]),
801                                    cursor: self.cursor,
802                                });
803                            }
804                        }
805                    }
806                }
807                TokenKind::Ident(ident_str) => {
808                    let mut curr_spans = vec![self.current_token.span.clone()];
809                    tracing::info!(target: "parser", "PARSING MACRO BODY: [IDENT: {}]", ident_str);
810                    self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?;
811                    // Can be a macro call or label call
812                    match self.current_token.kind {
813                        TokenKind::OpenParen => {
814                            // Parse Macro Call
815                            let lit_args = self.parse_macro_call_args(macro_name.to_owned())?;
816                            // Grab all spans following our macro invocation spam
817                            if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
818                                curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
819                            }
820                            statements.push(Statement {
821                                ty: StatementType::MacroInvocation(MacroInvocation {
822                                    macro_name: ident_str.to_string(),
823                                    args: lit_args,
824                                    span: AstSpan(curr_spans.clone()),
825                                }),
826                                span: AstSpan(curr_spans),
827                            });
828                        }
829                        _ => {
830                            tracing::info!(target: "parser", "LABEL CALL TO: {}", ident_str);
831                            statements.push(Statement { ty: StatementType::LabelCall(ident_str), span: AstSpan(curr_spans) });
832                        }
833                    }
834                }
835                // Allow keywords (if/else/for) to be used as label names
836                // Only match when NOT followed by control flow syntax '(' or '{'
837                TokenKind::If | TokenKind::Else | TokenKind::For if !matches!(self.peek(), Some(t) if matches!(t.kind, TokenKind::OpenParen | TokenKind::OpenBrace)) =>
838                {
839                    let keyword_str = match &self.current_token.kind {
840                        TokenKind::If => "if",
841                        TokenKind::Else => "else",
842                        TokenKind::For => "for",
843                        _ => unreachable!(),
844                    };
845                    let curr_spans = vec![self.current_token.span.clone()];
846                    tracing::info!(target: "parser", "PARSING MACRO BODY: [KEYWORD AS LABEL: {}]", keyword_str);
847                    self.consume();
848                    // These are treated as label calls (not control flow) when used as identifiers
849                    tracing::info!(target: "parser", "LABEL CALL TO: {}", keyword_str);
850                    statements.push(Statement { ty: StatementType::LabelCall(keyword_str.to_string()), span: AstSpan(curr_spans) });
851                }
852                TokenKind::Label(l) => {
853                    let mut curr_spans = vec![self.current_token.span.clone()];
854                    self.consume();
855                    self.check_duplicate_label(contract, macro_name, l.to_string(), self.current_token.span.clone())?;
856                    let inner_statements: Vec<Statement> = self.parse_label(macro_name.to_owned())?;
857                    inner_statements.iter().for_each(|a| curr_spans.extend_from_slice(a.span.inner_ref()));
858                    tracing::info!(target: "parser", "PARSED LABEL \"{}\" INSIDE MACRO WITH {} STATEMENTS.", l, inner_statements.len());
859                    statements.push(Statement {
860                        ty: StatementType::Label(Label { name: l, inner: inner_statements, span: AstSpan(curr_spans.clone()) }),
861                        span: AstSpan(curr_spans),
862                    });
863                }
864                TokenKind::OpenBracket => {
865                    let (constant, const_span) = self.parse_constant_push()?;
866                    tracing::info!(target: "parser", "PARSING MACRO BODY: [CONSTANT: {}]", constant);
867                    statements.push(Statement { ty: StatementType::Constant(constant), span: AstSpan(vec![const_span]) });
868                }
869                TokenKind::LeftAngle => {
870                    let stmt = self.parse_arg_call_or_invocation(macro_name.to_owned())?;
871                    statements.push(stmt);
872                }
873                TokenKind::BuiltinFunction(f) => {
874                    let mut curr_spans = vec![self.current_token.span.clone()];
875                    self.match_kind(TokenKind::BuiltinFunction(String::default()))?;
876                    let args = self.parse_builtin_args()?;
877                    args.iter().for_each(|a| curr_spans.extend_from_slice(a.span().inner_ref()));
878                    tracing::info!(target: "parser", "PARSING MACRO BODY: [BUILTIN FN: {}({:?})]", f, args);
879                    statements.push(Statement {
880                        ty: StatementType::BuiltinFunctionCall(BuiltinFunctionCall {
881                            kind: BuiltinFunctionKind::from(f),
882                            args,
883                            span: AstSpan(curr_spans.clone()),
884                        }),
885                        span: AstSpan(curr_spans),
886                    });
887                }
888                TokenKind::Noop => {
889                    tracing::info!(target: "parser", "PARSING MACRO BODY: [__NOOP] - Skipping (no bytecode)");
890                    self.consume();
891                    // Don't push any statement - __NOOP generates no bytecode
892                }
893                TokenKind::For => {
894                    let for_loop = self.parse_for_loop(macro_name)?;
895                    statements.push(for_loop);
896                }
897                TokenKind::If => {
898                    let if_statement = self.parse_if_statement(macro_name)?;
899                    statements.push(if_statement);
900                }
901                kind => {
902                    tracing::error!(target: "parser", "TOKEN MISMATCH - MACRO BODY: {}", kind);
903                    return Err(ParserError {
904                        kind: ParserErrorKind::InvalidTokenInMacroBody(kind),
905                        hint: None,
906                        spans: AstSpan(vec![self.current_token.span.clone()]),
907                        cursor: self.cursor,
908                    });
909                }
910            };
911        }
912        // consume close brace
913        self.match_kind(TokenKind::CloseBrace)?;
914        Ok(statements)
915    }
916
917    /// Parse a for loop statement
918    ///
919    /// Syntax: `for(var in start..end) { body }` or `for(var in start..end step N) { body }`
920    pub fn parse_for_loop(&mut self, macro_name: &str) -> Result<Statement, ParserError> {
921        let mut curr_spans = vec![];
922
923        // Match 'for' keyword
924        curr_spans.push(self.current_token.span.clone());
925        self.match_kind(TokenKind::For)?;
926
927        // Match '('
928        curr_spans.push(self.current_token.span.clone());
929        self.match_kind(TokenKind::OpenParen)?;
930
931        // Parse variable name (should be Ident)
932        let variable = match self.current_token.kind.clone() {
933            TokenKind::Ident(name) => {
934                curr_spans.push(self.current_token.span.clone());
935                self.consume();
936                name
937            }
938            _ => {
939                return Err(ParserError {
940                    kind: ParserErrorKind::InvalidName(self.current_token.kind.clone()),
941                    hint: Some("Expected loop variable name after 'for('".to_string()),
942                    spans: AstSpan(vec![self.current_token.span.clone()]),
943                    cursor: self.cursor,
944                });
945            }
946        };
947
948        // Match 'in' keyword
949        curr_spans.push(self.current_token.span.clone());
950        self.match_kind(TokenKind::In)?;
951
952        // Parse start expression
953        let start = self.parse_constant_expression()?;
954        curr_spans.extend_from_slice(start.span().inner_ref());
955
956        // Match '..'
957        curr_spans.push(self.current_token.span.clone());
958        self.match_kind(TokenKind::DoubleDot)?;
959
960        // Parse end expression
961        let end = self.parse_constant_expression()?;
962        curr_spans.extend_from_slice(end.span().inner_ref());
963
964        // Check for optional 'step' keyword
965        let step = if self.check(TokenKind::Step) {
966            curr_spans.push(self.current_token.span.clone());
967            self.match_kind(TokenKind::Step)?;
968            let step_expr = self.parse_constant_expression()?;
969            curr_spans.extend_from_slice(step_expr.span().inner_ref());
970            Some(step_expr)
971        } else {
972            None
973        };
974
975        // Match ')'
976        curr_spans.push(self.current_token.span.clone());
977        self.match_kind(TokenKind::CloseParen)?;
978
979        // Capture '{' span before parsing body
980        curr_spans.push(self.current_token.span.clone());
981
982        // Push loop variable to track it during body parsing
983        self.loop_variables.push(variable.clone());
984
985        // Parse the loop body (this consumes '{' and '}')
986        let body = self.parse_for_body(macro_name)?;
987
988        // Pop loop variable after parsing body
989        self.loop_variables.pop();
990
991        // Collect spans from body
992        body.iter().for_each(|s| curr_spans.extend_from_slice(s.span.inner_ref()));
993
994        // Capture '}' span - parse_for_body consumed it, so use peek_behind
995        if let Some(close_brace_token) = self.peek_behind() {
996            curr_spans.push(close_brace_token.span);
997        }
998
999        tracing::info!(target: "parser", "PARSED FOR LOOP: {} in {}..{} step {:?} with {} statements",
1000                      variable, "start", "end", step, body.len());
1001
1002        Ok(Statement { ty: StatementType::ForLoop { variable, start, end, step, body }, span: AstSpan(curr_spans) })
1003    }
1004
1005    /// Parse a compile-time if statement
1006    pub fn parse_if_statement(&mut self, macro_name: &str) -> Result<Statement, ParserError> {
1007        let mut curr_spans = vec![];
1008
1009        // Match 'if' keyword
1010        curr_spans.push(self.current_token.span.clone());
1011        self.match_kind(TokenKind::If)?;
1012
1013        // Match '('
1014        curr_spans.push(self.current_token.span.clone());
1015        self.match_kind(TokenKind::OpenParen)?;
1016
1017        // Parse condition expression
1018        let condition = self.parse_constant_expression()?;
1019        curr_spans.extend_from_slice(condition.span().inner_ref());
1020
1021        // Match ')'
1022        curr_spans.push(self.current_token.span.clone());
1023        self.match_kind(TokenKind::CloseParen)?;
1024
1025        // Parse then branch body
1026        curr_spans.push(self.current_token.span.clone());
1027        let then_branch = self.parse_if_body(macro_name)?;
1028        then_branch.iter().for_each(|s| curr_spans.extend_from_slice(s.span.inner_ref()));
1029
1030        // Capture '}' span
1031        if let Some(close_brace_token) = self.peek_behind() {
1032            curr_spans.push(close_brace_token.span);
1033        }
1034
1035        // Parse else if clauses
1036        let mut else_if_branches = Vec::new();
1037        while self.check(TokenKind::Else) {
1038            // Peek ahead to see if it's 'else if' or just 'else'
1039            let next_is_if = self.peek().map(|t| matches!(t.kind, TokenKind::If)).unwrap_or(false);
1040
1041            if !next_is_if {
1042                break; // This is an 'else' clause, not 'else if'
1043            }
1044
1045            // Match 'else' keyword
1046            curr_spans.push(self.current_token.span.clone());
1047            self.match_kind(TokenKind::Else)?;
1048
1049            // Match 'if' keyword
1050            curr_spans.push(self.current_token.span.clone());
1051            self.match_kind(TokenKind::If)?;
1052
1053            // Match '('
1054            curr_spans.push(self.current_token.span.clone());
1055            self.match_kind(TokenKind::OpenParen)?;
1056
1057            // Parse else if condition
1058            let else_if_condition = self.parse_constant_expression()?;
1059            curr_spans.extend_from_slice(else_if_condition.span().inner_ref());
1060
1061            // Match ')'
1062            curr_spans.push(self.current_token.span.clone());
1063            self.match_kind(TokenKind::CloseParen)?;
1064
1065            // Parse else if body
1066            curr_spans.push(self.current_token.span.clone());
1067            let else_if_body = self.parse_if_body(macro_name)?;
1068            else_if_body.iter().for_each(|s| curr_spans.extend_from_slice(s.span.inner_ref()));
1069
1070            // Capture '}' span
1071            if let Some(close_brace_token) = self.peek_behind() {
1072                curr_spans.push(close_brace_token.span);
1073            }
1074
1075            else_if_branches.push((else_if_condition, else_if_body));
1076        }
1077
1078        // Parse optional else clause
1079        let else_branch = if self.check(TokenKind::Else) {
1080            curr_spans.push(self.current_token.span.clone());
1081            self.match_kind(TokenKind::Else)?;
1082
1083            // Parse else body
1084            curr_spans.push(self.current_token.span.clone());
1085            let else_body = self.parse_if_body(macro_name)?;
1086            else_body.iter().for_each(|s| curr_spans.extend_from_slice(s.span.inner_ref()));
1087
1088            // Capture '}' span
1089            if let Some(close_brace_token) = self.peek_behind() {
1090                curr_spans.push(close_brace_token.span);
1091            }
1092
1093            Some(else_body)
1094        } else {
1095            None
1096        };
1097
1098        tracing::info!(target: "parser", "PARSED IF STATEMENT with {} else-if branches and else: {}",
1099                      else_if_branches.len(), else_branch.is_some());
1100
1101        Ok(Statement {
1102            ty: StatementType::IfStatement { condition, then_branch, else_if_branches, else_branch },
1103            span: AstSpan(curr_spans),
1104        })
1105    }
1106
1107    /// Parse the body of an if statement (reuses for loop body parsing logic)
1108    fn parse_if_body(&mut self, macro_name: &str) -> Result<Vec<Statement>, ParserError> {
1109        // Reuse the for loop body parser since it handles all statement types
1110        // If statements don't have loop variables, so loop variable handling won't trigger
1111        self.parse_for_body(macro_name)
1112    }
1113
1114    /// Parse the body of a for loop (similar to parse_body but handles interpolation)
1115    fn parse_for_body(&mut self, macro_name: &str) -> Result<Vec<Statement>, ParserError> {
1116        let mut statements: Vec<Statement> = Vec::new();
1117        self.match_kind(TokenKind::OpenBrace)?;
1118
1119        while !self.check(TokenKind::CloseBrace) {
1120            match self.current_token.kind.clone() {
1121                TokenKind::HexLiteral(hex_str) => {
1122                    let curr_spans = vec![self.current_token.span.clone()];
1123                    let val = str_to_bytes32(&hex_str);
1124                    self.consume();
1125                    statements.push(Statement { ty: StatementType::Literal(val), span: AstSpan(curr_spans) });
1126                }
1127                TokenKind::Opcode(o) => {
1128                    let curr_spans = vec![self.current_token.span.clone()];
1129                    self.consume();
1130                    if self.takes_opcode_operands(o) {
1131                        statements.push(self.parse_opcode_operands(o, curr_spans[0].clone())?);
1132                        continue;
1133                    }
1134                    statements.push(Statement { ty: StatementType::Opcode(o), span: AstSpan(curr_spans) });
1135                    if o.is_value_push() {
1136                        // Handle push with literal
1137                        match self.current_token.kind.clone() {
1138                            TokenKind::HexLiteral(hex_str) => {
1139                                let curr_spans = vec![self.current_token.span.clone()];
1140                                let val = str_to_bytes32(&hex_str);
1141                                self.consume();
1142                                statements.push(Statement { ty: StatementType::Literal(val), span: AstSpan(curr_spans) });
1143                            }
1144                            _ => {
1145                                return Err(ParserError {
1146                                    kind: ParserErrorKind::InvalidPush(o),
1147                                    hint: Some(format!("Expected literal or interpolation following \"{:?}\"", o)),
1148                                    spans: AstSpan(vec![self.current_token.span.clone()]),
1149                                    cursor: self.cursor,
1150                                });
1151                            }
1152                        }
1153                    }
1154                }
1155                TokenKind::Ident(ident_str) => {
1156                    let mut curr_spans = vec![self.current_token.span.clone()];
1157                    self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?;
1158                    // Can be a macro call or label call
1159                    match self.current_token.kind {
1160                        TokenKind::OpenParen => {
1161                            // Parse Macro Call
1162                            let lit_args = self.parse_macro_call_args(macro_name.to_owned())?;
1163                            if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
1164                                curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
1165                            }
1166                            statements.push(Statement {
1167                                ty: StatementType::MacroInvocation(MacroInvocation {
1168                                    macro_name: ident_str.to_string(),
1169                                    args: lit_args,
1170                                    span: AstSpan(curr_spans.clone()),
1171                                }),
1172                                span: AstSpan(curr_spans),
1173                            });
1174                        }
1175                        _ => {
1176                            statements.push(Statement { ty: StatementType::LabelCall(ident_str), span: AstSpan(curr_spans) });
1177                        }
1178                    }
1179                }
1180                TokenKind::OpenBracket => {
1181                    let (constant, const_span) = self.parse_constant_push()?;
1182                    statements.push(Statement { ty: StatementType::Constant(constant), span: AstSpan(vec![const_span]) });
1183                }
1184                TokenKind::LeftAngle => {
1185                    // Check if this is a loop variable reference <var>
1186                    let angle_span = self.current_token.span.clone(); // Save the < span
1187                    self.consume(); // consume <
1188
1189                    if let TokenKind::Ident(ref ident_name) = self.current_token.kind {
1190                        // Check if this identifier is an active loop variable
1191                        if self.loop_variables.contains(ident_name) {
1192                            // This is a loop variable reference
1193                            let var_name = ident_name.clone();
1194                            self.consume(); // consume identifier
1195                            self.match_kind(TokenKind::RightAngle)?; // consume >
1196
1197                            tracing::info!(target: "parser", "PARSING FOR BODY: [LOOP VAR: <{}>]", var_name);
1198                            statements.push(Statement {
1199                                ty: StatementType::Constant(format!("__LOOP_VAR_{}", var_name)),
1200                                span: AstSpan(vec![angle_span]),
1201                            });
1202                            continue;
1203                        }
1204                    }
1205
1206                    // Not a loop variable - parse as arg call or macro invocation
1207                    // We've already consumed the <, so we need to handle the rest
1208                    let stmt = self.parse_arg_call_or_invocation_after_angle(macro_name.to_owned(), angle_span)?;
1209                    statements.push(stmt);
1210                }
1211                TokenKind::BuiltinFunction(f) => {
1212                    let mut curr_spans = vec![self.current_token.span.clone()];
1213                    self.match_kind(TokenKind::BuiltinFunction(String::default()))?;
1214                    let args = self.parse_builtin_args()?;
1215                    args.iter().for_each(|a| curr_spans.extend_from_slice(a.span().inner_ref()));
1216                    statements.push(Statement {
1217                        ty: StatementType::BuiltinFunctionCall(BuiltinFunctionCall {
1218                            kind: BuiltinFunctionKind::from(f),
1219                            args,
1220                            span: AstSpan(curr_spans.clone()),
1221                        }),
1222                        span: AstSpan(curr_spans),
1223                    });
1224                }
1225                TokenKind::Label(l) => {
1226                    let mut curr_spans = vec![self.current_token.span.clone()];
1227                    self.consume();
1228                    let inner_statements: Vec<Statement> = self.parse_label(macro_name.to_owned())?;
1229                    inner_statements.iter().for_each(|a| curr_spans.extend_from_slice(a.span.inner_ref()));
1230                    tracing::info!(target: "parser", "PARSED LABEL \"{}\" INSIDE FOR LOOP WITH {} STATEMENTS.", l, inner_statements.len());
1231                    statements.push(Statement {
1232                        ty: StatementType::Label(Label { name: l, inner: inner_statements, span: AstSpan(curr_spans.clone()) }),
1233                        span: AstSpan(curr_spans),
1234                    });
1235                }
1236                TokenKind::Noop => {
1237                    tracing::info!(target: "parser", "PARSING FOR BODY: [__NOOP] - Skipping (no bytecode)");
1238                    self.consume();
1239                    // Don't push any statement - __NOOP generates no bytecode
1240                }
1241                TokenKind::For => {
1242                    // Support nested for loops
1243                    let nested_for_loop = self.parse_for_loop(macro_name)?;
1244                    statements.push(nested_for_loop);
1245                }
1246                TokenKind::If => {
1247                    // Support if statements inside for loops
1248                    let if_statement = self.parse_if_statement(macro_name)?;
1249                    statements.push(if_statement);
1250                }
1251                kind => {
1252                    return Err(ParserError {
1253                        kind: ParserErrorKind::InvalidTokenInMacroBody(kind),
1254                        hint: Some("Unexpected token in for loop body".to_string()),
1255                        spans: AstSpan(vec![self.current_token.span.clone()]),
1256                        cursor: self.cursor,
1257                    });
1258                }
1259            }
1260        }
1261
1262        self.match_kind(TokenKind::CloseBrace)?;
1263        Ok(statements)
1264    }
1265
1266    /// Parse the body of a label.
1267    ///
1268    /// ## Examples
1269    ///
1270    /// Below is an example of a label that contains a Macro Invocation, Literals, and Opcodes.
1271    ///
1272    /// ```huff
1273    /// error:
1274    ///     TRANSFER()
1275    ///     0x20 0x00 return
1276    /// ```
1277    pub fn parse_label(&mut self, parent_macro_name: String) -> Result<Vec<Statement>, ParserError> {
1278        let mut statements: Vec<Statement> = Vec::new();
1279        self.match_kind(TokenKind::Colon)?;
1280        while !self.check(TokenKind::Label("NEXT_LABEL".to_string()))
1281            && !self.check(TokenKind::CloseBrace)
1282            && !self.check(TokenKind::For)
1283            && !self.check(TokenKind::If)
1284        {
1285            match self.current_token.kind.clone() {
1286                TokenKind::HexLiteral(hex_str) => {
1287                    let curr_spans = vec![self.current_token.span.clone()];
1288                    let val = str_to_bytes32(&hex_str);
1289                    tracing::info!(target: "parser", "PARSING LABEL BODY: [HEX LITERAL: {}]", hex::encode(val));
1290                    self.consume();
1291                    statements.push(Statement { ty: StatementType::Literal(val), span: AstSpan(curr_spans) });
1292                }
1293                TokenKind::Opcode(o) => {
1294                    let curr_spans = vec![self.current_token.span.clone()];
1295                    tracing::info!(target: "parser", "PARSING LABEL BODY: [OPCODE: {}]", o);
1296                    self.consume();
1297                    if self.takes_opcode_operands(o) {
1298                        statements.push(self.parse_opcode_operands(o, curr_spans[0].clone())?);
1299                        continue;
1300                    }
1301                    statements.push(Statement { ty: StatementType::Opcode(o), span: AstSpan(curr_spans) });
1302                }
1303                TokenKind::Ident(ident_str) => {
1304                    let mut curr_spans = vec![self.current_token.span.clone()];
1305                    tracing::info!(target: "parser", "PARSING LABEL BODY: [IDENT: {}]", ident_str);
1306                    self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?;
1307                    // Can be a macro call or label call
1308                    match self.current_token.kind.clone() {
1309                        TokenKind::OpenParen => {
1310                            // Parse Macro Call
1311                            let lit_args = self.parse_macro_call_args(ident_str.to_string())?;
1312                            // Grab all spans following our macro invocation spam
1313                            if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
1314                                curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
1315                            }
1316                            statements.push(Statement {
1317                                ty: StatementType::MacroInvocation(MacroInvocation {
1318                                    macro_name: ident_str.to_string(),
1319                                    args: lit_args,
1320                                    span: AstSpan(curr_spans.clone()),
1321                                }),
1322                                span: AstSpan(curr_spans),
1323                            });
1324                        }
1325                        _ => {
1326                            tracing::info!(target: "parser", "LABEL CALL TO: {}", ident_str);
1327                            statements.push(Statement { ty: StatementType::LabelCall(ident_str), span: AstSpan(curr_spans) });
1328                        }
1329                    }
1330                }
1331                TokenKind::OpenBracket => {
1332                    let (constant, const_span) = self.parse_constant_push()?;
1333                    tracing::info!(target: "parser", "PARSING LABEL BODY: [CONSTANT: {}]", constant);
1334                    statements.push(Statement { ty: StatementType::Constant(constant), span: AstSpan(vec![const_span]) });
1335                }
1336                TokenKind::LeftAngle => {
1337                    // Check if this is a loop variable reference <var>
1338                    let angle_span = self.current_token.span.clone(); // Save the < span
1339                    self.consume(); // consume <
1340
1341                    if let TokenKind::Ident(ref ident_name) = self.current_token.kind {
1342                        // Check if this identifier is an active loop variable
1343                        if self.loop_variables.contains(ident_name) {
1344                            // This is a loop variable reference
1345                            let var_name = ident_name.clone();
1346                            self.consume(); // consume identifier
1347                            self.match_kind(TokenKind::RightAngle)?; // consume >
1348
1349                            tracing::info!(target: "parser", "PARSING LABEL BODY: [LOOP VAR: <{}>]", var_name);
1350                            statements.push(Statement {
1351                                ty: StatementType::Constant(format!("__LOOP_VAR_{}", var_name)),
1352                                span: AstSpan(vec![angle_span]),
1353                            });
1354                            continue;
1355                        }
1356                    }
1357
1358                    // Not a loop variable - parse as arg call or macro invocation
1359                    let stmt = self.parse_arg_call_or_invocation_after_angle(parent_macro_name.clone(), angle_span)?;
1360                    statements.push(stmt);
1361                }
1362                TokenKind::BuiltinFunction(f) => {
1363                    let mut curr_spans = vec![self.current_token.span.clone()];
1364                    self.match_kind(TokenKind::BuiltinFunction(String::default()))?;
1365                    let args = self.parse_builtin_args()?;
1366                    args.iter().for_each(|a| curr_spans.extend_from_slice(a.span().inner_ref()));
1367                    tracing::info!(target: "parser", "PARSING LABEL BODY: [BUILTIN FN: {}({:?})]", f, args);
1368                    statements.push(Statement {
1369                        ty: StatementType::BuiltinFunctionCall(BuiltinFunctionCall {
1370                            kind: BuiltinFunctionKind::from(f),
1371                            args,
1372                            span: AstSpan(curr_spans.clone()),
1373                        }),
1374                        span: AstSpan(curr_spans),
1375                    });
1376                }
1377                TokenKind::Noop => {
1378                    tracing::info!(target: "parser", "PARSING LABEL BODY: [__NOOP] - Skipping (no bytecode)");
1379                    self.consume();
1380                    // Don't push any statement - __NOOP generates no bytecode
1381                }
1382                // Allow keywords (if/else/for) to be used as label names in label bodies
1383                // Only match when NOT followed by control flow syntax '(' or '{'
1384                TokenKind::If | TokenKind::Else | TokenKind::For if !matches!(self.peek(), Some(t) if matches!(t.kind, TokenKind::OpenParen | TokenKind::OpenBrace)) =>
1385                {
1386                    let keyword_str = match &self.current_token.kind {
1387                        TokenKind::If => "if",
1388                        TokenKind::Else => "else",
1389                        TokenKind::For => "for",
1390                        _ => unreachable!(),
1391                    };
1392                    let curr_spans = vec![self.current_token.span.clone()];
1393                    tracing::info!(target: "parser", "PARSING LABEL BODY: [KEYWORD AS LABEL: {}]", keyword_str);
1394                    self.consume();
1395                    // These are treated as label calls (not control flow) when used as identifiers
1396                    tracing::info!(target: "parser", "LABEL CALL TO: {}", keyword_str);
1397                    statements.push(Statement { ty: StatementType::LabelCall(keyword_str.to_string()), span: AstSpan(curr_spans) });
1398                }
1399                kind => {
1400                    tracing::error!(target: "parser", "TOKEN MISMATCH - LABEL BODY: {}", kind);
1401                    return Err(ParserError {
1402                        kind: ParserErrorKind::InvalidTokenInLabelDefinition(kind),
1403                        hint: None,
1404                        spans: AstSpan(vec![self.current_token.span.clone()]),
1405                        cursor: self.cursor,
1406                    });
1407                }
1408            };
1409        }
1410        Ok(statements)
1411    }
1412
1413    /// Parse new lines.
1414    ///
1415    /// No-return since newlines are non-essential.
1416    pub fn parse_newline(&mut self) -> Result<(), ParserError> {
1417        self.match_kind(TokenKind::Whitespace)?;
1418        while self.check(TokenKind::Whitespace) {
1419            self.consume();
1420        }
1421        Ok(())
1422    }
1423
1424    /// Returns true if the current builtin argument is a compile-time expression rather than a
1425    /// single literal, constant, identifier, or builtin call, e.g. `<arg>` or `[BASE] + 0x20`.
1426    fn at_builtin_expression_arg(&self) -> bool {
1427        let ends_arg = |offset: usize| {
1428            self.tokens.get(self.cursor + offset).is_some_and(|t| matches!(t.kind, TokenKind::Comma | TokenKind::CloseParen))
1429        };
1430        match self.current_token.kind {
1431            TokenKind::LeftAngle | TokenKind::OpenParen | TokenKind::Integer(_) => true,
1432            TokenKind::HexLiteral(_) => !ends_arg(1),
1433            TokenKind::OpenBracket => !ends_arg(3),
1434            _ => false,
1435        }
1436    }
1437
1438    /// Parse the argument of a builtin function call.
1439    pub fn parse_builtin_args(&mut self) -> Result<Vec<BuiltinFunctionArg>, ParserError> {
1440        let mut args: Vec<BuiltinFunctionArg> = Vec::new();
1441        self.match_kind(TokenKind::OpenParen)?;
1442
1443        tracing::debug!(target: "parser", "PARSING ARGs: {:?}", self.current_token.kind);
1444        while !self.check(TokenKind::CloseParen) {
1445            let mut is_builtin = false;
1446            let mut builtin = "".to_string();
1447
1448            if self.at_builtin_expression_arg() {
1449                args.push(BuiltinFunctionArg::Expression(self.parse_constant_expression()?));
1450                if self.check(TokenKind::Comma) {
1451                    self.consume();
1452                }
1453                continue;
1454            }
1455
1456            match &self.current_token.kind {
1457                TokenKind::Str(s) => {
1458                    args.push(BuiltinFunctionArg::StringLiteral(s.to_owned(), AstSpan(vec![self.current_token.span.clone()])));
1459                    self.consume();
1460                }
1461                TokenKind::HexLiteral(bytes) => {
1462                    args.push(BuiltinFunctionArg::HexLiteral(bytes.to_owned(), AstSpan(vec![self.current_token.span.clone()])));
1463                    self.consume();
1464                }
1465                TokenKind::Ident(ident) => {
1466                    args.push(BuiltinFunctionArg::Identifier(ident.to_owned(), AstSpan(vec![self.current_token.span.clone()])));
1467                    self.consume();
1468                }
1469                TokenKind::BuiltinFunction(builtin_ref) => {
1470                    is_builtin = true;
1471                    builtin = builtin_ref.clone();
1472                    self.consume();
1473                }
1474                TokenKind::OpenBracket => {
1475                    let (constant_name, span) = self.parse_constant_push()?;
1476                    args.push(BuiltinFunctionArg::Constant(constant_name, AstSpan(vec![span])));
1477                }
1478                _ => {
1479                    return Err(ParserError {
1480                        kind: ParserErrorKind::UnexpectedType(self.current_token.kind.clone()),
1481                        hint: Some("Expected string, literal, hex, identifier or build-in".to_string()),
1482                        spans: AstSpan(vec![self.current_token.span.clone()]),
1483                        cursor: self.cursor,
1484                    });
1485                }
1486            }
1487
1488            if is_builtin {
1489                args.push(BuiltinFunctionArg::BuiltinFunctionCall(BuiltinFunctionCall {
1490                    kind: BuiltinFunctionKind::from(builtin.clone()),
1491                    args: self.parse_builtin_args()?, // Recursively parse the arguments
1492                    span: AstSpan(vec![self.current_token.span.clone()]),
1493                }));
1494            }
1495
1496            if self.check(TokenKind::Comma) {
1497                self.consume();
1498            }
1499        }
1500
1501        // consume close parenthesis
1502        self.match_kind(TokenKind::CloseParen)?;
1503        Ok(args)
1504    }
1505
1506    /// Parse abi arguments
1507    ///
1508    /// Arguments can be typed or not. Between parenthesis.
1509    /// Works for both inputs and outputs.
1510    /// It should parse the following : (uint256 a, bool b, ...)
1511    pub fn parse_args(&mut self, select_name: bool, select_type: bool, has_indexed: bool) -> Result<Vec<Argument>, ParserError> {
1512        let mut args: Vec<Argument> = Vec::new();
1513        self.match_kind(TokenKind::OpenParen)?;
1514        let mut on_type = true;
1515        tracing::debug!(target: "parser", "PARSING ABI ARGs: {:?}", self.current_token.kind);
1516        while !self.check(TokenKind::CloseParen) {
1517            let mut arg = Argument::default();
1518            let mut arg_spans = vec![];
1519
1520            // type comes first
1521            if select_type {
1522                arg_spans.push(self.current_token.span.clone());
1523                arg.arg_type = Some(self.parse_arg_type()?);
1524                // Check if the argument is indexed
1525                if has_indexed && self.check(TokenKind::Indexed) {
1526                    arg.indexed = true;
1527                    arg_spans.push(self.current_token.span.clone());
1528                    self.consume(); // consume "indexed" keyword
1529                }
1530                on_type = false;
1531            }
1532
1533            // It can also be a data location
1534            match &self.current_token.kind {
1535                TokenKind::Calldata => {
1536                    arg.arg_location = Some(ArgumentLocation::Calldata);
1537                    arg_spans.push(self.current_token.span.clone());
1538                    self.consume();
1539                }
1540                TokenKind::Memory => {
1541                    arg.arg_location = Some(ArgumentLocation::Memory);
1542                    arg_spans.push(self.current_token.span.clone());
1543                    self.consume();
1544                }
1545                TokenKind::Storage => {
1546                    arg.arg_location = Some(ArgumentLocation::Storage);
1547                    arg_spans.push(self.current_token.span.clone());
1548                    self.consume();
1549                }
1550                _ => {}
1551            }
1552
1553            // name comes second (is optional)
1554            if select_name
1555                && (self.check(TokenKind::Ident("x".to_string())) || self.check(TokenKind::PrimitiveType(PrimitiveEVMType::Address)))
1556            {
1557                // We need to check if the name is a keyword - not the type
1558                if !on_type {
1559                    // Check for reserved primitive type keyword use and throw an error if so
1560                    match self.current_token.kind.clone() {
1561                        TokenKind::Ident(arg_str) if PrimitiveEVMType::try_from(&arg_str).is_ok() => {
1562                            return Err(ParserError {
1563                                kind: ParserErrorKind::InvalidTypeAsArgumentName(self.current_token.kind.clone()),
1564                                hint: Some(format!("Argument names cannot be EVM types: {arg_str}")),
1565                                spans: AstSpan(vec![self.current_token.span.clone()]),
1566                                cursor: self.cursor,
1567                            });
1568                        }
1569                        TokenKind::PrimitiveType(ty) => {
1570                            return Err(ParserError {
1571                                kind: ParserErrorKind::InvalidTypeAsArgumentName(self.current_token.kind.clone()),
1572                                hint: Some(format!("Argument names cannot be EVM types: {ty}")),
1573                                spans: AstSpan(vec![self.current_token.span.clone()]),
1574                                cursor: self.cursor,
1575                            });
1576                        }
1577                        _ => { /* continue, valid string */ }
1578                    }
1579                }
1580                arg_spans.push(self.current_token.span.clone());
1581                arg.name = Some(self.match_kind(TokenKind::Ident("x".to_string()))?.to_string());
1582                on_type = !on_type;
1583            }
1584
1585            // multiple args possible
1586            if self.check(TokenKind::Comma) {
1587                self.consume();
1588                on_type = true;
1589            }
1590
1591            // If both arg type and arg name are none, we didn't consume anything
1592            if arg.arg_type.is_none() && arg.name.is_none() {
1593                tracing::error!(target: "parser", "INVALID ARGUMENT TOKEN: {:?}", self.current_token.kind);
1594                return Err(ParserError {
1595                    kind: ParserErrorKind::InvalidArgs(self.current_token.kind.clone()),
1596                    hint: None,
1597                    spans: AstSpan(vec![self.current_token.span.clone()]),
1598                    cursor: self.cursor,
1599                });
1600            }
1601
1602            arg.span = AstSpan(arg_spans);
1603
1604            args.push(arg);
1605        }
1606        // consume close parenthesis
1607        self.match_kind(TokenKind::CloseParen)?;
1608        Ok(args)
1609    }
1610
1611    /// Parses the following : (x)
1612    pub fn parse_single_arg(&mut self) -> Result<usize, ParserError> {
1613        self.match_kind(TokenKind::OpenParen)?;
1614        let single_arg_span = vec![self.current_token.span.clone()];
1615        let value: usize = match self.match_kind(TokenKind::Integer(0)) {
1616            Ok(TokenKind::Integer(value)) => value,
1617            _ => {
1618                return Err(ParserError {
1619                    kind: ParserErrorKind::InvalidSingleArg(self.current_token.kind.clone()),
1620                    hint: Some("Expected number representing stack item count.".to_string()),
1621                    spans: AstSpan(single_arg_span),
1622                    cursor: self.cursor,
1623                });
1624            }
1625        };
1626        self.match_kind(TokenKind::CloseParen)?;
1627        Ok(value)
1628    }
1629
1630    /// Parse a single macro argument
1631    fn parse_single_macro_argument(&mut self) -> Result<MacroArg, ParserError> {
1632        match self.current_token.kind.clone() {
1633            TokenKind::HexLiteral(hex_str) => {
1634                let lit = str_to_bytes32(&hex_str);
1635                self.consume();
1636                Ok(MacroArg::HexLiteral(lit))
1637            }
1638            TokenKind::Integer(n) => {
1639                self.consume();
1640                Ok(MacroArg::HexLiteral(str_to_bytes32(&format!("{n:x}"))))
1641            }
1642            TokenKind::Opcode(o) => {
1643                self.consume();
1644                Ok(MacroArg::Opcode(o))
1645            }
1646            TokenKind::Noop => {
1647                self.consume();
1648                Ok(MacroArg::Noop)
1649            }
1650            TokenKind::BuiltinFunction(f) => {
1651                let mut curr_spans = vec![self.current_token.span.clone()];
1652                self.match_kind(TokenKind::BuiltinFunction(String::default()))?;
1653                let args = self.parse_builtin_args()?;
1654                if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
1655                    curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
1656                }
1657                Ok(MacroArg::BuiltinFunctionCall(BuiltinFunctionCall {
1658                    kind: BuiltinFunctionKind::from(f),
1659                    args,
1660                    span: AstSpan(curr_spans),
1661                }))
1662            }
1663            TokenKind::Ident(ident) => {
1664                if self.peek().is_some() && self.peek().unwrap().kind == TokenKind::OpenParen {
1665                    // It's a nested macro call
1666                    let mut curr_spans = vec![self.current_token.span.clone()];
1667                    self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?;
1668                    // Parse Macro Call - use empty string as we don't have the parent macro name here
1669                    let lit_args = self.parse_macro_call_args(String::new())?;
1670                    // Grab all spans following our macro invocation
1671                    if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
1672                        curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
1673                    }
1674                    Ok(MacroArg::MacroCall(MacroInvocation { macro_name: ident, args: lit_args, span: AstSpan(curr_spans.clone()) }))
1675                } else {
1676                    self.consume();
1677                    Ok(MacroArg::Ident(ident))
1678                }
1679            }
1680            TokenKind::Calldata => {
1681                self.consume();
1682                Ok(MacroArg::Ident("calldata".to_string()))
1683            }
1684            TokenKind::LeftAngle => {
1685                // ArgCall: <arg> or ArgCallMacroInvocation: <arg>(...)
1686                self.consume();
1687                let arg_name = self.match_kind(TokenKind::Ident("ARG_CALL".to_string()))?.to_string();
1688                let span = AstSpan(vec![self.current_token.span.clone()]);
1689                self.match_kind(TokenKind::RightAngle)?;
1690
1691                // Check if this is an arg macro call <arg>(...)
1692                if self.current_token.kind == TokenKind::OpenParen {
1693                    self.consume(); // consume '('
1694
1695                    // Parse arguments for the arg macro invocation
1696                    let mut args = Vec::new();
1697                    while self.current_token.kind != TokenKind::CloseParen {
1698                        args.push(self.parse_single_macro_argument()?);
1699
1700                        if self.current_token.kind == TokenKind::Comma {
1701                            self.consume();
1702                        } else if self.current_token.kind != TokenKind::CloseParen {
1703                            break; // Let the outer parser handle the error
1704                        }
1705                    }
1706
1707                    self.match_kind(TokenKind::CloseParen)?; // consume ')'
1708
1709                    Ok(MacroArg::ArgCallMacroInvocation(arg_name, args))
1710                } else if self.loop_variables.contains(&arg_name) {
1711                    // Loop variables are substituted with their value when the loop is unrolled
1712                    Ok(MacroArg::Ident(format!("__LOOP_VAR_{arg_name}")))
1713                } else {
1714                    // Simple arg call <arg>
1715                    Ok(MacroArg::ArgCall(ArgCall {
1716                        macro_name: String::new(), // Will be filled in by caller
1717                        name: arg_name,
1718                        span,
1719                    }))
1720                }
1721            }
1722            arg => Err(ParserError {
1723                kind: ParserErrorKind::InvalidMacroArgs(arg),
1724                hint: Some("Expected literal, identifier, opcode, builtin function, __NOOP, or argument call".to_string()),
1725                spans: AstSpan(vec![self.current_token.span.clone()]),
1726                cursor: self.cursor,
1727            }),
1728        }
1729    }
1730
1731    /// Parse the arguments of a macro call.
1732    pub fn parse_macro_call_args(&mut self, macro_name: String) -> Result<Vec<MacroArg>, ParserError> {
1733        let mut args = vec![];
1734        self.match_kind(TokenKind::OpenParen)?;
1735        while !self.check(TokenKind::CloseParen) {
1736            match self.current_token.kind.clone() {
1737                TokenKind::HexLiteral(hex_str) => {
1738                    let lit = str_to_bytes32(&hex_str);
1739                    args.push(MacroArg::HexLiteral(lit));
1740                    self.consume();
1741                }
1742                TokenKind::Integer(n) => {
1743                    args.push(MacroArg::HexLiteral(str_to_bytes32(&format!("{n:x}"))));
1744                    self.consume();
1745                }
1746                TokenKind::Opcode(o) => {
1747                    args.push(MacroArg::Opcode(o));
1748                    self.consume();
1749                }
1750                TokenKind::Ident(ident) => {
1751                    if self.peek().unwrap().kind == TokenKind::OpenParen {
1752                        // It's a nested macro call
1753                        let mut curr_spans = vec![self.current_token.span.clone()];
1754                        self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?;
1755                        // Parse Macro Call
1756                        let lit_args = self.parse_macro_call_args(macro_name.clone())?;
1757                        // Grab all spans following our macro invocation spam
1758                        if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
1759                            curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
1760                        }
1761                        args.push(MacroArg::MacroCall(MacroInvocation {
1762                            macro_name: ident,
1763                            args: lit_args,
1764                            span: AstSpan(curr_spans.clone()),
1765                        }));
1766                    } else {
1767                        args.push(MacroArg::Ident(ident));
1768                        self.consume();
1769                    }
1770                }
1771                TokenKind::Calldata => {
1772                    args.push(MacroArg::Ident("calldata".to_string()));
1773                    self.consume();
1774                }
1775                TokenKind::Noop => {
1776                    args.push(MacroArg::Noop);
1777                    self.consume();
1778                }
1779                TokenKind::BuiltinFunction(f) => {
1780                    let mut curr_spans = vec![self.current_token.span.clone()];
1781                    self.match_kind(TokenKind::BuiltinFunction(String::default()))?;
1782                    let builtin_args = self.parse_builtin_args()?;
1783                    if let Some(i) = self.spans.iter().position(|s| s.eq(&curr_spans[0])) {
1784                        curr_spans.append(&mut self.spans[(i + 1)..].to_vec());
1785                    }
1786                    args.push(MacroArg::BuiltinFunctionCall(BuiltinFunctionCall {
1787                        kind: BuiltinFunctionKind::from(f),
1788                        args: builtin_args,
1789                        span: AstSpan(curr_spans),
1790                    }));
1791                }
1792                TokenKind::LeftAngle => {
1793                    // Passed into the Macro Call like:
1794                    // GET_SLOT_FROM_KEY(<mem_ptr>)  // [slot]
1795                    // Or invoked as a macro: MACRO2(<m>())
1796                    self.consume();
1797                    let arg_name = self.match_kind(TokenKind::Ident("ARG_CALL".to_string()))?.to_string();
1798                    let closing_angle_span = self.current_token.span.clone(); // Capture > span
1799                    self.match_kind(TokenKind::RightAngle)?;
1800
1801                    // Check if followed by parentheses for invocation
1802                    if self.check(TokenKind::OpenParen) {
1803                        let invoc_args = self.parse_macro_call_args(macro_name.clone())?;
1804                        args.push(MacroArg::ArgCallMacroInvocation(arg_name, invoc_args));
1805                    } else if self.loop_variables.contains(&arg_name) {
1806                        // Loop variables are substituted with their value when the loop is unrolled
1807                        args.push(MacroArg::Ident(format!("__LOOP_VAR_{arg_name}")));
1808                    } else {
1809                        args.push(MacroArg::ArgCall(ArgCall {
1810                            macro_name: macro_name.clone(),
1811                            name: arg_name,
1812                            span: AstSpan(vec![closing_angle_span]),
1813                        }));
1814                    }
1815                }
1816                arg => {
1817                    tracing::error!(
1818                        target: "parser",
1819                        "Invalid macro call arguments. Must be of kind Ident, Literal, Builtin Function, etc. Got: {}",
1820                        self.current_token.kind
1821                    );
1822                    let new_spans = self.spans.clone();
1823                    self.spans = vec![];
1824                    return Err(ParserError {
1825                        kind: ParserErrorKind::InvalidMacroArgs(arg),
1826                        hint: Some("Expected literal, identifier (string), builtin function, or an argument call".to_string()),
1827                        spans: AstSpan(new_spans),
1828                        cursor: self.cursor,
1829                    });
1830                }
1831            }
1832            if self.check(TokenKind::Comma) {
1833                self.consume();
1834            }
1835        }
1836        // consume close parenthesis
1837        self.consume();
1838        Ok(args)
1839    }
1840
1841    /// Parses a table (JumpTable, JumpTablePacked, or CodeTable).
1842    ///
1843    /// It should parse the following : (jumptable|jumptable__packed|table) NAME() {...}
1844    pub fn parse_table(&mut self) -> Result<TableDefinition, ParserError> {
1845        let is_code_table = self.current_token.kind == TokenKind::CodeTable;
1846        let kind = TableKind::from(self.match_kind(self.current_token.kind.clone())?);
1847        let table_name: String = self.match_kind(TokenKind::Ident("TABLE_NAME".to_string()))?.to_string();
1848
1849        // Parenthesis and assignment are optional
1850        let _ = self.match_kind(TokenKind::OpenParen);
1851        let _ = self.match_kind(TokenKind::CloseParen);
1852        let _ = self.match_kind(TokenKind::Assign);
1853
1854        // Parse the core table
1855        let table_statements: Vec<Statement> = self.parse_table_body(is_code_table)?;
1856        let size = match kind {
1857            TableKind::JumpTablePacked => Some(table_statements.len() * 0x02),
1858            TableKind::JumpTable => Some(table_statements.len() * 0x20),
1859            TableKind::CodeTable => {
1860                let mut table_size = 0;
1861                // If builtins or constants are used, we cannot determine the size of the table. This will happen during code generation.
1862                let mut unknown_size = false;
1863                for s in &table_statements {
1864                    if let StatementType::Code(c) = &s.ty {
1865                        // Calculate bytes for this hex string
1866                        // Each pair of hex digits represents 1 byte
1867                        // div_ceil rounds up for odd-length strings (e.g., "abc" = 3 chars → 2 bytes)
1868                        table_size += c.len().div_ceil(2);
1869                    } else if let StatementType::BuiltinFunctionCall(_) = &s.ty {
1870                        unknown_size = true;
1871                    } else if let StatementType::Constant(_) = &s.ty {
1872                        unknown_size = true;
1873                    } else {
1874                        return Err(ParserError {
1875                            kind: ParserErrorKind::InvalidTableStatement(format!("{}", s.ty)),
1876                            hint: Some(format!("Invalid table statement. Must be valid hex bytecode. Got: {s:?}")),
1877                            spans: AstSpan(s.span.inner_ref().to_vec()),
1878                            cursor: self.cursor,
1879                        });
1880                    }
1881                }
1882                if unknown_size { None } else { Some(table_size) }
1883            }
1884        };
1885
1886        let table_size = size.map(|s| str_to_bytes32(format!("{s:02x}").as_str()));
1887        Ok(TableDefinition::new(table_name, kind, table_statements, table_size, AstSpan(self.spans.clone())))
1888    }
1889
1890    /// Parse the body of a table.
1891    ///
1892    /// Only `LabelCall` and `Code` Statements should be authorized.
1893    pub fn parse_table_body(&mut self, is_code_table: bool) -> Result<Vec<Statement>, ParserError> {
1894        let mut statements: Vec<Statement> = Vec::new();
1895
1896        self.match_kind(TokenKind::OpenBrace)?;
1897        while !self.check(TokenKind::CloseBrace) {
1898            let new_spans = vec![self.current_token.span.clone()];
1899            match self.current_token.kind.clone() {
1900                TokenKind::Ident(ident_str) => {
1901                    if is_code_table {
1902                        tracing::error!("Invalid CodeTable Body Token: {:?}", self.current_token.kind);
1903                        return Err(ParserError {
1904                            kind: ParserErrorKind::InvalidTableBodyToken(self.current_token.kind.clone()),
1905                            hint: Some("Expected valid hex bytecode.".to_string()),
1906                            spans: AstSpan(new_spans),
1907                            cursor: self.cursor,
1908                        });
1909                    }
1910                    statements.push(Statement { ty: StatementType::LabelCall(ident_str.to_string()), span: AstSpan(new_spans) });
1911                    self.consume();
1912                }
1913                TokenKind::HexLiteral(bytes) => {
1914                    if !is_code_table {
1915                        tracing::error!("Invalid JumpTable Body Token: {:?}", self.current_token.kind);
1916                        return Err(ParserError {
1917                            kind: ParserErrorKind::InvalidTableBodyToken(self.current_token.kind.clone()),
1918                            hint: Some("Expected an identifier string.".to_string()),
1919                            spans: AstSpan(new_spans),
1920                            cursor: self.cursor,
1921                        });
1922                    }
1923                    let curr_spans = vec![self.current_token.span.clone()];
1924                    tracing::info!(target: "parser", "PARSING CODE TABLE BODY: [BYTES: {}]", hex::encode(&bytes));
1925                    self.consume();
1926                    statements.push(Statement { ty: StatementType::Code(bytes), span: AstSpan(curr_spans) });
1927                }
1928                TokenKind::BuiltinFunction(f) => {
1929                    if !is_code_table {
1930                        tracing::error!("Invalid JumpTable Body Token: {:?}", self.current_token.kind);
1931                        return Err(ParserError {
1932                            kind: ParserErrorKind::InvalidTableBodyToken(self.current_token.kind.clone()),
1933                            hint: Some("Expected an identifier string.".to_string()),
1934                            spans: AstSpan(new_spans),
1935                            cursor: self.cursor,
1936                        });
1937                    }
1938                    let mut curr_spans = vec![self.current_token.span.clone()];
1939                    self.consume();
1940                    let args = self.parse_builtin_args()?;
1941                    args.iter().for_each(|a| curr_spans.extend_from_slice(a.span().inner_ref()));
1942                    tracing::info!(target: "parser", "PARSING CODE TABLE BODY: [BUILTIN FN: {}({:?})]", f, args);
1943                    statements.push(Statement {
1944                        ty: StatementType::BuiltinFunctionCall(BuiltinFunctionCall {
1945                            kind: BuiltinFunctionKind::from(f.clone()),
1946                            args,
1947                            span: AstSpan(curr_spans.clone()),
1948                        }),
1949                        span: AstSpan(curr_spans),
1950                    });
1951                }
1952                TokenKind::OpenBracket => {
1953                    let (constant, const_span) = self.parse_constant_push()?;
1954                    tracing::info!(target: "parser", "PARSING CODE TABLE BODY: [CONSTANT: {}]", constant);
1955                    statements.push(Statement { ty: StatementType::Constant(constant), span: AstSpan(vec![const_span]) });
1956                }
1957                kind => {
1958                    tracing::error!("Invalid Table Body Token: {:?}", kind);
1959                    return Err(ParserError {
1960                        kind: ParserErrorKind::InvalidTableBodyToken(kind.clone()),
1961                        hint: Some("Expected an identifier string.".to_string()),
1962                        spans: AstSpan(new_spans),
1963                        cursor: self.cursor,
1964                    });
1965                }
1966            };
1967        }
1968        // consume close brace
1969        self.match_kind(TokenKind::CloseBrace)?;
1970        Ok(statements)
1971    }
1972
1973    /// Parses a constant push.
1974    pub fn parse_constant_push(&mut self) -> Result<(String, Span), ParserError> {
1975        // Save the opening bracket span to include it in the constant reference span
1976        let start_span = self.current_token.span.clone();
1977        self.match_kind(TokenKind::OpenBracket)?;
1978        match self.current_token.kind.clone() {
1979            TokenKind::Ident(const_str) => {
1980                // Consume the Ident and Validate Close Bracket
1981                self.consume();
1982                let end_span = self.current_token.span.clone();
1983                self.match_kind(TokenKind::CloseBracket)?;
1984                // Create a span that includes [VAL] from opening bracket to closing bracket
1985                let full_span = Span { start: start_span.start, end: end_span.end, file: start_span.file };
1986                Ok((const_str, full_span))
1987            }
1988            kind => {
1989                let new_spans = self.spans.clone();
1990                self.spans = vec![];
1991                Err(ParserError {
1992                    kind: ParserErrorKind::InvalidConstant(kind),
1993                    hint: None,
1994                    spans: AstSpan(new_spans),
1995                    cursor: self.cursor,
1996                })
1997            }
1998        }
1999    }
2000
2001    /// Parses an argument call.
2002    ///
2003    /// ## Examples
2004    ///
2005    /// When an argument is called in Huff, it is wrapped in angle brackets like so:
2006    ///
2007    /// ```huff
2008    /// #define macro EXAMPLE_FUNCTION(error) = takes (0) returns (0) {
2009    ///     <error> jumpi
2010    /// }
2011    /// ```
2012    pub fn parse_arg_call(&mut self) -> Result<(String, Span), ParserError> {
2013        // Save the opening angle bracket span to include it in the arg call span
2014        let start_span = self.current_token.span.clone();
2015        self.match_kind(TokenKind::LeftAngle)?;
2016        match self.current_token.kind.clone() {
2017            TokenKind::Ident(arg_str) => {
2018                self.consume();
2019                let end_span = self.current_token.span.clone();
2020                self.match_kind(TokenKind::RightAngle)?;
2021                // Create a span that includes <arg> from opening angle to closing angle
2022                let full_span = Span { start: start_span.start, end: end_span.end, file: start_span.file };
2023                Ok((arg_str, full_span))
2024            }
2025            kind => {
2026                let new_spans = self.spans.clone();
2027                self.spans = vec![];
2028                Err(ParserError {
2029                    kind: ParserErrorKind::InvalidArgCallIdent(kind),
2030                    hint: None,
2031                    spans: AstSpan(new_spans),
2032                    cursor: self.cursor,
2033                })
2034            }
2035        }
2036    }
2037
2038    /// Parse an arg call or arg macro invocation: `<arg>` or `<arg>(...)`
2039    /// Returns either an ArgCall or ArgMacroInvocation statement
2040    fn parse_arg_call_or_invocation(&mut self, parent_macro_name: String) -> Result<Statement, ParserError> {
2041        let (arg_call, arg_span) = self.parse_arg_call()?;
2042
2043        // Check if this is a macro invocation through argument: <arg>()
2044        if self.current_token.kind == TokenKind::OpenParen {
2045            tracing::info!(target: "parser", "PARSING ARG MACRO INVOCATION: {}()", arg_call);
2046            self.consume(); // consume '('
2047
2048            // Parse arguments for the macro invocation
2049            let mut args = Vec::new();
2050            while self.current_token.kind != TokenKind::CloseParen {
2051                // Parse each argument similar to regular macro invocation
2052                let arg = self.parse_single_macro_argument()?;
2053                // Fix up ArgCall macro_name if needed
2054                let arg = if let MacroArg::ArgCall(mut ac) = arg {
2055                    ac.macro_name = parent_macro_name.clone();
2056                    MacroArg::ArgCall(ac)
2057                } else {
2058                    arg
2059                };
2060                args.push(arg);
2061
2062                // Handle comma separation
2063                if self.current_token.kind == TokenKind::Comma {
2064                    self.consume();
2065                } else if self.current_token.kind != TokenKind::CloseParen {
2066                    return Err(ParserError {
2067                        kind: ParserErrorKind::InvalidTokenInMacroBody(self.current_token.kind.clone()),
2068                        hint: Some("Expected ',' or ')' in macro argument list".to_string()),
2069                        spans: AstSpan(vec![self.current_token.span.clone()]),
2070                        cursor: self.cursor,
2071                    });
2072                }
2073            }
2074
2075            self.match_kind(TokenKind::CloseParen)?; // consume ')'
2076
2077            Ok(Statement { ty: StatementType::ArgMacroInvocation(parent_macro_name, arg_call, args), span: AstSpan(vec![arg_span]) })
2078        } else {
2079            tracing::info!(target: "parser", "PARSING ARG CALL: {}", arg_call);
2080            Ok(Statement { ty: StatementType::ArgCall(parent_macro_name, arg_call), span: AstSpan(vec![arg_span]) })
2081        }
2082    }
2083
2084    /// Parse an arg call or arg macro invocation after `<` has already been consumed
2085    /// This is used in for loop bodies where we check for loop variables first
2086    fn parse_arg_call_or_invocation_after_angle(&mut self, parent_macro_name: String, angle_span: Span) -> Result<Statement, ParserError> {
2087        // At this point, < has been consumed, we're at the identifier
2088        match self.current_token.kind.clone() {
2089            TokenKind::Ident(arg_str) => {
2090                self.consume();
2091                let end_span = self.current_token.span.clone();
2092                self.match_kind(TokenKind::RightAngle)?;
2093                let full_span = Span { start: angle_span.start, end: end_span.end, file: angle_span.file };
2094
2095                // Check if this is a macro invocation through argument: <arg>()
2096                if self.current_token.kind == TokenKind::OpenParen {
2097                    tracing::info!(target: "parser", "PARSING ARG MACRO INVOCATION: {}()", arg_str);
2098                    self.consume(); // consume '('
2099
2100                    // Parse arguments for the macro invocation
2101                    let mut args = Vec::new();
2102                    while self.current_token.kind != TokenKind::CloseParen {
2103                        let arg = self.parse_single_macro_argument()?;
2104                        let arg = if let MacroArg::ArgCall(mut ac) = arg {
2105                            ac.macro_name = parent_macro_name.clone();
2106                            MacroArg::ArgCall(ac)
2107                        } else {
2108                            arg
2109                        };
2110                        args.push(arg);
2111
2112                        if self.current_token.kind == TokenKind::Comma {
2113                            self.consume();
2114                        } else if self.current_token.kind != TokenKind::CloseParen {
2115                            return Err(ParserError {
2116                                kind: ParserErrorKind::InvalidTokenInMacroBody(self.current_token.kind.clone()),
2117                                hint: Some("Expected ',' or ')' in macro argument list".to_string()),
2118                                spans: AstSpan(vec![self.current_token.span.clone()]),
2119                                cursor: self.cursor,
2120                            });
2121                        }
2122                    }
2123
2124                    self.match_kind(TokenKind::CloseParen)?; // consume ')'
2125                    Ok(Statement {
2126                        ty: StatementType::ArgMacroInvocation(parent_macro_name, arg_str, args),
2127                        span: AstSpan(vec![full_span]),
2128                    })
2129                } else {
2130                    tracing::info!(target: "parser", "PARSING ARG CALL: {}", arg_str);
2131                    Ok(Statement { ty: StatementType::ArgCall(parent_macro_name, arg_str), span: AstSpan(vec![full_span]) })
2132                }
2133            }
2134            kind => Err(ParserError {
2135                kind: ParserErrorKind::InvalidArgCallIdent(kind),
2136                hint: None,
2137                spans: AstSpan(vec![self.current_token.span.clone()]),
2138                cursor: self.cursor,
2139            }),
2140        }
2141    }
2142
2143    /// Parses whitespaces and newlines until none are left.
2144    pub fn parse_nl_or_whitespace(&mut self) -> Result<(), ParserError> {
2145        while self.check(TokenKind::Whitespace) {
2146            self.consume();
2147        }
2148        Ok(())
2149    }
2150
2151    /// Parses the type of an argument as its canonical ABI name, such as `uint256[]` or
2152    /// `(address,uint256)[2]`.
2153    pub fn parse_arg_type(&mut self) -> Result<String, ParserError> {
2154        match self.current_token.kind.clone() {
2155            TokenKind::PrimitiveType(prim) => Ok(self.parse_primitive_type(prim)?.to_string()),
2156            TokenKind::ArrayType(prim, _) => {
2157                // The trick is that when we parse the primitive type
2158                // of the array, it will consume the current token which is the ArrayType.
2159                // So we have to preserve the token before parsing (and matching thus consuming).
2160                let token = self.current_token.kind.clone();
2161                let _ = self.parse_primitive_type(prim);
2162                Ok(token.to_string())
2163            }
2164            TokenKind::OpenParen => {
2165                self.consume();
2166                let mut components = vec![self.parse_tuple_component()?];
2167                while self.check(TokenKind::Comma) {
2168                    self.consume();
2169                    components.push(self.parse_tuple_component()?);
2170                }
2171                self.match_kind(TokenKind::CloseParen)?;
2172                let mut tuple = format!("({})", components.join(","));
2173                // Arrays of tuples, such as `(uint256,bool)[]` or `(uint256,bool)[2]`
2174                while self.check(TokenKind::OpenBracket) {
2175                    self.consume();
2176                    let size = match self.current_token.kind {
2177                        TokenKind::Integer(size) => {
2178                            self.consume();
2179                            size.to_string()
2180                        }
2181                        _ => String::new(),
2182                    };
2183                    self.match_kind(TokenKind::CloseBracket)?;
2184                    tuple.push('[');
2185                    tuple.push_str(&size);
2186                    tuple.push(']');
2187                }
2188                Ok(tuple)
2189            }
2190            kind => Err(ParserError {
2191                kind: ParserErrorKind::InvalidArgs(kind),
2192                hint: None,
2193                spans: AstSpan(vec![self.current_token.span.clone()]),
2194                cursor: self.cursor,
2195            }),
2196        }
2197    }
2198
2199    /// Parses a component of a tuple type, whose optional name is not part of the type
2200    fn parse_tuple_component(&mut self) -> Result<String, ParserError> {
2201        let component = self.parse_arg_type()?;
2202        if matches!(self.current_token.kind, TokenKind::Ident(_)) {
2203            self.consume();
2204        }
2205        Ok(component)
2206    }
2207
2208    /// Parses a primitive EVM type.
2209    /// Arrays of primitive types are not considered as primitive types themselves.
2210    pub fn parse_primitive_type(&mut self, prim: PrimitiveEVMType) -> Result<TokenKind, ParserError> {
2211        match prim {
2212            PrimitiveEVMType::Uint(size) => {
2213                if !(8..=256).contains(&size) || size % 8 != 0 {
2214                    return Err(ParserError {
2215                        kind: ParserErrorKind::InvalidUint256(size),
2216                        hint: None,
2217                        spans: AstSpan(vec![self.current_token.span.clone()]),
2218                        cursor: self.cursor,
2219                    });
2220                }
2221                Ok(self.match_kind(self.current_token.kind.clone())?)
2222            }
2223            PrimitiveEVMType::Bytes(size) => {
2224                if !(1..=32).contains(&size) {
2225                    return Err(ParserError {
2226                        kind: ParserErrorKind::InvalidBytes(size),
2227                        hint: None,
2228                        spans: AstSpan(vec![self.current_token.span.clone()]),
2229                        cursor: self.cursor,
2230                    });
2231                }
2232                Ok(self.match_kind(self.current_token.kind.clone())?)
2233            }
2234            PrimitiveEVMType::Bool => Ok(self.match_kind(self.current_token.kind.clone())?),
2235            PrimitiveEVMType::Address => Ok(self.match_kind(self.current_token.kind.clone())?),
2236            PrimitiveEVMType::String => Ok(self.match_kind(self.current_token.kind.clone())?),
2237            PrimitiveEVMType::DynBytes => Ok(self.match_kind(self.current_token.kind.clone())?),
2238            PrimitiveEVMType::Int(size) => {
2239                if !(8..=256).contains(&size) || size % 8 != 0 {
2240                    return Err(ParserError {
2241                        kind: ParserErrorKind::InvalidInt(size),
2242                        hint: None,
2243                        spans: AstSpan(vec![self.current_token.span.clone()]),
2244                        cursor: self.cursor,
2245                    });
2246                }
2247                let curr_token_kind = self.current_token.kind.clone();
2248                self.consume();
2249                Ok(curr_token_kind)
2250            }
2251        }
2252    }
2253
2254    /// Check if the current context indicates we're parsing an expression
2255    /// (i.e., the next token is an operator)
2256    fn is_expression_context(&mut self) -> bool {
2257        if let Some(next_token) = self.peek() {
2258            matches!(next_token.kind, TokenKind::Add | TokenKind::Sub | TokenKind::Mul | TokenKind::Div | TokenKind::Mod)
2259        } else {
2260            false
2261        }
2262    }
2263
2264    /// Parse an arithmetic expression (entry point for constant expressions).
2265    ///
2266    /// Implements operator precedence:
2267    /// - Lowest: ==, !=, <, >, <=, >= (comparison)
2268    /// - Higher: + - (additive)
2269    /// - Higher: * / % (multiplicative)
2270    /// - Highest: unary -, !, literals, parentheses
2271    fn parse_constant_expression(&mut self) -> Result<Expression, ParserError> {
2272        self.parse_comparison_expression()
2273    }
2274
2275    /// Parse comparison operators (lowest precedence binary operators).
2276    fn parse_comparison_expression(&mut self) -> Result<Expression, ParserError> {
2277        let mut left = self.parse_additive_expression()?;
2278
2279        while matches!(
2280            self.current_token.kind,
2281            TokenKind::EqualEqual
2282                | TokenKind::NotEqual
2283                | TokenKind::LeftAngle
2284                | TokenKind::RightAngle
2285                | TokenKind::LessEqual
2286                | TokenKind::GreaterEqual
2287        ) {
2288            let op = match self.current_token.kind {
2289                TokenKind::EqualEqual => BinaryOp::Eq,
2290                TokenKind::NotEqual => BinaryOp::NotEq,
2291                TokenKind::LeftAngle => BinaryOp::Lt,
2292                TokenKind::RightAngle => BinaryOp::Gt,
2293                TokenKind::LessEqual => BinaryOp::LtEq,
2294                TokenKind::GreaterEqual => BinaryOp::GtEq,
2295                _ => unreachable!(),
2296            };
2297            let op_span = self.current_token.span.clone();
2298            self.consume();
2299            let right = self.parse_additive_expression()?;
2300            // Span covers from the start of left to the end of right, including the operator
2301            let mut spans = left.span().inner_ref().to_vec();
2302            spans.push(op_span);
2303            spans.extend_from_slice(right.span().inner_ref());
2304            let span = AstSpan(spans);
2305            left = Expression::Binary { left: Box::new(left), op, right: Box::new(right), span };
2306        }
2307
2308        Ok(left)
2309    }
2310
2311    /// Parse addition and subtraction.
2312    fn parse_additive_expression(&mut self) -> Result<Expression, ParserError> {
2313        let mut left = self.parse_multiplicative_expression()?;
2314
2315        while matches!(self.current_token.kind, TokenKind::Add | TokenKind::Sub) {
2316            let op = match self.current_token.kind {
2317                TokenKind::Add => BinaryOp::Add,
2318                TokenKind::Sub => BinaryOp::Sub,
2319                _ => unreachable!(),
2320            };
2321            let op_span = self.current_token.span.clone();
2322            self.consume();
2323            let right = self.parse_multiplicative_expression()?;
2324            // Span covers from the start of left to the end of right, including the operator
2325            let mut spans = left.span().inner_ref().to_vec();
2326            spans.push(op_span);
2327            spans.extend_from_slice(right.span().inner_ref());
2328            let span = AstSpan(spans);
2329            left = Expression::Binary { left: Box::new(left), op, right: Box::new(right), span };
2330        }
2331
2332        Ok(left)
2333    }
2334
2335    /// Parse multiplication, division, and modulo (higher precedence).
2336    fn parse_multiplicative_expression(&mut self) -> Result<Expression, ParserError> {
2337        let mut left = self.parse_unary_expression()?;
2338
2339        while matches!(self.current_token.kind, TokenKind::Mul | TokenKind::Div | TokenKind::Mod) {
2340            let op = match self.current_token.kind {
2341                TokenKind::Mul => BinaryOp::Mul,
2342                TokenKind::Div => BinaryOp::Div,
2343                TokenKind::Mod => BinaryOp::Mod,
2344                _ => unreachable!(),
2345            };
2346            let op_span = self.current_token.span.clone();
2347            self.consume();
2348            let right = self.parse_unary_expression()?;
2349            // Span covers from the start of left to the end of right, including the operator
2350            let mut spans = left.span().inner_ref().to_vec();
2351            spans.push(op_span);
2352            spans.extend_from_slice(right.span().inner_ref());
2353            let span = AstSpan(spans);
2354            left = Expression::Binary { left: Box::new(left), op, right: Box::new(right), span };
2355        }
2356
2357        Ok(left)
2358    }
2359
2360    /// Parse unary operators (negation and logical NOT).
2361    fn parse_unary_expression(&mut self) -> Result<Expression, ParserError> {
2362        if matches!(self.current_token.kind, TokenKind::Sub | TokenKind::Not) {
2363            let op = match self.current_token.kind {
2364                TokenKind::Sub => UnaryOp::Neg,
2365                TokenKind::Not => UnaryOp::Not,
2366                _ => unreachable!(),
2367            };
2368            let start_span = self.current_token.span.clone();
2369            self.consume();
2370            let expr = self.parse_unary_expression()?;
2371            // Span includes operator and the expression
2372            let end_span = expr.span().inner_ref().last().cloned().unwrap_or_else(|| start_span.clone());
2373            let span = AstSpan(vec![start_span, end_span]);
2374            Ok(Expression::Unary { op, expr: Box::new(expr), span })
2375        } else {
2376            self.parse_primary_expression()
2377        }
2378    }
2379
2380    /// Parse primary expressions: literals, bracketed constants, and parenthesized expressions.
2381    fn parse_primary_expression(&mut self) -> Result<Expression, ParserError> {
2382        match self.current_token.kind.clone() {
2383            TokenKind::HexLiteral(hex_str) => {
2384                // In Constant context, hex literals are lexed as Bytes instead of Literal
2385                let span = AstSpan(vec![self.current_token.span.clone()]);
2386                self.consume();
2387                Ok(Expression::Literal { value: str_to_bytes32(&hex_str), span })
2388            }
2389            TokenKind::Integer(n) => {
2390                // Handle numeric literals (used in for loops)
2391                // Convert decimal to hex string before passing to str_to_bytes32
2392                let span = AstSpan(vec![self.current_token.span.clone()]);
2393                self.consume();
2394                let value = str_to_bytes32(&format!("{:x}", n));
2395                Ok(Expression::Literal { value, span })
2396            }
2397            TokenKind::OpenParen => {
2398                let start_span = self.current_token.span.clone();
2399                self.consume();
2400                let expr = self.parse_constant_expression()?;
2401                let end_span = self.current_token.span.clone();
2402                self.match_kind(TokenKind::CloseParen)?;
2403                // Span includes opening paren to closing paren
2404                let span = AstSpan(vec![start_span, end_span]);
2405                Ok(Expression::Grouped { expr: Box::new(expr), span })
2406            }
2407            TokenKind::OpenBracket => {
2408                // Support [CONSTANT_NAME] syntax in expressions
2409                let (name, full_span) = self.parse_constant_push()?;
2410                Ok(Expression::Constant { name, span: AstSpan(vec![full_span]) })
2411            }
2412            TokenKind::LeftAngle => {
2413                // Support <arg> syntax in expressions
2414                let start_span = self.current_token.span.clone();
2415                self.consume(); // consume <
2416
2417                let arg_name = match self.current_token.kind.clone() {
2418                    TokenKind::Ident(name) => {
2419                        self.consume();
2420                        name
2421                    }
2422                    _ => {
2423                        return Err(ParserError {
2424                            kind: ParserErrorKind::InvalidExpression(self.current_token.kind.clone()),
2425                            hint: Some("Expected identifier after '<' in argument reference".to_string()),
2426                            spans: AstSpan(vec![self.current_token.span.clone()]),
2427                            cursor: self.cursor,
2428                        });
2429                    }
2430                };
2431
2432                let end_span = self.current_token.span.clone();
2433                self.match_kind(TokenKind::RightAngle)?; // consume >
2434
2435                // Create a single span covering the full <arg> including the brackets and name
2436                let span = AstSpan(vec![Span { start: start_span.start, end: end_span.end, file: start_span.file.clone() }]);
2437                // Loop variables are substituted with their value when the loop is unrolled
2438                if self.loop_variables.contains(&arg_name) {
2439                    return Ok(Expression::Constant { name: format!("__LOOP_VAR_{arg_name}"), span });
2440                }
2441                Ok(Expression::ArgCall {
2442                    macro_name: String::new(), // Will be filled in during evaluation
2443                    name: arg_name,
2444                    span,
2445                })
2446            }
2447            _ => Err(ParserError {
2448                kind: ParserErrorKind::InvalidExpression(self.current_token.kind.clone()),
2449                hint: Some("Expected literal, bracketed constant [NAME], arg call <name>, or '('".to_string()),
2450                spans: AstSpan(vec![self.current_token.span.clone()]),
2451                cursor: self.cursor,
2452            }),
2453        }
2454    }
2455}