#ifndef EMPATHY_BUILTINS_OPERATORS_HELPERS_H
#define EMPATHY_BUILTINS_OPERATORS_HELPERS_H
#include "builtins/helpers.h"
namespace empathy::builtins
{
using namespace empathy::parse;
template< typename F >
void RegisterPrefixOp( sema::Env& env, const StringId& name, uint32_t precedence, F&& func )
{
parse::RegisterPrefixOp( env, name, AppendToVectorTerm( RootIdentity(), TERM( name ) ), precedence, forward< F >( func ) );
}
template< typename F >
void RegisterPostfixOp( sema::Env& env, const StringId& name, uint32_t precedence, F&& func )
{
parse::RegisterPostfixOp( env, name, AppendToVectorTerm( RootIdentity(), TERM( name ) ), precedence, forward< F >( func ) );
}
template< typename F >
void RegisterLeftAssInfixOp( sema::Env& env, const StringId& name, uint32_t precedence, F&& func )
{
parse::RegisterLeftAssInfixOp( env, name, AppendToVectorTerm( RootIdentity(), TERM( name ) ), precedence, forward< F >( func ) );
}
template< typename F >
void RegisterRightAssInfixOp( sema::Env& env, const StringId& name, uint32_t precedence, F&& func )
{
parse::RegisterRightAssInfixOp( env, name, AppendToVectorTerm( RootIdentity(), TERM( name ) ), precedence, forward< F >( func ) );
}
struct UnaryOpTag {};
struct BinaryOpTag {};
template< typename... R >
void CreatePrefixOp( Env& e, StringId name, StringId funcName, uint32_t precedence, R&&... rules )
{
RegisterPrefixOp( e, name, precedence,
BuildOpFunc< UnaryOpTag >( e, funcName, forward< R >( rules )... ) );
}
template< typename... R >
void CreatePostfixOp( Env& e, StringId name, StringId funcName, uint32_t precedence, R&&... rules )
{
RegisterPostfixOp( e, name, precedence,
BuildOpFunc< UnaryOpTag >( e, funcName, forward< R >( rules )... ) );
}
template< typename... R >
void CreateLeftAssOp( Env& e, StringId name, StringId funcName, uint32_t precedence, R&&... rules )
{
RegisterLeftAssOp( e, name, precedence,
BuildOpFunc< BinaryOpTag >( e, funcName, forward< R >( rules )... ) );
}
template< typename... R >
void CreateRightAssOp( Env& e, StringId name, StringId funcName, uint32_t precedence, R&&... rules )
{
RegisterRightAssOp( e, name, precedence,
BuildOpFunc< BinaryOpTag >( e, funcName, forward< R >( rules )... ) );
}
template< typename tag, typename... R >
auto BuildOpFunc( Env& e, StringId funcName, R&&... ruleBuilders )
{
auto pOvlSet = CreateOverloadSet( e, funcName );
( ( ruleBuilders( e, pOvlSet, tag() ) ), ... );
return [pOvlSet]< typename... O >( Parser& p, O&&... operands )
{
return InvokeOverloadSet( p.resolver()->context(), pOvlSet, MakeTuple( operands... ) );
};
}
template< typename T, typename I >
auto ForType()
{
return []< typename tag >( auto&& e, auto&& pOvlSet, tag t )
{
if constexpr( is_same_v< tag, UnaryOpTag > )
{
using intrinsicType = Intrinsic< Value ( T ) >;
auto intrinsicFunc = []( const Value& operand )
{
return Value( GetValueType< T >(),
make_shared< llr::Instruction >( I( operand ) ) );
};
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ) );
}
else
{
using intrinsicType = Intrinsic< Value ( T, T ) >;
auto intrinsicFunc = []( const Value& lhs, const Value& rhs )
{
return Value( GetValueType< T >(),
make_shared< llr::Instruction >( I( lhs, rhs ) ) );
};
pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ) );
}
};
}
template< typename T, typename F >
auto ForType( F&& func )
{
return [&]< typename tag >( auto&& e, auto&& pOvlSet, tag t )
{
if constexpr( is_same_v< tag, UnaryOpTag > )
{
using intrinsicType = Intrinsic< Value ( T ) >;
pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ) );
}
else
{
using intrinsicType = Intrinsic< Value ( T, T ) >;
pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ) );
}
};
}
}
#endif