use super::ast::*;
use crate::compiler::lexer::{Lexer, Token, TokenType};

pub struct Parser {
    pub lexer: Lexer,
    current: Option<Token>,
    peek_token: Option<Token>,

    saved_pos: usize,
    saved_line: u32,
    saved_col: u32,
    allow_in: bool,
}

impl Parser {
    pub fn new(source: &str) -> Self {
        let mut lexer = Lexer::new(source);
        let current = lexer.next_token();
        let saved_pos = lexer.pos;
        let saved_line = lexer.line;
        let saved_col = lexer.column;
        let peek_token = lexer.next_token();
        Parser {
            lexer,
            current,
            peek_token,
            saved_pos,
            saved_line,
            saved_col,
            allow_in: true,
        }
    }

    fn advance(&mut self) -> Option<Token> {
        let cur = self.current.take();
        if let Some(ref t) = cur {
            self.saved_line = t.line;
            self.saved_col = t.column;
        }
        self.current = self.peek_token.take();
        self.saved_pos = self.lexer.pos;
        self.peek_token = self.lexer.next_token();
        cur
    }

    fn expect(&mut self, value: &str) -> Result<Token, String> {
        match &self.current {
            Some(t) if t.value == value => {
                let tok = t.clone();
                self.advance();
                Ok(tok)
            }
            Some(t) => Err(self.error(&format!(
                "Expected '{}', but got '{}' at pos {}",
                value,
                t.value,
                self.lexer.pos()
            ))),
            None => Err(self.error(&format!("Expected '{}', but got EOF", value))),
        }
    }

    fn expect_semicolon(&mut self) -> Result<(), String> {
        if let Some(ref t) = self.current {
            if t.value == ";" {
                self.advance();
            }
        }
        Ok(())
    }

    fn at(&self, value: &str) -> bool {
        self.current.as_ref().map_or(false, |t| t.value == value)
    }

    fn at_keyword(&self, kw: &str) -> bool {
        self.current.as_ref().map_or(false, |t| {
            t.token_type == TokenType::Keyword && t.value == kw
        })
    }

    fn at_punct(&self, p: &str) -> bool {
        self.current.as_ref().map_or(false, |t| {
            t.token_type == TokenType::Punctuator && t.value == p
        })
    }

    fn at_template_start(&self) -> bool {
        self.current.as_ref().map_or(false, |t| {
            matches!(
                t.token_type,
                TokenType::NoSubstitutionTemplate | TokenType::TemplateHead
            )
        })
    }

    fn peek_at(&self, value: &str) -> bool {
        self.peek_token.as_ref().map_or(false, |t| t.value == value)
    }

    fn peek_value(&self) -> Option<&str> {
        self.peek_token.as_ref().map(|t| t.value.as_str())
    }

    fn cur_value(&self) -> &str {
        self.current
            .as_ref()
            .map(|t| t.value.as_str())
            .unwrap_or("")
    }

    fn cur_type(&self) -> Option<TokenType> {
        self.current.as_ref().map(|t| t.token_type)
    }

    fn is_eof(&self) -> bool {
        self.current.is_none()
    }

    fn error(&self, msg: &str) -> String {
        let line = self.current.as_ref().map(|t| t.line).unwrap_or(0);
        let col = self.current.as_ref().map(|t| t.column).unwrap_or(0);
        format!("Parse error ({}:{}): {}", line, col, msg)
    }
}

impl Parser {
    pub fn parse(&mut self) -> Result<Program, String> {
        if let Some(ref t) = self.current {
            if t.token_type == TokenType::Hashbang {
                self.advance();
            }
        }

        let mut body = Vec::new();
        let mut lines = Vec::new();
        while !self.is_eof() {
            let line = self.current.as_ref().map(|t| t.line).unwrap_or(0);
            body.push(self.parse_statement_list_item()?);
            lines.push(line);
        }

        Ok(Program {
            body,
            lines,
            source_type: SourceType::Script,
        })
    }

    fn parse_statement_list_item(&mut self) -> Result<ASTNode, String> {
        if self.at_keyword("import") && !self.peek_at("(") {
            return self
                .parse_import_declaration()
                .map(ASTNode::ImportDeclaration);
        }
        if self.at_keyword("export") {
            return self.parse_export_declaration();
        }
        self.parse_statement()
    }

    fn parse_statement(&mut self) -> Result<ASTNode, String> {
        if self.is_eof() {
            return Ok(ASTNode::EmptyStatement);
        }

        let tok = self.current.clone();

        match tok.as_ref().map(|t| (t.token_type, t.value.as_str())) {
            Some((TokenType::Punctuator, "{")) => self.parse_block_statement(),
            Some((TokenType::Punctuator, ";")) => {
                self.advance();
                Ok(ASTNode::EmptyStatement)
            }
            Some((TokenType::Keyword, "var")) => self.parse_variable_declaration(),
            Some((TokenType::Keyword, "let")) => {
                let is_decl = self.peek_at("[")
                    || self.peek_at("{")
                    || self.peek_token.as_ref().map_or(false, |t| {
                        matches!(t.token_type, TokenType::Identifier)
                            || (matches!(t.token_type, TokenType::Keyword) && t.value != "in")
                    });
                if is_decl {
                    self.parse_variable_declaration()
                } else {
                    self.parse_expression_statement_or_labelled()
                }
            }
            Some((TokenType::Keyword, "const")) => self.parse_variable_declaration(),
            Some((TokenType::Keyword, "function")) => {
                self.advance();
                let generator = self.at_punct("*");
                if generator {
                    self.advance();
                }
                self.parse_function_declaration(false, generator)
            }
            Some((TokenType::Keyword, "async")) => {
                self.advance();
                self.expect("function")?;
                let generator = self.at_punct("*");
                if generator {
                    self.advance();
                }
                self.parse_function_declaration(true, generator)
            }
            Some((TokenType::Keyword, "class")) => self.parse_class_declaration(),
            Some((TokenType::Keyword, "if")) => self.parse_if_statement(),
            Some((TokenType::Keyword, "for")) => self.parse_for_statement(),
            Some((TokenType::Keyword, "while")) => self.parse_while_statement(),
            Some((TokenType::Keyword, "do")) => self.parse_do_while_statement(),
            Some((TokenType::Keyword, "switch")) => self.parse_switch_statement(),
            Some((TokenType::Keyword, "try")) => self.parse_try_statement(),
            Some((TokenType::Keyword, "with")) => self.parse_with_statement(),
            Some((TokenType::Keyword, "return")) => self.parse_return_statement(),
            Some((TokenType::Keyword, "throw")) => self.parse_throw_statement(),
            Some((TokenType::Keyword, "break")) => self.parse_break_statement(),
            Some((TokenType::Keyword, "continue")) => self.parse_continue_statement(),
            Some((TokenType::Keyword, "debugger")) => {
                self.advance();
                self.expect_semicolon()?;
                Ok(ASTNode::DebuggerStatement)
            }
            Some((TokenType::Keyword, "import")) if self.peek_at("(") => {
                self.parse_expression_statement()
            }
            _ => self.parse_expression_statement_or_labelled(),
        }
    }

    fn parse_block_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("{")?;
        let (body, lines) = self.parse_statement_list_with_lines()?;
        self.expect("}")?;
        Ok(ASTNode::BlockStatement(BlockStatement { body, lines }))
    }

    fn parse_statement_list_with_lines(&mut self) -> Result<(Vec<ASTNode>, Vec<u32>), String> {
        let mut stmts = Vec::new();
        let mut lines = Vec::new();
        while !self.is_eof() && !self.at_punct("}") {
            let line = self.current.as_ref().map(|t| t.line).unwrap_or(0);
            stmts.push(self.parse_statement()?);
            lines.push(line);
        }
        Ok((stmts, lines))
    }

    fn parse_variable_declaration(&mut self) -> Result<ASTNode, String> {
        let kind = match self.cur_value() {
            "var" => VariableKind::Var,
            "let" => VariableKind::Let,
            "const" => VariableKind::Const,
            _ => return Err(self.error("Expected var/let/const")),
        };
        self.advance();

        let mut declarations = Vec::new();
        loop {
            let id = self.parse_binding_pattern()?;
            let init = if self.at_punct("=") {
                self.advance();
                Some(self.parse_assignment_expression()?)
            } else {
                None
            };
            declarations.push(VariableDeclarator { id, init });
            if self.at_punct(",") {
                self.advance();
            } else {
                break;
            }
        }

        if !self.at_punct(")") && !self.is_eof() {
            self.expect_semicolon()?;
        }

        Ok(ASTNode::VariableDeclaration(VariableDeclaration {
            kind,
            declarations,
        }))
    }

    fn parse_binding_pattern(&mut self) -> Result<BindingPattern, String> {
        if self.at_punct("[") {
            self.advance();
            let mut elements = Vec::new();
            while !self.at_punct("]") && !self.is_eof() {
                if self.at_punct(",") {
                    elements.push(None);
                    self.advance();
                    continue;
                }
                let rest = if self.at_punct("...") {
                    self.advance();
                    let arg = self.parse_binding_pattern()?;
                    Some(Box::new(match arg {
                        BindingPattern::Identifier(name) => AssignmentTarget::Identifier(name),
                        other => AssignmentTarget::ArrayPattern(match other {
                            BindingPattern::ArrayPattern(p) => p,
                            BindingPattern::ObjectPattern(_) => {
                                return Err(self.error("rest element must be array/identifier"));
                            }
                            BindingPattern::AssignmentPattern(_) => {
                                return Err(self.error("rest element cannot be assignment pattern"));
                            }
                            BindingPattern::Identifier(_) => unreachable!(),
                        }),
                    }))
                } else {
                    None
                };
                if let Some(arg) = rest {
                    if self.at_punct(",") {
                        self.advance();
                    }
                    elements.push(Some(PatternElement::RestElement(RestElement {
                        argument: arg,
                    })));
                    continue;
                }
                let pattern = self.parse_binding_pattern()?;
                let elem = if self.at_punct("=") {
                    self.advance();
                    let right = self.parse_assignment_expression()?;
                    PatternElement::AssignmentPattern(AssignmentPattern {
                        left: Box::new(binding_to_target(pattern.clone())),
                        right: Box::new(right),
                    })
                } else {
                    PatternElement::Pattern(binding_to_target(pattern))
                };
                elements.push(Some(elem));
                if self.at_punct(",") {
                    self.advance();
                }
            }
            self.expect("]")?;
            return Ok(BindingPattern::ArrayPattern(ArrayPattern { elements }));
        }

        if self.at_punct("{") {
            self.advance();
            let mut properties = Vec::new();
            while !self.at_punct("}") && !self.is_eof() {
                if self.at_punct("...") {
                    self.advance();
                    let arg = self.parse_binding_pattern()?;
                    properties.push(ObjectPatternProperty::RestElement(RestElement {
                        argument: Box::new(binding_to_target(arg)),
                    }));
                    if self.at_punct(",") {
                        self.advance();
                    }
                    continue;
                }
                let (key, computed, shorthand) = self.parse_property_key()?;
                let value = if self.at_punct(":") {
                    self.advance();
                    binding_to_target(self.parse_binding_pattern()?)
                } else if shorthand
                    || (self.at_punct("=") && matches!(key, PropertyKey::Identifier(_)))
                {
                    match &key {
                        PropertyKey::Identifier(name) => AssignmentTarget::Identifier(name.clone()),
                        _ => return Err(self.error("invalid shorthand pattern")),
                    }
                } else {
                    return Err(self.error("expected ':' in object pattern"));
                };

                let value = if self.at_punct("=") {
                    self.advance();
                    let right = self.parse_assignment_expression()?;
                    AssignmentTarget::AssignmentPattern(AssignmentPattern {
                        left: Box::new(value),
                        right: Box::new(right),
                    })
                } else {
                    value
                };
                properties.push(ObjectPatternProperty::Property {
                    key,
                    value,
                    computed,
                    shorthand,
                });
                if self.at_punct(",") {
                    self.advance();
                }
            }
            self.expect("}")?;
            return Ok(BindingPattern::ObjectPattern(ObjectPattern { properties }));
        }

        let name = self.cur_value().to_string();
        if !self.is_identifier_name() {
            return Err(self.error("expected identifier"));
        }
        self.advance();
        Ok(BindingPattern::Identifier(name))
    }

    fn is_identifier_name(&self) -> bool {
        matches!(
            self.cur_type(),
            Some(TokenType::Identifier) | Some(TokenType::Keyword)
        ) && !matches!(self.cur_value(), "true" | "false" | "null")
    }

    fn parse_function_declaration(
        &mut self,
        is_async: bool,
        generator: bool,
    ) -> Result<ASTNode, String> {
        let name = match self.cur_type() {
            Some(TokenType::Identifier) | Some(TokenType::Keyword) => {
                let n = self.cur_value().to_string();
                self.advance();
                n
            }
            _ => return Err(self.error("expected function name")),
        };
        self.expect("(")?;
        let params = self.parse_parameter_list()?;
        self.expect(")")?;
        let body = self.parse_block_body()?;
        Ok(ASTNode::FunctionDeclaration(FunctionDeclaration {
            name,
            params,
            body,
            generator,
            is_async,
        }))
    }

    fn parse_function_expression(
        &mut self,
        is_async: bool,
        generator: bool,
    ) -> Result<Expression, String> {
        let name = if matches!(
            self.cur_type(),
            Some(TokenType::Identifier) | Some(TokenType::Keyword)
        ) && !self.at_punct("(")
        {
            let n = self.cur_value().to_string();
            self.advance();
            Some(n)
        } else {
            None
        };
        self.expect("(")?;
        let params = self.parse_parameter_list()?;
        self.expect(")")?;
        let body = self.parse_block_body()?;
        Ok(Expression::FunctionExpression(FunctionExpression {
            name,
            params,
            body,
            generator,
            is_async,
        }))
    }

    fn parse_parameter_list(&mut self) -> Result<Vec<Parameter>, String> {
        let mut params = Vec::new();
        while !self.at_punct(")") && !self.is_eof() {
            if self.at_punct("...") {
                self.advance();
                let arg = self.parse_binding_pattern()?;
                params.push(Parameter::RestElement(RestElement {
                    argument: Box::new(binding_to_target(arg)),
                }));
                break;
            }
            let pattern = self.parse_binding_pattern()?;
            if self.at_punct("=") {
                self.advance();
                let right = self.parse_assignment_expression()?;
                params.push(Parameter::AssignmentPattern(AssignmentPattern {
                    left: Box::new(binding_to_target(pattern)),
                    right: Box::new(right),
                }));
            } else {
                match pattern {
                    BindingPattern::Identifier(name) => params.push(Parameter::Identifier(name)),
                    other => params.push(Parameter::Pattern(other)),
                }
            }
            if self.at_punct(",") {
                self.advance();
            }
        }
        Ok(params)
    }

    fn parse_expression_no_in(&mut self) -> Result<Expression, String> {
        let prev_allow_in = self.allow_in;
        self.allow_in = false;
        let result = self.parse_expression();
        self.allow_in = prev_allow_in;
        result
    }

    fn parse_assignment_expression_no_in(&mut self) -> Result<Expression, String> {
        let prev_allow_in = self.allow_in;
        self.allow_in = false;
        let result = self.parse_assignment_expression();
        self.allow_in = prev_allow_in;
        result
    }

    fn parse_block_body(&mut self) -> Result<BlockStatement, String> {
        self.expect("{")?;
        let (body, lines) = self.parse_statement_list_with_lines()?;
        self.expect("}")?;
        Ok(BlockStatement { body, lines })
    }

    fn parse_class_declaration(&mut self) -> Result<ASTNode, String> {
        self.expect("class")?;
        let name = self.cur_value().to_string();
        self.advance();
        let super_class = if self.at_keyword("extends") {
            self.advance();
            Some(Box::new(self.parse_assignment_expression()?))
        } else {
            None
        };
        self.expect("{")?;
        let body = self.parse_class_body()?;
        self.expect("}")?;
        Ok(ASTNode::ClassDeclaration(ClassDeclaration {
            name,
            super_class,
            body,
        }))
    }

    fn parse_class_expression(&mut self) -> Result<Expression, String> {
        self.expect("class")?;
        let name = if self.is_identifier_name() && !self.at_keyword("extends") {
            let n = self.cur_value().to_string();
            self.advance();
            Some(n)
        } else {
            None
        };
        let super_class = if self.at_keyword("extends") {
            self.advance();
            Some(Box::new(self.parse_assignment_expression()?))
        } else {
            None
        };
        self.expect("{")?;
        let body = self.parse_class_body()?;
        self.expect("}")?;
        Ok(Expression::ClassExpression(ClassExpression {
            name,
            super_class,
            body,
        }))
    }

    fn parse_class_body(&mut self) -> Result<ClassBody, String> {
        let mut elements = Vec::new();
        while !self.at_punct("}") && !self.is_eof() {
            if self.at_punct(";") {
                self.advance();
                continue;
            }

            let is_static = if self.at_keyword("static") {
                self.advance();
                true
            } else {
                false
            };

            if is_static && self.at_punct("{") {
                self.expect("{")?;
                let (body, lines) = self.parse_statement_list_with_lines()?;
                self.expect("}")?;
                elements.push(ClassElement::StaticBlock(StaticBlock { body, lines }));
                continue;
            }

            let mut is_async = false;
            if self.at_keyword("async")
                && !self.peek_at(";")
                && !self.peek_at("=")
                && !self.peek_at("}")
            {
                self.advance();
                is_async = true;
            }

            let mut is_generator = false;
            if self.at_punct("*") {
                self.advance();
                is_generator = true;
            }

            let method_kind = if self.at_keyword("get") && !self.peek_at("(") && !self.peek_at(",")
            {
                self.advance();
                MethodKind::Get
            } else if self.at_keyword("set") && !self.peek_at("(") && !self.peek_at(",") {
                self.advance();
                MethodKind::Set
            } else if is_static && self.at_keyword("constructor") {
                MethodKind::Constructor
            } else {
                MethodKind::Method
            };

            let is_private = self.cur_type() == Some(TokenType::PrivateIdentifier);
            let (name, _computed, _shorthand) = self.parse_property_key()?;

            if self.at_punct("=") {
                self.advance();
                let value = Some(self.parse_assignment_expression()?);
                elements.push(ClassElement::Property(ClassProperty {
                    name,
                    value,
                    is_static,
                    is_private,
                }));
                if self.at_punct(";") {
                    self.advance();
                }
                continue;
            }

            if self.at_punct(";") {
                self.advance();
                elements.push(ClassElement::Property(ClassProperty {
                    name,
                    value: None,
                    is_static,
                    is_private,
                }));
                continue;
            }

            if !self.at_punct("(") {
                elements.push(ClassElement::Property(ClassProperty {
                    name,
                    value: None,
                    is_static,
                    is_private,
                }));
                continue;
            }

            self.expect("(")?;
            let params = self.parse_parameter_list()?;
            self.expect(")")?;
            let body = self.parse_block_body()?;

            let is_constructor_name =
                matches!(&name, PropertyKey::Identifier(n) if n == "constructor");
            let actual_kind = if !is_static && is_constructor_name {
                MethodKind::Constructor
            } else {
                method_kind
            };

            elements.push(ClassElement::Method(ClassMethod {
                name,
                params,
                body,
                kind: actual_kind,
                is_async,
                generator: is_generator,
                is_static,
                is_private,
            }));
        }
        Ok(ClassBody { elements })
    }

    fn parse_if_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("if")?;
        self.expect("(")?;
        let test = self.parse_expression()?;
        self.expect(")")?;
        let consequent = self.parse_statement()?;
        let alternate = if self.at_keyword("else") {
            self.advance();
            Some(Box::new(self.parse_statement()?))
        } else {
            None
        };
        Ok(ASTNode::IfStatement(IfStatement {
            test,
            consequent: Box::new(consequent),
            alternate,
        }))
    }

    fn parse_for_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("for")?;
        self.expect("(")?;

        if self.at_punct(";") {
            self.advance();
            return self.parse_for_rest(None);
        }

        let is_await = if self.at_keyword("await") {
            self.advance();
            true
        } else {
            false
        };

        let is_var = matches!(self.cur_value(), "var" | "let" | "const");
        if is_var {
            let kind = match self.cur_value() {
                "var" => VariableKind::Var,
                "let"
                    if self.peek_at("[")
                        || self.peek_at("{")
                        || self.peek_token.as_ref().map_or(false, |t| {
                            matches!(t.token_type, TokenType::Identifier)
                                || (matches!(t.token_type, TokenType::Keyword) && t.value != "in")
                        }) =>
                {
                    VariableKind::Let
                }
                "const" => VariableKind::Const,
                _ => {
                    if self.cur_value() == "let" {
                        let expr = self.parse_expression_no_in()?;
                        if self.at_keyword("in") {
                            self.advance();
                            let right = self.parse_expression()?;
                            self.expect(")")?;
                            let body = self.parse_statement()?;
                            return Ok(ASTNode::ForInStatement(ForInStatement {
                                left: ForInOfLeft::AssignmentTarget(expr_to_target(expr)?),
                                right,
                                body: Box::new(body),
                            }));
                        }
                        if self.at_keyword("of") {
                            self.advance();
                            let right = self.parse_expression()?;
                            self.expect(")")?;
                            let body = self.parse_statement()?;
                            return Ok(ASTNode::ForOfStatement(ForOfStatement {
                                left: ForInOfLeft::AssignmentTarget(expr_to_target(expr)?),
                                right,
                                body: Box::new(body),
                                is_await,
                            }));
                        }
                        self.expect(";")?;
                        return self.parse_for_rest(Some(ForInit::Expression(expr)));
                    }
                    unreachable!()
                }
            };
            self.advance();
            let mut declarations = Vec::new();
            let id = self.parse_binding_pattern()?;

            if self.at_keyword("in") {
                self.advance();
                let right = self.parse_expression()?;
                self.expect(")")?;
                let body = self.parse_statement()?;
                let decl = VariableDeclaration {
                    kind,
                    declarations: vec![VariableDeclarator { id, init: None }],
                };
                return Ok(ASTNode::ForInStatement(ForInStatement {
                    left: ForInOfLeft::VariableDeclaration(decl),
                    right,
                    body: Box::new(body),
                }));
            }
            if self.at_keyword("of") {
                self.advance();
                let right = self.parse_expression()?;
                self.expect(")")?;
                let body = self.parse_statement()?;
                let decl = VariableDeclaration {
                    kind,
                    declarations: vec![VariableDeclarator { id, init: None }],
                };
                return Ok(ASTNode::ForOfStatement(ForOfStatement {
                    left: ForInOfLeft::VariableDeclaration(decl),
                    right,
                    body: Box::new(body),
                    is_await,
                }));
            }
            let init = if self.at_punct("=") {
                self.advance();
                Some(self.parse_assignment_expression_no_in()?)
            } else {
                None
            };
            declarations.push(VariableDeclarator { id, init });
            while self.at_punct(",") {
                self.advance();
                let id = self.parse_binding_pattern()?;
                let init = if self.at_punct("=") {
                    self.advance();
                    Some(self.parse_assignment_expression_no_in()?)
                } else {
                    None
                };
                declarations.push(VariableDeclarator { id, init });
            }
            let decl = VariableDeclaration { kind, declarations };
            self.expect(";")?;
            return self.parse_for_rest(Some(ForInit::VariableDeclaration(decl)));
        }

        let expr = self.parse_expression_no_in()?;
        if self.at_keyword("in") {
            self.advance();
            let right = self.parse_expression()?;
            self.expect(")")?;
            let body = self.parse_statement()?;
            return Ok(ASTNode::ForInStatement(ForInStatement {
                left: ForInOfLeft::AssignmentTarget(expr_to_target(expr)?),
                right,
                body: Box::new(body),
            }));
        }
        if self.at_keyword("of") {
            self.advance();
            let right = self.parse_expression()?;
            self.expect(")")?;
            let body = self.parse_statement()?;
            return Ok(ASTNode::ForOfStatement(ForOfStatement {
                left: ForInOfLeft::AssignmentTarget(expr_to_target(expr)?),
                right,
                body: Box::new(body),
                is_await,
            }));
        }
        self.expect(";")?;
        self.parse_for_rest(Some(ForInit::Expression(expr)))
    }

    fn parse_for_rest(&mut self, init: Option<ForInit>) -> Result<ASTNode, String> {
        let test = if self.at_punct(";") {
            None
        } else {
            Some(self.parse_expression()?)
        };
        self.expect(";")?;
        let update = if self.at_punct(")") {
            None
        } else {
            Some(self.parse_expression()?)
        };
        self.expect(")")?;
        let body = self.parse_statement()?;
        Ok(ASTNode::ForStatement(ForStatement {
            init,
            test,
            update,
            body: Box::new(body),
        }))
    }

    fn parse_while_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("while")?;
        self.expect("(")?;
        let test = self.parse_expression()?;
        self.expect(")")?;
        let body = self.parse_statement()?;
        Ok(ASTNode::WhileStatement(WhileStatement {
            test,
            body: Box::new(body),
        }))
    }

    fn parse_do_while_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("do")?;
        let body = self.parse_statement()?;
        self.expect_keyword("while")?;
        self.expect("(")?;
        let test = self.parse_expression()?;
        self.expect(")")?;
        self.expect_semicolon()?;
        Ok(ASTNode::DoWhileStatement(DoWhileStatement {
            body: Box::new(body),
            test,
        }))
    }

    fn expect_keyword(&mut self, kw: &str) -> Result<(), String> {
        if self.at_keyword(kw) {
            self.advance();
            Ok(())
        } else {
            Err(self.error(&format!("Expected keyword '{}'", kw)))
        }
    }

    fn parse_switch_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("switch")?;
        self.expect("(")?;
        let discriminant = self.parse_expression()?;
        self.expect(")")?;
        self.expect("{")?;
        let mut cases = Vec::new();
        while !self.at_punct("}") && !self.is_eof() {
            if self.at_keyword("default") {
                self.advance();
                self.expect(":")?;
                let consequent = self.parse_statement_list_until_case()?;
                cases.push(SwitchCase {
                    test: None,
                    consequent,
                });
            } else {
                self.expect_keyword("case")?;
                let test = self.parse_expression()?;
                self.expect(":")?;
                let consequent = self.parse_statement_list_until_case()?;
                cases.push(SwitchCase {
                    test: Some(test),
                    consequent,
                });
            }
        }
        self.expect("}")?;
        Ok(ASTNode::SwitchStatement(SwitchStatement {
            discriminant,
            cases,
        }))
    }

    fn parse_statement_list_until_case(&mut self) -> Result<Vec<ASTNode>, String> {
        let (stmts, _) = self.parse_statement_list_until_case_with_lines()?;
        Ok(stmts)
    }

    fn parse_statement_list_until_case_with_lines(
        &mut self,
    ) -> Result<(Vec<ASTNode>, Vec<u32>), String> {
        let mut stmts = Vec::new();
        let mut lines = Vec::new();
        while !self.is_eof()
            && !self.at_punct("}")
            && !self.at_keyword("case")
            && !self.at_keyword("default")
        {
            let line = self.current.as_ref().map(|t| t.line).unwrap_or(0);
            stmts.push(self.parse_statement()?);
            lines.push(line);
        }
        Ok((stmts, lines))
    }

    fn parse_try_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("try")?;
        let block = self.parse_block_body()?;
        let handler = if self.at_keyword("catch") {
            self.advance();
            let param = if self.at_punct("(") {
                self.advance();
                let p = self.parse_binding_pattern()?;
                self.expect(")")?;
                Some(p)
            } else {
                None
            };
            let body = self.parse_block_body()?;
            Some(CatchClause { param, body })
        } else {
            None
        };
        let finalizer = if self.at_keyword("finally") {
            self.advance();
            Some(self.parse_block_body()?)
        } else {
            None
        };
        Ok(ASTNode::TryStatement(TryStatement {
            block,
            handler,
            finalizer,
        }))
    }

    fn parse_with_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("with")?;
        self.expect("(")?;
        let object = self.parse_expression()?;
        self.expect(")")?;
        let body = self.parse_statement()?;
        Ok(ASTNode::WithStatement(WithStatement {
            object,
            body: Box::new(body),
        }))
    }

    fn has_line_terminator(&self) -> bool {
        self.current
            .as_ref()
            .map_or(false, |t| t.line > self.saved_line)
    }

    fn parse_return_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("return")?;
        let argument = if self.is_eof()
            || self.at_punct(";")
            || self.at_punct("}")
            || self.has_line_terminator()
        {
            None
        } else {
            Some(self.parse_expression()?)
        };
        self.expect_semicolon()?;
        Ok(ASTNode::ReturnStatement(ReturnStatement { argument }))
    }

    fn parse_throw_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("throw")?;
        let argument = self.parse_expression()?;
        self.expect_semicolon()?;
        Ok(ASTNode::ThrowStatement(ThrowStatement { argument }))
    }

    fn parse_break_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("break")?;
        let label = if !self.has_line_terminator()
            && self.is_identifier_name()
            && !self.at_punct(";")
            && !self.is_eof()
        {
            Some(self.cur_value().to_string())
        } else {
            None
        };
        if label.is_some() {
            self.advance();
        }
        self.expect_semicolon()?;
        Ok(ASTNode::BreakStatement(BreakStatement { label }))
    }

    fn parse_continue_statement(&mut self) -> Result<ASTNode, String> {
        self.expect("continue")?;
        let label = if !self.has_line_terminator()
            && self.is_identifier_name()
            && !self.at_punct(";")
            && !self.is_eof()
        {
            Some(self.cur_value().to_string())
        } else {
            None
        };
        if label.is_some() {
            self.advance();
        }
        self.expect_semicolon()?;
        Ok(ASTNode::ContinueStatement(ContinueStatement { label }))
    }

    fn parse_expression_statement_or_labelled(&mut self) -> Result<ASTNode, String> {
        if self.is_identifier_name() && self.peek_at(":") {
            let label = self.cur_value().to_string();
            self.advance();
            self.advance();
            let body = self.parse_statement()?;
            return Ok(ASTNode::LabelledStatement(LabelledStatement {
                label,
                body: Box::new(body),
            }));
        }
        self.parse_expression_statement()
    }

    fn parse_expression_statement(&mut self) -> Result<ASTNode, String> {
        let expr = self.parse_expression()?;
        self.expect_semicolon()?;
        Ok(ASTNode::ExpressionStatement(ExpressionStatement {
            expression: expr,
        }))
    }

    fn parse_import_declaration(&mut self) -> Result<ImportDeclaration, String> {
        self.expect("import")?;
        let mut specifiers = Vec::new();

        if self.cur_type() == Some(TokenType::String) {
            let source = self.cur_value().to_string();
            self.advance();
            self.expect_semicolon()?;
            return Ok(ImportDeclaration { specifiers, source });
        }

        if self.is_identifier_name() {
            let local = self.cur_value().to_string();
            self.advance();
            specifiers.push(ImportSpecifier::Default { local });

            if self.at_punct(",") {
                self.advance();
            }
        }

        if self.at_punct("*") {
            self.advance();
            self.expect_keyword("as")?;
            let local = self.cur_value().to_string();
            self.advance();
            specifiers.push(ImportSpecifier::Namespace { local });
        }

        if self.at_punct("{") {
            self.advance();
            while !self.at_punct("}") && !self.is_eof() && !self.at_keyword("from") {
                if self.at_punct(",") {
                    self.advance();
                    continue;
                }
                let imported = self.cur_value().to_string();
                self.advance();
                let local = if self.at_keyword("as") {
                    self.advance();
                    self.cur_value().to_string()
                } else {
                    imported.clone()
                };
                if !self.at_punct(",") && !self.at_punct("}") && !self.at_keyword("from") {
                    self.advance();
                }
                specifiers.push(ImportSpecifier::Named { imported, local });
            }
            self.expect("}")?;
        }

        self.expect_keyword("from")?;
        let source = self.cur_value().to_string();
        self.advance();
        self.expect_semicolon()?;
        Ok(ImportDeclaration { specifiers, source })
    }

    fn parse_export_declaration(&mut self) -> Result<ASTNode, String> {
        self.expect("export")?;

        if self.at_keyword("default") {
            self.advance();
            let decl = if self.at_keyword("function") {
                self.advance();
                let generator = self.at_punct("*");
                if generator {
                    self.advance();
                }
                let func = self.parse_function_declaration_like(false, generator)?;
                ExportDefaultDeclarationKind::Function(func)
            } else if self.at_keyword("class") {
                self.advance();
                let cls = self.parse_class_declaration_inner()?;
                ExportDefaultDeclarationKind::Class(cls)
            } else if self.at_keyword("async") {
                self.advance();
                self.expect("function")?;
                let generator = self.at_punct("*");
                if generator {
                    self.advance();
                }
                let func = self.parse_function_declaration_like(true, generator)?;
                ExportDefaultDeclarationKind::Function(func)
            } else {
                let expr = self.parse_assignment_expression()?;
                ExportDefaultDeclarationKind::Expression(expr)
            };
            self.expect_semicolon()?;
            return Ok(ASTNode::ExportDefaultDeclaration(
                ExportDefaultDeclaration { declaration: decl },
            ));
        }

        if self.at_punct("*") {
            self.advance();
            self.expect_keyword("from")?;
            let source = self.cur_value().to_string();
            self.advance();
            self.expect_semicolon()?;
            return Ok(ASTNode::ExportAllDeclaration(ExportAllDeclaration {
                source,
                exported: None,
            }));
        }

        if self.at_punct("{") {
            self.advance();
            let mut specifiers = Vec::new();
            while !self.at_punct("}") && !self.is_eof() {
                let local = self.cur_value().to_string();
                self.advance();
                let exported = if self.at_keyword("as") {
                    self.advance();
                    let name = self.cur_value().to_string();
                    self.advance();
                    name
                } else {
                    local.clone()
                };
                specifiers.push(ExportSpecifier { exported, local });
                if self.at_punct(",") {
                    self.advance();
                }
            }
            self.expect("}")?;
            let source = if self.at_keyword("from") {
                self.advance();
                let s = self.cur_value().to_string();
                self.advance();
                Some(s)
            } else {
                None
            };
            self.expect_semicolon()?;
            return Ok(ASTNode::ExportNamedDeclaration(ExportNamedDeclaration {
                declaration: None,
                specifiers,
                source,
            }));
        }

        if self.at_keyword("var") || self.at_keyword("let") || self.at_keyword("const") {
            let decl = self.parse_variable_declaration()?;
            match decl {
                ASTNode::VariableDeclaration(v) => {
                    return Ok(ASTNode::ExportNamedDeclaration(ExportNamedDeclaration {
                        declaration: Some(ExportDeclaration::Variable(v)),
                        specifiers: vec![],
                        source: None,
                    }));
                }
                _ => unreachable!(),
            }
        }
        if self.at_keyword("function") {
            self.advance();
            let generator = self.at_punct("*");
            if generator {
                self.advance();
            }
            let func = self.parse_function_declaration_like(false, generator)?;
            return Ok(ASTNode::ExportNamedDeclaration(ExportNamedDeclaration {
                declaration: Some(ExportDeclaration::Function(func)),
                specifiers: vec![],
                source: None,
            }));
        }
        if self.at_keyword("async") {
            self.advance();
            self.expect("function")?;
            let generator = self.at_punct("*");
            if generator {
                self.advance();
            }
            let func = self.parse_function_declaration_like(true, generator)?;
            return Ok(ASTNode::ExportNamedDeclaration(ExportNamedDeclaration {
                declaration: Some(ExportDeclaration::Function(func)),
                specifiers: vec![],
                source: None,
            }));
        }
        if self.at_keyword("class") {
            self.advance();
            let cls = self.parse_class_declaration_inner()?;
            return Ok(ASTNode::ExportNamedDeclaration(ExportNamedDeclaration {
                declaration: Some(ExportDeclaration::Class(cls)),
                specifiers: vec![],
                source: None,
            }));
        }

        Err(self.error("expected export declaration"))
    }

    fn parse_function_declaration_like(
        &mut self,
        is_async: bool,
        generator: bool,
    ) -> Result<FunctionDeclaration, String> {
        let name = if matches!(
            self.cur_type(),
            Some(TokenType::Identifier) | Some(TokenType::Keyword)
        ) && !self.at_punct("(")
        {
            let n = self.cur_value().to_string();
            self.advance();
            n
        } else {
            String::new()
        };
        self.expect("(")?;
        let params = self.parse_parameter_list()?;
        self.expect(")")?;
        let body = self.parse_block_body()?;
        Ok(FunctionDeclaration {
            name,
            params,
            body,
            generator,
            is_async,
        })
    }

    fn parse_class_declaration_inner(&mut self) -> Result<ClassDeclaration, String> {
        let name = self.cur_value().to_string();
        self.advance();
        let super_class = if self.at_keyword("extends") {
            self.advance();
            Some(Box::new(self.parse_assignment_expression()?))
        } else {
            None
        };
        self.expect("{")?;
        let body = self.parse_class_body()?;
        self.expect("}")?;
        Ok(ClassDeclaration {
            name,
            super_class,
            body,
        })
    }

    fn parse_expression(&mut self) -> Result<Expression, String> {
        let expr = self.parse_assignment_expression()?;
        if self.at_punct(",") {
            let mut exprs = vec![expr];
            while self.at_punct(",") {
                self.advance();
                exprs.push(self.parse_assignment_expression()?);
            }
            return Ok(Expression::SequenceExpression(SequenceExpression {
                expressions: exprs,
            }));
        }
        Ok(expr)
    }

    fn parse_assignment_expression(&mut self) -> Result<Expression, String> {
        if self.at_keyword("async") && self.peek_at("function") {
            self.advance();
            self.expect("function")?;
            let generator = self.at_punct("*");
            if generator {
                self.advance();
            }
            return self.parse_function_expression(true, generator);
        }

        if self.at_keyword("async") {
            if self.peek_at("(") || (self.peek_value().map_or(false, |v| v != "function")) {
                let saved_pos = self.lexer.pos();
                let saved_kind = self.lexer.last_token_kind();
                self.advance();
                if self.at_keyword("function") {
                    self.lexer.set_pos(saved_pos);
                    self.lexer.set_last_token_kind(saved_kind);
                    self.current = self.lexer.next_token();
                    self.peek_token = self.lexer.next_token();
                } else if let Some(arrow) = self.try_parse_arrow_function(true)? {
                    return Ok(arrow);
                } else {
                    self.lexer.set_pos(saved_pos);
                    self.lexer.set_last_token_kind(saved_kind);
                    self.current = self.lexer.next_token();
                    self.peek_token = self.lexer.next_token();
                }
            }
        }

        if self.at_punct("(") || (self.is_identifier_name() && self.peek_at("=>")) {
            if let Some(arrow) = self.try_parse_arrow_function(false)? {
                return Ok(arrow);
            }
        }

        let expr = self.parse_conditional_expression()?;

        let assign_ops = [
            ("=", AssignOp::Assign),
            ("+=", AssignOp::AddAssign),
            ("-=", AssignOp::SubAssign),
            ("*=", AssignOp::MulAssign),
            ("/=", AssignOp::DivAssign),
            ("%=", AssignOp::ModAssign),
            ("**=", AssignOp::PowAssign),
            ("&=", AssignOp::BitAndAssign),
            ("|=", AssignOp::BitOrAssign),
            ("^=", AssignOp::BitXorAssign),
            ("<<=", AssignOp::ShlAssign),
            (">>=", AssignOp::ShrAssign),
            (">>>=", AssignOp::UShrAssign),
            ("&&=", AssignOp::LogicalAndAssign),
            ("||=", AssignOp::LogicalOrAssign),
            ("??=", AssignOp::NullishAssign),
        ];
        for (op_str, op) in &assign_ops {
            if self.at_punct(op_str) {
                self.advance();
                let right = self.parse_assignment_expression()?;
                let left = expr_to_target(expr)?;
                return Ok(Expression::AssignmentExpression(AssignmentExpression {
                    op: op.clone(),
                    left,
                    right: Box::new(right),
                }));
            }
        }

        Ok(expr)
    }

    fn try_parse_arrow_function(&mut self, is_async: bool) -> Result<Option<Expression>, String> {
        let saved_pos = self.lexer.pos();
        let saved_kind = self.lexer.last_token_kind();
        let saved_cur = self.current.clone();
        let saved_peek = self.peek_token.clone();

        let params = if self.at_punct("(") {
            self.advance();
            let p = match self.parse_parameter_list() {
                Ok(p) => p,
                Err(_) => {
                    self.restore(saved_pos, saved_kind, saved_cur, saved_peek);
                    return Ok(None);
                }
            };
            if !self.at_punct(")") {
                self.restore(saved_pos, saved_kind, saved_cur, saved_peek);
                return Ok(None);
            }
            self.advance();
            p
        } else if self.is_identifier_name() {
            let name = self.cur_value().to_string();
            self.advance();
            vec![Parameter::Identifier(name)]
        } else {
            self.restore(saved_pos, saved_kind, saved_cur, saved_peek);
            return Ok(None);
        };

        if !self.at_punct("=>") {
            self.restore(saved_pos, saved_kind, saved_cur, saved_peek);
            return Ok(None);
        }
        self.advance();

        let body = if self.at_punct("{") {
            ArrowBody::Block(self.parse_block_body()?)
        } else {
            ArrowBody::Expression(Box::new(self.parse_assignment_expression()?))
        };

        Ok(Some(Expression::ArrowFunction(ArrowFunction {
            params,
            body,
            is_async,
        })))
    }

    fn restore(
        &mut self,
        pos: usize,
        kind: crate::compiler::lexer::LastTokenKind,
        cur: Option<Token>,
        peek: Option<Token>,
    ) {
        self.lexer.set_pos(pos);
        self.lexer.set_last_token_kind(kind);
        self.current = cur;
        self.peek_token = peek;
    }

    fn parse_conditional_expression(&mut self) -> Result<Expression, String> {
        let expr = self.parse_logical_or()?;
        if self.at_punct("?") {
            self.advance();
            let consequent = self.parse_assignment_expression()?;
            self.expect(":")?;
            let alternate = self.parse_assignment_expression()?;
            return Ok(Expression::ConditionalExpression(ConditionalExpression {
                test: Box::new(expr),
                consequent: Box::new(consequent),
                alternate: Box::new(alternate),
            }));
        }
        Ok(expr)
    }

    fn parse_logical_or(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_logical_and()?;
        while self.at_punct("||") || self.at_punct("??") {
            let op = if self.at_punct("||") {
                self.advance();
                LogicalOp::Or
            } else {
                self.advance();
                LogicalOp::NullishCoalescing
            };
            let right = self.parse_logical_and()?;
            left = Expression::LogicalExpression(LogicalExpression {
                op,
                left: Box::new(left),
                right: Box::new(right),
            });
        }
        Ok(left)
    }

    fn parse_logical_and(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_bitwise_or()?;
        while self.at_punct("&&") {
            self.advance();
            let right = self.parse_bitwise_or()?;
            left = Expression::LogicalExpression(LogicalExpression {
                op: LogicalOp::And,
                left: Box::new(left),
                right: Box::new(right),
            });
        }
        Ok(left)
    }

    fn parse_bitwise_or(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_bitwise_xor()?;
        while self.at_punct("|") {
            self.advance();
            let right = self.parse_bitwise_xor()?;
            left = Expression::BinaryExpression(BinaryExpression {
                op: BinaryOp::BitOr,
                left: Box::new(left),
                right: Box::new(right),
            });
        }
        Ok(left)
    }

    fn parse_bitwise_xor(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_bitwise_and()?;
        while self.at_punct("^") {
            self.advance();
            let right = self.parse_bitwise_and()?;
            left = Expression::BinaryExpression(BinaryExpression {
                op: BinaryOp::BitXor,
                left: Box::new(left),
                right: Box::new(right),
            });
        }
        Ok(left)
    }

    fn parse_bitwise_and(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_equality()?;
        while self.at_punct("&") {
            self.advance();
            let right = self.parse_equality()?;
            left = Expression::BinaryExpression(BinaryExpression {
                op: BinaryOp::BitAnd,
                left: Box::new(left),
                right: Box::new(right),
            });
        }
        Ok(left)
    }

    fn parse_equality(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_relational()?;
        loop {
            let op = if self.at_punct("==") {
                Some(BinaryOp::Eq)
            } else if self.at_punct("!=") {
                Some(BinaryOp::Neq)
            } else if self.at_punct("===") {
                Some(BinaryOp::StrictEq)
            } else if self.at_punct("!==") {
                Some(BinaryOp::StrictNeq)
            } else {
                None
            };
            if let Some(op) = op {
                self.advance();
                let right = self.parse_relational()?;
                left = Expression::BinaryExpression(BinaryExpression {
                    op,
                    left: Box::new(left),
                    right: Box::new(right),
                });
            } else {
                break;
            }
        }
        Ok(left)
    }

    fn parse_relational(&mut self) -> Result<Expression, String> {
        if self.cur_type() == Some(TokenType::PrivateIdentifier) {
            let name = self.cur_value().to_string();
            self.advance();
            if self.at_keyword("in") {
                self.advance();
                let right = self.parse_shift()?;
                return Ok(Expression::BinaryExpression(BinaryExpression {
                    op: BinaryOp::In,
                    left: Box::new(Expression::PrivateIdentifier(name)),
                    right: Box::new(right),
                }));
            } else {
                return Err(self.error("Unexpected private identifier"));
            }
        }

        let mut left = self.parse_shift()?;
        loop {
            let op = if self.at_punct("<=") {
                Some(BinaryOp::Lte)
            } else if self.at_punct(">=") {
                Some(BinaryOp::Gte)
            } else if self.at_punct("<") {
                Some(BinaryOp::Lt)
            } else if self.at_punct(">") {
                Some(BinaryOp::Gt)
            } else if self.allow_in && self.at_keyword("in") {
                Some(BinaryOp::In)
            } else if self.at_keyword("instanceof") {
                Some(BinaryOp::InstanceOf)
            } else {
                None
            };
            if let Some(op) = op {
                self.advance();
                let right = self.parse_shift()?;
                left = Expression::BinaryExpression(BinaryExpression {
                    op,
                    left: Box::new(left),
                    right: Box::new(right),
                });
            } else {
                break;
            }
        }
        Ok(left)
    }

    fn parse_shift(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_additive()?;
        loop {
            let op = if self.at_punct(">>>") {
                Some(BinaryOp::UShr)
            } else if self.at_punct(">>") {
                Some(BinaryOp::Shr)
            } else if self.at_punct("<<") {
                Some(BinaryOp::Shl)
            } else {
                None
            };
            if let Some(op) = op {
                self.advance();
                let right = self.parse_additive()?;
                left = Expression::BinaryExpression(BinaryExpression {
                    op,
                    left: Box::new(left),
                    right: Box::new(right),
                });
            } else {
                break;
            }
        }
        Ok(left)
    }

    fn parse_additive(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_multiplicative()?;
        loop {
            let op = if self.at_punct("+") {
                Some(BinaryOp::Add)
            } else if self.at_punct("-") {
                Some(BinaryOp::Sub)
            } else {
                None
            };
            if let Some(op) = op {
                self.advance();
                let right = self.parse_multiplicative()?;
                left = Expression::BinaryExpression(BinaryExpression {
                    op,
                    left: Box::new(left),
                    right: Box::new(right),
                });
            } else {
                break;
            }
        }
        Ok(left)
    }

    fn parse_multiplicative(&mut self) -> Result<Expression, String> {
        let mut left = self.parse_exponentiation()?;
        loop {
            let op = if self.at_punct("*") {
                Some(BinaryOp::Mul)
            } else if self.at_punct("/") {
                Some(BinaryOp::Div)
            } else if self.at_punct("%") {
                Some(BinaryOp::Mod)
            } else {
                None
            };
            if let Some(op) = op {
                self.advance();
                let right = self.parse_exponentiation()?;
                left = Expression::BinaryExpression(BinaryExpression {
                    op,
                    left: Box::new(left),
                    right: Box::new(right),
                });
            } else {
                break;
            }
        }
        Ok(left)
    }

    fn parse_exponentiation(&mut self) -> Result<Expression, String> {
        let left = self.parse_unary()?;
        if self.at_punct("**") {
            self.advance();
            let right = self.parse_exponentiation()?;
            return Ok(Expression::BinaryExpression(BinaryExpression {
                op: BinaryOp::Pow,
                left: Box::new(left),
                right: Box::new(right),
            }));
        }
        Ok(left)
    }

    fn parse_unary(&mut self) -> Result<Expression, String> {
        if self.at_punct("!") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::Not,
                argument: Box::new(arg),
                prefix: true,
            }));
        }

        if self.at_punct("~") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::BitNot,
                argument: Box::new(arg),
                prefix: true,
            }));
        }

        if self.at_punct("-") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::Minus,
                argument: Box::new(arg),
                prefix: true,
            }));
        }

        if self.at_punct("+") && self.cur_type() == Some(TokenType::Punctuator) {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::Plus,
                argument: Box::new(arg),
                prefix: true,
            }));
        }
        if self.at_keyword("typeof") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::TypeOf,
                argument: Box::new(arg),
                prefix: true,
            }));
        }
        if self.at_keyword("void") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::Void,
                argument: Box::new(arg),
                prefix: true,
            }));
        }
        if self.at_keyword("delete") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UnaryExpression(UnaryExpression {
                op: UnaryOp::Delete,
                argument: Box::new(arg),
                prefix: true,
            }));
        }

        if self.at_punct("++") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UpdateExpression(UpdateExpression {
                op: UpdateOp::Increment,
                argument: Box::new(arg),
                prefix: true,
            }));
        }
        if self.at_punct("--") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::UpdateExpression(UpdateExpression {
                op: UpdateOp::Decrement,
                argument: Box::new(arg),
                prefix: true,
            }));
        }

        if self.at_keyword("await") {
            self.advance();
            let arg = self.parse_unary()?;
            return Ok(Expression::AwaitExpression(AwaitExpression {
                argument: Box::new(arg),
            }));
        }

        self.parse_postfix()
    }

    fn parse_postfix(&mut self) -> Result<Expression, String> {
        let expr = self.parse_member_expression()?;

        if self.at_punct("++") && !self.has_line_terminator() {
            self.advance();
            return Ok(Expression::UpdateExpression(UpdateExpression {
                op: UpdateOp::Increment,
                argument: Box::new(expr),
                prefix: false,
            }));
        }
        if self.at_punct("--") && !self.has_line_terminator() {
            self.advance();
            return Ok(Expression::UpdateExpression(UpdateExpression {
                op: UpdateOp::Decrement,
                argument: Box::new(expr),
                prefix: false,
            }));
        }

        Ok(expr)
    }

    fn parse_member_expression(&mut self) -> Result<Expression, String> {
        let mut expr = self.parse_primary()?;

        loop {
            if self.at_punct(".") {
                self.advance();

                if self.cur_type() == Some(TokenType::PrivateIdentifier) {
                    let name = self.cur_value().to_string();
                    self.advance();
                    expr = Expression::MemberExpression(MemberExpression {
                        object: Box::new(expr),
                        property: MemberProperty::PrivateIdentifier(name),
                        computed: false,
                    });
                } else {
                    let name = self.cur_value().to_string();
                    self.advance();
                    expr = Expression::MemberExpression(MemberExpression {
                        object: Box::new(expr),
                        property: MemberProperty::Identifier(name),
                        computed: false,
                    });
                }
            } else if self.at_punct("?.") {
                self.advance();
                if self.at_punct("[") {
                    self.advance();
                    let prop = self.parse_expression()?;
                    self.expect("]")?;
                    expr = Expression::OptionalMemberExpression(OptionalMemberExpression {
                        object: Box::new(expr),
                        property: MemberProperty::Computed(Box::new(prop)),
                        computed: true,
                        optional: true,
                    });
                } else if self.at_punct("(") {
                    let args = self.parse_arguments()?;
                    expr = Expression::OptionalCallExpression(OptionalCallExpression {
                        callee: Box::new(expr),
                        arguments: args,
                        optional: true,
                    });
                } else {
                    let name = self.cur_value().to_string();
                    self.advance();
                    expr = Expression::OptionalMemberExpression(OptionalMemberExpression {
                        object: Box::new(expr),
                        property: MemberProperty::Identifier(name),
                        computed: false,
                        optional: true,
                    });
                }
            } else if self.at_punct("[") {
                self.advance();
                let prop = self.parse_expression()?;
                self.expect("]")?;
                expr = Expression::MemberExpression(MemberExpression {
                    object: Box::new(expr),
                    property: MemberProperty::Computed(Box::new(prop)),
                    computed: true,
                });
            } else if self.at_punct("(") {
                let args = self.parse_arguments()?;
                expr = Expression::CallExpression(CallExpression {
                    callee: Box::new(expr),
                    arguments: args,
                });
            } else {
                break;
            }
        }

        Ok(expr)
    }

    fn parse_arguments(&mut self) -> Result<Vec<Argument>, String> {
        self.expect("(")?;
        let mut args = Vec::new();
        while !self.at_punct(")") && !self.is_eof() {
            if self.at_punct("...") {
                self.advance();
                args.push(Argument::Spread(self.parse_assignment_expression()?));
            } else {
                args.push(Argument::Expression(self.parse_assignment_expression()?));
            }
            if self.at_punct(",") {
                self.advance();
            }
        }
        self.expect(")")?;
        Ok(args)
    }

    fn parse_primary(&mut self) -> Result<Expression, String> {
        if self.at_punct("(") {
            self.advance();
            let expr = self.parse_expression()?;
            self.expect(")")?;
            return Ok(expr);
        }

        if self.at_keyword("new") {
            return self.parse_new_expression();
        }

        if self.at_keyword("import") {
            if self.peek_at(".") {
                self.advance();
                self.expect(".")?;
                self.expect_keyword("meta")?;
                return Ok(Expression::MetaProperty(MetaProperty {
                    meta: "import".to_string(),
                    property: "meta".to_string(),
                }));
            }
            if self.peek_at("(") {
                self.advance();
                self.expect("(")?;
                let arg = self.parse_assignment_expression()?;
                self.expect(")")?;

                return Ok(Expression::CallExpression(CallExpression {
                    callee: Box::new(Expression::Identifier(Identifier {
                        name: "import".to_string(),
                    })),
                    arguments: vec![Argument::Expression(arg)],
                }));
            }
        }

        if self.cur_type() == Some(TokenType::Number) {
            let raw = self.cur_value().to_string();
            let lit = parse_number_literal(&raw);
            self.advance();
            return Ok(match lit {
                NumberLit::Normal(v) => Expression::Literal(Literal::Number(v)),
                NumberLit::LegacyOctal(v) => Expression::Literal(Literal::LegacyOctal(v)),
            });
        }

        if self.cur_type() == Some(TokenType::BigInt) {
            let val = self.cur_value().to_string();
            self.advance();
            return Ok(Expression::Literal(Literal::BigInt(val)));
        }

        if self.cur_type() == Some(TokenType::String) {
            let val = self.cur_value().to_string();
            self.advance();
            let has_escape = self.lexer.last_string_had_escape;
            return Ok(Expression::Literal(Literal::String(val, has_escape)));
        }

        if self.at_keyword("true") {
            self.advance();
            return Ok(Expression::Literal(Literal::Boolean(true)));
        }
        if self.at_keyword("false") {
            self.advance();
            return Ok(Expression::Literal(Literal::Boolean(false)));
        }
        if self.at_keyword("null") {
            self.advance();
            return Ok(Expression::Literal(Literal::Null));
        }
        if self.cur_type() == Some(TokenType::Identifier) && self.cur_value() == "undefined" {
            self.advance();
            return Ok(Expression::Identifier(Identifier {
                name: "undefined".to_string(),
            }));
        }
        if self.cur_type() == Some(TokenType::Identifier) && self.cur_value() == "NaN" {
            self.advance();
            return Ok(Expression::Identifier(Identifier {
                name: "NaN".to_string(),
            }));
        }
        if self.cur_type() == Some(TokenType::Identifier) && self.cur_value() == "Infinity" {
            self.advance();
            return Ok(Expression::Identifier(Identifier {
                name: "Infinity".to_string(),
            }));
        }
        if self.at_keyword("this") {
            self.advance();
            return Ok(Expression::This);
        }
        if self.at_keyword("super") {
            self.advance();
            return Ok(Expression::Super);
        }

        if self.cur_type() == Some(TokenType::Regex) {
            let val = self.cur_value().to_string();
            self.advance();
            let (pattern, flags) = parse_regex_value(&val);
            return Ok(Expression::RegExpLiteral(RegExpLiteral { pattern, flags }));
        }

        if self.at_keyword("function") {
            self.advance();
            let generator = self.at_punct("*");
            if generator {
                self.advance();
            }
            return self.parse_function_expression(false, generator);
        }

        if self.at_keyword("class") {
            return self.parse_class_expression();
        }

        if self.at_punct("[") {
            return self.parse_array_expression();
        }

        if self.at_punct("{") {
            return self.parse_object_expression();
        }

        if self.at_template_start() {
            return self.parse_template_literal();
        }

        if self.at_keyword("yield") {
            self.advance();
            let delegate = if self.at_punct("*") {
                self.advance();
                true
            } else {
                false
            };
            let argument =
                if self.is_eof() || self.at_punct(";") || self.at_punct("}") || self.at(")") {
                    None
                } else {
                    Some(Box::new(self.parse_assignment_expression()?))
                };
            return Ok(Expression::YieldExpression(YieldExpression {
                argument,
                delegate,
            }));
        }

        if self.cur_type() == Some(TokenType::Identifier)
            || self.cur_type() == Some(TokenType::Keyword)
        {
            let name = self.cur_value().to_string();
            match name.as_str() {
                "NaN" => {
                    self.advance();
                    return Ok(Expression::Literal(Literal::Number(f64::NAN)));
                }
                "Infinity" => {
                    self.advance();
                    return Ok(Expression::Literal(Literal::Number(f64::INFINITY)));
                }
                _ => {
                    self.advance();
                    return Ok(Expression::Identifier(Identifier { name }));
                }
            }
        }

        Err(self.error(&format!("Unexpected token: '{}'", self.cur_value())))
    }

    fn parse_new_expression(&mut self) -> Result<Expression, String> {
        self.expect("new")?;

        let callee = if self.at_keyword("new") {
            Box::new(self.parse_new_expression()?)
        } else {
            Box::new(self.parse_primary()?)
        };

        let mut callee = callee;
        loop {
            if self.at_punct(".") {
                self.advance();
                let name = self.cur_value().to_string();
                self.advance();
                callee = Box::new(Expression::MemberExpression(MemberExpression {
                    object: callee,
                    property: MemberProperty::Identifier(name),
                    computed: false,
                }));
            } else if self.at_punct("[") {
                self.advance();
                let prop = self.parse_expression()?;
                self.expect("]")?;
                callee = Box::new(Expression::MemberExpression(MemberExpression {
                    object: callee,
                    property: MemberProperty::Computed(Box::new(prop)),
                    computed: true,
                }));
            } else {
                break;
            }
        }

        let arguments = if self.at_punct("(") {
            self.parse_arguments()?
        } else {
            vec![]
        };

        Ok(Expression::NewExpression(NewExpression {
            callee,
            arguments,
        }))
    }

    fn parse_array_expression(&mut self) -> Result<Expression, String> {
        self.expect("[")?;
        let mut elements = Vec::new();
        while !self.at_punct("]") && !self.is_eof() {
            if self.at_punct(",") {
                elements.push(None);
                self.advance();
                continue;
            }
            if self.at_punct("...") {
                self.advance();
                elements.push(Some(ArrayElement::Spread(
                    self.parse_assignment_expression()?,
                )));
            } else {
                elements.push(Some(ArrayElement::Expression(
                    self.parse_assignment_expression()?,
                )));
            }
            if self.at_punct(",") {
                self.advance();
            }
        }
        self.expect("]")?;
        Ok(Expression::ArrayExpression(ArrayExpression { elements }))
    }

    fn parse_object_expression(&mut self) -> Result<Expression, String> {
        self.expect("{")?;
        let mut properties = Vec::new();
        while !self.at_punct("}") && !self.is_eof() {
            if self.at_punct("...") {
                self.advance();
                properties.push(Property::SpreadElement(self.parse_assignment_expression()?));
                if self.at_punct(",") {
                    self.advance();
                }
                continue;
            }

            let mut is_async = false;
            if self.at_keyword("async")
                && !self.peek_at(";")
                && !self.peek_at(":")
                && !self.peek_at(",")
                && !self.peek_at("}")
                && !self.peek_at("=")
            {
                self.advance();
                is_async = true;
            }

            let mut is_generator = false;
            if self.at_punct("*") {
                self.advance();
                is_generator = true;
            }

            let (key, computed, shorthand) = self.parse_property_key()?;

            if self.at_punct("(") && !shorthand {
                self.expect("(")?;
                let params = self.parse_parameter_list()?;
                self.expect(")")?;
                let body = self.parse_block_body()?;
                properties.push(Property::Property {
                    key,
                    value: Box::new(Expression::FunctionExpression(FunctionExpression {
                        name: None,
                        params,
                        body,
                        generator: is_generator,
                        is_async,
                    })),
                    computed,
                    shorthand: false,
                    method: true,
                    getter: false,
                    setter: false,
                });
                if self.at_punct(",") {
                    self.advance();
                }
                continue;
            }

            if !computed {
                let accessor = match &key {
                    PropertyKey::Identifier(name) if name == "get" || name == "set" => {
                        Some(name.clone())
                    }
                    _ => None,
                };

                if let Some(accessor_kind) = accessor {
                    if self.at_punct(":") {
                    } else {
                        let (acc_key, _acc_computed, _acc_shorthand) = self.parse_property_key()?;
                        if self.at_punct("(") {
                            self.expect("(")?;
                            let params = self.parse_parameter_list()?;
                            self.expect(")")?;
                            let body = self.parse_block_body()?;

                            if accessor_kind == "get" && !params.is_empty() {
                                return Err(self.error("getter must not have parameters"));
                            }
                            if accessor_kind == "set" && params.len() != 1 {
                                return Err(self.error("setter must have exactly one parameter"));
                            }

                            let is_getter = accessor_kind == "get";
                            properties.push(Property::Property {
                                key: acc_key,
                                value: Box::new(Expression::FunctionExpression(
                                    FunctionExpression {
                                        name: None,
                                        params,
                                        body,
                                        generator: false,
                                        is_async: false,
                                    },
                                )),
                                computed: false,
                                shorthand: false,
                                method: true,
                                getter: is_getter,
                                setter: !is_getter,
                            });

                            if self.at_punct(",") {
                                self.advance();
                            }
                            continue;
                        }
                    }
                }
            }

            if self.at_punct(":") {
                self.advance();
                let value = self.parse_assignment_expression()?;
                properties.push(Property::Property {
                    key,
                    value: Box::new(value),
                    computed,
                    shorthand: false,
                    method: false,
                    getter: false,
                    setter: false,
                });
            } else if shorthand {
                let name = match &key {
                    PropertyKey::Identifier(n) => n.clone(),
                    _ => return Err(self.error("invalid shorthand property")),
                };
                properties.push(Property::Property {
                    key,
                    value: Box::new(Expression::Identifier(Identifier { name })),
                    computed: false,
                    shorthand: true,
                    method: false,
                    getter: false,
                    setter: false,
                });
            } else {
                return Err(self.error("expected ':' or '(' in object literal"));
            }
            if self.at_punct(",") {
                self.advance();
            }
        }
        self.expect("}")?;
        Ok(Expression::ObjectExpression(ObjectExpression {
            properties,
        }))
    }

    fn parse_property_key(&mut self) -> Result<(PropertyKey, bool, bool), String> {
        if self.at_punct("[") {
            self.advance();
            let expr = self.parse_assignment_expression()?;
            self.expect("]")?;
            return Ok((PropertyKey::Computed(Box::new(expr)), true, false));
        }
        if self.cur_type() == Some(TokenType::PrivateIdentifier) {
            let name = self.cur_value().to_string();
            self.advance();
            return Ok((PropertyKey::PrivateIdentifier(name), false, false));
        }
        if self.cur_type() == Some(TokenType::String) {
            let val = self.cur_value().to_string();
            self.advance();
            let has_escape = self.lexer.last_string_had_escape;
            return Ok((
                PropertyKey::Literal(Literal::String(val, has_escape)),
                false,
                false,
            ));
        }
        if self.cur_type() == Some(TokenType::Number) {
            let raw = self.cur_value().to_string();
            let lit = parse_number_literal(&raw);
            self.advance();
            return Ok(match lit {
                NumberLit::Normal(v) => (PropertyKey::Literal(Literal::Number(v)), false, false),
                NumberLit::LegacyOctal(v) => {
                    (PropertyKey::Literal(Literal::LegacyOctal(v)), false, false)
                }
            });
        }
        if self.is_identifier_name()
            || matches!(
                self.cur_value(),
                "true" | "false" | "null" | "undefined" | "NaN" | "Infinity"
            )
        {
            let name = self.cur_value().to_string();
            self.advance();

            let shorthand = self.at_punct(":") || self.at_punct(",") || self.at_punct("}");
            return Ok((PropertyKey::Identifier(name), false, shorthand));
        }
        Err(self.error("expected property key"))
    }

    fn parse_template_literal(&mut self) -> Result<Expression, String> {
        let mut quasis = Vec::new();
        let mut expressions = Vec::new();

        let tok = self
            .current
            .take()
            .ok_or_else(|| self.error("Expected template literal"))?;

        match tok.token_type {
            TokenType::NoSubstitutionTemplate => {
                quasis.push(TemplateElement {
                    value: tok.value,
                    tail: true,
                });

                self.current = self.peek_token.take();
                self.saved_pos = self.lexer.pos;
                self.saved_line = self.lexer.line;
                self.saved_col = self.lexer.column;
                self.peek_token = self.lexer.next_token();
                return Ok(Expression::TemplateLiteral(TemplateLiteral {
                    quasis,
                    expressions,
                }));
            }
            TokenType::TemplateHead => {
                quasis.push(TemplateElement {
                    value: tok.value,
                    tail: false,
                });

                self.current = self.peek_token.take();
                self.saved_pos = self.lexer.pos;
                self.saved_line = self.lexer.line;
                self.saved_col = self.lexer.column;
                self.peek_token = self.lexer.next_token();
            }
            _ => return Err(self.error("Expected template literal")),
        }

        loop {
            let expr = self.parse_expression()?;
            expressions.push(expr);

            if !self.at("}") {
                return Err(self.error("Expected '}' after template expression"));
            }

            self.lexer.pos = self.saved_pos;
            self.lexer.line = self.saved_line;
            self.lexer.column = self.saved_col;
            self.peek_token = None;

            let segment = self
                .lexer
                .scan_template_continuation()
                .ok_or_else(|| self.error("Unterminated template literal"))?;

            match segment.token_type {
                TokenType::TemplateTail => {
                    quasis.push(TemplateElement {
                        value: segment.value,
                        tail: true,
                    });

                    self.current = self.lexer.next_token();
                    self.saved_pos = self.lexer.pos;
                    self.saved_line = self.lexer.line;
                    self.saved_col = self.lexer.column;
                    self.peek_token = self.lexer.next_token();
                    break;
                }
                TokenType::TemplateMiddle => {
                    quasis.push(TemplateElement {
                        value: segment.value,
                        tail: false,
                    });

                    self.current = self.lexer.next_token();
                    self.saved_pos = self.lexer.pos;
                    self.saved_line = self.lexer.line;
                    self.saved_col = self.lexer.column;
                    self.peek_token = self.lexer.next_token();
                }
                _ => return Err(self.error("Unexpected token in template literal")),
            }
        }

        Ok(Expression::TemplateLiteral(TemplateLiteral {
            quasis,
            expressions,
        }))
    }
}

fn binding_to_target(bp: BindingPattern) -> AssignmentTarget {
    match bp {
        BindingPattern::Identifier(name) => AssignmentTarget::Identifier(name),
        BindingPattern::ArrayPattern(p) => AssignmentTarget::ArrayPattern(p),
        BindingPattern::ObjectPattern(p) => AssignmentTarget::ObjectPattern(p),
        BindingPattern::AssignmentPattern(p) => AssignmentTarget::AssignmentPattern(p),
    }
}

fn expr_to_target(expr: Expression) -> Result<AssignmentTarget, String> {
    match expr {
        Expression::Identifier(id) => Ok(AssignmentTarget::Identifier(id.name)),
        Expression::MemberExpression(m) => Ok(AssignmentTarget::MemberExpression(m)),
        Expression::ArrayPattern(p) => Ok(AssignmentTarget::ArrayPattern(p)),
        Expression::ObjectPattern(p) => Ok(AssignmentTarget::ObjectPattern(p)),
        Expression::ArrayExpression(arr) => {
            let mut elements = Vec::new();
            for elem in arr.elements {
                match elem {
                    Some(ArrayElement::Expression(e)) => {
                        elements.push(Some(PatternElement::Pattern(expr_to_target(e)?)));
                    }
                    Some(ArrayElement::Spread(e)) => {
                        elements.push(Some(PatternElement::RestElement(RestElement {
                            argument: Box::new(expr_to_target(e)?),
                        })));
                    }
                    None => {
                        elements.push(None);
                    }
                }
            }
            Ok(AssignmentTarget::ArrayPattern(ArrayPattern { elements }))
        }
        Expression::ObjectExpression(obj) => {
            let mut properties = Vec::new();
            for prop in obj.properties {
                match prop {
                    Property::SpreadElement(arg) => {
                        properties.push(ObjectPatternProperty::RestElement(RestElement {
                            argument: Box::new(expr_to_target(arg)?),
                        }));
                    }
                    Property::Property {
                        key,
                        value,
                        computed,
                        shorthand,
                        ..
                    } => {
                        if shorthand {
                            let name = match &key {
                                PropertyKey::Identifier(n) => n.clone(),
                                _ => {
                                    return Err(
                                        "invalid shorthand property in destructuring".to_string()
                                    );
                                }
                            };
                            properties.push(ObjectPatternProperty::Property {
                                key,
                                value: AssignmentTarget::Identifier(name),
                                computed: false,
                                shorthand: true,
                            });
                        } else {
                            let target = expr_to_target(*value)?;
                            properties.push(ObjectPatternProperty::Property {
                                key,
                                value: target,
                                computed,
                                shorthand: false,
                            });
                        }
                    }
                }
            }
            Ok(AssignmentTarget::ObjectPattern(ObjectPattern {
                properties,
            }))
        }
        Expression::AssignmentExpression(a) => {
            Ok(AssignmentTarget::AssignmentPattern(AssignmentPattern {
                left: Box::new(a.left),
                right: a.right,
            }))
        }
        _ => Err(format!("invalid assignment target: {:?}", expr)),
    }
}

fn parse_regex_value(value: &str) -> (String, String) {
    if let Some(idx) = value.rfind('/') {
        let pattern = value[0..idx].to_string();
        let flags = value[idx + 1..].to_string();
        (pattern, flags)
    } else {
        (value.to_string(), String::new())
    }
}

enum NumberLit {
    Normal(f64),
    LegacyOctal(i64),
}

fn parse_number_literal(raw: &str) -> NumberLit {
    if raw.starts_with("0x") || raw.starts_with("0X") {
        let clean: String = raw[2..].chars().filter(|&c| c != '_').collect();
        NumberLit::Normal(
            i64::from_str_radix(&clean, 16)
                .map(|n| n as f64)
                .unwrap_or(0.0),
        )
    } else if raw.starts_with("0o") || raw.starts_with("0O") {
        let clean: String = raw[2..].chars().filter(|&c| c != '_').collect();
        NumberLit::Normal(
            i64::from_str_radix(&clean, 8)
                .map(|n| n as f64)
                .unwrap_or(0.0),
        )
    } else if raw.starts_with("0b") || raw.starts_with("0B") {
        let clean: String = raw[2..].chars().filter(|&c| c != '_').collect();
        NumberLit::Normal(
            i64::from_str_radix(&clean, 2)
                .map(|n| n as f64)
                .unwrap_or(0.0),
        )
    } else if raw.len() > 1 && raw.as_bytes()[0] == b'0' && raw.as_bytes()[1].is_ascii_digit() {
        let chars: Vec<char> = raw.chars().collect();
        if chars[1] == '8' || chars[1] == '9' {
            let clean: String = raw.chars().filter(|&c| c != '_').collect();
            NumberLit::Normal(clean.parse::<f64>().unwrap_or(0.0))
        } else if chars[1..]
            .iter()
            .all(|&c| c == '_' || (c.is_ascii_digit() && c <= '7'))
        {
            let clean: String = raw[1..].chars().filter(|&c| c != '_').collect();
            NumberLit::LegacyOctal(i64::from_str_radix(&clean, 8).unwrap_or(0))
        } else {
            let clean: String = raw.chars().filter(|&c| c != '_').collect();
            NumberLit::Normal(clean.parse::<f64>().unwrap_or(0.0))
        }
    } else {
        let clean: String = raw.chars().filter(|&c| c != '_').collect();
        NumberLit::Normal(clean.parse::<f64>().unwrap_or(0.0))
    }
}
