#include "symbol.hpp"
#include "context.hpp"

std::map<type_t, std::string> type_helper::type_map;

type_t type_helper::get_type_id(const std::string& name) {
    // Note: id 0 is reserved
    static type_t last_id = 0;

    ++last_id;
    type_map.insert(std::make_pair(last_id, name));

    return last_id;
}

std::string type_helper::get_type_name(type_t t) {
    auto iter = type_map.find(t);
    if (iter != type_map.end()) return iter->second;
    return "";
}

symbol::symbol(symbol_impl* s) : impl(s) {}

symbol_impl* symbol::release() {
    return impl.release();
}

symbol symbol::clone() const {
    if (impl) {
        return symbol(impl->clone());
    } else {
        return symbol();
    }
}

symbol symbol::evaluate(const interpreter_context& context) const {
    cycle_detector c = context.detect_cycles();
    if (impl) {
        return symbol(impl->evaluate(context));
    } else {
        return symbol();
    }
}

std::string symbol::serialize(const interpreter_context& context) const {
    if (impl) {
        return impl->serialize(context);
    } else {
        return std::string();
    }
}

const std::string& symbol::type_name() const {
    if (impl) {
        return impl->type_name();
    } else {
        static const std::string name = "";
        return name;
    }
}

type_t symbol::type_id() const {
    if (impl) {
        return impl->type_id();
    } else {
        return 0;
    }
}

bool symbol::is_litteral() const {
    if (impl) {
        return impl->is_litteral();
    } else {
        return true;
    }
}

std::pair<std::size_t,std::size_t> symbol::priority(const interpreter_context& context) const {
    if (impl) {
        return impl->priority(context);
    } else {
        return std::pair<std::size_t,std::size_t>(0, 0);
    }
}

symbol::operator bool() const {
    return impl != nullptr;
}

bool symbol::operator ! () const {
    return impl == nullptr;
}


no_type* no_type::clone() const {
    return new no_type();
}

no_type* no_type::evaluate(const interpreter_context&) const {
    return clone();
}

std::string no_type::serialize(const interpreter_context&) const {
    return "void";
}

const std::string& no_type::static_type_name() {
    static const std::string name = "void";
    return name;
}

bool no_type::is_litteral() const {
    return true;
}

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


any_type* any_type::clone() const {
    return new any_type();
}

any_type* any_type::evaluate(const interpreter_context&) const {
    return clone();
}

std::string any_type::serialize(const interpreter_context&) const {
    return "";
}

const std::string& any_type::static_type_name() {
    static const std::string name = "any";
    return name;
}

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

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


variadic_type* variadic_type::clone() const {
    return new variadic_type();
}

variadic_type* variadic_type::evaluate(const interpreter_context&) const {
    return clone();
}

std::string variadic_type::serialize(const interpreter_context&) const {
    return "";
}

const std::string& variadic_type::static_type_name() {
    static const std::string name = "variadic";
    return name;
}

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

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