Goose  Artifact [a66d02ebe9]

Artifact a66d02ebe92b8268a6023c771fe241739b97340b9ecf9b3a13d5972f171a9a0a:

  • File bs/builtins/types/func/invoke.cpp — part of check-in [daee557086] at 2020-06-15 19:45:53 on branch trunk — Call "Postprocess" on unification solutions during the best solution lookup, so that custom postprocessing callbacks can trigger the rejection of a solution. (user: achavasse size: 4036)

#include "builtins/builtins.h"

using namespace goose::sema;

namespace goose::builtins
{
    class FunctionInvocationRule : public InvocationRule
    {
        public:
            Value resolveInvocation( const Context& c, uint32_t loc, const Value& callee, const Value& args ) const final
            {
                optional< UnificationContext > bestUC;
                optional< Term > bestSol;
                bool ambiguous = false;
                auto sig = GetFuncSig( callee );

                auto callPat = VEC( c.domain(), args.val(), HOLE( "_"_sid ) );

                auto us = FindBestUnification( sig, callPat, c );

                if( holds_alternative< NoUnification >( us ) )
                {
                    // TODO display details
                    DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                        "function arguments mismatch." );
                    return PoisonValue();
                }

                if( holds_alternative< AmbiguousUnification >( us ) )
                {
                    // TODO display details
                    DiagnosticsManager::GetInstance().emitErrorMessage( loc,
                        "ambiguous function call." );
                    return PoisonValue();
                }

                auto&& [s,uc] = get< UniSol >( us );

                return invoke( c, loc, callee, s, uc );
            }

            Value invoke( const Context& c, uint32_t loc, const Value& callee, const Term& unifiedCallPat, UnificationContext& uc ) const final
            {
                auto newCallee = prepareFunc( c, 0, callee, unifiedCallPat, uc );
                if( newCallee.isPoison() )
                    return PoisonValue();

                auto callDecomp = Decompose( unifiedCallPat,
                    Vec(
                        SubTerm(),  // domain
                        SubTerm(),  // args
                        SubTerm()   // return type
                    )
                );

                auto&& [domain, unifiedArgs, unifiedRType] = *callDecomp;

                newCallee.setLocationId( loc );

                if( IsBuiltinFunc( newCallee ) )
                    return BuildComputedValue( unifiedRType, llr::Call( newCallee, unifiedArgs ) );

                if( IsIntrinsicFunc( newCallee ) )
                    return GetBuiltinIntrinsicFuncWrapper( newCallee )( c, unifiedArgs );

                auto ft = *FromValue< FuncType >( *ValueFromIRExpr( newCallee.type() ) );
                auto argList = BuildArgListForCall( ft, unifiedArgs );

                return BuildComputedValue( unifiedRType, llr::Call( newCallee, argList ) );
            }

            optional< Term > getSignature( const Value& callee ) const final
            {
                return GetFuncSig( callee );
            }

            Value prepareFunc( const Context& c, uint32_t funcValLocation, const Value& callee, const Term& unifiedCallPat, UnificationContext& uc ) const final
            {
                if( IsBuiltinFunc( callee ) || IsIntrinsicFunc( callee ) )
                    return callee;

                // TODO better description with the function's name if possible (we may need to explicitely store it in the func)
                DiagnosticsContext dc( 0, true );
                VerbosityContext vc( Verbosity::Normal, true );

                return CompileFunc( c, callee );
            }
    };

    ptr< InvocationRule >& GetFuncInvocationRule()
    {
        static ptr< InvocationRule > pRule = make_shared< FunctionInvocationRule >();
        return pRule;
    }

    void SetupFunctionInvocationRule( Env& e )
    {
        e.invocationRuleSet()->addRule(
            ValueToIRExpr( ValuePattern( ANYTERM( _ ),

                ValueToIRExpr( Value( TypeType(), VEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ),
                ANYTERM( _ ), ANYTERM( _ ) ) ) ),

                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}