#include "eir.h"

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

    ostream& ToString( ostream& out, const LocationId& x )
    {
        return out << "LocationId(" << static_cast< uint32_t >( x ) << ')';
    }

    ostream& ToString( ostream& out, const string& x, char delim )
    {
        out << delim;

        for( auto c : x )
        {
            switch( c )
            {
                case '\n':
                    out << "\\n";
                    break;

                case '\t':
                    out << "\\t";
                    break;

                default:
                    if( c == delim )
                        out << '\\' << c;
                    else
                        out << c;
                    break;
            }
        }

        return out << delim;
    }

    ostream& ToString( ostream& out, const StringId& x )
    {
        return out << x;
    }

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

        switch( x )
        {
            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 Hole& x )
    {
        return out << '$' << x.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;
    }
}
