#ifndef GOOSE_BUILTINS_OPERATORS_HELPERS_H #define GOOSE_BUILTINS_OPERATORS_HELPERS_H namespace goose::builtins { using namespace goose::parse; template< typename... R > void BuildParseRule( sema::Env& env, StringId name, R&&... ruleBuilders ) { parse::BuildParseRule( env, name, AppendToVectorTerm( RootG0Identity(), TERM( name ) ), forward< R >( ruleBuilders )... ); } struct UnaryOpTag {}; struct BinaryOpTag {}; template< typename... R > auto PrefixOp( StringId funcName, uint32_t precedence, R&&... rules ) { return [&,precedence,funcName]( auto&& e, auto&& r, auto&& name ) { MakePrefixOp( e, r, name, precedence, BuildOpFunc< UnaryOpTag >( e, funcName, forward< R >( rules )... ) ); }; } template< typename... R > auto PostfixOp( StringId funcName, uint32_t precedence, R&&... rules ) { return [&,precedence,funcName]( auto&& e, auto&& r, auto&& name ) { MakePostfixOp( e, r, name, precedence, BuildOpFunc< UnaryOpTag >( e, funcName, forward< R >( rules )... ) ); }; } template< typename... R > auto LeftAssInfixOp( StringId funcName, uint32_t precedence, R&&... rules ) { return [&,precedence,funcName]( auto&& e, auto&& r, auto&& name ) { MakeLeftAssInfixOp( e, r, name, precedence, BuildOpFunc< BinaryOpTag >( e, funcName, forward< R >( rules )... ) ); }; } template< typename... R > auto RightAssInfixOp( StringId funcName, uint32_t precedence, R&&... rules ) { return [&,precedence,funcName]( auto&& e, auto&& r, auto&& name ) { MakeRightAssInfixOp( e, r, name, precedence, BuildOpFunc< BinaryOpTag >( e, funcName, forward< R >( rules )... ) ); }; } template< typename tag, typename... R > auto BuildOpFunc( Env& e, StringId funcName, R&&... ruleBuilders ) { auto pOvlSet = GetOrCreateOverloadSet( e, funcName ); ( ( ruleBuilders( e, pOvlSet, tag() ) ), ... ); return [pOvlSet, funcName]< typename... O >( Parser& p, O&&... operands ) { DiagnosticsContext dc( 0, format( "When invoking {}.", funcName.str() ) ); return InvokeOverloadSet( p.context(), pOvlSet, MakeClosedTuple( forward< O >( operands )... ) ); }; } template< typename T, typename I, typename RT = T > auto ForType() { return []< typename tag >( auto&& e, auto&& pOvlSet, tag t ) { using intrinsicType = Intrinsic< Value ( T, T ) >; auto intrinsicFunc = []( const Context& c, const Value& lhs, const Value& rhs ) { return BuildComputedValue( GetValueType< RT >(), lhs, rhs, I( ( c.locationId() ) ) ); }; pOvlSet->add( e, ToValue< intrinsicType >( move( intrinsicFunc ) ), GetBuiltinIntrinsicFuncInvocationRule() ); }; } 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 ) ), GetBuiltinIntrinsicFuncInvocationRule() ); } else { using intrinsicType = Intrinsic< Value ( T, T ) >; pOvlSet->add( e, ToValue< intrinsicType >( forward< F >( func ) ), GetBuiltinIntrinsicFuncInvocationRule() ); } }; } template< typename T1, typename T2, typename F > auto ForTypes( F&& func ) { return [=]< typename tag >( auto&& e, auto&& pOvlSet, tag t ) { using intrinsicType = Intrinsic< Value ( T1, T2 ) >; pOvlSet->add( e, ToValue< intrinsicType >( func ), GetBuiltinIntrinsicFuncInvocationRule() ); }; } } #endif