#include "Ast/Expressions/VarExpr.hpp"
#include <Ast/Statements/ErrorFlow.hpp>
#include <Ast/Statements/ImplementSt.hpp>
#include <Ast/astBase.hpp>
#include <Ast/functionParameters.hpp>
#include <Error/error.hpp>
#include <Token/token.hpp>
#include <Parser/parser.hpp>

namespace Fig
{
    // Operator : pair<LeftBindingPower, RightBindingPower>
    const std::unordered_map<Ast::Operator, std::pair<Parser::Precedence, Parser::Precedence>> Parser::opPrecedence = {
        // 赋值类 - 右结合
        {Ast::Operator::Assign, {20, 10}},
        {Ast::Operator::PlusAssign, {20, 10}},
        {Ast::Operator::MinusAssign, {20, 10}},
        {Ast::Operator::SlashAssign, {20, 10}},
        {Ast::Operator::AsteriskAssign, {20, 10}},
        {Ast::Operator::PercentAssign, {20, 10}},
        {Ast::Operator::CaretAssign, {20, 10}},

        // 三元条件 - 特殊处理，通常是右结合
        {Ast::Operator::TernaryCond, {30, 20}},

        // 逻辑或
        {Ast::Operator::Or, {40, 41}}, // leftBP < rightBP，左结合

        // 逻辑与
        {Ast::Operator::And, {50, 51}}, // 比 Or 高

        // 位或
        {Ast::Operator::BitOr, {60, 61}},

        // 位异或
        {Ast::Operator::BitXor, {70, 71}},

        // 位与
        {Ast::Operator::BitAnd, {80, 81}},

        // 相等比较
        {Ast::Operator::Equal, {90, 91}},
        {Ast::Operator::NotEqual, {90, 91}},

        // 关系比较
        {Ast::Operator::Less, {100, 101}},
        {Ast::Operator::LessEqual, {100, 101}},
        {Ast::Operator::Greater, {100, 101}},
        {Ast::Operator::GreaterEqual, {100, 101}},
        {Ast::Operator::Is, {100, 101}},

        // 位移
        {Ast::Operator::ShiftLeft, {110, 111}},
        {Ast::Operator::ShiftRight, {110, 111}},

        // 加减
        {Ast::Operator::Add, {120, 121}},
        {Ast::Operator::Subtract, {120, 121}},

        // 乘除模
        {Ast::Operator::Multiply, {130, 131}},
        {Ast::Operator::Divide, {130, 131}},
        {Ast::Operator::Modulo, {130, 131}},

        // 幂运算 - 右结合
        {Ast::Operator::Power, {140, 139}}, // leftBP > rightBP
    };

    // 赋值 < 三元 < 逻辑或 < 逻辑与 < 位运算 < 比较 < 位移 < 加减 < 乘除 < 幂 < 一元

    // 一元运算符的优先级比所有二元运算符都高
    const std::unordered_map<Ast::Operator, Parser::Precedence> Parser::unaryOpPrecedence = {
        {Ast::Operator::Subtract, 150}, // -
        {Ast::Operator::BitNot, 150},   // ~
        {Ast::Operator::Not, 150},      // !
        {Ast::Operator::BitAnd, 150},   // &（取地址）
    };

    Ast::VarDef Parser::__parseVarDef(bool isPublic)
    {
        // entry: current is keyword `var` or `const`
        bool isConst = (currentToken().getType() == TokenType::Const ? true : false);
        next();
        expect(TokenType::Identifier);
        FString name = currentToken().getValue();
        next();
        Ast::Expression declaredType = nullptr;
        bool hasSpecificType = false;
        if (isThis(TokenType::Colon)) // :
        {
            next(); // consume `:`
            declaredType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
            hasSpecificType = true;
        }
        if (isThis(TokenType::Semicolon))
        {
            next(); // consume `;`, no using expectConsume here cause we don't need to check again
            return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, nullptr, false);
        }
        if (!isThis(TokenType::Assign) and !isThis(TokenType::Walrus)) expect(TokenType::Assign, u8"assign or walrus");
        bool followupType = false;

        if (isThis(TokenType::Walrus))
        {
            if (hasSpecificType) throwAddressableError<SyntaxError>(FString(u8""));
            followupType = true;
        }
        next();
        Ast::Expression exp = parseExpression(0);
        expectSemicolon();
        return makeAst<Ast::VarDefAst>(isPublic, isConst, name, declaredType, exp, followupType);
    }

    ObjectPtr Parser::__parseValue()
    {
        FString _val = currentToken().getValue();
        if (currentToken().getType() == TokenType::LiteralNumber)
        {
            if (_val.contains(u8'.') || _val.contains(u8'e'))
            {
                // 非整数
                ValueType::DoubleClass d;
                try
                {
                    d = std::stod(_val.toBasicString());
                }
                catch (...)
                {
                    throwAddressableError<SyntaxError>(FString(u8"Illegal number literal"));
                }
                return std::make_shared<Object>(d);
            }
            else
            {
                // 整数
                ValueType::IntClass i;
                try
                {
                    i = std::stoi(_val.toBasicString());
                }
                catch (...)
                {
                    throwAddressableError<SyntaxError>(FString(u8"Illegal number literal"));
                }
                return std::make_shared<Object>(i);
            }
        }
        else if (currentToken().getType() == TokenType::LiteralString) { return std::make_shared<Object>(_val); }
        else if (currentToken().getType() == TokenType::LiteralBool)
        {
            return std::make_shared<Object>((_val == u8"true" ? true : false));
        }
        else if (currentToken().getType() == TokenType::LiteralNull) { return Object::getNullInstance(); }
        else
        {
            throw std::runtime_error(std::string("Internal Error at: ") + std::string(__func__));
        }
    }

    Ast::ValueExpr Parser::__parseValueExpr()
    {
        return makeAst<Ast::ValueExprAst>(__parseValue());
    }
    Ast::FunctionParameters Parser::__parseFunctionParameters()
    {
        // entry: current is Token::LeftParen
        // stop: current is `)` next one
        // *note: must called when parsing function

        next(); // skip `(`

        Ast::FunctionParameters::PosParasType pp;
        Ast::FunctionParameters::DefParasType dp;
        FString variaPara;
        while (true)
        {
            if (isThis(TokenType::RightParen))
            {
                next();
                return Ast::FunctionParameters(pp, dp);
            }
            expect(TokenType::Identifier, FString(u8"Identifier or `)`")); // check current
            FString pname = currentToken().getValue();
            next();                        // skip pname
            if (isThis(TokenType::Assign)) // =
            {
                next();
                dp.push_back({pname, {makeAst<Ast::VarExprAst>(u8"Any"), parseExpression(0, TokenType::Comma)}});
                if (isThis(TokenType::Comma))
                {
                    next(); // only skip `,` when it's there
                }
            }
            else if (isThis(TokenType::Colon)) // :
            {
                next(); // skip `:`
                Ast::Expression type_exp = parseExpression(0, TokenType::Comma, TokenType::RightParen, TokenType::Assign);
                if (isThis(TokenType::Assign)) // =
                {
                    next(); // skip `=`
                    dp.push_back({pname, {type_exp, parseExpression(0, TokenType::Comma)}});
                    if (isThis(TokenType::Comma))
                    {
                        next(); // only skip `,` when it's there
                    }
                }
                else
                {
                    pp.push_back({pname, type_exp});
                    if (isThis(TokenType::Comma))
                    {
                        next(); // only skip `,` when it's there
                    }
                }
            }
            else if (isThis(TokenType::TripleDot))
            {
                variaPara = pname;
                next(); // skip `...`
                if (!isThis(TokenType::RightParen))
                    throwAddressableError<SyntaxError>(
                        u8"Expects right paren, variable parameter function can only have one parameter",
                        currentAAI.line,
                        currentAAI.column);
                next(); // skip `)`
                return Ast::FunctionParameters(variaPara);
            }
            else
            {
                pp.push_back({pname, makeAst<Ast::VarExprAst>(u8"Any")});
                if (isThis(TokenType::Comma))
                {
                    next(); // only skip `,` when it's there
                }
            }
        }
    }
    Ast::FunctionDef Parser::__parseFunctionDef(bool isPublic)
    {
        FString funcName = currentToken().getValue();
        next();
        expect(TokenType::LeftParen);
        Ast::FunctionParameters params = __parseFunctionParameters();

        Ast::Expression returnType;

        if (isThis(TokenType::RightArrow)) // ->
        {
            next(); // skip `->`
            returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);
        }
        expect(TokenType::LeftBrace);
        Ast::BlockStatement body = __parseBlockStatement();
        return makeAst<Ast::FunctionDefSt>(funcName, params, isPublic, returnType, body);
    }
    Ast::StructDef Parser::__parseStructDef(bool isPublic)
    {
        // entry: current is struct name
        FString structName = currentToken().getValue();
        next();
        expect(TokenType::LeftBrace, u8"struct body");
        next();
        bool braceClosed = false;

        /*
        public name
        public const name
        public final name

        const name
        final name

        name
        */

        auto __parseStructField = [this](bool isPublic) -> Ast::StructDefField {
            AccessModifier am = AccessModifier::Normal;
            FString fieldName;
            if (isThis(TokenType::Identifier))
            {
                fieldName = currentToken().getValue();
                next();
                am = (isPublic ? AccessModifier::Public : AccessModifier::Normal);
            }
            else if (isThis(TokenType::Const))
            {
                next();
                expect(TokenType::Identifier, u8"field name");
                fieldName = currentToken().getValue();
                am = (isPublic ? AccessModifier::PublicConst : AccessModifier::Const);
            }
            else
            {
                throwAddressableError<SyntaxError>(FString(std::format("expect field name or field attribute")));
            }
            Ast::Expression fieldType = nullptr;
            if (isThis(TokenType::Colon))
            {
                next(); // consume `:`
                fieldType = parseExpression(0, TokenType::Assign, TokenType::Semicolon);
            }
            Ast::Expression initExpr = nullptr;
            if (isThis(TokenType::Assign))
            {
                next();
                if (isEOF()) throwAddressableError<SyntaxError>(FString(u8"expect an expression"));
                initExpr = parseExpression(0);
            }
            expectSemicolon();
            return Ast::StructDefField(am, fieldName, fieldType, initExpr);
        };
        std::vector<Ast::Statement> stmts;
        std::vector<Ast::StructDefField> fields;

        while (!isEOF())
        {
            if (isThis(TokenType::RightBrace))
            {
                braceClosed = true;
                next(); // consume `}`
                break;
            }
            if (isThis(TokenType::Identifier)) { fields.push_back(__parseStructField(false)); }
            else if (isThis(TokenType::Public))
            {
                if (isNext(TokenType::Const))
                {
                    next();
                    fields.push_back(__parseStructField(true));
                }
                else if (isNext(TokenType::Function))
                {
                    next(); // consume `public`
                    next(); // consume `function`
                    stmts.push_back(__parseFunctionDef(true));
                }
                else if (isNext(TokenType::Struct))
                {
                    next(); // consume `public`
                    next(); // consume `struct`
                    stmts.push_back(__parseStructDef(true));
                }
                else if (isNext(TokenType::Identifier))
                {
                    next(); // consume `public`
                    fields.push_back(__parseStructField(true));
                }
                else
                {
                    throwAddressableError<SyntaxError>(FString("Invalid syntax"));
                }
            }
            else if (isThis(TokenType::Function))
            {
                next();
                stmts.push_back(__parseFunctionDef(false));
            }
            else if (isThis(TokenType::Struct))
            {
                next(); // consume `struct`
                stmts.push_back(__parseStructDef(false));
            }
            else if (isThis(TokenType::Const)) { fields.push_back(__parseStructField(false)); }
            else if (isThis(TokenType::Variable))
            {
                throwAddressableError<SyntaxError>(
                    FString("Variables are not allowed to be defined within a structure."));
            }
            else
            {
                throwAddressableError<SyntaxError>(FString("Invalid syntax"));
            }
        }
        if (!braceClosed) { throwAddressableError<SyntaxError>(FString("braces are not closed")); }
        return makeAst<Ast::StructDefSt>(isPublic, structName, fields, makeAst<Ast::BlockStatementAst>(stmts));
    }

    Ast::InterfaceDef Parser::__parseInterfaceDef(bool isPublic)
    {
        // entry: current is interface name
        FString interfaceName = currentToken().getValue();
        next();                       // consume name
        expect(TokenType::LeftBrace); // `{
        next();                       // consume `{`

        std::vector<Ast::InterfaceMethod> methods;

        while (true)
        {
            if (isThis(TokenType::RightBrace))
            {
                next(); // consume `}`
                break;
            }
            if (isThis(TokenType::Identifier))
            {
                FString funcName = currentToken().getValue();
                next(); // consume func name

                expect(TokenType::LeftParen);
                Ast::FunctionParameters paras = __parseFunctionParameters();

                expect(TokenType::RightArrow); // ->
                next();                        // consume `->`

                Ast::Expression returnType = parseExpression(0, TokenType::LeftBrace, TokenType::Semicolon);

                if (isThis(TokenType::LeftBrace))
                {
                    Ast::BlockStatement block = __parseBlockStatement();

                    methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType, block));
                    continue;
                }
                expectSemicolon();

                methods.push_back(Ast::InterfaceMethod(funcName, paras, returnType));
            }
            else
            {
                throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
            }
        }
        return makeAst<Ast::InterfaceDefAst>(interfaceName, methods, isPublic);
    }

    Ast::Implement Parser::__parseImplement()
    {
        // entry: current is `impl`
        next(); // consume `impl`
        expect(TokenType::Identifier, u8"interface name");
        FString interfaceName = currentToken().getValue();
        next(); // consume interface name

        expect(TokenType::For);
        next(); // consume `for`

        expect(TokenType::Identifier, u8"struct name");
        FString structName = currentToken().getValue();
        next();                       // consume name
        expect(TokenType::LeftBrace); // {
        next();                       // consume `{`

        std::vector<Ast::ImplementMethod> methods;

        while (true)
        {
            if (isThis(TokenType::RightBrace))
            {
                next(); // consume `}`
                break;
            }
            if (isThis(TokenType::Identifier))
            {
                FString funcName = currentToken().getValue();
                next(); // consume func name
                expect(TokenType::LeftParen);
                Ast::FunctionParameters paras = __parseFunctionParameters();
                expect(TokenType::LeftBrace);
                Ast::BlockStatement body = __parseBlockStatement();
                methods.push_back(Ast::ImplementMethod(funcName, paras, body));
            }
            else
            {
                throwAddressableError<SyntaxError>(FString(u8"Invalid syntax"), currentAAI.line, currentAAI.column);
            }
        }

        return makeAst<Ast::ImplementAst>(interfaceName, structName, methods);
    }

    Ast::Throw Parser::__parseThrow()
    {
        // entry: current is `throw`
        next(); // consume `throw`
        Ast::Expression exp = parseExpression(0);
        expect(TokenType::Semicolon);
        next(); // consume `;`
        return makeAst<Ast::ThrowSt>(exp);
    }

    Ast::Try Parser::__parseTry()
    {
        // entry: current is `try`
        next(); // consume `try`

        /*
        try
        {
            ...
        }
        catch(e: IOError)
        {
        }
        catch(e: TimeOutError)
        {
        }
        */
        expect(TokenType::LeftBrace);
        Ast::BlockStatement body = __parseBlockStatement();
        std::vector<Ast::Catch> catches;
        Ast::BlockStatement finallyBlock = nullptr;
        while (true)
        {
            if (isThis(TokenType::Catch))
            {
                next(); // consume `catch`
                expect(TokenType::LeftParen);
                next(); // consume `(`
                expect(TokenType::Identifier, u8"error receive var name");
                FString errVarName = currentToken().getValue();
                next(); // consume name

                bool hasType = false;
                FString errVarType;
                if (isThis(TokenType::Colon)) // :
                {
                    next();
                    expect(TokenType::Identifier, u8"error type");
                    errVarType = currentToken().getValue();
                    next(); // consume var type
                    hasType = true;
                }
                expect(TokenType::RightParen); // ）
                next();                        // consume `)`
                expect(TokenType::LeftBrace);  // {
                Ast::BlockStatement catchBody = __parseBlockStatement();

                if (hasType) { catches.push_back(Ast::Catch(errVarName, errVarType, catchBody)); }
                else
                {
                    catches.push_back(Ast::Catch(errVarName, catchBody));
                }
            }
            else if (isThis(TokenType::Finally))
            {
                if (finallyBlock != nullptr)
                {
                    throwAddressableError<SyntaxError>(
                        u8"Duplicate try finally-block", currentAAI.line, currentAAI.column);
                }
                next(); // consume `finally`
                expect(TokenType::LeftBrace);
                finallyBlock = __parseBlockStatement();
            }
            else
            {
                break;
            }
        }
        return makeAst<Ast::TrySt>(body, catches, finallyBlock);
    }

    Ast::Statement Parser::__parseStatement(bool allowExp)
    {
        Ast::Statement stmt;
        if (isThis(TokenType::EndOfFile)) { return makeAst<Ast::EofStmt>(); }
        else if (isThis(TokenType::Import)) { stmt = __parseImport(); }
        else if (isThis(TokenType::Public))
        {
            next(); // consume `public`
            if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(true); }
            else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
            {
                next();
                stmt = __parseFunctionDef(true);
            }
            else if (isThis(TokenType::Struct))
            {
                next();
                stmt = __parseStructDef(true);
            }
            else if (isThis(TokenType::Interface)) { stmt = __parseInterfaceDef(true); }
            else
            {
                throwAddressableError<SyntaxError>(
                    FString(u8"Expected `var`, `const`, `function`, `struct` or `interface` after `public`"));
            }
        }
        else if (isThis(TokenType::Variable) || isThis(TokenType::Const)) { stmt = __parseVarDef(false); }
        else if (isThis(TokenType::Function) and isNext(TokenType::Identifier))
        {
            next();
            stmt = __parseFunctionDef(false);
        }
        else if (isThis(TokenType::Struct))
        {
            expectPeek(TokenType::Identifier, u8"struct name");
            next();
            stmt = __parseStructDef(false);
        }
        else if (isThis(TokenType::Interface))
        {
            expectPeek(TokenType::Identifier, u8"interface name");
            next();
            stmt = __parseInterfaceDef(false);
        }
        else if (isThis(TokenType::Implement)) { stmt = __parseImplement(); }
        else if (isThis(TokenType::If)) { stmt = __parseIf(); }
        else if (isThis(TokenType::Else))
        {
            throwAddressableError<SyntaxError>(FString(u8"`else` without matching `if`"));
        }
        else if (isThis(TokenType::LeftBrace)) { stmt = __parseBlockStatement(); }
        else if (isThis(TokenType::While)) { stmt = __parseWhile(); }
        else if (isThis(TokenType::For)) { stmt = __parseFor(); }
        else if (isThis(TokenType::Return)) { stmt = __parseReturn(); }
        else if (isThis(TokenType::Break)) { stmt = __parseBreak(); }
        else if (isThis(TokenType::Continue)) { stmt = __parseContinue(); }
        else if (isThis(TokenType::Throw)) { stmt = __parseThrow(); }
        else if (isThis(TokenType::Try)) { stmt = __parseTry(); }
        else if (allowExp)
        {
            // expression statement
            Ast::Expression exp = parseExpression(0);
            expectSemicolon();
            stmt = makeAst<Ast::ExpressionStmtAst>(exp);
        }
        else
        {
            throwAddressableError<SyntaxError>(u8"invalid syntax", currentAAI.line, currentAAI.column);
        }
        return stmt;
    }
    Ast::BlockStatement Parser::__parseBlockStatement()
    {
        // entry: current is `{`
        // stop: current is `}` next one
        next(); // consume `{`
        std::vector<Ast::Statement> stmts;
        while (true)
        {
            if (isThis(TokenType::RightBrace))
            {
                next();
                return makeAst<Ast::BlockStatementAst>(stmts);
            }
            stmts.push_back(__parseStatement());
        }
    }
    Ast::If Parser::__parseIf()
    {
        // entry: current is `if`
        next(); // consume `if`
        Ast::Expression condition;
        if (isThis(TokenType::LeftParen))
        {
            next(); // consume `(`
            condition = parseExpression(0, TokenType::RightParen);
            expect(TokenType::RightParen);
            next(); // consume `)`
        }
        else
        {
            condition = parseExpression(0, TokenType::LeftBrace);
        }
        // parenthesis is not required
        expect(TokenType::LeftBrace); // {
        Ast::BlockStatement body = __parseBlockStatement();
        std::vector<Ast::ElseIf> elifs;
        Ast::Else els = nullptr;
        while (isThis(TokenType::Else))
        {
            next(); // consume `else`
            if (isThis(TokenType::If))
            {
                // else if
                next(); // consume `if`
                Ast::Expression elifCondition;
                if (isThis(TokenType::LeftParen))
                {
                    elifCondition = parseExpression(0, TokenType::RightParen);
                    expect(TokenType::RightParen);
                    next(); // consume `)`
                }
                else
                {
                    elifCondition = parseExpression(0, TokenType::LeftBrace);
                }
                expect(TokenType::LeftBrace); // {
                Ast::BlockStatement elifBody = __parseBlockStatement();
                elifs.push_back(makeAst<Ast::ElseIfSt>(elifCondition, elifBody));
            }
            else
            {
                expect(TokenType::LeftBrace); // {
                Ast::BlockStatement elseBody = __parseBlockStatement();
                els = makeAst<Ast::ElseSt>(elseBody);
                break;
            }
        }
        return makeAst<Ast::IfSt>(condition, body, elifs, els);
    }
    Ast::While Parser::__parseWhile()
    {
        // entry: current is `while`
        next(); // consume `while`
        Ast::Expression condition;
        if (isThis(TokenType::LeftParen))
        {
            next(); // consume `(`
            condition = parseExpression(0, TokenType::RightParen);
            expect(TokenType::RightParen);
            next(); // consume `)`
        }
        else
        {
            condition = parseExpression(0, TokenType::LeftBrace);
        }
        expect(TokenType::LeftBrace); // {
        Ast::BlockStatement body = __parseBlockStatement();
        return makeAst<Ast::WhileSt>(condition, body);
    }
    Ast::Statement Parser::__parseIncrementStatement()
    {
        // allowed：
        // 1. assignment：i = 1, i += 1
        // 2. expression stmt：i++, foo()
        // ❌ not allowed：if/while/for/block stmt

        if (isThis(TokenType::LeftBrace))
        {
            throwAddressableError<SyntaxError>(u8"BlockStatement cannot be used as for loop increment");
        }

        if (isThis(TokenType::If) || isThis(TokenType::While) || isThis(TokenType::For) || isThis(TokenType::Return)
            || isThis(TokenType::Break) || isThis(TokenType::Continue))
        {
            throwAddressableError<SyntaxError>(u8"Control flow statements cannot be used as for loop increment");
        }

        Ast::Expression exp = parseExpression(0, TokenType::LeftBrace);
        // expectSemicolon(); we dont check the semicolon
        return makeAst<Ast::ExpressionStmtAst>(exp);
    }
    Ast::For Parser::__parseFor()
    {
        // entry: current is `for`
        // TODO: support enumeration
        next(); // consume `for`
        bool paren = isThis(TokenType::LeftParen);
        if (paren) next(); // consume `(`
        // support 3-part for loop
        // for init; condition; increment {}
        Ast::Statement initStmt = __parseStatement(false); // auto check ``
        Ast::Expression condition = parseExpression(0);
        expectSemicolon(); // auto consume `;`

        Ast::Statement incrementStmt = nullptr;
        if (!isThis(paren ? TokenType::RightParen : TokenType::LeftBrace)) // need parse increment?
        {
            // auto guard = disableSemicolon();
            incrementStmt = __parseIncrementStatement();
        } // after parse increment, semicolon check state restored
        if (paren) expectConsume(TokenType::RightParen);    // consume `)` if has `(`
        expect(TokenType::LeftBrace);                       // {
        Ast::BlockStatement body = __parseBlockStatement(); // auto consume `}`
        return makeAst<Ast::ForSt>(initStmt, condition, incrementStmt, body);
    }
    Ast::Return Parser::__parseReturn()
    {
        // entry: current is `return`
        next(); // consume `return`
        Ast::Expression retValue = parseExpression(0);
        expectSemicolon();
        return makeAst<Ast::ReturnSt>(retValue);
    }
    Ast::Continue Parser::__parseContinue()
    {
        // entry: current is `continue`
        next(); // consume `continue`
        expectSemicolon();
        return makeAst<Ast::ContinueSt>();
    }
    Ast::Break Parser::__parseBreak()
    {
        // entry: current is `break`
        next(); // consume `break`
        expectSemicolon();
        return makeAst<Ast::BreakSt>();
    }

    Ast::VarExpr Parser::__parseVarExpr(FString name)
    {
        return makeAst<Ast::VarExprAst>(name);
    }

    Ast::UnaryExpr Parser::__parsePrefix(Ast::Operator op, Precedence bp)
    {
        return makeAst<Ast::UnaryExprAst>(op, parseExpression(bp));
    }
    Ast::BinaryExpr Parser::__parseInfix(Ast::Expression lhs, Ast::Operator op, Precedence bp)
    {
        return makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(bp));
    }

    Ast::Expression Parser::__parseCall(Ast::Expression callee)
    {
        next(); // consume '('
        std::vector<Ast::Expression> args;

        if (!isThis(TokenType::RightParen))
        {
            while (true)
            {
                args.push_back(parseExpression(0, TokenType::Comma, TokenType::RightParen));

                if (isThis(TokenType::Comma))
                {
                    next();
                    continue;
                }
                break;
            }
        }

        expect(TokenType::RightParen);
        next(); // consume ')'

        return makeAst<Ast::FunctionCallExpr>(callee, Ast::FunctionArguments(args));
    }

    Ast::ListExpr Parser::__parseListExpr()
    {
        // entry: current is `[`
        next(); // consume `[`
        std::vector<Ast::Expression> val;
        while (!isThis(TokenType::RightBracket))
        {
            val.push_back(parseExpression(0, TokenType::RightBracket, TokenType::Comma));
            if (isThis(TokenType::Comma))
            {
                next(); // consume `,`
            }
        }
        expect(TokenType::RightBracket);
        next(); // consume `]`
        return makeAst<Ast::ListExprAst>(val);
    }

    Ast::MapExpr Parser::__parseMapExpr()
    {
        // entry: current is `{`
        next(); // consume `{`
        std::map<Ast::Expression, Ast::Expression> val;
        while (!isThis(TokenType::RightBrace))
        {
            Ast::Expression key = parseExpression(0, TokenType::Colon);
            expect(TokenType::Colon);
            next(); // consume `:`
            val[key] = parseExpression(0, TokenType::RightBrace, TokenType::Comma);
            if (isThis(TokenType::Comma))
            {
                next(); // consume `,`
            }
        }
        expect(TokenType::RightBrace);
        next(); // consume `}`
        return makeAst<Ast::MapExprAst>(val);
    }

    Ast::InitExpr Parser::__parseInitExpr(Ast::Expression structe)
    {
        // entry: current is `{`
        next(); // consume `{`
        std::vector<std::pair<FString, Ast::Expression>> args;
        /*
        3 ways of calling constructor
        .1 Person {"Fig", 1, "IDK"};
        .2 Person {name: "Fig", age: 1, sex: "IDK"}; // can be unordered
        .3 Person {name, age, sex};
        */
        uint8_t mode = 0; // 0=undetermined, 1=positional, 2=named, 3=shorthand

        while (!isThis(TokenType::RightBrace))
        {
            if (mode == 0)
            {
                if (isThis(TokenType::Identifier) && isNext(TokenType::Colon)) { mode = 2; }
                else if (isThis(TokenType::Identifier) && (isNext(TokenType::Comma) || isNext(TokenType::RightBrace)))
                {
                    mode = 3;
                }
                else
                {
                    mode = 1;
                }
            }

            if (mode == 1)
            {
                // 1 Person {"Fig", 1, "IDK"};
                Ast::Expression expr = parseExpression(0, TokenType::Comma, TokenType::RightBrace);
                args.push_back({FString(), std::move(expr)});
            }
            else if (mode == 2)
            {
                // 2 Person {name: "Fig", age: 1, sex: "IDK"};
                expect(TokenType::Identifier);
                FString fieldName = currentToken().getValue();
                next(); // consume identifier
                expect(TokenType::Colon);
                next(); // consume colon
                Ast::Expression expr = parseExpression(0, TokenType::Comma, TokenType::RightBrace);
                args.push_back({fieldName, std::move(expr)});
            }
            else if (mode == 3)
            {
                // 3 Person {name, age, sex};
                expect(TokenType::Identifier);
                FString fieldName = currentToken().getValue();
                Ast::Expression expr = makeAst<Ast::VarExprAst>(fieldName);
                args.push_back({fieldName, std::move(expr)});
                next(); // consume identifier
            }

            if (isThis(TokenType::Comma))
            {
                next(); // consume comma
            }
            else if (!isThis(TokenType::RightBrace))
            {
                throwAddressableError<SyntaxError>(
                    FString(std::format("Expect `,` or `}}` in struct initialization expression, got {}",
                                        currentToken().toString().toBasicString())));
            }
        }
        expect(TokenType::RightBrace);
        next(); // consume `}`
        return makeAst<Ast::InitExprAst>(
            structe,
            args,
            static_cast<Ast::InitExprAst::InitMode>(mode));
    }

    Ast::Expression Parser::__parseTupleOrParenExpr()
    {
        next();

        if (currentToken().getType() == TokenType::RightParen)
        {
            next(); // consume ')'
            return makeAst<Ast::TupleExprAst>();
        }

        Ast::Expression firstExpr = parseExpression(0);

        if (currentToken().getType() == TokenType::Comma)
        {
            std::vector<Ast::Expression> elements;
            elements.push_back(firstExpr);

            while (currentToken().getType() == TokenType::Comma)
            {
                next(); // consume ','

                if (currentToken().getType() == TokenType::RightParen) break;

                elements.push_back(parseExpression(0));
            }

            expect(TokenType::RightParen);
            next(); // consume ')'

            return makeAst<Ast::TupleExprAst>(std::move(elements));
        }
        else if (currentToken().getType() == TokenType::RightParen)
        {
            next(); // consume ')'
            return firstExpr;
        }
        else
        {
            throwAddressableError<SyntaxError>(FString(u8"Expect ')' or ',' after expression in parentheses"));
        }
        return nullptr; // to suppress compiler warning
    }

    Ast::FunctionLiteralExpr Parser::__parseFunctionLiteralExpr()
    {
        // entry: current is Token::LeftParen and last is Token::Function
        /*
        Function literal:
            func (params){...}
            or
            func (params) => <expression>
        */
        Ast::FunctionParameters params = __parseFunctionParameters();
        if (isThis(TokenType::DoubleArrow)) // =>
        {
            next();
            Ast::Expression bodyExpr = parseExpression(0);
            return makeAst<Ast::FunctionLiteralExprAst>(params, bodyExpr);
        }
        expect(TokenType::LeftBrace); // `{`
        return makeAst<Ast::FunctionLiteralExprAst>(params, __parseBlockStatement());
    }

    Ast::Import Parser::__parseImport()
    {
        next(); // consume `import`
        std::vector<FString> path;
        while (true)
        {
            expect(TokenType::Identifier, u8"package name");
            path.push_back(currentToken().getValue());
            next(); // consume package name
            if (isThis(TokenType::Semicolon)) { break; }
            else if (isThis(TokenType::Dot))
            {
                next(); // consume `.`
            }
            else
            {
                throw SyntaxError();
            }
        }
        expectSemicolon();
        return makeAst<Ast::ImportSt>(path);
    }

    Ast::Expression Parser::parseExpression(Precedence bp, TokenType stop, TokenType stop2, TokenType stop3)
    {
        Ast::Expression lhs;
        Ast::Operator op;

        Token tok = currentToken();
        if (tok == EOFTok) throwAddressableError<SyntaxError>(FString(u8"Unexpected end of expression"));
        if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3)
        {
            if (lhs == nullptr) throwAddressableError<SyntaxError>(FString(u8"Expected expression"));
            return lhs;
        }
        if (tok.getType() == TokenType::LeftBracket)
        {
            lhs = __parseListExpr(); // auto consume
        }
        else if (tok.getType() == TokenType::LeftParen)
        {
            lhs = __parseTupleOrParenExpr(); // auto consume
        }
        else if (tok.getType() == TokenType::LeftBrace)
        {
            lhs = __parseMapExpr(); // auto consume
        }
        else if (tok.getType() == TokenType::Function)
        {
            next(); // consume `function`
            if (currentToken().getType() == TokenType::Identifier)
            {
                // err
                throwAddressableError<SyntaxError>(FString(u8"Function literal should not have a name"));
            }
            expect(TokenType::LeftParen);
            lhs = __parseFunctionLiteralExpr();
        }
        else if (tok.isLiteral())
        {
            lhs = __parseValueExpr();
            next();
        }
        else if (tok.isIdentifier())
        {
            FString id = tok.getValue();
            next();
            lhs = __parseVarExpr(id);
        }
        else if (isTokenOp(tok) && isOpUnary((op = Ast::TokenToOp.at(tok.getType()))))
        {
            // prefix
            next();
            lhs = makeAst<Ast::UnaryExprAst>(op, parseExpression(bp, stop, stop2));
        }
        else if (tok.getType() == TokenType::New)
        {
            // `new` now is an independent syntax
            next();
            Ast::Expression operand = parseExpression(bp, TokenType::LeftBrace);
            expect(TokenType::LeftBrace);
            lhs = __parseInitExpr(operand);
        }
        else
        {
            throwAddressableError<SyntaxError>(FString(u8"Unexpected token in expression:") + tok.toString());
        }

        // infix / (postfix) ?
        while (true)
        {
            tok = currentToken();
            if (tok.getType() == stop || tok.getType() == stop2 || tok.getType() == stop3 || tok == EOFTok) break;

            /* Postfix */

            if (tok.getType() == TokenType::LeftBrace)
            {
                throwAddressableError<SyntaxError>(
                    FString(u8"Since Fig v0.4.2, please use new struct{} to avoid syntax ambiguity"));
            }

            if (tok.getType() == TokenType::LeftParen)
            {
                lhs = __parseCall(lhs);
                continue;
            }
            // else if (tok.getType() == TokenType::LeftBrace) { lhs = __parseInitExpr(lhs); }
            /*
                since Fig v0.4.2, use new struct{};

                if a == A{}
                is A{} struct init?
                or A a variable, {} is the body?

                fuck.
            */

            // member access: a.b
            if (tok.getType() == TokenType::Dot)
            {
                next(); // consume '.'
                Token idTok = currentToken();
                if (!idTok.isIdentifier())
                    throwAddressableError<SyntaxError>(FString(u8"Expected identifier after '.'"));

                FString member = idTok.getValue();
                next(); // consume identifier

                lhs = makeAst<Ast::MemberExprAst>(lhs, member);
                continue;
            }
            // index: x[expr]
            if (tok.getType() == TokenType::LeftBracket)
            {
                next(); // consume '['
                auto indexExpr = parseExpression(0, TokenType::RightBracket, stop2);
                expect(TokenType::RightBracket);
                next(); // consume ']'

                lhs = makeAst<Ast::IndexExprAst>(lhs, indexExpr);
                continue;
            }
            // ternary
            if (tok.getType() == TokenType::Question)
            {
                auto [lbp, rbp] = getBindingPower(Ast::Operator::TernaryCond);
                if (bp >= lbp) break;

                next(); // consume ?
                Ast::Expression trueExpr = parseExpression(0, TokenType::Colon);
                expectConsume(TokenType::Colon);

                Ast::Expression falseExpr = parseExpression(0);
                lhs = makeAst<Ast::TernaryExprAst>(lhs, trueExpr, falseExpr);
                continue;
            }

            if (!isTokenOp(tok)) break;

            op = Ast::TokenToOp.at(tok.getType());
            auto [lbp, rbp] = getBindingPower(op);
            if (bp >= lbp) break;

            next(); // consume op
            lhs = makeAst<Ast::BinaryExprAst>(lhs, op, parseExpression(rbp, stop, stop2));
        }

        return lhs;
    }

    std::vector<Ast::AstBase> Parser::parseAll()
    {
        output.clear();
        Token tok = currentToken();
        if (tok == EOFTok) { return output; }

        while (!isEOF())
        {
            auto stmt = __parseStatement();
            if (!output.empty() && stmt->getType() == Ast::AstType::PackageSt)
            {
                throwAddressableError<SyntaxError>(
                    u8"Package must be at the beginning of the file", currentAAI.line, currentAAI.column);
            }
            pushNode(stmt);
        }
        return output;
    }

} // namespace Fig