#include "builtins/builtins.h"
using namespace empathy::sema;
namespace empathy::builtins
{
class FunctionInvocationRule : public InvocationRule
{
public:
virtual optional< Value > resolveInvocation( const Context& c, const Value& callee, const Value& args ) const final
{
const auto& env = c.env();
UnificationContext uc( env );
optional< UnificationContext > bestUC;
optional< Term > bestSol;
bool ambiguous = false;
auto&& [sig, rtype] = GetFuncSigAndRType( callee );
auto callPat = TVEC( args.val(), sema::MkHole( "_"_sid ) );
for( auto&& [s, uc] : Unify( sig, callPat, uc ) )
{
if( uc.numUnknownValues() )
continue;
auto ssol = Substitute( s, uc );
if( !ssol )
continue;
if( !bestSol || uc.score() > bestUC->score() )
{
bestUC = uc;
bestSol = ssol;
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
{
const auto& env = c.env();
if( !IsBuiltinFunc( callee ) )
PerformLazyFuncParsing( env, callee );
auto callDecomp = Decompose( unifiedCallPat,
Vec(
SubTerm(), // args
SubTerm() // return type
)
);
auto&& [unifiedArgs, unifiedRType] = *callDecomp;
return Value( unifiedRType, make_shared< llr::Element >( llr::Call( callee, unifiedArgs ) ) );
}
virtual optional< Term > getSignature( const Value& callee ) const final
{
return GetFuncSigAndRType( callee ).first;
}
};
void SetupFunctionInvocationRule( Env& e )
{
e.invocationRuleSet()->addRule(
ValueToIRExpr( Value( TSID( type ), TVEC( TSID( func ),
ANYTERM( k ), ANYTERM( rt ), ANYTERM( p ) ) ) ),
make_shared< FunctionInvocationRule >() );
}
}