#include "function.hpp"
#include "context.hpp"

const std::string function::type_name = "function";

function::function(const std::string& n) : name(n) {}

void function::push(symbol&& s) {
    params.push_back(std::move(s));
}

function* function::clone() const {
    function* f = new function(name);
    for (const symbol& p : params)
        f->params.push_back(p.clone());
    return f;
}

symbol_impl* function::evaluate(const interpreter_context& context) const {
    try {
        return context.call_function(name, params);
    } catch (no_function_match_exception e) {
        context.msg("error: no matching function call to '" + name + "(" + e.prototype + ")'");
        context.msg("note: candidates are:");
        for (const auto& s : e.available)
            context.msg("note: '" + name + "(" + s + ")'");

        throw parser_exception();
    } catch (...) {
        throw;
    }
}

std::string function::serialize(const interpreter_context& context) const {
    std::string s = name;
    s += "(";
    for (size_t i = 0; i < params.size(); ++i) {
        if (i != 0)
            s += ", ";

        s += params[i].serialize(context);
    }
    s += ")";
    return s;
}

const std::string& function::type() const {
    return type_name;
}

bool function::is_litteral() const {
    return false;
}

std::pair<size_t,size_t> function::priority(const interpreter_context&) const {
    return std::pair<size_t,size_t>(0, 0);
}
