Goose  Artifact [75ba6b2b32]

Artifact 75ba6b2b32f18a8b66105debde3e1a41f28255edccdc2bd4db9fbb8429f88964:

  • File bs/builtins/operators/helpers.h — part of check-in [ed31e6303b] at 2019-08-01 15:53:57 on branch trunk —
    • Rewrote the operator helpers: they now generate and invoke an overloadable intrinsic.
    • Implemented the logical not operator.
    (user: achavasse size: 4577)

#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