
#ifndef PORYGONLANG_BINDER_HPP
#define PORYGONLANG_BINDER_HPP
#include "../Parser/ParsedStatements/ParsedStatement.hpp"
#include "BoundStatements/BoundStatement.hpp"
#include "../Script.hpp"
#include "BoundVariables/BoundScope.hpp"
#include "../Parser/ParsedExpressions/ParsedTableExpression.hpp"
#include "../ScriptTypes/FunctionScriptType.hpp"
#include "BoundExpressions/BoundFunctionCallExpression.hpp"

using namespace std;
using namespace Porygon::Parser;

namespace Porygon::Binder {
    class Binder {
        Porygon::Script *_scriptData;
        BoundScope *_scope;
        GenericFunctionOption* _currentFunction;

        ~Binder();

        // Statements

        BoundStatement *BindStatement(const ParsedStatement *statement);
        BoundStatement *BindBlockStatement(const ParsedStatement *statement);
        BoundStatement *BindExpressionStatement(const ParsedStatement *statement);
        BoundStatement *BindAssignmentStatement(const ParsedStatement *statement);
        BoundStatement *BindIndexAssignmentStatement(const ParsedStatement *statement);
        BoundStatement *BindFunctionDeclarationStatement(const ParsedStatement *statement);
        BoundStatement *BindReturnStatement(const ParsedStatement *statement);
        BoundStatement *BindConditionalStatement(const ParsedStatement *statement);
        BoundStatement *BindNumericalForStatement(const ParsedStatement *statement);
        BoundStatement *BindGenericForStatement(const ParsedStatement *statement);
        BoundStatement *BindWhileStatement(const ParsedStatement *statement);

        // Expressions

        BoundExpression *BindExpression(const ParsedExpression *expression);
        BoundExpression *BindVariableExpression(const VariableExpression *expression);
        BoundExpression *BindBinaryOperator(const BinaryExpression *expression);
        BoundExpression *BindUnaryOperator(const UnaryExpression *expression);
        BoundExpression *BindFunctionCall(const FunctionCallExpression *expression);
        BoundExpression *BindRequire(const FunctionCallExpression *exp);
        BoundExpression *BindIndexExpression(const IndexExpression *expression, bool setter);
        BoundExpression *BindNumericalTableExpression(const ParsedNumericalTableExpression *expression);
        BoundExpression *BindTableExpression(const ParsedTableExpression *expression);
        BoundExpression *BindPeriodIndexExpression(const PeriodIndexExpression *expression, bool setter);

    public:
        Binder(){
            _scriptData = nullptr;
            _scope = nullptr;
            _currentFunction = nullptr;
        }

        static BoundScriptStatement *
        Bind(Porygon::Script *script, const ParsedScriptStatement *s, BoundScope *scriptScope);

    };
}

#endif //PORYGONLANG_BINDER_HPP
