#include "builtins/builtins.h"

using namespace empathy;
using namespace empathy::builtins;

namespace empathy::builtins
{
    void SetupRuntimeBasicTypes( Env& e )
    {
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( rt_half ) ), ANYTERM( _ ), ValueToIRExpr( ToValue( RTHalf() ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( rt_float ) ), ANYTERM( _ ), ValueToIRExpr( ToValue( RTFloat() ) ) );
        e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( rt_double ) ), ANYTERM( _ ), ValueToIRExpr( ToValue( RTDouble() ) ) );

        RegisterBuiltinFunc< Value ( uint64_t ) >( e, "RTInteger"_sid,
            []( uint64_t numBits )
            {
                return ToValue( RTInteger( numBits ) );
            } );
    }
}

namespace empathy::ir
{
    //// Half
    Value Bridge< RTHalf >::ToValue( const RTHalf& i )
    {
        return Value( Type(), TVEC( TSID( rt_type ), TSID( rt_half ) ) );
    }

    optional< RTHalf > Bridge< RTHalf >::FromValue( const Value& v )
    {
        if( v != ToValue( RTHalf() ) )
            return nullopt;

        return {};
    }

    //// Float
    Value Bridge< RTFloat >::ToValue( const RTFloat& i )
    {
        return Value( Type(), TVEC( TSID( rt_type ), TSID( rt_float ) ) );
    }

    optional< RTFloat > Bridge< RTFloat >::FromValue( const Value& v )
    {
        if( v != ToValue( RTFloat() ) )
            return nullopt;

        return {};
    }

    //// Double
    Value Bridge< RTDouble >::ToValue( const RTDouble& i )
    {
        return Value( Type(), TVEC( TSID( rt_type ), TSID( rt_double ) ) );
    }

    optional< RTDouble > Bridge< RTDouble >::FromValue( const Value& v )
    {
        if( v != ToValue( RTDouble() ) )
            return nullopt;

        return {};
    }

    //// Integer
    Value Bridge< RTInteger >::ToValue( const RTInteger& i )
    {
        return Value( Type(), TVEC( TSID( rt_type ), TSID( rt_integer ), TERM( i.m_numBits ) ) );
    }

    optional< RTInteger > Bridge< RTInteger >::FromValue( const Value& v )
    {
        auto result = Decompose( v.val(),
            Vec(
                Lit( "rt_type"_sid ),
                Lit( "rt_integer"_sid ),
                Val< uint64_t >()
            )
        );

        if( !result )
            return nullopt;

        auto&& [numBits] = *result;
        return RTInteger( numBits );
    }
}
