<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 "OptimizationEngine.hpp"

#include <boost/variant/static_visitor.hpp>

#include "Types.hpp"
#include "Options.hpp"

#include "IsConstantVisitor.hpp"
#include "GetTypeVisitor.hpp"
#include "VisitorUtils.hpp"
#include "ASTVisitor.hpp"

using namespace eddic;

struct GetIntValue : public boost::static_visitor<int> {
    int operator()(ASTComposedValue& value) const {
        int acc = boost::apply_visitor(*this, value.first);

        for(auto& operation : value.operations){
            int v = boost::apply_visitor(*this, operation.get<1>());
            char op = operation.get<0>();

            switch(op){
                case '+':
                    acc += v;
                    break;
                case '-':
                    acc -= v;
                    break;
                case '*':
                    acc *= v;
                    break;
                case '/':
                    acc /= v;
                    break;
                case '%':
                    acc %= v;
                    break;
            }
        }

        return acc;
    }

    int operator()(ASTInteger& integer) const {
        return integer.value; 
    }
    
    int operator()(ASTVariable&) const {
        assert(false); //A variable is not constant

        return -1; 
    }
    
    int operator()(ASTLitteral&) const {
        assert(false); //A litteral is not integer

        return -1;
    }
};

struct ValueOptimizer : public boost::static_visitor<ASTValue> {
    ASTValue operator()(ASTComposedValue& value) const {
        if(value.operations.empty()){
            return boost::apply_visitor(*this, value.first);   
        }

        //If the value is constant, we can replace it with the results of the computation
        if(IsConstantVisitor()(value)){
            Type type = GetTypeVisitor()(value);

            if(type == Type::INT){
                if (Options::isSet(BooleanOption::OPTIMIZE_INTEGERS)) {
                    ASTInteger integer;
                    integer.value = GetIntValue()(value);
                    return integer; 
                }
            } else if(type == Type::STRING){
                if (Options::isSet(BooleanOption::OPTIMIZE_STRINGS)) {
                    //No optimizations for now
                }
            }
        }

        //If we get there, that means that no addition has been (or can be) performed
        return value;
    }

    ASTValue operator()(ASTVariable& variable) const {
        return variable; //A variable is not optimizable
    }
    
    ASTValue operator()(ASTInteger& integer) const {
        return integer; //A variable is not optimizable
    }
    
    ASTValue operator()(ASTLitteral& litteral) const {
        return litteral; //A variable is not optimizable
    }<commit_msg>Improve optimization for composed values<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 "OptimizationEngine.hpp"

#include <boost/variant/static_visitor.hpp>

#include "Types.hpp"
#include "Options.hpp"

#include "IsConstantVisitor.hpp"
#include "GetTypeVisitor.hpp"
#include "VisitorUtils.hpp"
#include "ASTVisitor.hpp"

using namespace eddic;

struct GetIntValue : public boost::static_visitor<int> {
    int operator()(ASTComposedValue& value) const {
        int acc = boost::apply_visitor(*this, value.first);

        for(auto& operation : value.operations){
            int v = boost::apply_visitor(*this, operation.get<1>());
            char op = operation.get<0>();

            switch(op){
                case '+':
                    acc += v;
                    break;
                case '-':
                    acc -= v;
                    break;
                case '*':
                    acc *= v;
                    break;
                case '/':
                    acc /= v;
                    break;
                case '%':
                    acc %= v;
                    break;
            }
        }

        return acc;
    }

    int operator()(ASTInteger& integer) const {
        return integer.value; 
    }
    
    int operator()(ASTVariable&) const {
        assert(false); //A variable is not constant

        return -1; 
    }
    
    int operator()(ASTLitteral&) const {
        assert(false); //A litteral is not integer

        return -1;
    }
};

struct ValueOptimizer : public boost::static_visitor<ASTValue> {
    ASTValue operator()(ASTComposedValue& value) const {
        if(value.operations.empty()){
            return boost::apply_visitor(*this, value.first);   
        }

        //If the value is constant, we can replace it with the results of the computation
        if(IsConstantVisitor()(value)){
            Type type = GetTypeVisitor()(value);

            if(type == Type::INT){
                if (Options::isSet(BooleanOption::OPTIMIZE_INTEGERS)) {
                    ASTInteger integer;
                    integer.value = GetIntValue()(value);
                    return integer; 
                }
            } else if(type == Type::STRING){
                if (Options::isSet(BooleanOption::OPTIMIZE_STRINGS)) {
                    //No optimizations for now
                }
            }
        }

        //Optimize the first value
        value.first = boost::apply_visitor(*this, value.first);

        //We can try to optimize every part of the composed value
        auto start = value.operations.begin();
        auto end = value.operations.end();

        while(start != end){
            start->get<1>() = boost::apply_visitor(*this, start->get<1>());
            
            ++start;
        }

        assert(value.operations.size() > 0); //Once here, there is no more empty composed value 

        //If we get there, that means that no optimization has been (or can be) performed
        return value;
    }

    ASTValue operator()(ASTVariable& variable) const {
        return variable; //A variable is not optimizable
    }
    
    ASTValue operator()(ASTInteger& integer) const {
        return integer; //A variable is not optimizable
    }
    
    ASTValue operator()(ASTLitteral& litteral) const {
        return litteral; //A variable is not optimizable
    }
{'fraction_non_alphanumeric': 0.14755060134936931, 'fraction_numerical': 0.004546787914344382, 'mean_word_length': 1.8236024844720498, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 20, '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': '4008876', 'n_tokens_mistral': 1853, 'n_tokens_neox': 1722, 'n_words': 469}