#include "sema.h"
#include "builtins/builtins.h"
namespace empathy::sema
{
ptr< InvocationRule > GetInvocationRule( const Env& e, const Value& callee )
{
const auto& rules = e.invocationRuleSet()->rules();
MatchSolution bestSol;
ptr< InvocationRule > pBestRule;
bool ambiguous = false;
auto calleeTerm = ValueToIRExpr( callee );
for( auto&& [s, rule] : Match( calleeTerm, rules ) )
{
if( !pBestRule || s > bestSol )
{
bestSol = s;
pBestRule = rule;
ambiguous = false;
continue;
}
if( s < bestSol )
continue;
ambiguous = true;
}
// Let's not really worry about how to properly report this for now.
if( ambiguous )
throw runtime_error( "ambiguous invocation rule" );
return pBestRule;
}
bool CanBeInvoked( const Context& c, const Value& callee )
{
return !!GetInvocationRule( *c.env(), callee );
}
Value ResolveInvocation( const Context& c, const ptr< InvocationRule >& pInvRule, const Value& callee, const Value& args )
{
auto loc = Location::CreateSpanningLocation( callee.locationId(), args.locationId() );
// If the current domain isn't compile time and the args are constant, attempt to resolve it as a compile time invocation
// first.
if( args.isConstant() && c.domain() != DomainCompileTime() && builtins::IsTupleConstant( args ) )
{
// This is a speculative attempt at compile time execution. It it doesn't work, we'll
// just try to resolve the invocation in its originally intended domain.
// So don't display any error message during the attempt.
VerbosityContext vc( Verbosity::Silent );
Context localC( c.env(), InjectDomainIntoIdentity( c.identity(), DomainCompileTime() ) );
auto result = pInvRule->resolveInvocation( localC, loc, callee, args ).setLocationId( loc );
if( !result.isPoison() )
return result;
}
if( loc == ~0 )
DiagnosticsManager::GetInstance().setCurrentVerbosityLevel( Verbosity::SilentLocally );
return pInvRule->resolveInvocation( c, loc, callee, args ).setLocationId( loc );
}
}