"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
const types_1 = require("./types");
const lexer_1 = require("./lexer");
const import_handler_1 = require("./handlers/import-handler");
const declaration_handler_1 = require("./handlers/declaration-handler");
const loop_handler_1 = require("./handlers/loop-handler");
class Parser {
    constructor(tokens) {
        this.current = 0;
        this.errors = [];
        this.tokens = tokens;
        this.importHandler = new import_handler_1.ImportHandler(this);
        this.declarationHandler = new declaration_handler_1.DeclarationHandler(this);
        this.loopHandler = new loop_handler_1.LoopHandler(this);
    }
    getErrors() {
        return this.errors;
    }
    parse() {
        const body = [];
        this.errors = []; // Reset errors
        while (!this.isAtEnd()) {
            const stmt = this.statement();
            if (stmt) {
                body.push(stmt);
            }
            // Don't advance here - statement() handles its own token consumption
        }
        return {
            type: 'Program',
            body,
            line: 1,
            column: 1,
        };
    }
    statement() {
        try {
            if (this.match(types_1.TokenType.NEWLINE)) {
                return null;
            }
            const parsers = [
                () => this.importHandler.parseStatement(),
                () => this.declarationHandler.parseStatement(),
                () => this.loopHandler.parseStatement(),
                () => (this.match(types_1.TokenType.КӮШИШ) ? this.tryStatement() : null),
                () => (this.match(types_1.TokenType.ПАРТОФТАН) ? this.throwStatement() : null),
                () => (this.match(types_1.TokenType.АГАР) ? this.ifStatement() : null),
                () => (this.match(types_1.TokenType.ИНТИХОБ) ? this.switchStatement() : null),
                () => (this.match(types_1.TokenType.ШИКАСТАН) ? this.breakStatement() : null),
                () => (this.match(types_1.TokenType.ДАВОМ) ? this.continueStatement() : null),
                () => (this.match(types_1.TokenType.БОЗГАШТ) ? this.returnStatement() : null),
                () => (this.match(types_1.TokenType.LEFT_BRACE) ? this.blockStatement() : null),
            ];
            for (const parse of parsers) {
                const result = parse();
                if (result) {
                    return result;
                }
            }
            return this.expressionStatement();
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            this.errors.push(errorMessage);
            this.synchronize();
            return null;
        }
    }
    variableDeclaration() {
        const kindToken = this.previous();
        const kind = kindToken.type === types_1.TokenType.ТАҒЙИРЁБАНДА ? 'ТАҒЙИРЁБАНДА' : 'СОБИТ';
        // Parse pattern (identifier, array destructuring, or object destructuring)
        const identifier = this.parsePattern();
        // Parse optional type annotation
        let typeAnnotation;
        if (this.match(types_1.TokenType.COLON)) {
            typeAnnotation = this.typeAnnotation();
        }
        let init;
        if (this.match(types_1.TokenType.ASSIGN)) {
            init = this.expression();
        }
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after variable declaration");
        return {
            type: 'VariableDeclaration',
            kind,
            identifier,
            typeAnnotation,
            init,
            line: kindToken.line,
            column: kindToken.column,
        };
    }
    functionDeclaration() {
        const funcToken = this.previous();
        let name;
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            name = this.advance();
        }
        else if (this.matchBuiltinIdentifier()) {
            name = this.previous();
        }
        else {
            throw new Error(`Expected function name at line ${this.peek().line}, column ${this.peek().column}`);
        }
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after function name");
        // Skip any newlines after opening parenthesis
        while (this.match(types_1.TokenType.NEWLINE)) {
            // Skip newlines
        }
        const params = [];
        if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
            do {
                const param = this.parseParameter();
                params.push(param);
                // Skip any newlines after parameter before checking for comma
                while (this.match(types_1.TokenType.NEWLINE)) {
                    // Skip newlines
                }
            } while (this.match(types_1.TokenType.COMMA) &&
                (() => {
                    // Skip any newlines after comma
                    while (this.match(types_1.TokenType.NEWLINE)) {
                        // Skip newlines
                    }
                    return true;
                })());
        }
        // Skip any newlines before closing parenthesis
        while (this.match(types_1.TokenType.NEWLINE)) {
            // Skip newlines
        }
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after parameters");
        // Parse optional return type
        let returnType;
        if (this.match(types_1.TokenType.COLON)) {
            returnType = this.typeAnnotation();
        }
        this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' before function body");
        const body = this.blockStatement();
        return {
            type: 'FunctionDeclaration',
            name: {
                type: 'Identifier',
                name: name.value,
                line: name.line,
                column: name.column,
            },
            params,
            returnType,
            body,
            line: funcToken.line,
            column: funcToken.column,
        };
    }
    blockStatement() {
        const leftBrace = this.previous();
        const body = [];
        // Skip any newlines after opening brace
        while (this.match(types_1.TokenType.NEWLINE)) {
            // Skip newlines
        }
        while (!this.check(types_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
            const stmt = this.statement();
            if (stmt) {
                body.push(stmt);
            }
        }
        this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after block");
        return {
            type: 'BlockStatement',
            body,
            line: leftBrace.line,
            column: leftBrace.column,
        };
    }
    ifStatement() {
        const ifToken = this.previous();
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'агар'");
        const test = this.expression();
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after if condition");
        const consequent = this.statement();
        let alternate;
        if (this.match(types_1.TokenType.ВАГАРНА)) {
            alternate = this.statement();
        }
        return {
            type: 'IfStatement',
            test,
            consequent,
            alternate,
            line: ifToken.line,
            column: ifToken.column,
        };
    }
    whileStatement() {
        const whileToken = this.previous();
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'то'");
        const test = this.expression();
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after while condition");
        const body = this.statement();
        return {
            type: 'WhileStatement',
            test,
            body,
            line: whileToken.line,
            column: whileToken.column,
        };
    }
    forStatement() {
        const forToken = this.previous();
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'барои'");
        // Parse init (variable declaration)
        let init = null;
        if (this.match(types_1.TokenType.ТАҒЙИРЁБАНДА)) {
            init = this.variableDeclaration();
        }
        else if (!this.check(types_1.TokenType.SEMICOLON)) {
            init = this.expressionStatement();
        }
        // Consume semicolon after init (if not already consumed by variable declaration)
        if (init && init.type !== 'VariableDeclaration') {
            // ExpressionStatement already consumed the semicolon
        }
        else if (!init) {
            this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after for loop initializer");
        }
        // Parse test condition
        let test = null;
        if (!this.check(types_1.TokenType.SEMICOLON)) {
            test = this.expression();
        }
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after for loop condition");
        // Parse update expression
        let update = null;
        if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
            update = this.expression();
        }
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after for clauses");
        // Parse body
        const body = this.statement();
        return {
            type: 'ForStatement',
            init,
            test,
            update,
            body,
            line: forToken.line,
            column: forToken.column,
        };
    }
    returnStatement() {
        const returnToken = this.previous();
        let argument;
        if (!this.check(types_1.TokenType.SEMICOLON) && !this.check(types_1.TokenType.NEWLINE)) {
            argument = this.expression();
        }
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after return value");
        return {
            type: 'ReturnStatement',
            argument,
            line: returnToken.line,
            column: returnToken.column,
        };
    }
    expressionStatement() {
        const expr = this.expression();
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after expression");
        return {
            type: 'ExpressionStatement',
            expression: expr,
            line: expr.line,
            column: expr.column,
        };
    }
    expression() {
        return this.assignment();
    }
    assignment() {
        const expr = this.or();
        if (this.match(types_1.TokenType.ASSIGN, types_1.TokenType.PLUS_ASSIGN, types_1.TokenType.MINUS_ASSIGN, types_1.TokenType.MULTIPLY_ASSIGN, types_1.TokenType.DIVIDE_ASSIGN, types_1.TokenType.MODULO_ASSIGN, types_1.TokenType.BITWISE_AND_ASSIGN, types_1.TokenType.BITWISE_OR_ASSIGN, types_1.TokenType.BITWISE_XOR_ASSIGN, types_1.TokenType.LEFT_SHIFT_ASSIGN, types_1.TokenType.RIGHT_SHIFT_ASSIGN, types_1.TokenType.UNSIGNED_RIGHT_SHIFT_ASSIGN)) {
            const operator = this.previous();
            const value = this.assignment();
            return {
                type: 'AssignmentExpression',
                left: expr,
                operator: operator.value,
                right: value,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    or() {
        let expr = this.and();
        while (this.match(types_1.TokenType.OR)) {
            const operator = this.previous();
            const right = this.and();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    and() {
        let expr = this.bitwiseOr();
        while (this.match(types_1.TokenType.AND)) {
            const operator = this.previous();
            const right = this.bitwiseOr();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    bitwiseOr() {
        let expr = this.bitwiseXor();
        while (this.match(types_1.TokenType.BITWISE_OR)) {
            const operator = this.previous();
            const right = this.bitwiseXor();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    bitwiseXor() {
        let expr = this.bitwiseAnd();
        while (this.match(types_1.TokenType.BITWISE_XOR)) {
            const operator = this.previous();
            const right = this.bitwiseAnd();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    bitwiseAnd() {
        let expr = this.equality();
        while (this.match(types_1.TokenType.BITWISE_AND)) {
            const operator = this.previous();
            const right = this.equality();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    equality() {
        let expr = this.comparison();
        while (this.match(types_1.TokenType.EQUAL, types_1.TokenType.NOT_EQUAL)) {
            const operator = this.previous();
            const right = this.comparison();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    comparison() {
        let expr = this.shift();
        while (this.match(types_1.TokenType.GREATER_THAN, types_1.TokenType.GREATER_EQUAL, types_1.TokenType.LESS_THAN, types_1.TokenType.LESS_EQUAL)) {
            const operator = this.previous();
            const right = this.shift();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    shift() {
        let expr = this.term();
        while (this.match(types_1.TokenType.LEFT_SHIFT, types_1.TokenType.RIGHT_SHIFT, types_1.TokenType.UNSIGNED_RIGHT_SHIFT)) {
            const operator = this.previous();
            const right = this.term();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    term() {
        let expr = this.factor();
        while (this.match(types_1.TokenType.MINUS, types_1.TokenType.PLUS)) {
            const operator = this.previous();
            const right = this.factor();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    factor() {
        let expr = this.unary();
        while (this.match(types_1.TokenType.DIVIDE, types_1.TokenType.MULTIPLY, types_1.TokenType.MODULO)) {
            const operator = this.previous();
            const right = this.unary();
            expr = {
                type: 'BinaryExpression',
                left: expr,
                operator: operator.value,
                right,
                line: expr.line,
                column: expr.column,
            };
        }
        return expr;
    }
    unary() {
        if (this.match(types_1.TokenType.NOT, types_1.TokenType.MINUS, types_1.TokenType.BITWISE_NOT)) {
            const operator = this.previous();
            const right = this.unary();
            return {
                type: 'UnaryExpression',
                operator: operator.value,
                argument: right,
                line: operator.line,
                column: operator.column,
            };
        }
        if (this.match(types_1.TokenType.ИНТИЗОР)) {
            const awaitToken = this.previous();
            const argument = this.unary();
            return {
                type: 'AwaitExpression',
                argument,
                line: awaitToken.line,
                column: awaitToken.column,
            };
        }
        if (this.match(types_1.TokenType.НАВ)) {
            const newToken = this.previous();
            const callee = this.primary();
            // Check if there are arguments
            const args = [];
            if (this.match(types_1.TokenType.LEFT_PAREN)) {
                if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
                    do {
                        args.push(this.expression());
                    } while (this.match(types_1.TokenType.COMMA));
                }
                this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after arguments");
            }
            return {
                type: 'NewExpression',
                callee,
                arguments: args,
                line: newToken.line,
                column: newToken.column,
            };
        }
        return this.call();
    }
    call() {
        let expr = this.primary();
        // eslint-disable-next-line no-constant-condition
        while (true) {
            if (this.match(types_1.TokenType.LEFT_PAREN)) {
                expr = this.finishCall(expr);
            }
            else if (this.match(types_1.TokenType.DOT)) {
                let name;
                if (this.check(types_1.TokenType.IDENTIFIER)) {
                    name = this.advance();
                }
                else if (this.matchBuiltinIdentifier()) {
                    name = this.previous();
                }
                else {
                    throw new Error(`Expected property name after '.' at line ${this.peek().line}, column ${this.peek().column}`);
                }
                expr = {
                    type: 'MemberExpression',
                    object: expr,
                    property: {
                        type: 'Identifier',
                        name: name.value,
                        line: name.line,
                        column: name.column,
                    },
                    computed: false,
                    line: expr.line,
                    column: expr.column,
                };
            }
            else if (this.match(types_1.TokenType.LEFT_BRACKET)) {
                // Computed member expression: obj[expr]
                const property = this.expression();
                this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after computed property");
                expr = {
                    type: 'MemberExpression',
                    object: expr,
                    property: property,
                    computed: true,
                    line: expr.line,
                    column: expr.column,
                };
            }
            else if (this.match(types_1.TokenType.INCREMENT, types_1.TokenType.DECREMENT)) {
                // Postfix increment/decrement
                const operator = this.previous();
                expr = {
                    type: 'UpdateExpression',
                    operator: operator.value,
                    argument: expr,
                    prefix: false,
                    line: expr.line,
                    column: expr.column,
                };
            }
            else {
                break;
            }
        }
        return expr;
    }
    finishCall(callee) {
        const args = [];
        if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
            do {
                args.push(this.expression());
            } while (this.match(types_1.TokenType.COMMA));
        }
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after arguments");
        return {
            type: 'CallExpression',
            callee,
            arguments: args,
            line: callee.line,
            column: callee.column,
        };
    }
    // eslint-disable-next-line complexity
    primary() {
        if (this.match(types_1.TokenType.ДУРУСТ)) {
            const token = this.previous();
            return {
                type: 'Literal',
                value: true,
                raw: token.value,
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.НОДУРУСТ)) {
            const token = this.previous();
            return {
                type: 'Literal',
                value: false,
                raw: token.value,
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.ХОЛӢ)) {
            const token = this.previous();
            return {
                type: 'Literal',
                value: null,
                raw: token.value,
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.NUMBER)) {
            const token = this.previous();
            return {
                type: 'Literal',
                value: parseFloat(token.value),
                raw: token.value,
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.STRING)) {
            const token = this.previous();
            return {
                type: 'Literal',
                value: token.value,
                raw: `"${token.value}"`,
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.TEMPLATE_LITERAL)) {
            return this.parseTemplateLiteral();
        }
        if (this.match(types_1.TokenType.ИН)) {
            const token = this.previous();
            return {
                type: 'ThisExpression',
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.СУПЕР)) {
            const token = this.previous();
            return {
                type: 'Super',
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.НАВ)) {
            const token = this.previous();
            const callee = this.primary();
            this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'нав'");
            const args = [];
            if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
                do {
                    args.push(this.expression());
                } while (this.match(types_1.TokenType.COMMA));
            }
            this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after arguments");
            return {
                type: 'NewExpression',
                callee: callee,
                arguments: args,
                line: token.line,
                column: token.column,
            };
        }
        // Dynamic import: ворид(specifier)
        if (this.check(types_1.TokenType.ВОРИД) && this.peekNext()?.type === types_1.TokenType.LEFT_PAREN) {
            const importToken = this.advance();
            this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'ворид'");
            const source = this.expression();
            this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after import specifier");
            return {
                type: 'ImportExpression',
                source,
                line: importToken.line,
                column: importToken.column,
            };
        }
        if (this.match(types_1.TokenType.IDENTIFIER) || this.matchBuiltinIdentifier()) {
            const token = this.previous();
            return {
                type: 'Identifier',
                name: token.value,
                line: token.line,
                column: token.column,
            };
        }
        // Allow certain keywords to be used as identifiers in expression contexts
        if (this.match(types_1.TokenType.НАВЪ, types_1.TokenType.МАЪЛУМОТ, types_1.TokenType.РӮЙХАТ, types_1.TokenType.ОБЪЕКТ, types_1.TokenType.БЕҚИМАТ)) {
            const token = this.previous();
            return {
                type: 'Identifier',
                name: token.value,
                line: token.line,
                column: token.column,
            };
        }
        if (this.match(types_1.TokenType.LEFT_PAREN)) {
            const expr = this.expression();
            this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after expression");
            return expr;
        }
        if (this.match(types_1.TokenType.LEFT_BRACKET)) {
            return this.arrayExpression();
        }
        if (this.match(types_1.TokenType.LEFT_BRACE)) {
            return this.objectExpression();
        }
        const token = this.peek();
        throw new Error(`Unexpected token '${token.value}' at line ${token.line}, column ${token.column}`);
    }
    parseTemplateLiteral() {
        const token = this.previous();
        const templateValue = token.value;
        // Parse the template literal content
        const quasis = [];
        const expressions = [];
        // For now, we'll implement a simple version that handles basic interpolation
        // This can be enhanced later for more complex cases
        const parts = this.parseTemplateString(templateValue);
        // Process parts and separate text from expressions
        for (let i = 0; i < parts.length; i++) {
            const part = parts[i];
            if (part.type === 'text') {
                quasis.push({
                    type: 'TemplateElement',
                    value: {
                        raw: part.value,
                        cooked: part.value,
                    },
                    tail: false, // Will be updated later
                    line: token.line,
                    column: token.column,
                });
            }
            else if (part.type === 'expression') {
                // Parse the expression inside ${}
                const trimmedValue = part.value.trim();
                // Handle empty expressions by using undefined
                if (!trimmedValue) {
                    expressions.push({
                        type: 'Identifier',
                        name: 'undefined',
                        line: token.line,
                        column: token.column,
                    });
                }
                else {
                    const exprParser = new Parser([]);
                    const exprTokens = this.tokenizeExpression(part.value);
                    exprParser.tokens = exprTokens;
                    exprParser.current = 0;
                    try {
                        const expr = exprParser.expression();
                        expressions.push(expr);
                    }
                    catch (error) {
                        // If parsing fails, treat as identifier
                        expressions.push({
                            type: 'Identifier',
                            name: part.value.trim(),
                            line: token.line,
                            column: token.column,
                        });
                    }
                }
            }
        }
        // Ensure we have the right number of quasis (should be expressions.length + 1)
        if (quasis.length === expressions.length) {
            quasis.push({
                type: 'TemplateElement',
                value: {
                    raw: '',
                    cooked: '',
                },
                tail: true,
                line: token.line,
                column: token.column,
            });
        }
        // Mark the last quasi as tail
        if (quasis.length > 0) {
            quasis[quasis.length - 1].tail = true;
        }
        return {
            type: 'TemplateLiteral',
            quasis,
            expressions,
            line: token.line,
            column: token.column,
        };
    }
    parseTemplateString(template) {
        const parts = [];
        let current = '';
        let i = 0;
        while (i < template.length) {
            if (template[i] === '$' && template[i + 1] === '{') {
                // Save current text part (even if empty at the start)
                if (current || parts.length === 0) {
                    parts.push({ type: 'text', value: current });
                    current = '';
                }
                // Find the matching closing brace
                i += 2; // Skip ${
                let braceCount = 1;
                let expr = '';
                while (i < template.length && braceCount > 0) {
                    if (template[i] === '{') {
                        braceCount++;
                    }
                    else if (template[i] === '}') {
                        braceCount--;
                    }
                    if (braceCount > 0) {
                        expr += template[i];
                    }
                    i++;
                }
                parts.push({ type: 'expression', value: expr });
            }
            else {
                current += template[i];
                i++;
            }
        }
        // Add remaining text (even if empty)
        if (current || parts.length === 0) {
            parts.push({ type: 'text', value: current });
        }
        return parts;
    }
    tokenizeExpression(expr) {
        const trimmed = expr.trim();
        if (!trimmed) {
            return [
                {
                    type: types_1.TokenType.EOF,
                    value: '',
                    line: 1,
                    column: 1,
                },
            ];
        }
        // Use the main lexer to properly tokenize the interpolation content
        // This ensures all language features (keywords, built-ins, etc.) work properly
        const lexer = new lexer_1.Lexer(trimmed);
        return lexer.tokenize();
    }
    match(...types) {
        for (const type of types) {
            if (this.check(type)) {
                this.advance();
                return true;
            }
        }
        return false;
    }
    check(type) {
        if (this.isAtEnd())
            return false;
        return this.peek().type === type;
    }
    advance() {
        if (!this.isAtEnd())
            this.current++;
        return this.previous();
    }
    isAtEnd() {
        return this.peek().type === types_1.TokenType.EOF;
    }
    peek() {
        return this.tokens[this.current];
    }
    peekNext() {
        if (this.current + 1 >= this.tokens.length)
            return undefined;
        return this.tokens[this.current + 1];
    }
    previous() {
        return this.tokens[this.current - 1];
    }
    consume(type, message) {
        if (this.check(type))
            return this.advance();
        const token = this.peek();
        const errorMsg = `${message}. Got '${token.value}' at line ${token.line}, column ${token.column}`;
        this.errors.push(errorMsg);
        // Try to recover by returning a dummy token
        return {
            type: type,
            value: '',
            line: token.line,
            column: token.column,
        };
    }
    importDeclaration() {
        const importToken = this.previous();
        const specifiers = [];
        // Handle default import or named imports
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            const local = this.advance();
            specifiers.push({
                type: 'ImportDefaultSpecifier',
                local: {
                    type: 'Identifier',
                    name: local.value,
                    line: local.line,
                    column: local.column,
                },
                line: local.line,
                column: local.column,
            });
            if (this.match(types_1.TokenType.COMMA)) {
                // Handle named imports after default
                this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after default import");
                this.parseNamedImports(specifiers);
                this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after named imports");
            }
        }
        else if (this.match(types_1.TokenType.MULTIPLY)) {
            this.consume(types_1.TokenType.ЧУН, "Expected 'чун' after '*' in namespace import");
            let local;
            if (this.check(types_1.TokenType.IDENTIFIER)) {
                local = this.advance();
            }
            else if (this.matchBuiltinIdentifier()) {
                local = this.previous();
            }
            else {
                const token = this.peek();
                throw new Error(`Expected namespace alias after 'чун' at line ${token.line}, column ${token.column}`);
            }
            specifiers.push({
                type: 'ImportNamespaceSpecifier',
                local: {
                    type: 'Identifier',
                    name: local.value,
                    line: local.line,
                    column: local.column,
                },
                line: local.line,
                column: local.column,
            });
        }
        else if (this.match(types_1.TokenType.LEFT_BRACE)) {
            // Handle only named imports
            this.parseNamedImports(specifiers);
            this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after named imports");
        }
        this.consume(types_1.TokenType.АЗ, "Expected 'аз' after import specifiers");
        const source = this.consume(types_1.TokenType.STRING, 'Expected module path');
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after import");
        return {
            type: 'ImportDeclaration',
            specifiers,
            source: {
                type: 'Literal',
                value: source.value,
                raw: `"${source.value}"`,
                line: source.line,
                column: source.column,
            },
            line: importToken.line,
            column: importToken.column,
        };
    }
    parseNamedImports(specifiers) {
        if (!this.check(types_1.TokenType.RIGHT_BRACE)) {
            do {
                let imported;
                if (this.check(types_1.TokenType.IDENTIFIER)) {
                    imported = this.advance();
                }
                else if (this.matchBuiltinIdentifier()) {
                    imported = this.previous();
                }
                else {
                    throw new Error(`Expected import name at line ${this.peek().line}, column ${this.peek().column}`);
                }
                let local = imported;
                // Handle 'as' alias (we'll use 'чун' for 'as')
                if (this.match(types_1.TokenType.ЧУН)) {
                    if (this.check(types_1.TokenType.IDENTIFIER)) {
                        local = this.advance();
                    }
                    else if (this.matchBuiltinIdentifier()) {
                        local = this.previous();
                    }
                    else {
                        throw new Error(`Expected local name after 'чун' at line ${this.peek().line}, column ${this.peek().column}`);
                    }
                }
                specifiers.push({
                    type: 'ImportSpecifier',
                    imported: {
                        type: 'Identifier',
                        name: imported.value,
                        line: imported.line,
                        column: imported.column,
                    },
                    local: {
                        type: 'Identifier',
                        name: local.value,
                        line: local.line,
                        column: local.column,
                    },
                    line: imported.line,
                    column: imported.column,
                });
            } while (this.match(types_1.TokenType.COMMA));
        }
    }
    exportDeclaration() {
        const exportToken = this.previous();
        if (this.match(types_1.TokenType.ПЕШФАРЗ)) {
            // Export default
            const declaration = this.statement();
            return {
                type: 'ExportDeclaration',
                declaration: declaration,
                default: true,
                line: exportToken.line,
                column: exportToken.column,
            };
        }
        else {
            // Export named
            const declaration = this.statement();
            return {
                type: 'ExportDeclaration',
                declaration: declaration,
                default: false,
                line: exportToken.line,
                column: exportToken.column,
            };
        }
    }
    matchBuiltinIdentifier() {
        const builtinTypes = [
            types_1.TokenType.ЧОП,
            types_1.TokenType.САБТ,
            types_1.TokenType.ХАТО,
            types_1.TokenType.ОГОҲӢ,
            types_1.TokenType.МАЪЛУМОТ,
            types_1.TokenType.РӮЙХАТ,
            types_1.TokenType.ИЛОВА,
            types_1.TokenType.БАРОВАРДАН,
            types_1.TokenType.ДАРОЗӢ,
            types_1.TokenType.ХАРИТА,
            types_1.TokenType.ФИЛТР,
            types_1.TokenType.КОФТАН,
            types_1.TokenType.САТР_МЕТОДҲО,
            types_1.TokenType.ДАРОЗИИ_САТР,
            types_1.TokenType.ПАЙВАСТАН,
            types_1.TokenType.ҶОЙИВАЗКУНӢ,
            types_1.TokenType.ҶУДОКУНӢ,
            types_1.TokenType.ОБЪЕКТ,
            types_1.TokenType.КАЛИДҲО,
            types_1.TokenType.ҚИМАТҲО,
            types_1.TokenType.МАТЕМАТИКА,
            types_1.TokenType.ҶАМЪ,
            types_1.TokenType.ТАРҲ,
            types_1.TokenType.ЗАРБ,
            types_1.TokenType.ТАҚСИМ,
            types_1.TokenType.ҲОЛАТ, // Allow 'case' keyword as identifier (for property names)
            // Basic type keywords can appear as variable names in examples
            types_1.TokenType.РАҚАМ,
            types_1.TokenType.САТР,
            types_1.TokenType.МАНТИҚӢ,
            types_1.TokenType.ХОЛӢ,
            // Note: We don't include control flow keywords here as they have special parsing
        ];
        for (const type of builtinTypes) {
            if (this.check(type)) {
                this.advance();
                return true;
            }
        }
        return false;
    }
    arrayExpression() {
        const leftBracket = this.previous();
        const elements = [];
        // Skip any leading newlines
        while (this.match(types_1.TokenType.NEWLINE)) {
            // consume newlines
        }
        if (!this.check(types_1.TokenType.RIGHT_BRACKET)) {
            do {
                // Skip newlines before each element
                while (this.match(types_1.TokenType.NEWLINE)) {
                    // consume newlines
                }
                if (this.check(types_1.TokenType.SPREAD)) {
                    elements.push(this.parseSpreadElement());
                }
                else {
                    elements.push(this.expression());
                }
                // Skip newlines after each element
                while (this.match(types_1.TokenType.NEWLINE)) {
                    // consume newlines
                }
            } while (this.match(types_1.TokenType.COMMA));
        }
        // Skip any trailing newlines
        while (this.match(types_1.TokenType.NEWLINE)) {
            // consume newlines
        }
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after array elements");
        return {
            type: 'ArrayExpression',
            elements,
            line: leftBracket.line,
            column: leftBracket.column,
        };
    }
    objectExpression() {
        const leftBrace = this.previous();
        const properties = [];
        // Skip any newlines after opening brace
        while (this.match(types_1.TokenType.NEWLINE)) {
            // Skip newlines
        }
        if (!this.check(types_1.TokenType.RIGHT_BRACE)) {
            do {
                // Skip any newlines before property
                while (this.match(types_1.TokenType.NEWLINE)) {
                    // Skip newlines
                }
                if (this.check(types_1.TokenType.RIGHT_BRACE)) {
                    break; // End of object
                }
                const property = this.parseProperty();
                properties.push(property);
                // Skip any newlines after property
                while (this.match(types_1.TokenType.NEWLINE)) {
                    // Skip newlines
                }
            } while (this.match(types_1.TokenType.COMMA));
        }
        // Skip any newlines before closing brace
        while (this.match(types_1.TokenType.NEWLINE)) {
            // Skip newlines
        }
        this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after object properties");
        return {
            type: 'ObjectExpression',
            properties,
            line: leftBrace.line,
            column: leftBrace.column,
        };
    }
    parseProperty() {
        let key;
        let computed = false;
        if (this.check(types_1.TokenType.LEFT_BRACKET)) {
            // Computed property
            this.advance(); // consume '['
            key = this.expression();
            this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']'");
            computed = true;
        }
        else {
            // Regular property
            const keyToken = this.advance();
            key = {
                type: 'Identifier',
                name: keyToken.value,
                line: keyToken.line,
                column: keyToken.column,
            };
        }
        this.consume(types_1.TokenType.COLON, "Expected ':' after property key");
        const value = this.expression();
        return {
            type: 'Property',
            key,
            value,
            computed,
            shorthand: false,
            line: key.line,
            column: key.column,
        };
    }
    tryStatement() {
        const tryToken = this.previous();
        // Consume the opening brace for try block
        this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after 'кӯшиш'");
        const block = this.blockStatement();
        let handler = undefined;
        if (this.match(types_1.TokenType.ГИРИФТАН)) {
            this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'гирифтан'");
            let param = undefined;
            if (this.check(types_1.TokenType.IDENTIFIER) || this.matchBuiltinIdentifier()) {
                const paramToken = this.check(types_1.TokenType.IDENTIFIER) ? this.advance() : this.previous();
                param = {
                    type: 'Identifier',
                    name: paramToken.value,
                    line: paramToken.line,
                    column: paramToken.column,
                };
            }
            this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after catch parameter");
            this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after catch clause");
            const body = this.blockStatement();
            handler = {
                type: 'CatchClause',
                param,
                body,
                line: this.previous().line,
                column: this.previous().column,
            };
        }
        let finalizer = undefined;
        if (this.match(types_1.TokenType.НИҲОЯТ)) {
            this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after 'ниҳоят'");
            finalizer = this.blockStatement();
        }
        return {
            type: 'TryStatement',
            block,
            handler,
            finalizer,
            line: tryToken.line,
            column: tryToken.column,
        };
    }
    throwStatement() {
        const throwToken = this.previous();
        const argument = this.expression();
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after throw statement");
        return {
            type: 'ThrowStatement',
            argument,
            line: throwToken.line,
            column: throwToken.column,
        };
    }
    parseParameter() {
        let paramName;
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            paramName = this.advance();
        }
        else if (this.matchBuiltinIdentifier()) {
            paramName = this.previous();
        }
        else if (this.match(types_1.TokenType.НАВЪ, types_1.TokenType.МАЪЛУМОТ, types_1.TokenType.РӮЙХАТ, types_1.TokenType.ОБЪЕКТ, types_1.TokenType.БЕҚИМАТ)) {
            // Allow common Tajik words as parameter names
            paramName = this.previous();
        }
        else {
            throw new Error(`Expected parameter name at line ${this.peek().line}, column ${this.peek().column}`);
        }
        // Parse optional indicator
        let optional = false;
        if (this.match(types_1.TokenType.QUESTION)) {
            optional = true;
        }
        // Parse optional type annotation
        let typeAnnotation;
        if (this.match(types_1.TokenType.COLON)) {
            typeAnnotation = this.typeAnnotation();
        }
        return {
            type: 'Parameter',
            name: {
                type: 'Identifier',
                name: paramName.value,
                line: paramName.line,
                column: paramName.column,
            },
            typeAnnotation,
            optional,
            line: paramName.line,
            column: paramName.column,
        };
    }
    typeAnnotation() {
        const typeNode = this.parseType();
        return {
            type: 'TypeAnnotation',
            typeAnnotation: typeNode,
            line: typeNode.line,
            column: typeNode.column,
        };
    }
    parseType() {
        return this.unionType();
    }
    unionType() {
        let type = this.intersectionType();
        while (this.match(types_1.TokenType.BITWISE_OR)) {
            const types = [type];
            do {
                types.push(this.intersectionType());
            } while (this.match(types_1.TokenType.BITWISE_OR));
            type = {
                type: 'UnionType',
                types,
                line: type.line,
                column: type.column,
            };
        }
        return type;
    }
    intersectionType() {
        let type = this.primaryType();
        while (this.match(types_1.TokenType.BITWISE_AND)) {
            const types = [type];
            do {
                types.push(this.primaryType());
            } while (this.match(types_1.TokenType.BITWISE_AND));
            type = {
                type: 'IntersectionType',
                types,
                line: type.line,
                column: type.column,
            };
        }
        return type;
    }
    primaryType() {
        return (this.parseParenthesizedOrArrayType() ??
            this.parseUniqueType() ??
            this.parsePrimitiveType() ??
            this.parseGenericOrIdentifierType() ??
            this.parseTupleType() ??
            this.errorExpectedType());
    }
    parseParenthesizedOrArrayType() {
        if (!this.match(types_1.TokenType.LEFT_PAREN))
            return undefined;
        const type = this.unionType();
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after type");
        if (!this.match(types_1.TokenType.LEFT_BRACKET))
            return type;
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after '['");
        return {
            type: 'ArrayType',
            elementType: type,
            line: type.line,
            column: type.column,
        };
    }
    parseUniqueType() {
        if (!this.match(types_1.TokenType.БЕНАЗИР))
            return undefined;
        const uniqueToken = this.previous();
        const baseType = this.primaryType();
        const uniqueType = {
            type: 'UniqueType',
            baseType,
            line: uniqueToken.line,
            column: uniqueToken.column,
        };
        if (!this.match(types_1.TokenType.LEFT_BRACKET))
            return uniqueType;
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after '['");
        return {
            type: 'ArrayType',
            elementType: uniqueType,
            line: uniqueType.line,
            column: uniqueType.column,
        };
    }
    parsePrimitiveType() {
        if (!this.match(types_1.TokenType.САТР, types_1.TokenType.РАҚАМ, types_1.TokenType.МАНТИҚӢ, types_1.TokenType.ХОЛӢ)) {
            return undefined;
        }
        const token = this.previous();
        const primitiveType = {
            type: 'PrimitiveType',
            name: token.value,
            line: token.line,
            column: token.column,
        };
        if (!this.match(types_1.TokenType.LEFT_BRACKET))
            return primitiveType;
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after '['");
        return {
            type: 'ArrayType',
            elementType: primitiveType,
            line: primitiveType.line,
            column: primitiveType.column,
        };
    }
    parseGenericOrIdentifierType() {
        if (!this.check(types_1.TokenType.IDENTIFIER) && !this.matchBuiltinIdentifier()) {
            return undefined;
        }
        const nameToken = this.check(types_1.TokenType.IDENTIFIER) ? this.advance() : this.previous();
        const name = {
            type: 'Identifier',
            name: nameToken.value,
            line: nameToken.line,
            column: nameToken.column,
        };
        let typeParameters;
        if (this.match(types_1.TokenType.LESS_THAN)) {
            typeParameters = [];
            do {
                typeParameters.push(this.parseType());
            } while (this.match(types_1.TokenType.COMMA));
            this.consume(types_1.TokenType.GREATER_THAN, "Expected '>' after type parameters");
        }
        const genericType = {
            type: 'GenericType',
            name,
            typeParameters,
            line: name.line,
            column: name.column,
        };
        if (!this.match(types_1.TokenType.LEFT_BRACKET))
            return genericType;
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after '['");
        return {
            type: 'ArrayType',
            elementType: genericType,
            line: genericType.line,
            column: genericType.column,
        };
    }
    parseTupleType() {
        if (!this.match(types_1.TokenType.LEFT_BRACKET))
            return undefined;
        const types = [];
        if (!this.check(types_1.TokenType.RIGHT_BRACKET)) {
            do {
                types.push(this.unionType());
            } while (this.match(types_1.TokenType.COMMA));
        }
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after tuple types");
        const tupleType = {
            type: 'TupleType',
            elementTypes: types,
            line: this.previous().line,
            column: this.previous().column,
        };
        if (!this.match(types_1.TokenType.LEFT_BRACKET))
            return tupleType;
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' after '['");
        return {
            type: 'ArrayType',
            elementType: tupleType,
            line: tupleType.line,
            column: tupleType.column,
        };
    }
    errorExpectedType() {
        throw new Error(`Expected type at line ${this.peek().line}, column ${this.peek().column}`);
    }
    interfaceDeclaration() {
        const interfaceToken = this.previous();
        let name;
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            name = this.advance();
        }
        else if (this.matchBuiltinIdentifier()) {
            name = this.previous();
        }
        else {
            throw new Error(`Expected interface name at line ${this.peek().line}, column ${this.peek().column}`);
        }
        // Parse optional type parameters
        let typeParameters;
        if (this.match(types_1.TokenType.LESS_THAN)) {
            typeParameters = [];
            do {
                const paramName = this.consume(types_1.TokenType.IDENTIFIER, 'Expected type parameter name');
                typeParameters.push({
                    type: 'TypeParameter',
                    name: {
                        type: 'Identifier',
                        name: paramName.value,
                        line: paramName.line,
                        column: paramName.column,
                    },
                    line: paramName.line,
                    column: paramName.column,
                });
            } while (this.match(types_1.TokenType.COMMA));
            this.consume(types_1.TokenType.GREATER_THAN, "Expected '>' after type parameters");
        }
        // Parse optional extends clause (interface inheritance)
        // Note: extends clause is parsed but not used in JavaScript generation
        if (this.match(types_1.TokenType.МЕРОС)) {
            if (this.check(types_1.TokenType.IDENTIFIER)) {
                this.advance(); // consume interface name
            }
            else if (this.matchBuiltinIdentifier()) {
                // already consumed by matchBuiltinIdentifier
            }
            else {
                throw new Error(`Expected interface name after 'мерос' at line ${this.peek().line}, column ${this.peek().column}`);
            }
        }
        this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after interface name");
        const properties = [];
        while (!this.check(types_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
            // Skip newlines and whitespace
            if (this.match(types_1.TokenType.NEWLINE)) {
                continue;
            }
            const property = this.propertySignature();
            properties.push(property);
            // After parsing a property, ensure we're positioned correctly for the next one
            // Skip any trailing whitespace or newlines
            while (this.check(types_1.TokenType.NEWLINE)) {
                this.advance();
            }
        }
        this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after interface body");
        const result = {
            type: 'InterfaceDeclaration',
            name: {
                type: 'Identifier',
                name: name.value,
                line: name.line,
                column: name.column,
            },
            typeParameters,
            body: {
                type: 'InterfaceBody',
                properties,
                line: interfaceToken.line,
                column: interfaceToken.column,
            },
            line: interfaceToken.line,
            column: interfaceToken.column,
        };
        return result;
    }
    propertySignature() {
        // Parse optional readonly modifier
        let readonly = false;
        if (this.match(types_1.TokenType.ТАНҲОХОНӢ)) {
            readonly = true;
        }
        let keyName;
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            keyName = this.advance();
        }
        else if (this.matchBuiltinIdentifier()) {
            keyName = this.previous();
        }
        else if (this.check(types_1.TokenType.САТР) ||
            this.check(types_1.TokenType.РАҚАМ) ||
            this.check(types_1.TokenType.МАНТИҚӢ) ||
            this.check(types_1.TokenType.ХОЛӢ)) {
            // Allow type keywords as property names
            keyName = this.advance();
        }
        else {
            throw new Error(`Expected property name at line ${this.peek().line}, column ${this.peek().column}`);
        }
        // Check if this is a method signature (has parentheses)
        if (this.check(types_1.TokenType.LEFT_PAREN)) {
            // Method signature: methodName(params): returnType;
            this.advance(); // consume '('
            // Skip parameters for now (just consume until ')')
            let parenCount = 1;
            while (parenCount > 0 && !this.isAtEnd()) {
                if (this.check(types_1.TokenType.LEFT_PAREN)) {
                    parenCount++;
                }
                else if (this.check(types_1.TokenType.RIGHT_PAREN)) {
                    parenCount--;
                }
                this.advance();
            }
            this.consume(types_1.TokenType.COLON, "Expected ':' after method parameters");
            const typeAnnotation = this.typeAnnotation();
            this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after method signature");
            return {
                type: 'PropertySignature',
                key: {
                    type: 'Identifier',
                    name: keyName.value,
                    line: keyName.line,
                    column: keyName.column,
                },
                typeAnnotation,
                optional: false,
                readonly,
                line: keyName.line,
                column: keyName.column,
            };
        }
        else {
            // Regular property signature: propName: type;
            // Check for optional property
            const optional = this.match(types_1.TokenType.QUESTION);
            this.consume(types_1.TokenType.COLON, "Expected ':' after property name");
            const typeAnnotation = this.typeAnnotation();
            this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after property type");
            return {
                type: 'PropertySignature',
                key: {
                    type: 'Identifier',
                    name: keyName.value,
                    line: keyName.line,
                    column: keyName.column,
                },
                typeAnnotation,
                optional: optional || false,
                readonly,
                line: keyName.line,
                column: keyName.column,
            };
        }
    }
    classDeclaration() {
        const classToken = this.previous();
        // Class name
        let nameToken;
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            nameToken = this.advance();
        }
        else if (this.matchBuiltinIdentifier()) {
            nameToken = this.previous();
        }
        else {
            throw new Error(`Expected class name at line ${this.peek().line}, column ${this.peek().column}`);
        }
        // Optional extends clause
        let superClassToken = undefined;
        if (this.match(types_1.TokenType.МЕРОС)) {
            if (this.check(types_1.TokenType.IDENTIFIER)) {
                superClassToken = this.advance();
            }
            else if (this.matchBuiltinIdentifier()) {
                superClassToken = this.previous();
            }
            else {
                throw new Error(`Expected superclass name after 'мерос' at line ${this.peek().line}, column ${this.peek().column}`);
            }
        }
        // Optional implements clause
        const implementsTokens = [];
        if (this.match(types_1.TokenType.ТАТБИҚ)) {
            do {
                if (this.check(types_1.TokenType.IDENTIFIER)) {
                    implementsTokens.push(this.advance());
                }
                else if (this.matchBuiltinIdentifier()) {
                    implementsTokens.push(this.previous());
                }
                else {
                    throw new Error(`Expected interface name in implements clause at line ${this.peek().line}, column ${this.peek().column}`);
                }
            } while (this.match(types_1.TokenType.COMMA));
        }
        // Class body
        this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after class declaration");
        const body = this.classBody();
        this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after class body");
        return {
            type: 'ClassDeclaration',
            name: {
                type: 'Identifier',
                name: nameToken.value,
                line: nameToken.line,
                column: nameToken.column,
            },
            superClass: superClassToken
                ? {
                    type: 'Identifier',
                    name: superClassToken.value,
                    line: superClassToken.line,
                    column: superClassToken.column,
                }
                : undefined,
            implements: implementsTokens.map(impl => ({
                type: 'Identifier',
                name: impl.value,
                line: impl.line,
                column: impl.column,
            })),
            body: body,
            line: classToken.line,
            column: classToken.column,
        };
    }
    classBody() {
        const members = [];
        while (!this.check(types_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
            // Skip newlines
            if (this.match(types_1.TokenType.NEWLINE)) {
                continue;
            }
            try {
                // Parse class member
                const member = this.classMember();
                if (member) {
                    members.push(member);
                }
                // After parsing a member, ensure we're positioned correctly for the next one
                // Skip any trailing whitespace or newlines
                while (this.check(types_1.TokenType.NEWLINE)) {
                    this.advance();
                }
            }
            catch (error) {
                // If class member parsing fails, break out of the class context
                // This prevents partial parsing from contaminating the rest of the program
                console.error(`Error parsing class member: ${error}`);
                // Try to recover by advancing to the next potential member or class end
                while (!this.check(types_1.TokenType.RIGHT_BRACE) &&
                    !this.check(types_1.TokenType.ҶАМЪИЯТӢ) &&
                    !this.check(types_1.TokenType.ХОСУСӢ) &&
                    !this.check(types_1.TokenType.КОНСТРУКТОР) &&
                    !this.check(types_1.TokenType.IDENTIFIER) &&
                    !this.isAtEnd()) {
                    this.advance();
                }
                // Don't break - continue trying to parse the rest of the class
                // The break was causing premature exit from class parsing
            }
        }
        return {
            type: 'ClassBody',
            body: members,
            line: this.peek().line,
            column: this.peek().column,
        };
    }
    classMember() {
        // Check for access modifiers
        let accessibility = undefined;
        if (this.match(types_1.TokenType.ҶАМЪИЯТӢ, types_1.TokenType.ХОСУСӢ, types_1.TokenType.МУҲОФИЗАТШУДА)) {
            const accessToken = this.previous();
            accessibility =
                accessToken.type === types_1.TokenType.ҶАМЪИЯТӢ
                    ? 'public'
                    : accessToken.type === types_1.TokenType.ХОСУСӢ
                        ? 'private'
                        : 'protected';
        }
        // Check for static
        let isStatic = false;
        if (this.match(types_1.TokenType.СТАТИКӢ)) {
            isStatic = true;
        }
        // Check for abstract
        let isAbstract = false;
        if (this.match(types_1.TokenType.МАВҲУМ)) {
            isAbstract = true;
        }
        // Constructor
        if (this.match(types_1.TokenType.КОНСТРУКТОР)) {
            return this.constructorMethod(accessibility, isStatic);
        }
        // Method or property
        let nameToken;
        if (this.check(types_1.TokenType.IDENTIFIER)) {
            nameToken = this.advance();
        }
        else if (this.matchBuiltinIdentifier()) {
            nameToken = this.previous();
        }
        else {
            throw new Error(`Expected class member at line ${this.peek().line}, column ${this.peek().column}`);
        }
        if (this.check(types_1.TokenType.LEFT_PAREN)) {
            // Method
            return this.classMethod(nameToken, accessibility, isStatic, isAbstract);
        }
        else {
            // Property
            return this.classProperty(nameToken, accessibility, isStatic);
        }
    }
    constructorMethod(accessibility, isStatic) {
        const constructorToken = this.previous();
        const access = accessibility === 'public' || accessibility === 'private' || accessibility === 'protected'
            ? accessibility
            : undefined;
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after constructor");
        const params = [];
        if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
            do {
                const param = this.parseParameter();
                params.push(param);
            } while (this.match(types_1.TokenType.COMMA));
        }
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after constructor parameters");
        this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after constructor parameters");
        const body = this.blockStatement();
        return {
            type: 'MethodDefinition',
            key: {
                type: 'Identifier',
                name: 'constructor',
                line: constructorToken.line,
                column: constructorToken.column,
            },
            value: {
                type: 'FunctionExpression',
                params: params,
                body: body,
                line: constructorToken.line,
                column: constructorToken.column,
            },
            kind: 'constructor',
            static: isStatic || false,
            accessibility: access,
            line: constructorToken.line,
            column: constructorToken.column,
        };
    }
    classMethod(nameToken, accessibility, isStatic, isAbstract) {
        const accessVar = accessibility === 'public' || accessibility === 'private' || accessibility === 'protected'
            ? accessibility
            : undefined;
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after method name");
        const params = [];
        if (!this.check(types_1.TokenType.RIGHT_PAREN)) {
            do {
                const param = this.parseParameter();
                params.push(param);
            } while (this.match(types_1.TokenType.COMMA));
        }
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after method parameters");
        let returnType;
        if (this.match(types_1.TokenType.COLON)) {
            returnType = this.typeAnnotation();
        }
        let body = null;
        if (isAbstract) {
            // Abstract methods end with semicolon, no body
            this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after abstract method signature");
        }
        else {
            // Regular methods have a body
            this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after method signature");
            body = this.blockStatement();
        }
        return {
            type: 'MethodDefinition',
            key: {
                type: 'Identifier',
                name: nameToken.value,
                line: nameToken.line,
                column: nameToken.column,
            },
            value: {
                type: 'FunctionExpression',
                params: params,
                body: body || this.blockStatement(),
                returnType,
                line: nameToken.line,
                column: nameToken.column,
            },
            kind: 'method',
            static: isStatic || false,
            accessibility: accessVar,
            line: nameToken.line,
            column: nameToken.column,
        };
    }
    classProperty(nameToken, accessibility, isStatic) {
        const accessProp = accessibility === 'public' || accessibility === 'private' || accessibility === 'protected'
            ? accessibility
            : undefined;
        // Optional type annotation
        let typeAnnotation;
        if (this.match(types_1.TokenType.COLON)) {
            typeAnnotation = this.typeAnnotation();
        }
        // Optional initializer
        let value = undefined;
        if (this.match(types_1.TokenType.ASSIGN)) {
            value = this.expression();
        }
        // Optional semicolon after property declaration
        this.match(types_1.TokenType.SEMICOLON);
        return {
            type: 'PropertyDefinition',
            key: {
                type: 'Identifier',
                name: nameToken.value,
                line: nameToken.line,
                column: nameToken.column,
            },
            value: value,
            typeAnnotation: typeAnnotation,
            static: isStatic || false,
            accessibility: accessProp,
            line: nameToken.line,
            column: nameToken.column,
        };
    }
    typeAlias() {
        const typeToken = this.previous();
        const name = this.consume(types_1.TokenType.IDENTIFIER, 'Expected type alias name');
        this.consume(types_1.TokenType.ASSIGN, "Expected '=' after type alias name");
        const typeAnnotation = this.typeAnnotation();
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after type alias");
        return {
            type: 'TypeAlias',
            name: {
                type: 'Identifier',
                name: name.value,
                line: name.line,
                column: name.column,
            },
            typeAnnotation,
            line: typeToken.line,
            column: typeToken.column,
        };
    }
    // eslint-disable-next-line complexity
    switchStatement() {
        const switchToken = this.previous();
        this.consume(types_1.TokenType.LEFT_PAREN, "Expected '(' after 'интихоб'");
        const discriminant = this.expression();
        this.consume(types_1.TokenType.RIGHT_PAREN, "Expected ')' after switch expression");
        this.consume(types_1.TokenType.LEFT_BRACE, "Expected '{' after switch expression");
        const cases = [];
        let foundDefault = false;
        while (!this.check(types_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
            if (this.match(types_1.TokenType.NEWLINE))
                continue;
            if (this.match(types_1.TokenType.ҲОЛАТ)) {
                // case
                const test = this.expression();
                this.consume(types_1.TokenType.COLON, "Expected ':' after case value");
                const consequent = [];
                while (!this.check(types_1.TokenType.ҲОЛАТ) &&
                    !this.check(types_1.TokenType.ПЕШФАРЗ) &&
                    !this.check(types_1.TokenType.RIGHT_BRACE) &&
                    !this.isAtEnd()) {
                    if (this.match(types_1.TokenType.NEWLINE))
                        continue;
                    const stmt = this.statement();
                    if (stmt)
                        consequent.push(stmt);
                }
                cases.push({ type: 'SwitchCase', test, consequent, line: test.line, column: test.column });
                continue;
            }
            if (this.match(types_1.TokenType.ПЕШФАРЗ)) {
                // default
                if (foundDefault) {
                    this.errors.push('Multiple default cases in switch');
                }
                foundDefault = true;
                this.consume(types_1.TokenType.COLON, "Expected ':' after default keyword");
                const startToken = this.previous();
                const consequent = [];
                while (!this.check(types_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
                    if (this.check(types_1.TokenType.ҲОЛАТ) || this.check(types_1.TokenType.ПЕШФАРЗ))
                        break;
                    if (this.match(types_1.TokenType.NEWLINE))
                        continue;
                    const stmt = this.statement();
                    if (stmt)
                        consequent.push(stmt);
                }
                cases.push({
                    type: 'SwitchCase',
                    test: undefined, // default case
                    consequent,
                    line: startToken.line,
                    column: startToken.column,
                });
                continue;
            }
            // Unrecognized token inside switch; attempt recovery
            this.errors.push(`Unexpected token '${this.peek().value}' in switch at line ${this.peek().line}`);
            this.advance();
        }
        this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' after switch cases");
        return {
            type: 'SwitchStatement',
            discriminant,
            cases,
            line: switchToken.line,
            column: switchToken.column,
        };
    }
    synchronize() {
        // Basic error recovery: advance until a probable statement boundary
        this.advance();
        while (!this.isAtEnd()) {
            if (this.previous().type === types_1.TokenType.SEMICOLON)
                return;
            switch (this.peek().type) {
                case types_1.TokenType.ТАҒЙИРЁБАНДА:
                case types_1.TokenType.СОБИТ:
                case types_1.TokenType.ФУНКСИЯ:
                case types_1.TokenType.АГАР:
                case types_1.TokenType.ТО: // while keyword
                case types_1.TokenType.БОЗГАШТ:
                    return;
            }
            this.advance();
        }
    }
    parsePattern() {
        if (this.match(types_1.TokenType.LEFT_BRACKET)) {
            return this.parseArrayPattern();
        }
        if (this.match(types_1.TokenType.LEFT_BRACE)) {
            return this.parseObjectPattern();
        }
        return this.parseIdentifierPattern();
    }
    parseArrayPattern() {
        const elements = [];
        while (!this.check(types_1.TokenType.RIGHT_BRACKET) && !this.isAtEnd()) {
            if (this.match(types_1.TokenType.COMMA)) {
                elements.push(null);
                continue;
            }
            if (this.match(types_1.TokenType.SPREAD)) {
                const spreadElem = this.parseSpreadElement();
                elements.push(spreadElem);
            }
            else {
                elements.push(this.parsePattern());
            }
            if (!this.match(types_1.TokenType.COMMA))
                break;
        }
        this.consume(types_1.TokenType.RIGHT_BRACKET, "Expected ']' in array pattern");
        return {
            type: 'ArrayPattern',
            elements,
            line: this.previous().line,
            column: this.previous().column,
        };
    }
    parseObjectPattern() {
        const properties = [];
        while (!this.check(types_1.TokenType.RIGHT_BRACE) && !this.isAtEnd()) {
            if (this.match(types_1.TokenType.SPREAD)) {
                properties.push(this.parseSpreadElement());
            }
            else {
                const key = this.consume(types_1.TokenType.IDENTIFIER, 'Expected identifier in object pattern');
                let value;
                if (this.match(types_1.TokenType.COLON)) {
                    value = this.parsePattern();
                }
                properties.push({
                    type: 'PropertyPattern',
                    key: { type: 'Identifier', name: key.value, line: key.line, column: key.column },
                    value,
                    line: key.line,
                    column: key.column,
                });
            }
            if (!this.match(types_1.TokenType.COMMA))
                break;
        }
        this.consume(types_1.TokenType.RIGHT_BRACE, "Expected '}' in object pattern");
        return {
            type: 'ObjectPattern',
            properties,
            line: this.previous().line,
            column: this.previous().column,
        };
    }
    parseIdentifierPattern() {
        // Allow certain keyword tokens to be treated as identifiers in binding patterns
        // 'объект' is a keyword mapped to TokenType.ОБЪЕКТ but test suite expects it
        // can be used as a normal variable name. Extendable list if more appear.
        if (this.check(types_1.TokenType.IDENTIFIER) || this.check(types_1.TokenType.ОБЪЕКТ)) {
            const identTok = this.advance();
            return {
                type: 'Identifier',
                name: identTok.value,
                line: identTok.line,
                column: identTok.column,
            };
        }
        if (this.matchBuiltinIdentifier()) {
            const token = this.previous();
            return {
                type: 'Identifier',
                name: token.value,
                line: token.line,
                column: token.column,
            };
        }
        const ident = this.consume(types_1.TokenType.IDENTIFIER, 'Expected identifier');
        return {
            type: 'Identifier',
            name: ident.value,
            line: ident.line,
            column: ident.column,
        };
    }
    parseSpreadElement() {
        const spreadToken = this.previous(); // SPREAD token consumed by caller
        const argument = this.parsePattern();
        return {
            type: 'SpreadElement',
            argument,
            line: spreadToken.line,
            column: spreadToken.column,
        };
    }
    breakStatement() {
        const token = this.previous();
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after 'шикастан'");
        return { type: 'BreakStatement', line: token.line, column: token.column };
    }
    continueStatement() {
        const token = this.previous();
        this.consume(types_1.TokenType.SEMICOLON, "Expected ';' after 'давом'");
        return { type: 'ContinueStatement', line: token.line, column: token.column };
    }
}
exports.Parser = Parser;
//# sourceMappingURL=parser.js.map