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

const std::string symbol::type_name = "";
const std::string no_type::type_name = "void";
const std::string any_type::type_name = "any";
const std::string variadic_type::type_name = "variadic";

symbol::symbol() : impl(nullptr) {}
symbol::symbol(symbol_impl* s) : impl(s) {}
symbol::symbol(symbol&& s) : impl(s.release()) {}
symbol& symbol::operator = (symbol&& s) {
    impl = s.release();
    return *this;
}
symbol::~symbol() {
    delete impl;
}

symbol_impl* symbol::release() {
    symbol_impl* tmp = impl;
    impl = nullptr;
    return tmp;
}

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() const {
    if (impl)
        return impl->type();
    else
        return type_name;
}

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

std::pair<size_t,size_t> symbol::priority(const interpreter_context& context) const {
    if (impl)
        return impl->priority(context);
    else
        return std::pair<size_t,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::type() const {
    return type_name;
}

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

std::pair<size_t,size_t> no_type::priority(const interpreter_context&) const {
    return std::pair<size_t,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::type() const {
    return type_name;
}

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

std::pair<size_t,size_t> any_type::priority(const interpreter_context&) const {
    return std::pair<size_t,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::type() const {
    return type_name;
}

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

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