<commit_before>//=======================================================================
// Copyright <NAME> 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <string>

#include "VisitorUtils.hpp"
#include "Variable.hpp"
#include "SemanticalException.hpp"
#include "FunctionContext.hpp"
#include "GetTypeVisitor.hpp"
#include "GetConstantValue.hpp"
#include "IsConstantVisitor.hpp"
#include "mangling.hpp"

#include "tac/TacCompiler.hpp"
#include "tac/Program.hpp"

#include "ast/Program.hpp"

//TODO Move label generator system in another folder
#include "il/Labels.hpp"

using namespace eddic;

void moveToVariable(ast::Value& value, std::shared_ptr<Variable> variable, std::shared_ptr<tac::Function> function);
void performStringOperation(ast::ComposedValue& value, std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> v1, std::shared_ptr<Variable> v2);
void executeCall(ast::FunctionCall& functionCall, std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> return_, std::shared_ptr<Variable> return2_);

void performIntOperation(ast::ComposedValue& value, std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> variable){
    assert(value.Content->operations.size() > 0); //This has been enforced by previous phases

    auto t1 = value.Content->context->newTemporary();
    auto t2 = value.Content->context->newTemporary();

    moveToVariable(value.Content->first, t1, function);

    //Apply all the operations in chain
    for(auto& operation : value.Content->operations){
        moveToVariable(value.Content->first, t2, function);
        
        function->add(tac::Quadruple(t2, t1, tac::toOperator(operation.get<0>()), t2));

        t1 = t2;
        t2 = value.Content->context->newTemporary();
    }

    function->add(tac::Quadruple(variable, t1));
}

std::shared_ptr<Variable> computeIndexOfArray(std::shared_ptr<Variable> array, std::shared_ptr<Variable> iterVar, std::shared_ptr<tac::Function> function){
    auto temp = function->context->newTemporary();
    
    function->add(tac::Quadruple(temp, iterVar, tac::Operator::MUL, array->type().size()));
    function->add(tac::Quadruple(temp, temp, tac::Operator::ADD, size(BaseType::INT)));

    return temp;
}

std::shared_ptr<Variable> computeIndexOfArray(std::shared_ptr<Variable> array, ast::Value& indexValue, std::shared_ptr<tac::Function> function){
    auto t1 = function->context->newTemporary();

    moveToVariable(indexValue, t1, function);

    return computeIndexOfArray(array, t1, function);
}

std::shared_ptr<Variable> computeLengthOfArray(std::shared_ptr<Variable> array, std::shared_ptr<tac::Function> function){
    auto t1 = function->context->newTemporary();
    
    auto position = array->position();
    if(position.isGlobal() || position.isStack()){
        function->add(tac::Quadruple(t1, array->type().size()));
    } else if(position.isParameter()){
        function->add(tac::Quadruple(t1, array, tac::Operator::ARRAY, 0));
    }

    return t1;
}

struct AssignValueToArray : public boost::static_visitor<> {
    AssignValueToArray(std::shared_ptr<tac::Function> f, std::shared_ptr<Variable> v, ast::Value& i) : function(f), variable(v), indexValue(i) {}
    
    mutable std::shared_ptr<tac::Function> function;
    std::shared_ptr<Variable> variable;
    ast::Value& indexValue;

    void intAssign(tac::Argument value) const {
        auto index = computeIndexOfArray(variable, indexValue, function); 

        function->add(tac::Quadruple(variable, index, tac::Operator::ARRAY_ASSIGN, value));
    }

    void stringAssign(tac::Argument v1, tac::Argument v2) const {
        auto index = computeIndexOfArray(variable, indexValue, function); 
        
        function->add(tac::Quadruple(variable, index, tac::Operator::ARRAY_ASSIGN, v1));

        auto temp1 = function->context->newTemporary();
        function->add(tac::Quadruple(temp1, index, tac::Operator::ADD, 4));
        function->add(tac::Quadruple(variable, temp1, tac::Operator::ARRAY_ASSIGN, v2));
    }

    void operator()(ast::Litteral& litteral) const {
        stringAssign(litteral.label, litteral.value.size() - 2);
    }

    void operator()(ast::Integer& integer) const {
        intAssign(integer.value);
    }

    void operator()(ast::FunctionCall& call) const {
        Type type = call.Content->function->returnType;

        switch(type.base()){
            case BaseType::INT:{
                auto t1 = function->context->newTemporary();

                executeCall(call, function, t1, {});

                intAssign(t1);
        
                break;
            }
            case BaseType::STRING:{
                auto t1 = function->context->newTemporary();
                auto t2 = function->context->newTemporary();

                executeCall(call, function, t1, t2);

                stringAssign(t1, t2);

                break;
            }
            default:
                throw SemanticalException("This function doesn't return anything");   
        }
    }

    void operator()(ast::VariableValue& value) const {
        auto type = value.Content->var->type();

        if(type.base() == BaseType::INT){
            intAssign(value.Content->var);
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            function->add(tac::Quadruple(t1, value.Content->var, tac::Operator::DOT, 4));

            stringAssign(value.Content->var, t1);
        }
    }

    void operator()(ast::ArrayValue& array) const {
        auto sourceIndex = computeIndexOfArray(array.Content->var, array.Content->indexValue, function); 

        if(array.Content->var->type().base() == BaseType::INT){
            auto t1 = function->context->newTemporary();
            function->add(tac::Quadruple(t1, array.Content->var, tac::Operator::ARRAY, sourceIndex));

            intAssign(t1);
        } else {
            auto t1 = function->context->newTemporary();
            function->add(tac::Quadruple(t1, array.Content->var, tac::Operator::ARRAY, sourceIndex));
             
            auto t2 = array.Content->context->newTemporary();
            auto t3 = array.Content->context->newTemporary();
            
            //Assign the second part of the string
            function->add(tac::Quadruple(t3, sourceIndex, tac::Operator::ADD, 4));
            function->add(tac::Quadruple(t2, array.Content->var, tac::Operator::ARRAY, t3));

            stringAssign(t1, t2);
        }
    }

    void operator()(ast::ComposedValue& value) const {
        Type type = GetTypeVisitor()(value);

        auto index = computeIndexOfArray(variable, indexValue, function); 
        
        if(type.base() == BaseType::INT){
            auto t1 = value.Content->context->newTemporary();
            performIntOperation(value, function, t1);
            intAssign(t1);
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            auto t2 = value.Content->context->newTemporary();

            performStringOperation(value, function, t1, t2);
            
            stringAssign(t1, t2);
        }
    }
};

void assignStringToVariable(std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> variable, tac::Argument v1, tac::Argument v2){
    function->add(tac::Quadruple(variable, v1));
    function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, v2));
}
 
struct AssignValueToVariable : public boost::static_visitor<> {
    AssignValueToVariable(std::shared_ptr<tac::Function> f, std::shared_ptr<Variable> v) : function(f), variable(v) {}
    
    mutable std::shared_ptr<tac::Function> function;
    std::shared_ptr<Variable> variable;

    void operator()(ast::Litteral& litteral) const {
        assignStringToVariable(function, variable, litteral.label, litteral.value.size() - 2);
    }

    void operator()(ast::Integer& integer) const {
        function->add(tac::Quadruple(variable, integer.value));
    }

    void operator()(ast::FunctionCall& call) const {
        Type type = call.Content->function->returnType;

        switch(type.base()){
            case BaseType::INT:
                executeCall(call, function, variable, {});

                break;
            case BaseType::STRING:{
                auto t1 = function->context->newTemporary();

                executeCall(call, function, variable, t1);

                function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, t1));

                break;
            }
            default:
                throw SemanticalException("This function doesn't return anything");   
        }
    }

    void operator()(ast::VariableValue& value) const {
        auto type = value.Content->var->type();

        if(type.base() == BaseType::INT){
            function->add(tac::Quadruple(variable, value.Content->var));
        } else if(type.base() == BaseType::STRING){
            auto temp = value.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, value.Content->var, tac::Operator::DOT, 4));
            
            assignStringToVariable(function, variable, value.Content->var, temp);
        }
    }

    void operator()(ast::ArrayValue& array) const {
        auto index = computeIndexOfArray(array.Content->var, array.Content->indexValue, function); 

        if(array.Content->var->type().base() == BaseType::INT){
            function->add(tac::Quadruple(variable, array.Content->var, tac::Operator::ARRAY, index));
        } else {
            function->add(tac::Quadruple(variable, array.Content->var, tac::Operator::ARRAY, index));
                
            auto t2 = array.Content->context->newTemporary();
            
            //Assign the second part of the string
            function->add(tac::Quadruple(index, index, tac::Operator::ADD, 4));
            function->add(tac::Quadruple(t2, array.Content->var, tac::Operator::ARRAY, index));
            function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, t2));
        }
    }

    void operator()(ast::ComposedValue& value) const {
        Type type = GetTypeVisitor()(value);

        if(type.base() == BaseType::INT){
            performIntOperation(value, function, variable);
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            performStringOperation(value, function, variable, t1);
            
            function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, t1));
        }
    }
};

struct PassValueAsParam : public boost::static_visitor<> {
    PassValueAsParam(std::shared_ptr<tac::Function> f) : function(f) {}
    
    mutable std::shared_ptr<tac::Function> function;

    void operator()(ast::Litteral& litteral) const {
        function->add(tac::Param(litteral.label));
        function->add(tac::Param(litteral.value.size() - 2));
    }

    void operator()(ast::Integer& integer) const {
        function->add(tac::Param(integer.value));
    }

    void operator()(ast::FunctionCall& call) const {
        Type type = call.Content->function->returnType;

        switch(type.base()){
            case BaseType::INT:{
                auto t1 = function->context->newTemporary();

                executeCall(call, function, t1, {});

                function->add(tac::Param(t1));

                break;
            }
            case BaseType::STRING:{
                auto t1 = function->context->newTemporary();
                auto t2 = function->context->newTemporary();

                executeCall(call, function, t1, t2);

                function->add(tac::Param(t1));
                function->add(tac::Param(t2));

                break;
            }
            default:
                throw SemanticalException("This function doesn't return anything");   
        }
    }

    void operator()(ast::VariableValue& value) const {
        auto type = value.Content->var->type();

        if(type.base() == BaseType::INT){
            function->add(tac::Param(value.Content->var));
        } else if(type.base() == BaseType::STRING){
            function->add(tac::Param(value.Content->var));

            auto temp = value.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, value.Content->var, tac::Operator::DOT, 4));
            function->add(tac::Param(temp));
        }
    }

    void operator()(ast::ArrayValue& array) const {
        auto index = computeIndexOfArray(array.Content->var, array.Content->indexValue, function); 

        if(array.Content->var->type().base() == BaseType::INT){
            auto temp = array.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, array.Content->var, tac::Operator::ARRAY, index));
            function->add(tac::Param(temp)); 
        } else {
            auto temp = array.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, array.Content->var, tac::Operator::ARRAY, index));
            function->add(tac::Param(temp)); 
                
            auto t2 = array.Content->context->newTemporary();
            
            //Assign the second part of the string
            function->add(tac::Quadruple(index, index, tac::Operator::ADD, 4));
            function->add(tac::Quadruple(t2, array.Content->var, tac::Operator::ARRAY, index));
            
            function->add(tac::Param(t2)); 
        }
    }

    void operator()(ast::ComposedValue& value) const {
        Type type = GetTypeVisitor()(value);

        if(type.base() == BaseType::INT){
            auto t1 = value.Content->context->newTemporary();
            performIntOperation(value, function, t1);
            function->add(tac::Param(t1));
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            auto t2 = value.Content->context->newTemporary();

            performStringOperation(value, function, t1, t2);
            
            function->add(tac::Param(t1)); 
            function->add(tac::Param(t2)); 
        }
    }
};
<commit_msg>Review the order of parameter passing<commit_after>//=======================================================================
// Copyright <NAME> 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <string>

#include "VisitorUtils.hpp"
#include "Variable.hpp"
#include "SemanticalException.hpp"
#include "FunctionContext.hpp"
#include "GetTypeVisitor.hpp"
#include "GetConstantValue.hpp"
#include "IsConstantVisitor.hpp"
#include "mangling.hpp"

#include "tac/TacCompiler.hpp"
#include "tac/Program.hpp"

#include "ast/Program.hpp"

//TODO Move label generator system in another folder
#include "il/Labels.hpp"

using namespace eddic;

void moveToVariable(ast::Value& value, std::shared_ptr<Variable> variable, std::shared_ptr<tac::Function> function);
void performStringOperation(ast::ComposedValue& value, std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> v1, std::shared_ptr<Variable> v2);
void executeCall(ast::FunctionCall& functionCall, std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> return_, std::shared_ptr<Variable> return2_);

void performIntOperation(ast::ComposedValue& value, std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> variable){
    assert(value.Content->operations.size() > 0); //This has been enforced by previous phases

    auto t1 = value.Content->context->newTemporary();
    auto t2 = value.Content->context->newTemporary();

    moveToVariable(value.Content->first, t1, function);

    //Apply all the operations in chain
    for(auto& operation : value.Content->operations){
        moveToVariable(value.Content->first, t2, function);
        
        function->add(tac::Quadruple(t2, t1, tac::toOperator(operation.get<0>()), t2));

        t1 = t2;
        t2 = value.Content->context->newTemporary();
    }

    function->add(tac::Quadruple(variable, t1));
}

std::shared_ptr<Variable> computeIndexOfArray(std::shared_ptr<Variable> array, std::shared_ptr<Variable> iterVar, std::shared_ptr<tac::Function> function){
    auto temp = function->context->newTemporary();
    
    function->add(tac::Quadruple(temp, iterVar, tac::Operator::MUL, array->type().size()));
    function->add(tac::Quadruple(temp, temp, tac::Operator::ADD, size(BaseType::INT)));

    return temp;
}

std::shared_ptr<Variable> computeIndexOfArray(std::shared_ptr<Variable> array, ast::Value& indexValue, std::shared_ptr<tac::Function> function){
    auto t1 = function->context->newTemporary();

    moveToVariable(indexValue, t1, function);

    return computeIndexOfArray(array, t1, function);
}

std::shared_ptr<Variable> computeLengthOfArray(std::shared_ptr<Variable> array, std::shared_ptr<tac::Function> function){
    auto t1 = function->context->newTemporary();
    
    auto position = array->position();
    if(position.isGlobal() || position.isStack()){
        function->add(tac::Quadruple(t1, array->type().size()));
    } else if(position.isParameter()){
        function->add(tac::Quadruple(t1, array, tac::Operator::ARRAY, 0));
    }

    return t1;
}

struct AssignValueToArray : public boost::static_visitor<> {
    AssignValueToArray(std::shared_ptr<tac::Function> f, std::shared_ptr<Variable> v, ast::Value& i) : function(f), variable(v), indexValue(i) {}
    
    mutable std::shared_ptr<tac::Function> function;
    std::shared_ptr<Variable> variable;
    ast::Value& indexValue;

    void intAssign(tac::Argument value) const {
        auto index = computeIndexOfArray(variable, indexValue, function); 

        function->add(tac::Quadruple(variable, index, tac::Operator::ARRAY_ASSIGN, value));
    }

    void stringAssign(tac::Argument v1, tac::Argument v2) const {
        auto index = computeIndexOfArray(variable, indexValue, function); 
        
        function->add(tac::Quadruple(variable, index, tac::Operator::ARRAY_ASSIGN, v1));

        auto temp1 = function->context->newTemporary();
        function->add(tac::Quadruple(temp1, index, tac::Operator::ADD, 4));
        function->add(tac::Quadruple(variable, temp1, tac::Operator::ARRAY_ASSIGN, v2));
    }

    void operator()(ast::Litteral& litteral) const {
        stringAssign(litteral.label, litteral.value.size() - 2);
    }

    void operator()(ast::Integer& integer) const {
        intAssign(integer.value);
    }

    void operator()(ast::FunctionCall& call) const {
        Type type = call.Content->function->returnType;

        switch(type.base()){
            case BaseType::INT:{
                auto t1 = function->context->newTemporary();

                executeCall(call, function, t1, {});

                intAssign(t1);
        
                break;
            }
            case BaseType::STRING:{
                auto t1 = function->context->newTemporary();
                auto t2 = function->context->newTemporary();

                executeCall(call, function, t1, t2);

                stringAssign(t1, t2);

                break;
            }
            default:
                throw SemanticalException("This function doesn't return anything");   
        }
    }

    void operator()(ast::VariableValue& value) const {
        auto type = value.Content->var->type();

        if(type.base() == BaseType::INT){
            intAssign(value.Content->var);
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            function->add(tac::Quadruple(t1, value.Content->var, tac::Operator::DOT, 4));

            stringAssign(value.Content->var, t1);
        }
    }

    void operator()(ast::ArrayValue& array) const {
        auto sourceIndex = computeIndexOfArray(array.Content->var, array.Content->indexValue, function); 

        if(array.Content->var->type().base() == BaseType::INT){
            auto t1 = function->context->newTemporary();
            function->add(tac::Quadruple(t1, array.Content->var, tac::Operator::ARRAY, sourceIndex));

            intAssign(t1);
        } else {
            auto t1 = function->context->newTemporary();
            function->add(tac::Quadruple(t1, array.Content->var, tac::Operator::ARRAY, sourceIndex));
             
            auto t2 = array.Content->context->newTemporary();
            auto t3 = array.Content->context->newTemporary();
            
            //Assign the second part of the string
            function->add(tac::Quadruple(t3, sourceIndex, tac::Operator::ADD, 4));
            function->add(tac::Quadruple(t2, array.Content->var, tac::Operator::ARRAY, t3));

            stringAssign(t1, t2);
        }
    }

    void operator()(ast::ComposedValue& value) const {
        Type type = GetTypeVisitor()(value);

        auto index = computeIndexOfArray(variable, indexValue, function); 
        
        if(type.base() == BaseType::INT){
            auto t1 = value.Content->context->newTemporary();
            performIntOperation(value, function, t1);
            intAssign(t1);
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            auto t2 = value.Content->context->newTemporary();

            performStringOperation(value, function, t1, t2);
            
            stringAssign(t1, t2);
        }
    }
};

void assignStringToVariable(std::shared_ptr<tac::Function> function, std::shared_ptr<Variable> variable, tac::Argument v1, tac::Argument v2){
    function->add(tac::Quadruple(variable, v1));
    function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, v2));
}
 
struct AssignValueToVariable : public boost::static_visitor<> {
    AssignValueToVariable(std::shared_ptr<tac::Function> f, std::shared_ptr<Variable> v) : function(f), variable(v) {}
    
    mutable std::shared_ptr<tac::Function> function;
    std::shared_ptr<Variable> variable;

    void operator()(ast::Litteral& litteral) const {
        assignStringToVariable(function, variable, litteral.label, litteral.value.size() - 2);
    }

    void operator()(ast::Integer& integer) const {
        function->add(tac::Quadruple(variable, integer.value));
    }

    void operator()(ast::FunctionCall& call) const {
        Type type = call.Content->function->returnType;

        switch(type.base()){
            case BaseType::INT:
                executeCall(call, function, variable, {});

                break;
            case BaseType::STRING:{
                auto t1 = function->context->newTemporary();

                executeCall(call, function, variable, t1);

                function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, t1));

                break;
            }
            default:
                throw SemanticalException("This function doesn't return anything");   
        }
    }

    void operator()(ast::VariableValue& value) const {
        auto type = value.Content->var->type();

        if(type.base() == BaseType::INT){
            function->add(tac::Quadruple(variable, value.Content->var));
        } else if(type.base() == BaseType::STRING){
            auto temp = value.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, value.Content->var, tac::Operator::DOT, 4));
            
            assignStringToVariable(function, variable, value.Content->var, temp);
        }
    }

    void operator()(ast::ArrayValue& array) const {
        auto index = computeIndexOfArray(array.Content->var, array.Content->indexValue, function); 

        if(array.Content->var->type().base() == BaseType::INT){
            function->add(tac::Quadruple(variable, array.Content->var, tac::Operator::ARRAY, index));
        } else {
            function->add(tac::Quadruple(variable, array.Content->var, tac::Operator::ARRAY, index));
                
            auto t2 = array.Content->context->newTemporary();
            
            //Assign the second part of the string
            function->add(tac::Quadruple(index, index, tac::Operator::ADD, 4));
            function->add(tac::Quadruple(t2, array.Content->var, tac::Operator::ARRAY, index));
            function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, t2));
        }
    }

    void operator()(ast::ComposedValue& value) const {
        Type type = GetTypeVisitor()(value);

        if(type.base() == BaseType::INT){
            performIntOperation(value, function, variable);
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            performStringOperation(value, function, variable, t1);
            
            function->add(tac::Quadruple(variable, 4, tac::Operator::DOT_ASSIGN, t1));
        }
    }
};

struct PassValueAsParam : public boost::static_visitor<> {
    PassValueAsParam(std::shared_ptr<tac::Function> f) : function(f) {}
    
    mutable std::shared_ptr<tac::Function> function;

    void operator()(ast::Litteral& litteral) const {
        function->add(tac::Param(litteral.label));
        function->add(tac::Param(litteral.value.size() - 2));
    }

    void operator()(ast::Integer& integer) const {
        function->add(tac::Param(integer.value));
    }

    void operator()(ast::FunctionCall& call) const {
        Type type = call.Content->function->returnType;

        switch(type.base()){
            case BaseType::INT:{
                auto t1 = function->context->newTemporary();

                executeCall(call, function, t1, {});

                function->add(tac::Param(t1));

                break;
            }
            case BaseType::STRING:{
                auto t1 = function->context->newTemporary();
                auto t2 = function->context->newTemporary();

                executeCall(call, function, t1, t2);

                function->add(tac::Param(t1));
                function->add(tac::Param(t2));

                break;
            }
            default:
                throw SemanticalException("This function doesn't return anything");   
        }
    }

    void operator()(ast::VariableValue& value) const {
        auto type = value.Content->var->type();

        if(type.base() == BaseType::INT){
            function->add(tac::Param(value.Content->var));
        } else if(type.base() == BaseType::STRING){
            auto temp = value.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, value.Content->var, tac::Operator::DOT, 4));
            
            function->add(tac::Param(value.Content->var));
            function->add(tac::Param(temp));
        }
    }

    void operator()(ast::ArrayValue& array) const {
        auto index = computeIndexOfArray(array.Content->var, array.Content->indexValue, function); 

        if(array.Content->var->type().base() == BaseType::INT){
            auto temp = array.Content->context->newTemporary();
            function->add(tac::Quadruple(temp, array.Content->var, tac::Operator::ARRAY, index));
            function->add(tac::Param(temp)); 
        } else {
            auto t1 = array.Content->context->newTemporary();
            function->add(tac::Quadruple(t1, array.Content->var, tac::Operator::ARRAY, index));
                
            auto t2 = array.Content->context->newTemporary();
            
            //Assign the second part of the string
            function->add(tac::Quadruple(index, index, tac::Operator::ADD, 4));
            function->add(tac::Quadruple(t2, array.Content->var, tac::Operator::ARRAY, index));
            
            function->add(tac::Param(t1)); 
            function->add(tac::Param(t2)); 
        }
    }

    void operator()(ast::ComposedValue& value) const {
        Type type = GetTypeVisitor()(value);

        if(type.base() == BaseType::INT){
            auto t1 = value.Content->context->newTemporary();
            performIntOperation(value, function, t1);
            function->add(tac::Param(t1));
        } else if(type.base() == BaseType::STRING){
            auto t1 = value.Content->context->newTemporary();
            auto t2 = value.Content->context->newTemporary();

            performStringOperation(value, function, t1, t2);
            
            function->add(tac::Param(t1)); 
            function->add(tac::Param(t2)); 
        }
    }
};

{'fraction_non_alphanumeric': 0.1592050209205021, 'fraction_numerical': 0.008612273361227336, 'mean_word_length': 2.869535887749595, 'pattern_counts': {'":': 0, '<': 79, '<?xml version=': 0, '>': 401, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3914558', 'n_tokens_mistral': 8562, 'n_tokens_neox': 8170, 'n_words': 1491}