#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;
return CompileFunc( c, callee );
}
};
void SetupFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToIRExpr( ValuePattern( ANYTERM( _ ),
ValueToIRExpr( Value( TypeType(), TVEC( TSID( func ),
ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ), ANYTERM( _ ) ) ) ),
ANYTERM( _ ) ) ),
make_shared< FunctionInvocationRule >() );
}
}