#include "ir.h"

namespace empathy::ir
{
    ostream& ToString( ostream& out, const uint32_t& x )
    {
        return out << x;
    }

    ostream& ToString( ostream& out, const string& x )
    {
        return out << '"' << x << '"';
    }

    ostream& ToString( ostream& out, const StringId& x )
    {
        if( x.isAnonymous() )
            return out << '#' << hex << x.uniqueId() << dec;
        return out << x;
    }

    ostream& ToString( ostream& out, const Delimiter& x )
    {
        const char* name = "";

        switch( x )
        {
            case Delimiter::Newline:
                name = "Newline";
                break;

            case Delimiter::OpenParen:
                name = "OpenParen";
                break;

            case Delimiter::CloseParen:
                name = "CloseParen";
                break;

            case Delimiter::OpenBrace:
                name = "OpenBrace";
                break;

            case Delimiter::CloseBrace:
                name = "CloseBrace";
                break;

            case Delimiter::OpenBracket:
                name = "OpenBracket";
                break;

            case Delimiter::CloseBracket:
                name = "CloseBracket";
                break;
        }

        return out << name;
    }

    ostream& ToString( ostream& out, const ptr< void >& x )
    {
        return out << "pvoid(" << x << ')';
    }

    ostream& ToString( ostream& out, const void* x )
    {
        return out << "void(" << x << ')';
    }

    ostream& ToString( ostream& out, const AnyTerm& v )
    {
        return out << "@AnyTerm(" << v.m_varName << ')';
    }

    ostream& ToString( ostream& out, const VecOfLength& v )
    {
        return out << "@VecOfLength(" << v.m_varName << ')';
    }

    ostream& ToString( ostream& out, const ptr< Vector >& v )
    {
        if( v->m_terms.empty() && !v->repetitionTerm() )
            return out << "()";

        out << "( ";

        for( auto&& x : v->m_terms )
            ToString( out, x ) << ' ';

        if( v->repetitionTerm() )
        {
            out << '*';
            ToString( out, *v->repetitionTerm() );
            out << ' ';
        }

        return out << ')';
    }

    ostream& ToString( ostream& out, const BigInt& bi )
    {
        return out << "BigInt(" << bi << ')';
    }

    ostream& ToString( ostream& out, const APSInt& i )
    {
        return out << "APSint(" << i.toString( 10 ) << ')';
    }

    ostream& ToString( ostream& out, const Term& t )
    {
        visit( [&]( auto&& t )
        {
            ToString( out, t );
        }, t );

        return out;
    }
}
