text:
// Copyright 2020-2022 The Defold Foundation
// Copyright 2014-2020 King
// Copyright 2009-2014 Ragnar Svensson, Christian Murray
// Licensed under the Defold License version 1.0 (the "License"); you may not use
// this file except in compliance with the License.
//
// You may obtain a copy of the License, together with FAQs at
// https://www.defold.com/license
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.

#include <stdint.h>
#define JC_TEST_IMPLEMENTATION
#include <jc_test/jc_test.h>

#include <dlib/hash.h>
#include <script/script.h>

#include "render/render_ddf.h"
#include "render/render.h"
#include "render/display_profiles.h"
#include "render/display_profiles_private.h"

TEST(dmDisplayProfilesTest, TestDeviceModel)
{
    dmSys::SystemInfo sys_info;
    memcpy(&sys_info.m_DeviceModel, "banana-phone", 13);

    dmRender::DisplayProfiles::Qualifier qualifier;
    qualifier.m_DeviceModels = new char*[1];

    qualifier.m_DeviceModels[0] =strdup("apple-phone");
    qualifier.m_NumDeviceModels = 1;
    ASSERT_EQ(false, dmRender::DeviceModelMatch(&qualifier, &sys_info));
    free(qualifier.m_DeviceModels[0]);

    qualifier.m_DeviceModels[0] = strdup("banana-phone");
    ASSERT_EQ(true, dmRender::DeviceModelMatch(&qualifier, &sys_info));
    free(qualifier.m_DeviceModels[0]);

    delete[] qualifier.m_DeviceModels;
}

TEST(dmDisplayProfilesTest, TestOptimalProfile)
{
    char** device_models = new char*[1];
    device_models[0] = strdup("a device model");
    dmRenderDDF::DisplayProfileQualifier qualifiers[] =
    {
        { 1280, 720, {0x0, 0} },
        { 720, 1280, {0x0, 0} },
        { 722, 1280, {0x0, 0} },
        { 722, 1280, {0x0, 0} },
        { 2560, 960, {0x0, 0} },
        { 1280, 722, {0x0, 0} },
        { 1280, 900, {(const char**)device_models, 1} }
    };
    dmRenderDDF::DisplayProfile profile[] =
    {
        { "profile1", { &qualifiers[0], 1 }},
        { "profile2", { &qualifiers[1], 1 }},
        { "profile3", { &qualifiers[2], 1 }},
        { "profile4", { &qualifiers[3], 1 }},
        { "profile5", { &qualifiers[4], 2 }},
        { "profile6", { &qualifiers[5], 1 }},
        { "profile7", { &qualifiers[6], 1 }}
    };
    dmRenderDDF::DisplayProfiles display_profiles =
    {
        { &profile[0], 7 }
    };

    dmhash_t q_hash[] = {
        dmHashString64(profile[0].m_Name),
        dmHashString64(profile[1].m_Name),
        dmHashString64(profile[2].m_Name),
        dmHashString64(profile[3].m_Name),
        dmHashString64(profile[4].m_Name),
        dmHashString64(profile[5].m_Name),
        dmHashString64(profile[6].m_Name)
    };

    dmRender::HDisplayProfiles profiles = dmRender::NewDisplayProfiles();
    ASSERT_NE((uintptr_t)profiles, 0);

    dmRender::DisplayProfilesParams params;
    params.m_DisplayProfilesDDF = &display_profiles;
    params.m_NameHash = dmHashString64("profiles");
    uint32_t profile_count = display_profiles.m_Profiles.m_Count;
    ASSERT_EQ(profile_count, dmRender::SetDisplayProfiles(profiles, params));
    ASSERT_EQ(params.m_NameHash, dmRender::GetDisplayProfilesName(profiles));

    for(uint32_t i = 0; i < profile_count; ++i)
    {
        dmRender::DisplayProfileDesc desc;
        dmRender::Result r = dmRender::GetDisplayProfileDesc(profiles, q_hash[i], desc);
        ASSERT_EQ(dmRender::RESULT_OK, r);
        ASSERT_EQ(qualifiers[i].m_Width, desc.m_Width);
        ASSERT_EQ(qualifiers[i].m_Height, desc.m_Height);
    }

    ASSERT_EQ(q_hash[0],  dmRender::GetOptimalDisplayProfile(profiles, 1280, 720, 0, 0));
    ASSERT_EQ(q_hash[1],  dmRender::GetOptimalDisplayProfile(profiles, 720, 1280, 0, 0));
    ASSERT_EQ(q_hash[2],  dmRender::GetOptimalDisplayProfile(profiles, 721, 1280, 0, 0));   // testing result is first found match
    ASSERT_EQ(q_hash[4],  dmRender::GetOptimalDisplayProfile(profiles, 1280, 722, 0, 0));   // testing multiple qualifiers
    // testing really large screen (i.e. if you start using a new device, but haven't yet added new display profiles)
    ASSERT_EQ(q_hash[4],  dmRender::GetOptimalDisplayProfile(profiles, 10000, 5625, 0, 0));
    ASSERT_EQ(q_hash[2],  dmRender::GetOptimalDisplayProfile(profiles, 5625, 10000, 0, 0));
    // should never pick q_hash[6] with device-model qualifier even though it has the best resolution match
    ASSERT_NE(q_hash[6],  dmRender::GetOptimalDisplayProfile(profiles, 1280, 900, 0, 0));
    ASSERT_EQ(q_hash[4],  dmRender::GetOptimalDisplayProfile(profiles, 1280, 900, 0, 0));

    dmArray<dmhash_t> choices;
    choices.SetCapacity(2);
    choices.Push(q_hash[0]);
    choices.Push(q_hash[1]);
    ASSERT_EQ(q_hash[1], dmRender::GetOptimalDisplayProfile(profiles, 721, 1280, 0, &choices)); // cherry picking

    dmRender::DeleteDisplayProfiles(profiles);
    free(device_models[0]);
    delete[] device_models;
}

TEST(dmDisplayProfilesTest, TestProjectWithoutProfiles)
{
    dmRenderDDF::DisplayProfiles display_profiles = {};

    dmRender::HDisplayProfiles profiles = dmRender::NewDisplayProfiles();
    dmRender::DisplayProfilesParams params;
    params.m_DisplayProfilesDDF = &display_profiles;
    params.m_NameHash = dmHashString64("profiles");

    dmRender::SetDisplayProfiles(profiles, params);
    dmRender::DeleteDisplayProfiles(profiles);
}

int main(int argc, char **argv)
{
    jc_test_init(&argc, argv);
    return jc_test_run_all();
}

max_stars_repo_name: cmarincia/defold

max_issues_repo_name: cmarincia/defold

max_forks_repo_name: cmarincia/defold


text:
#include <iostream>
#include <cassert>
#include <vector>
#include <iomanip>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/successive_shortest_path_nonnegative_weights.hpp>
#include <boost/graph/find_flow_cost.hpp>

typedef boost::adjacency_list_traits<boost::vecS, boost::vecS, boost::directedS> GraphTraits;
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, boost::no_property,
                              boost::property<boost::edge_capacity_t, long,
                                              boost::property<boost::edge_residual_capacity_t, long,
                                                              boost::property<boost::edge_reverse_t, GraphTraits::edge_descriptor,
                                                                              boost::property<boost::edge_weight_t, long>>>>>
    Graph;

const int debug_level = 0;

#define DEBUG(min_level, x)      \
  if (debug_level >= min_level)  \
  {                              \
    std::cerr << x << std::endl; \
  }

struct Booking
{
  int s, t, d, a, p;
};

const int max_possible_profit = 100;

class TimeIndexer
{
public:
  void add_time(int t)
  {
    time_set.insert(t);
  }

  void rebuild()
  {
    time_vector.resize(time_set.size());
    std::copy(time_set.begin(), time_set.end(), time_vector.begin());
  }

  int time_to_index(int t) const
  {
    const auto it = std::lower_bound(time_vector.begin(), time_vector.end(), t);
    assert(it != time_vector.end() && *it == t);
    return it - time_vector.begin();
  }

  int index_to_time(int i) const
  {
    return time_vector.at(i);
  }

  int size() const
  {
    return time_set.size();
  }

private:
  std::set<int> time_set;
  std::vector<int> time_vector;
};

void testcase()
{
  int n, s;
  std::cin >> n >> s;
  assert(n >= 1 && n <= 10000 && s >= 2 && s <= 10);

  int total_cars = 0;
  std::vector<int> initial_cars_by_station(s);
  for (int &l : initial_cars_by_station)
  {
    std::cin >> l;
    assert(l >= 0 && l <= 100);
    total_cars += l;
  }

  std::vector<Booking> bookings(n);
  for (Booking &b : bookings)
  {
    std::cin >> b.s >> b.t >> b.d >> b.a >> b.p;
    assert(b.s >= 1 && b.s <= s && b.t >= 1 && b.t <= s);
    b.s--;
    b.t--;
    assert(b.d >= 0 && b.d < b.a && b.a <= 100000);
    assert(b.p >= 1 && b.p <= max_possible_profit);
  }

  TimeIndexer global_time_indexer;
  std::vector<TimeIndexer> local_time_indexers(s);
  for (Booking &b : bookings)
  {
    global_time_indexer.add_time(b.d);
    global_time_indexer.add_time(b.a);
    local_time_indexers.at(b.s).add_time(b.d);
    local_time_indexers.at(b.t).add_time(b.a);
  }

  global_time_indexer.rebuild();
  for (TimeIndexer &local_time_indexer : local_time_indexers)
  {
    // IMPORTANT The first and last global time must exist at every station, otherwise
    // the max_possible_profit * global_time_slot_delta compensation won't work correctly
    local_time_indexer.add_time(global_time_indexer.index_to_time(0));
    local_time_indexer.add_time(global_time_indexer.index_to_time(global_time_indexer.size() - 1));

    local_time_indexer.rebuild();
  }

  std::vector<int> local_time_slot_cumulative_sum{0};
  for (int i = 0; i < s; i++)
  {
    local_time_slot_cumulative_sum.push_back(local_time_slot_cumulative_sum.back() + local_time_indexers.at(i).size());
  }

  int next_free_node = 0;
  const int node_source = next_free_node++;
  const int node_target = next_free_node++;
  const auto get_station_time_node = [next_free_node, s, &local_time_indexers, &local_time_slot_cumulative_sum](const int i_time, const int i_station) {
    assert(i_station >= 0 && i_station < s && i_time >= 0 && i_time < local_time_indexers.at(i_station).size());
    return next_free_node + local_time_slot_cumulative_sum.at(i_station) + i_time;
  };
  next_free_node += local_time_slot_cumulative_sum.back();
  const auto get_trip_node = [next_free_node, n](const int i_trip) {
    assert(i_trip >= 0 && i_trip < n);
    return next_free_node + i_trip;
  };
  next_free_node += n;
  const int num_nodes = next_free_node;
  Graph G(num_nodes);

  const auto add_edge = [&G](int from, int to, long capacity, long cost) {
    auto c_map = boost::get(boost::edge_capacity, G);
    auto r_map = boost::get(boost::edge_reverse, G);
    auto w_map = boost::get(boost::edge_weight, G);
    const Graph::edge_descriptor e = boost::add_edge(from, to, G).first;
    const Graph::edge_descriptor rev_e = boost::add_edge(to, from, G).first;
    c_map[e] = capacity;
    c_map[rev_e] = 0;
    r_map[e] = rev_e;
    r_map[rev_e] = e;
    w_map[e] = cost;
    w_map[rev_e] = -cost;
  };

  for (int i_station = 0; i_station < s; i_station++)
  {
    const TimeIndexer &local_time_indexer = local_time_indexers.at(i_station);

    add_edge(node_source, get_station_time_node(0, i_station), initial_cars_by_station.at(i_station), 0);
    add_edge(get_station_time_node(local_time_indexer.size() - 1, i_station), node_target, total_cars, 0);

    for (int i_time = 1; i_time < local_time_indexer.size(); i_time++)
    {
      const int global_time_slot_delta = global_time_indexer.time_to_index(local_time_indexer.index_to_time(i_time)) - global_time_indexer.time_to_index(local_time_indexer.index_to_time(i_time - 1));
      assert(global_time_slot_delta > 0);
      add_edge(get_station_time_node(i_time - 1, i_station), get_station_time_node(i_time, i_station), total_cars, global_time_slot_delta * max_possible_profit);
    }
  }

  for (int i_trip = 0; i_trip < n; i_trip++)
  {
    Booking &b = bookings.at(i_trip);
    const int i_d = local_time_indexers.at(b.s).time_to_index(b.d), i_a = local_time_indexers.at(b.t).time_to_index(b.a);
    const int global_time_slot_delta = global_time_indexer.time_to_index(b.a) - global_time_indexer.time_to_index(b.d);
    assert(global_time_slot_delta > 0);
    add_edge(get_station_time_node(i_d, b.s), get_trip_node(i_trip), 1, max_possible_profit * global_time_slot_delta - b.p);
    add_edge(get_trip_node(i_trip), get_station_time_node(i_a, b.t), 1, 0);
  }

  boost::successive_shortest_path_nonnegative_weights(G, node_source, node_target);
  const int flow_cost = boost::find_flow_cost(G);
  const int total_profit = total_cars * (global_time_indexer.size() - 1) * max_possible_profit - flow_cost;
  std::cout << total_profit << "\n";
}

int main()
{
  std::ios_base::sync_with_stdio(false);
  std::cout << std::fixed << std::setprecision(0);

  int t;
  std::cin >> t;
  for (int i = 0; i < t; i++)
  {
    testcase();
    DEBUG(1, "");
  }

  return 0;
}

ext: cpp

max_stars_repo_name: tehwalris/algolab

max_issues_repo_name: tehwalris/algolab

max_forks_repo_name: tehwalris/algolab


text:
#include <boost/python.hpp>
#include "bloom_filter.hpp"
using namespace boost::python;

BOOST_PYTHON_MODULE(google_bloom) {
    class_<bloom_parameters>("BloomParameters")
        .def("compute_optimal_paramters", &bloom_parameters::compute_optimal_paramters);
        .def_readwrite("projected_element_count", &bloom_parameters::projected_element_count)
        .def_readwrite("false_positive_probability", &bloom_parameters::false_positive_probability)
        .def_readwrite("random_seed", &bloom_parameters::random_seed);

    class_<bloom_parameters::optimal_parameters_t>("OptimalParameters");

    class_<bloom_filter>("BloomFilter")
        .def(init<bloom_parameters>())
        .def(init<bloom_filter>())
        .def("clear", &bloom_filter::clear)
        .def("insert", &bloom_filter::insert0)
        .def("insert", &bloom_filter::insert1)
        .def("insert", &bloom_filter::insert2)
        .def("insert", &bloom_filter::insert3)
        .def("insert", &bloom_filter::insert4)
        .def("contains", &bloom_filter::contains0)
        .def("contains", &bloom_filter::contains1)
        .def("contains", &bloom_filter::contains2)
        .def("contains", &bloom_filter::contains3)
        .def("contains", &bloom_filter::contains4)
        .def("contains_all", &bloom_filter::contains_all)
        .def("contains_none", &bloom_filter::contains_none)
        .def("size", &bloom_filter::size)
        .def("element_count", &bloom_filter::element_count)
        .def("effective_fpp", &bloom_filter::effective_fpp);
}

max_stars_repo_name: yaatehr/learnedbloomfilter

max_issues_repo_name: yaatehr/learnedbloomfilter

max_forks_repo_name: yaatehr/learnedbloomfilter


text:
//==================================================================================================
/*!
  @file

  @copyright 2016 NumScale SAS

  Distributed under the Boost Software License, Version 1.0.
  (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/
//==================================================================================================
#ifndef BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_HMSB_HPP_INCLUDED
#define BOOST_SIMD_ARCH_COMMON_SIMD_FUNCTION_HMSB_HPP_INCLUDED
#include <boost/simd/detail/overload.hpp>

#include <boost/simd/meta/hierarchy/simd.hpp>
#include <boost/simd/function/bitwise_cast.hpp>
#include <boost/simd/detail/dispatch/meta/as_integer.hpp>
#include <boost/simd/function/genmask.hpp>
#include <boost/simd/detail/dispatch/meta/scalar_of.hpp>
#include <climits>
#include <cstddef>

namespace boost { namespace simd { namespace ext
{
   namespace bd = boost::dispatch;
   namespace bs = boost::simd;
   BOOST_DISPATCH_OVERLOAD(hmsb_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , bs::pack_<bd::arithmetic_<A0>, X>
                          )
   {
      BOOST_FORCEINLINE std::size_t operator()( const A0& a0) const BOOST_NOEXCEPT
      {
        using stype = bd::scalar_of_t<A0>;
        using itype = bd::as_integer_t<stype, unsigned>;
        std::size_t z = 0;
        const std::size_t N = A0::static_size;
        for(std::size_t i = 0; i != N; ++i)
        {
          stype t = a0[i]; // TO DO why must I use t or else bitwise_cast does not compile (clang 3.6)?
          z |= size_t((bitwise_cast<itype>(t) >> (sizeof(stype)*CHAR_BIT - 1)) << i);
        }
         return z;
      }
   };

   BOOST_DISPATCH_OVERLOAD(hmsb_
                          , (typename A0, typename X)
                          , bd::cpu_
                          , bs::pack_<bs::logical_<A0>, X>
                          )
   {
     BOOST_FORCEINLINE std::size_t operator()( const A0& a0) const BOOST_NOEXCEPT
      {
        return bs::hmsb(bs::genmask(a0));
      }
   };

} } }

#endif

ext: hpp

max_stars_repo_name: xmar/pythran

max_issues_repo_name: xmar/pythran

max_forks_repo_name: xmar/pythran


text:
/*

MIT License

Copyright (c) 2018 Federico Terzi

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

#include <iostream>
#include <string>
#include <unordered_set>
#include <algorithm>
#include <memory>
#include <set>
#include <limits>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/lexical_cast/bad_lexical_cast.hpp>
#include "DefaultEvaluator.h"
#include "../parser/element/TextElement.h"
#include "../parser/element/Block.h"
#include "../parser/element/Assignment.h"
#include "../parser/element/VariableRead.h"
#include "../parser/element/FunctionDefinition.h"
#include "../parser/element/FunctionCall.h"
#include "../parser/element/FunctionCallArgument.h"
#include "../parser/element/IfCase.h"
#include "parser/element/IfStatement.h"
#include "parser/element/ForStatement.h"
#include "parser/element/expression/BinaryExpression.h"
#include "parser/element/expression/AddExpression.h"
#include "parser/element/expression/MultiplicationExpression.h"
#include "parser/element/expression/DivisionExpression.h"
#include "parser/element/expression/SubtractExpression.h"
#include "parser/element/expression/EqualExpression.h"
#include "parser/element/expression/NotEqualExpression.h"
#include "parser/element/NoopStatement.h"
#include "parser/util/LateCallDescriptor.h"
#include "exception/RuntimeException.h"

ninx::evaluator::DefaultEvaluator::DefaultEvaluator(std::ostream &output) : output(output) {}

void ninx::evaluator::DefaultEvaluator::evaluate(ninx::parser::element::Block *e) {
    this->visit(e);
}

// RETURN BLOCK MECHANISM

ninx::parser::element::Block * current_return_block;  // This is used to obtain the result block from an expression

std::unique_ptr<ninx::parser::element::Block> get_owned_return_block() {
    std::unique_ptr<ninx::parser::element::Block> new_obj(current_return_block);
    // Reset the current return block
    current_return_block = nullptr;

    return new_obj;
};

void reset_return_block() {
    // Free up the memory if a previous block was used
    delete current_return_block;
    current_return_block = nullptr;
}

void replace_return_block(std::unique_ptr<ninx::parser::element::Block> new_block) {
    reset_return_block();

    current_return_block = new_block.release();
}

// ECHOING MECHANISM

bool is_echoing_disabled = false;

bool disable_echoing() {
    bool changed = false;

    if (!is_echoing_disabled) {
        is_echoing_disabled = true;
        changed = true;
    }

    return changed;
}

void enable_echoing(bool changed) {
    if (changed) {
        is_echoing_disabled = false;
    }
}

void no_echo(const std::function<void()> &block) {
    bool changed = disable_echoing();

    block();

    enable_echoing(changed);
}

// NAVIGATING OBJECT TREES

ninx::parser::element::Block * navigate_object_tree(ninx::parser::element::Block * parent, const std::string &target, std::string &field_name) {
    // Resolve the name, navigating the call hierarchy.
    std::vector<std::string> hierarchy;
    boost::split(hierarchy, target, boost::is_any_of("."));
    ninx::parser::element::Block * current_object {parent};
    for (int i = 0; i<hierarchy.size()-1; i++) {
        auto object {current_object->get_variable(hierarchy[i])};

        if (!object) {
            // TODO: add information of line number and origin
            throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Object \""+hierarchy[i]+"\" does not have child '"+hierarchy[i]+"'!");
        }

        current_object = object;
    }

    field_name = hierarchy[hierarchy.size()-1];

    return current_object;
}

// FUNCTION RELATED VISITING

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::FunctionCall *call) {
    // Obtain the referenced object by navigating the name structure
    std::string field_name;
    auto target_object { navigate_object_tree(call->get_parent(), call->get_name(), field_name) };

    // Get the target function
    auto function {target_object->get_function(field_name)};

    if (!function) {
        // The function is not defined, check if it is a builtin one.
        auto builtin{target_object->get_builtin(field_name)};

        if (builtin) { // Builtin function exist.
            function = builtin;
        } else {  // Not a builtin either
            // TODO: add information of line number and origin
            throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Function \"" + call->get_name() +
                                                                          "\" has not been declared!");
        }
    }

    // Clone the function definition body, to generate a new instance
    auto body {function->get_body()->clone<ninx::parser::element::Block>()};

    body->__set_output_block(call->__get_output_block());

    // Load all the call arguments

    // Check if the call arguments are too many
    if (call->get_argument_count() > function->get_arguments().size()) {
        // TODO: add information of line number and origin
        throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Function \""+call->get_name()+"\" is called with too many parameters!");
    }

    // Check if the named call arguments are present in the function definition and make sure that
    // after a named parameter, no ordinal parameters can be used.
    // Then populate the call arguments as function body block local variables
    bool named_started {false};
    int index {0};  // Current ordinal parameter index

    std::unordered_set<std::string> call_mandatory_arguments;

    for (auto &argument : call->get_arguments()) {
        if (argument->get_name()) {
            auto argument_name {*(argument->get_name())};
            named_started = true;

            if (!function->check_argument(argument_name)){
                // TODO: add information of line number and origin
                throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Argument \"" + *(argument->get_name()) +
                                                                              "\" is not a valid for function \""+call->get_name()+"\"");
            }

            if (function->check_mandatory(argument_name)) {
                call_mandatory_arguments.insert(argument_name);
            }

            // Evaluate the argument value and get the result
            reset_return_block();
            argument->accept(this);
            auto result_value {get_owned_return_block()};

            // Setup the argument as a local variable
            body->set_variable(argument_name, std::move(result_value), true);
        }else{
            // Check if an ordinal parameter has been used after a named parameter
            if (named_started) {
                // TODO: add information of line number and origin
                throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Cannot use ordinals arguments after a named argument");
            }

            auto definition_argument {function->get_arguments().at(static_cast<unsigned long long int>(index)).get()};

            if (function->check_mandatory(definition_argument->get_name())) {
                call_mandatory_arguments.insert(definition_argument->get_name());
            }

            // Evaluate the argument value and get the result
            reset_return_block();
            argument->accept(this);
            auto result_value {get_owned_return_block()};

            // Setup the argument as a local variable
            body->set_variable(definition_argument->get_name(), std::move(result_value), true);
        }
        index++;
    }

    // Add also the outer_argument
    if (call->get_outer_argument()) {
        auto last_definition_argument {function->get_arguments().at(function->get_arguments().size()-1).get()};

        if (function->check_mandatory(last_definition_argument->get_name())) {
            call_mandatory_arguments.insert(last_definition_argument->get_name());
        }

        // Evaluate the argument value and get the result
        reset_return_block();
        call->get_outer_argument()->accept(this);
        auto result_value {get_owned_return_block()};

        // Setup the argument as a local variable
        body->set_variable(last_definition_argument->get_name(), std::move(result_value), true);
    }

    // Check if all mandatory arguments are been used
    if (call_mandatory_arguments.size() != function->get_mandatory_arguments().size()) {
        std::set<std::string> missing;

        // Find the missing parameters by calculating the difference between the definition and the call
        std::set_difference(function->get_mandatory_arguments().begin(), function->get_mandatory_arguments().end(),
                            call_mandatory_arguments.begin(), call_mandatory_arguments.end(),
                            std::inserter(missing, missing.end()));

        auto joined_missing {boost::algorithm::join(missing, ", ")};
        // TODO: add information of line number and origin
        throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Missing required arguments: \""+joined_missing+"\"");
    }

    if (!call->is_late_call()) {  // Not a late call, evaluate immediately
        evaluate_function(target_object, function, std::move(body));
    }else{  // Late call, register it to be called later.
        // Create the late call descriptor
        auto descriptor = std::make_unique<ninx::parser::util::LateCallDescriptor>(std::move(body), function, target_object);
        call->get_parent()->__add_late_call(std::move(descriptor));
    }
}

void ninx::evaluator::DefaultEvaluator::evaluate_function(ninx::parser::element::Block *target_object,
                                                          ninx::parser::element::FunctionDefinition *function,
                                                          std::unique_ptr<ninx::parser::element::Block> body) {
    // Evaluate the result. ( Used for builtin functions, otherwise it is a noop ).
    auto result {function->evaluate(target_object, std::move(body))};

    if (result) {
        result->accept(this);
    }
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::FunctionDefinition *e) {
    auto definition_copy {e->clone<ninx::parser::element::FunctionDefinition>()};

    // Load all the function argument default as local variables in the function body block
    for (auto &argument : definition_copy->get_arguments()) {
        // Evaluate the argument
        reset_return_block();
        argument->accept(this);

        auto argument_value {get_owned_return_block()};
        // If the argument is non-null, copy the value
        if (argument_value) {
            definition_copy->get_body()->set_variable(argument->get_name(), std::move(argument_value), true);
        }
    }

    e->get_parent()->set_function(e->get_name(), std::move(definition_copy));
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::FunctionArgument *e) {
    no_echo([&]{
        // Evaluate the default value if present
        if (e->get_default_value()) {
            e->get_default_value()->accept(this);
        }
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::FunctionCallArgument *e) {
    no_echo([&]{
        // Evaluate the argument value
        e->get_value()->accept(this);
    });
}

// VARIABLES

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::VariableRead *e) {
    // Obtain the referenced object by navigating the name structure
    std::string field_name;
    auto target_object { navigate_object_tree(e->get_parent(), e->get_name(), field_name) };

    auto variable {target_object->get_variable(field_name)};

    if (!variable) {
        // TODO: add information of line number and origin
        throw ninx::evaluator::exception::RuntimeException(0, "TODO", "Variable \""+e->get_name()+"\" has not been declared!");
    }

    variable->__set_output_block(e->get_parent());
    variable->accept(this);

    // Recover the trailing spaces
    if (e->get_parent()->is_echoing() && !is_echoing_disabled) {
        e->get_parent()->__add_output_segment(std::string(e->get_trailing_spaces(), ' '));
    }
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::Assignment *e) {
    no_echo([&]{
        // Evaluate the expression
        reset_return_block();
        e->get_value()->accept(this);

        // Get the result as a unique pointer and move it to the block scope
        auto result {get_owned_return_block()};

        // Obtain the correct object by traversing the name structure
        std::string field_name;
        auto target_object { navigate_object_tree(e->get_parent(), e->get_name(), field_name) };

        target_object->set_variable(field_name, std::move(result), false);
    });
}

// EXPRESSION EVALUATION

double last_evaluation_value = 0;  // Used to keep the current total for the expression evaluation

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::TextElement *e) {
    // If the parent is echoing, print the text
    if (e->get_parent()->is_echoing() && !is_echoing_disabled) {
        e->__get_output_block()->__add_output_segment(e->get_text());
    }

    // If the text is a numeric value, store the value for the expression evaluation
    // TODO: make this check more efficient
    try
    {
        last_evaluation_value = e->convert_to_double();
    }
    catch(const boost::bad_lexical_cast &)
    {
        last_evaluation_value = std::numeric_limits<double>::quiet_NaN();
    }
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::Block *e) {
    for (auto &statement : e->get_children()) {
        statement->__set_output_block(e);
        statement->accept(this);
    }

    // Evaluate late calls
    for (auto& call : e->__get_late_calls()) {
        size_t position {call.first};

        e->__set_output_segment_position(position);

        evaluate_function(call.second->get_target_object(), call.second->get_function(), call.second->get_body()->clone<ninx::parser::element::Block>());
    }

    auto block_output {e->__render_output()};

    if (e->__get_output_block()) {
        e->__get_output_block()->__add_output_segment(block_output);
    }else{
        this->output << block_output;
    }

    // Clone the block and make it available as a return value
    replace_return_block(e->clone<ninx::parser::element::Block>());
}

void ninx::evaluator::DefaultEvaluator::visit_binary_expression(ninx::parser::element::BinaryExpression *e,
                                                                std::function<double(double, double)> const &operation) {
    no_echo([&]{
        // Reset the return block pointer
        reset_return_block();

        e->get_first()->accept(this);
        double first_operand {last_evaluation_value};

        e->get_second()->accept(this);
        double second_operand {last_evaluation_value};

        last_evaluation_value = operation(first_operand, second_operand);

        auto result_block {ninx::parser::element::Block::make_text_block(e->get_parent(), boost::lexical_cast<std::string>(last_evaluation_value))};
        replace_return_block(std::move(result_block));
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::AddExpression *e) {
    visit_binary_expression(e, [](double first, double second) {
        return first + second;
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::SubtractExpression *e) {
    visit_binary_expression(e, [](double first, double second) {
        return first - second;
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::MultiplicationExpression *e) {
    visit_binary_expression(e, [](double first, double second) {
        return first * second;
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::DivisionExpression *e) {
    visit_binary_expression(e, [](double first, double second) {
        return first / second;
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::EqualExpression *e) {
    visit_binary_expression(e, [](double first, double second) {
        return first == second;
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::NotEqualExpression *e) {
    visit_binary_expression(e, [](double first, double second) {
        return first != second;
    });
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::IfStatement *e) {
    bool condition_fulfilled {false};  // Becomes true if at least one case of the if is correct, used to trigger the else body.

    for (auto &if_case : e->get_cases()) {
        // Evaluate the condition
        if_case->accept(this);

        if (last_evaluation_value == 1) {
            condition_fulfilled = true;

            auto body { if_case->get_body()->clone<ninx::parser::element::Block>() };
            body->__set_output_block(e->__get_output_block());

            body->accept(this);

            break;
        }
    }

    if (!condition_fulfilled && e->get_else_body()) {  // No conditions where fulfilled, execute the else block
        auto body { e->get_else_body()->clone<ninx::parser::element::Block>() };
        body->__set_output_block(e->__get_output_block());

        body->accept(this);
    }
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::IfCase *e) {
    // Evaluate the condition
    e->get_condition()->accept(this);
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::ForStatement *e) {
    // Evaluate the condition and get the range_expr list
    no_echo([&]{
        e->get_range_expr()->accept(this);
    });
    auto range_expr {std::move(get_owned_return_block())};

    int index = 0;
    for (auto &element : range_expr->get_children()) {
        // Clone the body
        auto body {e->get_body()->clone<ninx::parser::element::Block>()};
        body->__set_output_block(e->__get_output_block());

        // Inject all the variables
        body->set_variable(e->get_iterator_name(), element->clone<ninx::parser::element::Block>(), true);
        body->set_variable("index0", ninx::parser::element::Block::make_text_block(body.get(), boost::lexical_cast<std::string>(index)), true);
        body->set_variable("index1", ninx::parser::element::Block::make_text_block(body.get(), boost::lexical_cast<std::string>(index+1)), true);

        // Now execute the body
        body->accept(this);

        index++;
    }
}

void ninx::evaluator::DefaultEvaluator::visit(ninx::parser::element::NoopStatement *e) {}  // NOOP

max_stars_repo_name: federico-terzi/ninx

max_issues_repo_name: federico-terzi/ninx

max_forks_repo_name: federico-terzi/ninx