Goose  Artifact [fa4f4d0524]

Artifact fa4f4d0524823a74dd6c6de6020ad0b4cac17d83e9b4235c86096979c6a59320:

  • File bs/builtins/types/func/invoke.cpp — part of check-in [2efa23555d] at 2019-08-11 01:26:17 on branch trunk —
    • ir: created a new type for LocationId which is handled in a specific way so that two LocationIds are always considered equal by pattern matching. This prevent the values' locationIds stored in ir expressions from fucking up everything.
    • propagate value locations in a few places: in the parser, when resolving invocations and when doing eager evaluation. There are probably a lot of other places still missing.
    • converted all the builtin statements to use the DiagnosticsManager.
    (user: achavasse size: 4211)

#include "builtins/builtins.h"

using namespace empathy::sema;

namespace empathy::builtins
{
    class FunctionInvocationRule : public InvocationRule
    {
        public:
            optional< Value > resolveInvocation( const Context& c, const Value& callee, const Value& args ) const final
            {
                UnificationContext uc( c );

                optional< UnificationContext > bestUC;
                optional< Term > bestSol;
                bool ambiguous = false;
                auto sig = GetFuncSig( callee );

                auto callPat = TVEC( c.domain(), args.val(), MkHole( "_"_sid ) );
                for( auto&& [s, uc] : FullUnify( sig, callPat, uc ) )
                {
                    if( !bestSol || uc.score() > bestUC->score() )
                    {
                        bestUC = uc;
                        bestSol = s;
                        ambiguous = false;
                        continue;
                    }

                    if( uc.score() < bestUC->score() )
                        continue;

                    ambiguous = true;
                }

                if( ambiguous )
                {
                    // TODO error mgmt
                    cout << "ambiguous function call.\n";
                    return nullopt;
                }

                if( !bestSol )
                {
                    // TODO error mgmt
                    cout << "function arguments mismatch.\n";
                    return nullopt;
                }

                return invoke( c, callee, *bestSol, *bestUC );
            }

            optional< Value > invoke( const Context& c, const Value& callee, const Term& unifiedCallPat, UnificationContext& uc ) const final
            {
                auto newCallee = prepareFunc( c, callee, unifiedCallPat, uc );
                if( !newCallee )
                    return nullopt;

                auto ppCallPat = Postprocess( unifiedCallPat, uc );
                if( !ppCallPat )
                    return nullopt;

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

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

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

                if( IsIntrinsicFunc( *newCallee ) )
                    return GetBuiltinFuncWrapper( *newCallee )( 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 );
            }

            optional< Value > prepareFunc( const Context& c, 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( callee.locationId(), "function being compiled", 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(), TVEC( TSID( func ),
                ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) ),
                ANYTERM( _ ) ) ),
            GetFuncInvocationRule() );
    }
}