pub mod sys_call;
#[cfg(test)]
mod test;
pub mod tree_node;

use crate::sys_call::{Math, System};
use helpers::Span;
use std::{borrow::Cow, io::SeekFrom};
use sys_call::SysCall;
use thiserror::Error;
use tokenizer::{
    self, Tokenizer, TokenizerBuffer,
    token::{Keyword, Symbol, Token, TokenType},
};
use tree_node::*;

pub trait Documentation {
    fn docs(&self) -> String;
}

#[macro_export]
/// A macro to create a boxed value.
macro_rules! boxed {
    ($e:expr) => {
        Box::new($e)
    };
}

#[derive(Error, Debug)]
pub enum Error<'a> {
    #[error(transparent)]
    Tokenizer(#[from] tokenizer::Error),

    #[error("Unexpected token: {1}")]
    UnexpectedToken(Span, Token<'a>),

    #[error("Duplicate identifier: {1}")]
    DuplicateIdentifier(Span, Token<'a>),

    #[error("Invalid Syntax: {1}")]
    InvalidSyntax(Span, String),

    #[error("Unsupported Keyword: {1}")]
    UnsupportedKeyword(Span, Token<'a>),

    #[error("Expected semicolon")]
    MissingSemicolon(Span),

    #[error("Unexpected End of File")]
    UnexpectedEOF(Option<Span>),
}

impl<'a> From<Error<'a>> for lsp_types::Diagnostic {
    fn from(value: Error) -> Self {
        use Error::*;
        use lsp_types::*;
        match value {
            Tokenizer(e) => e.into(),
            UnexpectedToken(span, _)
            | DuplicateIdentifier(span, _)
            | InvalidSyntax(span, _)
            | UnsupportedKeyword(span, _)
            | MissingSemicolon(span) => Diagnostic {
                message: value.to_string(),
                severity: Some(DiagnosticSeverity::ERROR),
                range: span.into(),
                ..Default::default()
            },
            UnexpectedEOF(span) => {
                let range = span.map(|s| s.into()).unwrap_or_default();
                Diagnostic {
                    message: value.to_string(),
                    severity: Some(DiagnosticSeverity::ERROR),
                    range,
                    ..Default::default()
                }
            }
        }
    }
}

macro_rules! self_matches_peek {
    ($self:ident, $pattern:pat) => {
        matches!($self.tokenizer.peek()?, Some(Token { token_type: $pattern, .. }))
    };
    ($self:ident, $pattern:pat if $cond:expr) => {
        matches!($self.tokenizer.peek()?, Some(Token { token_type: $pattern, .. }) if $cond)
    };
}

macro_rules! token_matches {
    ($token:ident, $pattern:pat) => {
        matches!($token.token_type, $pattern)
    };
    ($token:expr, $pattern:pat) => {
        matches!($token.token_type, $pattern)
    };
    ($token:ident, $pattern:pat if $cond:expr) => {
        matches!($token.token_type, $pattern if $cond)
    };
    ($token:expr, $pattern:pat if $cond:expr) => {
        matches!($token.token_type, $pattern if $cond)
    };
}

macro_rules! self_matches_current {
    ($self:ident, $pattern:pat) => {
        matches!($self.current_token, Some(Token { token_type: $pattern, .. }))
    };
    ($self:ident, $pattern:pat if $cond:expr) => {
        matches!($self.current_token, Some(Token { token_type: $pattern, .. }) if $cond)
    };
}

pub struct Parser<'a> {
    tokenizer: TokenizerBuffer<'a>,
    current_token: Option<Token<'a>>,
    last_token_span: Option<Span>,
    pub errors: Vec<Error<'a>>,
}

impl<'a> Parser<'a> {
    pub fn new(tokenizer: Tokenizer<'a>) -> Self {
        Parser {
            tokenizer: TokenizerBuffer::new(tokenizer),
            current_token: None,
            last_token_span: None,
            errors: Vec::new(),
        }
    }

    /// Calculates a Span from a given Token reference.
    fn token_to_span(t: &Token<'a>) -> Span {
        Span {
            start_line: t.line,
            start_col: t.span.start,
            end_line: t.line,
            end_col: t.span.end,
        }
    }

    fn current_span(&self) -> Span {
        self.current_token
            .as_ref()
            .map(Self::token_to_span)
            .unwrap_or(Span {
                start_line: 0,
                start_col: 0,
                end_line: 0,
                end_col: 0,
            })
    }

    fn unexpected_eof(&self) -> Error<'a> {
        Error::UnexpectedEOF(self.last_token_span)
    }

    /// Helper to run a parsing closure and wrap the result in a Spanned struct
    fn spanned<F, T>(&mut self, parser: F) -> Result<Spanned<T>, Error<'a>>
    where
        F: FnOnce(&mut Self) -> Result<T, Error<'a>>,
    {
        let start_token = if self.current_token.is_some() {
            self.current_token.clone()
        } else {
            self.tokenizer.peek()?
        };

        let (start_line, start_col) = start_token
            .as_ref()
            .map(|t| (t.line, t.span.start))
            .unwrap_or((0, 0));

        let node = parser(self)?;

        let end_token = &self.current_token;

        let (end_line, end_col) = end_token
            .clone()
            .map(|t| (t.line, t.span.end))
            .unwrap_or((start_line, start_col));

        Ok(Spanned {
            span: Span {
                start_line,
                start_col,
                end_line,
                end_col,
            },
            node,
        })
    }

    fn synchronize(&mut self) -> Result<(), Error<'a>> {
        self.assign_next()?;

        while let Some(token) = &self.current_token {
            if token.token_type == TokenType::Symbol(Symbol::Semicolon) {
                self.assign_next()?;
                return Ok(());
            }

            match token.token_type {
                TokenType::Keyword(Keyword::Fn)
                | TokenType::Keyword(Keyword::Let)
                | TokenType::Keyword(Keyword::If)
                | TokenType::Keyword(Keyword::While)
                | TokenType::Keyword(Keyword::Loop)
                | TokenType::Keyword(Keyword::Device)
                | TokenType::Keyword(Keyword::Return) => return Ok(()),
                _ => {}
            }

            self.assign_next()?;
        }

        Ok(())
    }

    pub fn parse_all(&mut self) -> Result<Option<tree_node::Expression<'a>>, Error<'a>> {
        let first_token = self.tokenizer.peek().unwrap_or(None);
        let (start_line, start_col) = first_token
            .as_ref()
            .map(|tok| (tok.line, tok.span.start))
            .unwrap_or((0, 0));

        let mut expressions = Vec::<Spanned<Expression<'a>>>::new();

        loop {
            match self.tokenizer.peek() {
                Ok(None) => break,
                Err(e) => {
                    self.errors.push(Error::Tokenizer(e));
                    break;
                }
                _ => {}
            }

            match self.parse() {
                Ok(Some(expression)) => {
                    expressions.push(expression);
                }
                Ok(None) => break,
                Err(e) => {
                    self.errors.push(e);
                    if self.synchronize().is_err() {
                        break;
                    }
                }
            }
        }

        let end_token_opt = self.tokenizer.peek().unwrap_or(None);
        let (end_line, end_col) = end_token_opt
            .map(|tok| (tok.line, tok.span.end))
            .unwrap_or((start_line, start_col));

        let span = Span {
            start_line,
            end_line,
            start_col,
            end_col,
        };

        Ok(Some(Expression::Block(Spanned {
            node: BlockExpression(expressions),
            span,
        })))
    }

    pub fn parse(&mut self) -> Result<Option<Spanned<tree_node::Expression<'a>>>, Error<'a>> {
        self.assign_next()?;

        if self.current_token.is_none() {
            return Ok(None);
        }

        let expr = self.expression()?;

        if self_matches_peek!(self, TokenType::Symbol(Symbol::Semicolon)) {
            self.assign_next()?;
        }

        Ok(expr)
    }

    fn assign_next(&mut self) -> Result<(), Error<'a>> {
        if let Some(token) = &self.current_token {
            self.last_token_span = Some(Self::token_to_span(token));
        }
        self.current_token = self.tokenizer.next_token()?;
        Ok(())
    }

    fn get_next(&mut self) -> Result<Option<Token<'a>>, Error<'a>> {
        self.assign_next()?;
        Ok(self.current_token.clone())
    }

    fn expression(&mut self) -> Result<Option<Spanned<tree_node::Expression<'a>>>, Error<'a>> {
        // Parse the Left Hand Side (unary/primary expression)
        let lhs = self.unary()?;

        let Some(lhs) = lhs else {
            return Ok(None);
        };

        // Handle Postfix operators (Member Access, Method Call) immediately after unary
        let lhs = self.parse_postfix(lhs)?;

        // Handle Infix operators (Binary, Logical, Assignment)
        if self_matches_peek!(
            self,
            TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || s.is_bitwise() || matches!(s, Symbol::Assign | Symbol::Question)
        ) {
            return Ok(Some(self.infix(lhs)?));
        } else if self_matches_current!(
            self,
            TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || s.is_bitwise() || matches!(s, Symbol::Assign | Symbol::Question)
        ) {
            self.tokenizer.seek(SeekFrom::Current(-1))?;
            return Ok(Some(self.infix(lhs)?));
        }

        Ok(Some(lhs))
    }

    /// Handles dot notation chains: x.y.z() and bracket notation: x[i]
    fn parse_postfix(
        &mut self,
        mut lhs: Spanned<Expression<'a>>,
    ) -> Result<Spanned<Expression<'a>>, Error<'a>> {
        loop {
            if self_matches_peek!(self, TokenType::Symbol(Symbol::Dot)) {
                self.assign_next()?; // consume Dot

                let identifier_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                let identifier_span = Self::token_to_span(&identifier_token);
                let identifier = match identifier_token.token_type {
                    TokenType::Identifier(ref id) => id.clone(),
                    _ => {
                        return Err(Error::UnexpectedToken(
                            identifier_span,
                            identifier_token.clone(),
                        ));
                    }
                };

                // Check for Method Call '()'
                if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) {
                    // Method Call
                    self.assign_next()?; // consume '('
                    let mut arguments = Vec::<Spanned<Expression<'a>>>::new();

                    while !token_matches!(
                        self.get_next()?.ok_or_else(|| self.unexpected_eof())?,
                        TokenType::Symbol(Symbol::RParen)
                    ) {
                        let expression = self.expression()?.ok_or_else(|| self.unexpected_eof())?;

                        // Block expressions not allowed in args
                        if let Expression::Block(_) = expression.node {
                            return Err(Error::InvalidSyntax(
                                self.current_span(),
                                String::from("Block expressions are not allowed in method calls"),
                            ));
                        }
                        arguments.push(expression);

                        if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
                            && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
                        {
                            let next_token =
                                self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                            return Err(Error::UnexpectedToken(
                                Self::token_to_span(&next_token),
                                next_token,
                            ));
                        }

                        if !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) {
                            self.assign_next()?;
                        }
                    }

                    // End span is the ')'
                    let end_span = self.current_span();
                    let combined_span = Span {
                        start_line: lhs.span.start_line,
                        start_col: lhs.span.start_col,
                        end_line: end_span.end_line,
                        end_col: end_span.end_col,
                    };

                    lhs = Spanned {
                        span: combined_span,
                        node: Expression::MethodCall(Spanned {
                            span: combined_span,
                            node: MethodCallExpression {
                                object: boxed!(lhs),
                                method: Spanned {
                                    span: identifier_span,
                                    node: identifier,
                                },
                                arguments,
                            },
                        }),
                    };
                } else {
                    // Member Access
                    let combined_span = Span {
                        start_line: lhs.span.start_line,
                        start_col: lhs.span.start_col,
                        end_line: identifier_span.end_line,
                        end_col: identifier_span.end_col,
                    };

                    lhs = Spanned {
                        span: combined_span,
                        node: Expression::MemberAccess(Spanned {
                            span: combined_span,
                            node: MemberAccessExpression {
                                object: boxed!(lhs),
                                member: Spanned {
                                    span: identifier_span,
                                    node: identifier,
                                },
                            },
                        }),
                    };
                }
            } else if self_matches_peek!(self, TokenType::Symbol(Symbol::LBracket)) {
                // Index Access
                self.assign_next()?; // consume '[', now current is '['
                self.assign_next()?; // advance to the expression, now current is first token of index expr
                let index = self.expression()?.ok_or_else(|| self.unexpected_eof())?;

                // After expression(), current is still on the last token of the index expression
                // We need to get the next token and verify it's ']'
                let rbracket_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                if !token_matches!(rbracket_token, TokenType::Symbol(Symbol::RBracket)) {
                    return Err(Error::UnexpectedToken(
                        Self::token_to_span(&rbracket_token),
                        rbracket_token.clone(),
                    ));
                }

                let end_span = Self::token_to_span(&rbracket_token);
                let combined_span = Span {
                    start_line: lhs.span.start_line,
                    start_col: lhs.span.start_col,
                    end_line: end_span.end_line,
                    end_col: end_span.end_col,
                };

                lhs = Spanned {
                    span: combined_span,
                    node: Expression::IndexAccess(Spanned {
                        span: combined_span,
                        node: IndexAccessExpression {
                            object: boxed!(lhs),
                            index: boxed!(index),
                        },
                    }),
                };
            } else {
                break;
            }
        }
        Ok(lhs)
    }

    fn unary(&mut self) -> Result<Option<Spanned<tree_node::Expression<'a>>>, Error<'a>> {
        macro_rules! matches_keyword {
            ($keyword:expr, $($pattern:pat),+) => {
                matches!($keyword, $($pattern)|+)
            };
        }

        let Some(current_token) = self.current_token.as_ref() else {
            return Ok(None);
        };

        if token_matches!(current_token, TokenType::EOF) {
            return Ok(None);
        }

        let expr = match current_token.token_type {
            TokenType::Keyword(e) if matches_keyword!(e, Keyword::Enum) => {
                return Err(Error::UnsupportedKeyword(
                    self.current_span(),
                    current_token.clone(),
                ));
            }

            TokenType::Keyword(Keyword::Let) => {
                if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) {
                    Some(self.spanned(|p| p.tuple_declaration())?)
                } else {
                    Some(self.spanned(|p| p.declaration())?)
                }
            }

            TokenType::Keyword(Keyword::Device) => {
                let spanned_dev = self.spanned(|p| p.device())?;
                Some(Spanned {
                    span: spanned_dev.span,
                    node: Expression::DeviceDeclaration(spanned_dev),
                })
            }

            TokenType::Keyword(Keyword::Const) => {
                let spanned_const = self.spanned(|p| p.const_declaration())?;

                Some(Spanned {
                    span: spanned_const.span,
                    node: Expression::ConstDeclaration(spanned_const),
                })
            }

            TokenType::Keyword(Keyword::Fn) => {
                let spanned_fn = self.spanned(|p| p.function())?;
                Some(Spanned {
                    span: spanned_fn.span,
                    node: Expression::Function(spanned_fn),
                })
            }

            TokenType::Keyword(Keyword::If) => {
                let spanned_if = self.spanned(|p| p.if_expression())?;
                Some(Spanned {
                    span: spanned_if.span,
                    node: Expression::If(spanned_if),
                })
            }

            TokenType::Keyword(Keyword::Loop) => {
                let spanned_loop = self.spanned(|p| p.loop_expression())?;
                Some(Spanned {
                    span: spanned_loop.span,
                    node: Expression::Loop(spanned_loop),
                })
            }

            TokenType::Keyword(Keyword::While) => {
                let spanned_while = self.spanned(|p| p.while_expression())?;
                Some(Spanned {
                    span: spanned_while.span,
                    node: Expression::While(spanned_while),
                })
            }

            TokenType::Keyword(Keyword::Break) => {
                let span = self.current_span();
                let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) {
                    return Err(Error::MissingSemicolon(span));
                }
                Some(Spanned {
                    span,
                    node: Expression::Break(span),
                })
            }

            TokenType::Keyword(Keyword::Continue) => {
                let span = self.current_span();
                let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) {
                    return Err(Error::MissingSemicolon(span));
                }
                Some(Spanned {
                    span,
                    node: Expression::Continue(span),
                })
            }

            TokenType::Identifier(ref id) if SysCall::is_syscall(id) => {
                let spanned_call = self.spanned(|p| p.syscall())?;
                Some(Spanned {
                    span: spanned_call.span,
                    node: Expression::Syscall(spanned_call),
                })
            }

            TokenType::Identifier(_)
                if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) =>
            {
                let spanned_invoke = self.spanned(|p| p.invocation())?;
                Some(Spanned {
                    span: spanned_invoke.span,
                    node: Expression::Invocation(spanned_invoke),
                })
            }

            TokenType::Identifier(ref id) => {
                let span = self.current_span();
                Some(Spanned {
                    span,
                    node: Expression::Variable(Spanned {
                        span,
                        node: id.clone(),
                    }),
                })
            }

            TokenType::Symbol(Symbol::LBrace) => {
                let spanned_block = self.spanned(|p| p.block())?;
                Some(Spanned {
                    span: spanned_block.span,
                    node: Expression::Block(spanned_block),
                })
            }

            TokenType::Number(_) | TokenType::String(_) | TokenType::Boolean(_) => {
                let spanned_lit = self.spanned(|p| p.literal())?;
                Some(Spanned {
                    span: spanned_lit.span,
                    node: Expression::Literal(spanned_lit),
                })
            }

            TokenType::Symbol(Symbol::LParen) => self.parenthesized_or_tuple()?,

            TokenType::Symbol(Symbol::Minus) => {
                let start_span = self.current_span();
                self.assign_next()?;
                let inner_expr = self.unary()?.ok_or_else(|| self.unexpected_eof())?;

                let inner_with_postfix = self.parse_postfix(inner_expr)?;

                let combined_span = Span {
                    start_line: start_span.start_line,
                    start_col: start_span.start_col,
                    end_line: inner_with_postfix.span.end_line,
                    end_col: inner_with_postfix.span.end_col,
                };
                Some(Spanned {
                    span: combined_span,
                    node: Expression::Negation(boxed!(inner_with_postfix)),
                })
            }

            TokenType::Symbol(Symbol::LogicalNot) => {
                let start_span = self.current_span();
                self.assign_next()?;
                let inner_expr = self.unary()?.ok_or_else(|| self.unexpected_eof())?;
                let inner_with_postfix = self.parse_postfix(inner_expr)?;
                let combined_span = Span {
                    start_line: start_span.start_line,
                    start_col: start_span.start_col,
                    end_line: inner_with_postfix.span.end_line,
                    end_col: inner_with_postfix.span.end_col,
                };
                Some(Spanned {
                    span: combined_span,
                    node: Expression::Logical(Spanned {
                        span: combined_span,
                        node: LogicalExpression::Not(boxed!(inner_with_postfix)),
                    }),
                })
            }

            TokenType::Symbol(Symbol::BitwiseNot) => {
                let start_span = self.current_span();
                self.assign_next()?;
                let inner_expr = self.unary()?.ok_or_else(|| self.unexpected_eof())?;
                let inner_with_postfix = self.parse_postfix(inner_expr)?;
                let combined_span = Span {
                    start_line: start_span.start_line,
                    start_col: start_span.start_col,
                    end_line: inner_with_postfix.span.end_line,
                    end_col: inner_with_postfix.span.end_col,
                };
                Some(Spanned {
                    span: combined_span,
                    node: Expression::BitwiseNot(boxed!(inner_with_postfix)),
                })
            }

            _ => {
                return Err(Error::UnexpectedToken(
                    self.current_span(),
                    current_token.clone(),
                ));
            }
        };

        Ok(expr)
    }

    fn get_infix_child_node(&mut self) -> Result<Spanned<tree_node::Expression<'a>>, Error<'a>> {
        let current_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;

        let start_span = self.current_span();

        let expr = match current_token.token_type {
            TokenType::Number(_) | TokenType::Boolean(_) => {
                let lit = self.spanned(|p| p.literal())?;
                Spanned {
                    span: lit.span,
                    node: Expression::Literal(lit),
                }
            }
            TokenType::Identifier(ref ident)
                if !self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) =>
            {
                // This is a Variable. We need to check for Postfix operations on it.
                let span = self.current_span();
                Spanned {
                    span,
                    node: Expression::Variable(Spanned {
                        span,
                        node: ident.clone(),
                    }),
                }
            }
            TokenType::Symbol(Symbol::LParen) => *self
                .parenthesized_or_tuple()?
                .map(Box::new)
                .ok_or_else(|| self.unexpected_eof())?,

            TokenType::Identifier(ref id) if SysCall::is_syscall(id) => {
                let spanned_call = self.spanned(|p| p.syscall())?;

                Spanned {
                    span: spanned_call.span,
                    node: Expression::Syscall(spanned_call),
                }
            }

            TokenType::Identifier(_)
                if self_matches_peek!(self, TokenType::Symbol(Symbol::LParen)) =>
            {
                let inv = self.spanned(|p| p.invocation())?;
                Spanned {
                    span: inv.span,
                    node: Expression::Invocation(inv),
                }
            }
            TokenType::Symbol(Symbol::Minus) => {
                self.assign_next()?;
                let inner = self.get_infix_child_node()?;
                let span = Span {
                    start_line: start_span.start_line,
                    start_col: start_span.start_col,
                    end_line: inner.span.end_line,
                    end_col: inner.span.end_col,
                };
                Spanned {
                    span,
                    node: Expression::Negation(boxed!(inner)),
                }
            }
            TokenType::Symbol(Symbol::LogicalNot) => {
                self.assign_next()?;
                let inner = self.get_infix_child_node()?;
                let span = Span {
                    start_line: start_span.start_line,
                    start_col: start_span.start_col,
                    end_line: inner.span.end_line,
                    end_col: inner.span.end_col,
                };
                Spanned {
                    span,
                    node: Expression::Logical(Spanned {
                        span,
                        node: LogicalExpression::Not(boxed!(inner)),
                    }),
                }
            }
            TokenType::Symbol(Symbol::BitwiseNot) => {
                self.assign_next()?;
                let inner = self.get_infix_child_node()?;
                let span = Span {
                    start_line: start_span.start_line,
                    start_col: start_span.start_col,
                    end_line: inner.span.end_line,
                    end_col: inner.span.end_col,
                };
                Spanned {
                    span,
                    node: Expression::BitwiseNot(boxed!(inner)),
                }
            }
            _ => {
                return Err(Error::UnexpectedToken(
                    self.current_span(),
                    current_token.clone(),
                ));
            }
        };

        // Important: We must check for postfix operations here too
        // e.g. a + b.c
        self.parse_postfix(expr)
    }

    fn device(&mut self) -> Result<DeviceDeclarationExpression<'a>, Error<'a>> {
        let current_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;
        if !self_matches_current!(self, TokenType::Keyword(Keyword::Device)) {
            return Err(Error::UnexpectedToken(
                self.current_span(),
                current_token.clone(),
            ));
        }

        let identifier_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        let identifier_span = Self::token_to_span(&identifier_token);
        let identifier = match identifier_token.token_type {
            TokenType::Identifier(ref id) => id.clone(),
            _ => {
                return Err(Error::UnexpectedToken(
                    Self::token_to_span(&identifier_token),
                    identifier_token.clone(),
                ));
            }
        };

        let current_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) {
            return Err(Error::UnexpectedToken(
                Self::token_to_span(&current_token),
                current_token.clone(),
            ));
        }

        let device_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        let device = match device_token.token_type {
            TokenType::String(ref id) => id.clone(),
            _ => {
                return Err(Error::UnexpectedToken(
                    Self::token_to_span(&device_token),
                    device_token.clone(),
                ));
            }
        };

        Ok(DeviceDeclarationExpression {
            name: Spanned {
                span: identifier_span,
                node: identifier,
            },
            device,
        })
    }

    fn infix(
        &mut self,
        previous: Spanned<Expression<'a>>,
    ) -> Result<Spanned<Expression<'a>>, Error<'a>> {
        let current_token = self
            .get_next()?
            .ok_or_else(|| self.unexpected_eof())?
            .clone();

        match previous.node {
            Expression::Binary(_)
            | Expression::Logical(_)
            | Expression::Invocation(_)
            | Expression::Syscall(_)
            | Expression::Priority(_)
            | Expression::Literal(_)
            | Expression::Variable(_)
            | Expression::Ternary(_)
            | Expression::Negation(_)
            | Expression::BitwiseNot(_)
            | Expression::MemberAccess(_)
            | Expression::MethodCall(_)
            | Expression::IndexAccess(_)
            | Expression::Tuple(_) => {}
            _ => {
                return Err(Error::InvalidSyntax(
                    self.current_span(),
                    String::from("Invalid expression for binary/logical operation"),
                ));
            }
        }

        let mut expressions = vec![previous];
        let mut operators = Vec::<Symbol>::new();

        let mut temp_token = current_token.clone();

        // Include Assign in the operator loop
        while token_matches!(
            temp_token,
            TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || s.is_bitwise() || matches!(s, Symbol::Assign | Symbol::Question | Symbol::Colon)
        ) {
            let operator = match temp_token.token_type {
                TokenType::Symbol(s) => s,
                _ => unreachable!(),
            };
            operators.push(operator);
            self.assign_next()?;
            expressions.push(self.get_infix_child_node()?);

            temp_token = self
                .get_next()?
                .ok_or_else(|| self.unexpected_eof())?
                .clone();
        }

        if operators.len() != expressions.len() - 1 {
            return Err(Error::InvalidSyntax(
                self.current_span(),
                String::from("Invalid number of operators"),
            ));
        }

        // --- PRECEDENCE LEVEL 1: Exponent (**) ---
        for (i, operator) in operators.iter().enumerate().rev() {
            if operator == &Symbol::Exp {
                let right = expressions.remove(i + 1);
                let left = expressions.remove(i);
                let span = Span {
                    start_line: left.span.start_line,
                    start_col: left.span.start_col,
                    end_line: right.span.end_line,
                    end_col: right.span.end_col,
                };
                expressions.insert(
                    i,
                    Spanned {
                        span,
                        node: Expression::Binary(Spanned {
                            span,
                            node: BinaryExpression::Exponent(boxed!(left), boxed!(right)),
                        }),
                    },
                );
            }
        }
        operators.retain(|symbol| symbol != &Symbol::Exp);

        // Common macro for binary ops
        macro_rules! process_binary_ops {
            ($ops:pat, $variant:ident) => {
                let mut current_iteration = 0;
                for (i, operator) in operators.iter().enumerate() {
                    if matches!(operator, $ops) {
                        let index = i - current_iteration;
                        let left = expressions.remove(index);
                        let right = expressions.remove(index);
                        let span = Span {
                            start_line: left.span.start_line,
                            start_col: left.span.start_col,
                            end_line: right.span.end_line,
                            end_col: right.span.end_col,
                        };

                        let node = match operator {
                            Symbol::Asterisk => {
                                BinaryExpression::Multiply(boxed!(left), boxed!(right))
                            }
                            Symbol::Slash => BinaryExpression::Divide(boxed!(left), boxed!(right)),
                            Symbol::Percent => {
                                BinaryExpression::Modulo(boxed!(left), boxed!(right))
                            }
                            Symbol::Plus => BinaryExpression::Add(boxed!(left), boxed!(right)),
                            Symbol::Minus => {
                                BinaryExpression::Subtract(boxed!(left), boxed!(right))
                            }
                            Symbol::LeftShift => {
                                BinaryExpression::LeftShift(boxed!(left), boxed!(right))
                            }
                            Symbol::RightShiftArithmetic => {
                                BinaryExpression::RightShiftArithmetic(boxed!(left), boxed!(right))
                            }
                            Symbol::RightShiftLogical => {
                                BinaryExpression::RightShiftLogical(boxed!(left), boxed!(right))
                            }
                            Symbol::BitwiseAnd => {
                                BinaryExpression::BitwiseAnd(boxed!(left), boxed!(right))
                            }
                            Symbol::BitwiseOr => {
                                BinaryExpression::BitwiseOr(boxed!(left), boxed!(right))
                            }
                            Symbol::Caret => {
                                BinaryExpression::BitwiseXor(boxed!(left), boxed!(right))
                            }
                            _ => unreachable!(),
                        };

                        expressions.insert(
                            index,
                            Spanned {
                                span,
                                node: Expression::Binary(Spanned { span, node }),
                            },
                        );
                        current_iteration += 1;
                    }
                }
                operators.retain(|symbol| !matches!(symbol, $ops));
            };
        }

        // --- PRECEDENCE LEVEL 2: Multiplicative (*, /, %) ---
        process_binary_ops!(
            Symbol::Slash | Symbol::Asterisk | Symbol::Percent,
            BinaryExpression
        );

        // --- PRECEDENCE LEVEL 3: Additive (+, -) ---
        process_binary_ops!(Symbol::Plus | Symbol::Minus, BinaryExpression);

        // --- PRECEDENCE LEVEL 4: Shift Operations (<<, >>, >>>) ---
        process_binary_ops!(
            Symbol::LeftShift | Symbol::RightShiftArithmetic | Symbol::RightShiftLogical,
            BinaryExpression
        );

        // --- PRECEDENCE LEVEL 5: Bitwise AND (&) ---
        process_binary_ops!(Symbol::BitwiseAnd, BinaryExpression);

        // --- PRECEDENCE LEVEL 6: Bitwise XOR (^) ---
        process_binary_ops!(Symbol::Caret, BinaryExpression);

        // --- PRECEDENCE LEVEL 7: Bitwise OR (|) ---
        process_binary_ops!(Symbol::BitwiseOr, BinaryExpression);

        // --- PRECEDENCE LEVEL 8: Comparison (<, >, <=, >=) ---
        let mut current_iteration = 0;
        for (i, operator) in operators.iter().enumerate() {
            if operator.is_comparison() && !matches!(operator, Symbol::Equal | Symbol::NotEqual) {
                let index = i - current_iteration;
                let left = expressions.remove(index);
                let right = expressions.remove(index);
                let span = Span {
                    start_line: left.span.start_line,
                    start_col: left.span.start_col,
                    end_line: right.span.end_line,
                    end_col: right.span.end_col,
                };

                let node = match operator {
                    Symbol::LessThan => LogicalExpression::LessThan(boxed!(left), boxed!(right)),
                    Symbol::GreaterThan => {
                        LogicalExpression::GreaterThan(boxed!(left), boxed!(right))
                    }
                    Symbol::LessThanOrEqual => {
                        LogicalExpression::LessThanOrEqual(boxed!(left), boxed!(right))
                    }
                    Symbol::GreaterThanOrEqual => {
                        LogicalExpression::GreaterThanOrEqual(boxed!(left), boxed!(right))
                    }
                    _ => unreachable!(),
                };

                expressions.insert(
                    index,
                    Spanned {
                        span,
                        node: Expression::Logical(Spanned { span, node }),
                    },
                );
                current_iteration += 1;
            }
        }
        operators.retain(|symbol| {
            !symbol.is_comparison() || matches!(symbol, Symbol::Equal | Symbol::NotEqual)
        });

        // --- PRECEDENCE LEVEL 5: Equality (==, !=) ---
        current_iteration = 0;
        for (i, operator) in operators.iter().enumerate() {
            if matches!(operator, Symbol::Equal | Symbol::NotEqual) {
                let index = i - current_iteration;
                let left = expressions.remove(index);
                let right = expressions.remove(index);
                let span = Span {
                    start_line: left.span.start_line,
                    start_col: left.span.start_col,
                    end_line: right.span.end_line,
                    end_col: right.span.end_col,
                };

                let node = match operator {
                    Symbol::Equal => LogicalExpression::Equal(boxed!(left), boxed!(right)),
                    Symbol::NotEqual => LogicalExpression::NotEqual(boxed!(left), boxed!(right)),
                    _ => unreachable!(),
                };

                expressions.insert(
                    index,
                    Spanned {
                        span,
                        node: Expression::Logical(Spanned { span, node }),
                    },
                );
                current_iteration += 1;
            }
        }
        operators.retain(|symbol| !matches!(symbol, Symbol::Equal | Symbol::NotEqual));

        // --- PRECEDENCE LEVEL 6: Logical AND (&&) ---
        current_iteration = 0;
        for (i, operator) in operators.iter().enumerate() {
            if matches!(operator, Symbol::LogicalAnd) {
                let index = i - current_iteration;
                let left = expressions.remove(index);
                let right = expressions.remove(index);
                let span = Span {
                    start_line: left.span.start_line,
                    start_col: left.span.start_col,
                    end_line: right.span.end_line,
                    end_col: right.span.end_col,
                };

                expressions.insert(
                    index,
                    Spanned {
                        span,
                        node: Expression::Logical(Spanned {
                            span,
                            node: LogicalExpression::And(boxed!(left), boxed!(right)),
                        }),
                    },
                );
                current_iteration += 1;
            }
        }
        operators.retain(|symbol| !matches!(symbol, Symbol::LogicalAnd));

        // --- PRECEDENCE LEVEL 7: Logical OR (||) ---
        current_iteration = 0;
        for (i, operator) in operators.iter().enumerate() {
            if matches!(operator, Symbol::LogicalOr) {
                let index = i - current_iteration;
                let left = expressions.remove(index);
                let right = expressions.remove(index);
                let span = Span {
                    start_line: left.span.start_line,
                    start_col: left.span.start_col,
                    end_line: right.span.end_line,
                    end_col: right.span.end_col,
                };

                expressions.insert(
                    index,
                    Spanned {
                        span,
                        node: Expression::Logical(Spanned {
                            span,
                            node: LogicalExpression::Or(boxed!(left), boxed!(right)),
                        }),
                    },
                );
                current_iteration += 1;
            }
        }
        operators.retain(|symbol| !matches!(symbol, Symbol::LogicalOr));

        // -- PRECEDENCE LEVEL 8: Ternary (x ? 1 : 2)
        for i in (0..operators.len()).rev() {
            if matches!(operators[i], Symbol::Question) {
                // Ensure next operator is a colon
                if i + 1 >= operators.len() || !matches!(operators[i + 1], Symbol::Colon) {
                    return Err(Error::InvalidSyntax(
                        self.current_span(),
                        "Ternary operator '?' missing matching ':'".to_string(),
                    ));
                }

                let false_branch = expressions.remove(i + 2);
                let true_branch = expressions.remove(i + 1);
                let condition = expressions.remove(i);

                let span = Span {
                    start_line: condition.span.start_line,
                    end_line: false_branch.span.end_line,
                    start_col: condition.span.start_col,
                    end_col: false_branch.span.end_col,
                };

                let ternary_node = Spanned {
                    span,
                    node: TernaryExpression {
                        condition: Box::new(condition),
                        true_value: Box::new(true_branch),
                        false_value: Box::new(false_branch),
                    },
                };

                expressions.insert(
                    i,
                    Spanned {
                        node: Expression::Ternary(ternary_node),
                        span,
                    },
                );

                // Remove the `?` and the `:` from the operators list
                operators.remove(i);
                operators.remove(i);
            }
        }

        // --- PRECEDENCE LEVEL 9: Assignment (=) ---
        // Assignment is Right Associative: a = b = c => a = (b = c)
        // We iterate Right to Left
        for (i, operator) in operators.iter().enumerate().rev() {
            if matches!(operator, Symbol::Assign) {
                let right = expressions.remove(i + 1);
                let left = expressions.remove(i);
                let span = Span {
                    start_line: left.span.start_line,
                    start_col: left.span.start_col,
                    end_line: right.span.end_line,
                    end_col: right.span.end_col,
                };

                // Check if the left side is a tuple, and if so, create a TupleAssignment
                let node = if let Expression::Tuple(tuple_expr) = &left.node {
                    // Extract variable names from the tuple, handling underscores
                    let mut names = Vec::new();
                    for item in &tuple_expr.node {
                        if let Expression::Variable(var) = &item.node {
                            names.push(var.clone());
                        } else {
                            return Err(Error::InvalidSyntax(
                                item.span,
                                String::from("Tuple assignment can only contain variable names"),
                            ));
                        }
                    }

                    Expression::TupleAssignment(Spanned {
                        span,
                        node: TupleAssignmentExpression {
                            names,
                            value: boxed!(right),
                        },
                    })
                } else {
                    Expression::Assignment(Spanned {
                        span,
                        node: AssignmentExpression {
                            assignee: boxed!(left),
                            expression: boxed!(right),
                        },
                    })
                };

                expressions.insert(i, Spanned { span, node });
            }
        }
        operators.retain(|symbol| !matches!(symbol, Symbol::Assign));

        if expressions.len() != 1 || !operators.is_empty() {
            return Err(Error::InvalidSyntax(
                self.current_span(),
                String::from("Invalid number of operators"),
            ));
        }

        if token_matches!(
            temp_token,
            TokenType::Symbol(Symbol::Semicolon)
                | TokenType::Symbol(Symbol::RParen)
                | TokenType::Symbol(Symbol::Comma)
        ) {
            self.tokenizer.seek(SeekFrom::Current(-1))?;
        }

        expressions.pop().ok_or_else(|| self.unexpected_eof())
    }

    fn parenthesized_or_tuple(
        &mut self,
    ) -> Result<Option<Spanned<tree_node::Expression<'a>>>, Error<'a>> {
        let start_span = self.current_span();
        let current_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;

        if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) {
            return Err(Error::UnexpectedToken(
                self.current_span(),
                current_token.clone(),
            ));
        }

        self.assign_next()?;

        // Handle empty tuple '()'
        if self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) {
            self.assign_next()?;
            let end_span = self.current_span();
            let span = Span {
                start_line: start_span.start_line,
                start_col: start_span.start_col,
                end_line: end_span.end_line,
                end_col: end_span.end_col,
            };
            return Ok(Some(Spanned {
                span,
                node: Expression::Tuple(Spanned { span, node: vec![] }),
            }));
        }

        let first_expression = self.expression()?.ok_or_else(|| self.unexpected_eof())?;

        if self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) {
            // It is a tuple
            let mut items = vec![first_expression];
            while self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) {
                // Next toekn is a comma, we need to consume it and advance 1 more time.
                self.assign_next()?;
                self.assign_next()?;
                items.push(self.expression()?.ok_or_else(|| self.unexpected_eof())?);
            }

            let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
            if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) {
                return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
            }

            let end_span = Self::token_to_span(&next);
            let span = Span {
                start_line: start_span.start_line,
                start_col: start_span.start_col,
                end_line: end_span.end_line,
                end_col: end_span.end_col,
            };

            Ok(Some(Spanned {
                span,
                node: Expression::Tuple(Spanned { span, node: items }),
            }))
        } else {
            // It is just priority
            let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
            if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) {
                return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
            }

            Ok(Some(Spanned {
                span: first_expression.span,
                node: Expression::Priority(boxed!(first_expression)),
            }))
        }
    }

    fn tuple_declaration(&mut self) -> Result<Expression<'a>, Error<'a>> {
        // 'let' is consumed before this call
        // expect '('
        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::LParen)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }

        let mut names = Vec::new();
        while !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) {
            let token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
            let span = Self::token_to_span(&token);
            if let TokenType::Identifier(id) = token.token_type {
                names.push(Spanned { span, node: id });
            } else {
                return Err(Error::UnexpectedToken(span, token));
            }

            if self_matches_peek!(self, TokenType::Symbol(Symbol::Comma)) {
                self.assign_next()?;
            }
        }
        self.assign_next()?; // consume ')'

        let assign = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;

        if !token_matches!(assign, TokenType::Symbol(Symbol::Assign)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&assign), assign));
        }

        self.assign_next()?; // Consume the `=`

        let value = self.expression()?.ok_or_else(|| self.unexpected_eof())?;
        let value_span = value.span;

        let semi = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(semi, TokenType::Symbol(Symbol::Semicolon)) {
            return Err(Error::MissingSemicolon(value_span));
        }

        Ok(Expression::TupleDeclaration(Spanned {
            span: names.first().map(|n| n.span).unwrap_or(value.span),
            node: TupleDeclarationExpression {
                names,
                value: boxed!(value),
            },
        }))
    }

    fn invocation(&mut self) -> Result<InvocationExpression<'a>, Error<'a>> {
        let identifier_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;
        let identifier_span = Self::token_to_span(identifier_token);
        let identifier = match identifier_token.token_type {
            TokenType::Identifier(ref id) => id.clone(),
            _ => {
                return Err(Error::UnexpectedToken(
                    self.current_span(),
                    self.current_token
                        .clone()
                        .ok_or_else(|| self.unexpected_eof())?,
                ));
            }
        };

        let current_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) {
            return Err(Error::UnexpectedToken(
                Self::token_to_span(&current_token),
                current_token,
            ));
        }

        let mut arguments = Vec::<Spanned<Expression>>::new();

        while !token_matches!(
            self.get_next()?.ok_or_else(|| self.unexpected_eof())?,
            TokenType::Symbol(Symbol::RParen)
        ) {
            let expression = self.expression()?.ok_or_else(|| self.unexpected_eof())?;

            if let Expression::Block(_) = expression.node {
                return Err(Error::InvalidSyntax(
                    self.current_span(),
                    String::from("Block expressions are not allowed in function invocations"),
                ));
            }

            arguments.push(expression);

            if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
                && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
            {
                let next_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                return Err(Error::UnexpectedToken(
                    Self::token_to_span(&next_token),
                    next_token,
                ));
            }

            if !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) {
                self.assign_next()?;
            }
        }

        Ok(InvocationExpression {
            name: Spanned {
                span: identifier_span,
                node: identifier,
            },
            arguments,
        })
    }

    fn block(&mut self) -> Result<BlockExpression<'a>, Error<'a>> {
        let mut expressions = Vec::<Spanned<Expression>>::new();
        let current_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;

        if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) {
            return Err(Error::UnexpectedToken(
                self.current_span(),
                current_token.clone(),
            ));
        }

        while !self_matches_peek!(
            self,
            TokenType::Symbol(Symbol::RBrace) | TokenType::Keyword(Keyword::Return)
        ) {
            let expression = self.parse()?.ok_or_else(|| self.unexpected_eof())?;
            expressions.push(expression);
        }

        let current_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;

        if token_matches!(current_token, TokenType::Keyword(Keyword::Return)) {
            // Need to capture return span
            let ret_start_span = Self::token_to_span(&current_token);
            self.assign_next()?;

            let expr = if token_matches!(
                self.current_token
                    .as_ref()
                    .ok_or_else(|| self.unexpected_eof())?,
                TokenType::Symbol(Symbol::Semicolon)
            ) {
                // rewind 1 token so we can check for the semicolon at the bottom of this function.
                self.tokenizer.seek(SeekFrom::Current(-1))?;
                None
            } else {
                Some(self.expression()?.ok_or_else(|| self.unexpected_eof())?)
            };

            let ret_span = Span {
                start_line: ret_start_span.start_line,
                start_col: ret_start_span.start_col,
                end_line: expr
                    .as_ref()
                    .map(|e| e.span.end_line)
                    .unwrap_or(ret_start_span.end_line),
                end_col: expr
                    .as_ref()
                    .map(|e| e.span.end_col)
                    .unwrap_or(ret_start_span.end_col),
            };

            let return_expr = Spanned {
                span: ret_span,
                node: Expression::Return(expr.map(Box::new)),
            };
            expressions.push(return_expr);

            let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
            if !token_matches!(next, TokenType::Symbol(Symbol::Semicolon)) {
                return Err(Error::MissingSemicolon(ret_span));
            }

            let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
            if !token_matches!(next, TokenType::Symbol(Symbol::RBrace)) {
                return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
            }
        }

        Ok(BlockExpression(expressions))
    }

    fn const_declaration(&mut self) -> Result<ConstDeclarationExpression<'a>, Error<'a>> {
        // const
        let current_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;
        if !self_matches_current!(self, TokenType::Keyword(Keyword::Const)) {
            return Err(Error::UnexpectedToken(
                self.current_span(),
                current_token.clone(),
            ));
        }

        // variable_name
        let ident_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        let ident_span = Self::token_to_span(&ident_token);
        let ident = match ident_token.token_type {
            TokenType::Identifier(ref id) => id.clone(),
            _ => return Err(Error::UnexpectedToken(ident_span, ident_token.clone())),
        };

        // `=`
        let assign_token = self
            .get_next()?
            .ok_or_else(|| self.unexpected_eof())?
            .clone();
        if !token_matches!(assign_token, TokenType::Symbol(Symbol::Assign)) {
            return Err(Error::UnexpectedToken(
                Self::token_to_span(&assign_token),
                assign_token,
            ));
        }

        // literal or syscall, making sure the syscall is supported in hash
        self.assign_next()?;
        // cache the current token location
        let current_token_index = self.tokenizer.loc();

        if let Ok(lit) = self.spanned(|p| p.literal()) {
            Ok(ConstDeclarationExpression {
                name: Spanned {
                    span: ident_span,
                    node: ident,
                },
                value: LiteralOr::Literal(lit),
            })
        } else {
            // we need to rewind our tokenizer to our previous location
            self.tokenizer.seek(SeekFrom::Current(
                current_token_index - self.tokenizer.loc(),
            ))?;
            let syscall = self.spanned(|p| p.syscall())?;

            if !matches!(
                syscall,
                Spanned {
                    node: SysCall::System(sys_call::System::Hash(_)),
                    ..
                }
            ) {
                return Err(Error::UnexpectedToken(
                    syscall.span,
                    self.current_token
                        .clone()
                        .ok_or_else(|| self.unexpected_eof())?,
                ));
            }

            Ok(ConstDeclarationExpression {
                name: Spanned {
                    span: ident_span,
                    node: ident,
                },
                value: LiteralOr::Or(syscall),
            })
        }
    }

    fn declaration(&mut self) -> Result<Expression<'a>, Error<'a>> {
        let current_token = self
            .current_token
            .as_ref()
            .ok_or_else(|| self.unexpected_eof())?;
        if !self_matches_current!(self, TokenType::Keyword(Keyword::Let)) {
            return Err(Error::UnexpectedToken(
                self.current_span(),
                current_token.clone(),
            ));
        }
        let identifier_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        let identifier_span = Self::token_to_span(&identifier_token);
        let identifier = match identifier_token.token_type {
            TokenType::Identifier(ref id) => id.clone(),
            _ => {
                return Err(Error::UnexpectedToken(
                    Self::token_to_span(&identifier_token),
                    identifier_token,
                ));
            }
        };

        let current_token = self
            .get_next()?
            .ok_or_else(|| self.unexpected_eof())?
            .clone();

        if !token_matches!(current_token, TokenType::Symbol(Symbol::Assign)) {
            return Err(Error::UnexpectedToken(
                Self::token_to_span(&current_token),
                current_token.clone(),
            ));
        }

        self.assign_next()?;
        let assignment_expression = self.expression()?.ok_or_else(|| self.unexpected_eof())?;
        let expr_span = assignment_expression.span;

        let current_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(current_token, TokenType::Symbol(Symbol::Semicolon)) {
            return Err(Error::MissingSemicolon(expr_span));
        }

        Ok(Expression::Declaration(
            Spanned {
                span: identifier_span,
                node: identifier,
            },
            boxed!(assignment_expression),
        ))
    }

    fn literal(&mut self) -> Result<Literal<'a>, Error<'a>> {
        let current_token = self
            .current_token
            .clone()
            .ok_or_else(|| self.unexpected_eof())?;
        let literal = match current_token.token_type {
            TokenType::Number(num) => Literal::Number(num),
            TokenType::String(ref string) => Literal::String(string.clone()),
            TokenType::Boolean(boolean) => Literal::Boolean(boolean),
            TokenType::Symbol(Symbol::Minus) => match self.get_next()? {
                Some(Token {
                    token_type: TokenType::Number(num),
                    ..
                }) => Literal::Number(-num),
                Some(wrong_token) => {
                    return Err(Error::UnexpectedToken(
                        Self::token_to_span(&wrong_token),
                        wrong_token,
                    ));
                }
                None => return Err(self.unexpected_eof()),
            },
            _ => {
                return Err(Error::UnexpectedToken(
                    self.current_span(),
                    current_token.clone(),
                ));
            }
        };

        Ok(literal)
    }

    fn if_expression(&mut self) -> Result<IfExpression<'a>, Error<'a>> {
        // 'if' is current
        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::LParen)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }
        self.assign_next()?;

        let condition = self.expression()?.ok_or_else(|| self.unexpected_eof())?;

        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }

        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::LBrace)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }

        let body = self.spanned(|p| p.block())?;

        let else_branch = if self_matches_peek!(self, TokenType::Keyword(Keyword::Else)) {
            self.assign_next()?;

            if self_matches_peek!(self, TokenType::Keyword(Keyword::If)) {
                self.assign_next()?;
                // Recurse for else if
                let if_expr = self.spanned(|p| p.if_expression())?;
                Some(boxed!(Spanned {
                    span: if_expr.span,
                    node: Expression::If(if_expr),
                }))
            } else if self_matches_peek!(self, TokenType::Symbol(Symbol::LBrace)) {
                self.assign_next()?;
                let block = self.spanned(|p| p.block())?;
                Some(boxed!(Spanned {
                    span: block.span,
                    node: Expression::Block(block),
                }))
            } else {
                let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
            }
        } else {
            None
        };

        Ok(IfExpression {
            condition: boxed!(condition),
            body,
            else_branch,
        })
    }

    fn loop_expression(&mut self) -> Result<LoopExpression<'a>, Error<'a>> {
        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::LBrace)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }

        let body = self.spanned(|p| p.block())?;

        Ok(LoopExpression { body })
    }

    fn while_expression(&mut self) -> Result<WhileExpression<'a>, Error<'a>> {
        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::LParen)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }
        self.assign_next()?;

        let condition = self.expression()?.ok_or_else(|| self.unexpected_eof())?;

        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::RParen)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }

        let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(next, TokenType::Symbol(Symbol::LBrace)) {
            return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
        }

        let body = self.block()?;

        Ok(WhileExpression {
            condition: boxed!(condition),
            body,
        })
    }

    fn function(&mut self) -> Result<FunctionExpression<'a>, Error<'a>> {
        // 'fn' is current
        let fn_ident_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        let fn_ident_span = Self::token_to_span(&fn_ident_token);
        let fn_ident = match fn_ident_token.token_type {
            TokenType::Identifier(ref id) => id.clone(),
            _ => {
                return Err(Error::UnexpectedToken(fn_ident_span, fn_ident_token));
            }
        };

        let current_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(current_token, TokenType::Symbol(Symbol::LParen)) {
            return Err(Error::UnexpectedToken(
                Self::token_to_span(&current_token),
                current_token,
            ));
        }

        let mut arguments = Vec::<Spanned<Cow<'a, str>>>::new();

        while !token_matches!(
            self.get_next()?.ok_or_else(|| self.unexpected_eof())?,
            TokenType::Symbol(Symbol::RParen)
        ) {
            let current_token = self
                .current_token
                .as_ref()
                .ok_or_else(|| self.unexpected_eof())?;
            let arg_span = Self::token_to_span(current_token);
            let argument = match current_token.token_type {
                TokenType::Identifier(ref id) => id.clone(),
                _ => {
                    return Err(Error::UnexpectedToken(arg_span, current_token.clone()));
                }
            };

            let spanned_arg = Spanned {
                span: arg_span,
                node: argument,
            };

            if arguments.contains(&spanned_arg) {
                return Err(Error::DuplicateIdentifier(
                    Self::token_to_span(current_token),
                    current_token.clone(),
                ));
            }

            arguments.push(spanned_arg);

            if !self_matches_peek!(self, TokenType::Symbol(Symbol::Comma))
                && !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen))
            {
                let next = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
                return Err(Error::UnexpectedToken(Self::token_to_span(&next), next));
            }

            if !self_matches_peek!(self, TokenType::Symbol(Symbol::RParen)) {
                self.assign_next()?;
            }
        }

        let current_token = self.get_next()?.ok_or_else(|| self.unexpected_eof())?;
        if !token_matches!(current_token, TokenType::Symbol(Symbol::LBrace)) {
            return Err(Error::UnexpectedToken(
                Self::token_to_span(&current_token),
                current_token,
            ));
        };

        Ok(FunctionExpression {
            name: Spanned {
                span: fn_ident_span,
                node: fn_ident,
            },
            arguments,
            body: self.block()?,
        })
    }

    fn syscall(&mut self) -> Result<SysCall<'a>, Error<'a>> {
        let invocation = self.invocation()?;

        let check_length = |len: usize| -> Result<(), Error> {
            if invocation.arguments.len() != len {
                return Err(Error::InvalidSyntax(
                    self.current_span(),
                    format!("Expected {} arguments", len),
                ));
            }
            Ok(())
        };

        macro_rules! args {
            ($count:expr) => {{
                check_length($count)?;
                invocation.arguments.into_iter()
            }};
        }

        macro_rules! literal_or_variable {
            ($iter:expr) => {
                match &$iter {
                    Some(expr) => {
                        let span = expr.span;
                        match &expr.node {
                            Expression::Literal(literal) => Spanned {
                                span,
                                node: LiteralOrVariable::Literal(literal.node.clone()),
                            },
                            Expression::Variable(ident) => Spanned {
                                span,
                                node: LiteralOrVariable::Variable(ident.clone()),
                            },
                            _ => {
                                return Err(Error::InvalidSyntax(
                                    expr.span,
                                    "Expected a literal or variable".to_string(),
                                ));
                            }
                        }
                    }
                    _ => {
                        return Err(Error::UnexpectedToken(
                            self.current_span(),
                            self.current_token
                                .clone()
                                .ok_or_else(|| self.unexpected_eof())?,
                        ))
                    }
                }
            };
        }

        macro_rules! get_arg {
            ($matcher: ident, $arg: expr) => {
                match $arg.node {
                    LiteralOrVariable::$matcher(i) => Spanned {
                        node: i,
                        span: $arg.span,
                    },
                    _ => {
                        return Err(Error::InvalidSyntax(
                            $arg.span,
                            format!("Expected a {}", stringify!($matcher).to_lowercase()),
                        ))
                    }
                }
            };
        }

        match invocation.name.node.as_ref() {
            // System SysCalls
            "yield" => {
                check_length(0)?;
                Ok(SysCall::System(sys_call::System::Yield))
            }
            "sleep" => {
                let mut args = args!(1);
                let expr = args.next().ok_or_else(|| self.unexpected_eof())?;
                Ok(SysCall::System(System::Sleep(boxed!(expr))))
            }
            "clr" => {
                let mut args = args!(1);
                let expr = args.next().ok_or_else(|| self.unexpected_eof())?;
                Ok(SysCall::System(System::Clr(boxed!(expr))))
            }
            "hash" => {
                let mut args = args!(1);
                let lit_str = literal_or_variable!(args.next());

                let Spanned {
                    node: LiteralOrVariable::Literal(lit_str),
                    span,
                } = lit_str
                else {
                    return Err(Error::InvalidSyntax(
                        lit_str.span,
                        "Expected a string literal".to_string(),
                    ));
                };

                Ok(SysCall::System(System::Hash(Spanned {
                    node: lit_str,
                    span,
                })))
            }
            "load" | "l" => {
                let mut args = args!(2);

                let tmp = args.next();
                let device = literal_or_variable!(tmp);
                let next_arg = args.next();

                let variable = match next_arg {
                    Some(expr) => match expr.node {
                        Expression::Literal(spanned_lit) => match spanned_lit.node {
                            Literal::String(s) => Spanned {
                                node: s,
                                span: spanned_lit.span,
                            },
                            _ => {
                                return Err(Error::InvalidSyntax(
                                    spanned_lit.span,
                                    "Expected a string literal".to_string(),
                                ));
                            }
                        },
                        _ => {
                            return Err(Error::InvalidSyntax(
                                expr.span,
                                "Expected a string literal".to_string(),
                            ));
                        }
                    },
                    _ => {
                        return Err(Error::UnexpectedToken(
                            self.current_span(),
                            self.current_token
                                .clone()
                                .ok_or_else(|| self.unexpected_eof())?,
                        ));
                    }
                };

                Ok(SysCall::System(sys_call::System::LoadFromDevice(
                    device,
                    Spanned {
                        node: Literal::String(variable.node),
                        span: variable.span,
                    },
                )))
            }
            "loadBatched" | "lb" => {
                let mut args = args!(3);
                let tmp = args.next();
                let device_hash = literal_or_variable!(tmp);

                let tmp = args.next();
                let logic_type = get_arg!(Literal, literal_or_variable!(tmp));

                let tmp = args.next();
                let batch_mode = get_arg!(Literal, literal_or_variable!(tmp));

                Ok(SysCall::System(System::LoadBatch(
                    device_hash,
                    logic_type,
                    batch_mode,
                )))
            }
            "loadBatchedNamed" | "lbn" => {
                let mut args = args!(4);
                let tmp = args.next();
                let dev_hash = literal_or_variable!(tmp);

                let tmp = args.next();
                let name_hash = literal_or_variable!(tmp);

                let tmp = args.next();
                let logic_type = get_arg!(Literal, literal_or_variable!(tmp));

                let tmp = args.next();
                let batch_mode = get_arg!(Literal, literal_or_variable!(tmp));

                Ok(SysCall::System(System::LoadBatchNamed(
                    dev_hash, name_hash, logic_type, batch_mode,
                )))
            }
            "set" | "s" => {
                let mut args = args!(3);
                let tmp = args.next();
                let device = literal_or_variable!(tmp);

                let tmp = args.next();
                let logic_type = get_arg!(Literal, literal_or_variable!(tmp));

                let variable = args.next().ok_or_else(|| self.unexpected_eof())?;
                Ok(SysCall::System(sys_call::System::SetOnDevice(
                    device,
                    Spanned {
                        node: Literal::String(Cow::from(
                            logic_type.node.to_string().replace("\"", ""),
                        )),
                        span: logic_type.span,
                    },
                    boxed!(variable),
                )))
            }
            "setBatched" | "sb" => {
                let mut args = args!(3);
                let tmp = args.next();
                let device_hash = literal_or_variable!(tmp);

                let tmp = args.next();
                let logic_type = get_arg!(Literal, literal_or_variable!(tmp));
                let variable = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::System(sys_call::System::SetOnDeviceBatched(
                    device_hash,
                    Spanned {
                        node: Literal::String(Cow::from(logic_type.to_string().replace("\"", ""))),
                        span: logic_type.span,
                    },
                    boxed!(variable),
                )))
            }
            "setBatchedNamed" | "sbn" => {
                let mut args = args!(4);
                let tmp = args.next();
                let device_hash = literal_or_variable!(tmp);

                let tmp = args.next();
                let name_hash = literal_or_variable!(tmp);

                let tmp = args.next();
                let logic_type = get_arg!(Literal, literal_or_variable!(tmp));

                let tmp = args.next();
                let expr = Box::new(tmp.ok_or_else(|| self.unexpected_eof())?);

                Ok(SysCall::System(System::SetOnDeviceBatchedNamed(
                    device_hash,
                    name_hash,
                    logic_type,
                    expr,
                )))
            }
            "loadSlot" | "ls" => {
                let mut args = args!(3);
                let next = args.next();
                let dev_name = literal_or_variable!(next);
                let slot_index = args.next().ok_or_else(|| self.unexpected_eof())?;

                let next = args.next();
                let slot_logic = get_arg!(Literal, literal_or_variable!(next));
                if !matches!(
                    slot_logic,
                    Spanned {
                        node: Literal::String(_),
                        ..
                    }
                ) {
                    return Err(Error::InvalidSyntax(
                        slot_logic.span,
                        "Expected a String".into(),
                    ));
                }

                Ok(SysCall::System(System::LoadSlot(
                    dev_name,
                    boxed!(slot_index),
                    slot_logic,
                )))
            }
            "setSlot" | "ss" => {
                let mut args = args!(4);
                let next = args.next();
                let dev_name = literal_or_variable!(next);
                let slot_index = args.next().ok_or_else(|| self.unexpected_eof())?;

                let next = args.next();
                let slot_logic = get_arg!(Literal, literal_or_variable!(next));
                if !matches!(
                    slot_logic,
                    Spanned {
                        node: Literal::String(_),
                        ..
                    }
                ) {
                    return Err(Error::InvalidSyntax(
                        slot_logic.span,
                        "Expected a string".into(),
                    ));
                }
                let next = args.next();
                let expr = next.ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::System(System::SetSlot(
                    dev_name,
                    boxed!(slot_index),
                    slot_logic,
                    boxed!(expr),
                )))
            }
            "loadReagent" | "lr" => {
                let mut args = args!(3);
                let next = args.next();
                let device = literal_or_variable!(next);
                let next = args.next();
                let reagent_mode = get_arg!(Literal, literal_or_variable!(next));
                let reagent_hash = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::System(System::LoadReagent(
                    device,
                    reagent_mode,
                    Box::new(reagent_hash),
                )))
            }
            "rmap" => {
                let mut args = args!(2);
                let next = args.next();
                let device = literal_or_variable!(next);
                let reagent_hash = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::System(System::Rmap(
                    device,
                    Box::new(reagent_hash),
                )))
            }

            // Math SysCalls
            "acos" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let tmp = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Acos(boxed!(tmp))))
            }
            "asin" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let tmp = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Asin(boxed!(tmp))))
            }
            "atan" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let expr = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Atan(boxed!(expr))))
            }
            "atan2" => {
                check_length(2)?;
                let mut args = invocation.arguments.into_iter();
                let arg1 = args.next().ok_or_else(|| self.unexpected_eof())?;
                let arg2 = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Atan2(boxed!(arg1), boxed!(arg2))))
            }
            "abs" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let expr = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Abs(boxed!(expr))))
            }
            "ceil" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Ceil(boxed!(arg))))
            }
            "cos" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Cos(boxed!(arg))))
            }
            "floor" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Floor(boxed!(arg))))
            }
            "log" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Log(boxed!(arg))))
            }
            "max" => {
                check_length(2)?;
                let mut args = invocation.arguments.into_iter();
                let arg1 = args.next().ok_or_else(|| self.unexpected_eof())?;
                let arg2 = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Max(boxed!(arg1), boxed!(arg2))))
            }
            "min" => {
                check_length(2)?;
                let mut args = invocation.arguments.into_iter();
                let arg1 = args.next().ok_or_else(|| self.unexpected_eof())?;
                let arg2 = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Min(boxed!(arg1), boxed!(arg2))))
            }
            "rand" => {
                check_length(0)?;
                Ok(SysCall::Math(Math::Rand))
            }
            "sin" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Sin(boxed!(arg))))
            }
            "sqrt" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Sqrt(boxed!(arg))))
            }
            "tan" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Tan(boxed!(arg))))
            }
            "trunc" => {
                check_length(1)?;
                let mut args = invocation.arguments.into_iter();
                let arg = args.next().ok_or_else(|| self.unexpected_eof())?;

                Ok(SysCall::Math(Math::Trunc(boxed!(arg))))
            }
            _ => Err(Error::UnsupportedKeyword(
                self.current_span(),
                self.current_token
                    .clone()
                    .ok_or_else(|| self.unexpected_eof())?,
            )),
        }
    }
}
