#include "sema.h"
using namespace goose;
using namespace goose::llr;
using namespace goose::sema;
vector< ptr< llr::Func > > Env::ms_llrFuncs;
uint32_t Env::ms_nextUniqueId = 0;
// Env just instantiates the builtin unification rule set for now. The rule set will
// need to be extendable by compile time code later on.
Env::Env() :
m_templateRuleSet( make_shared< TemplateRuleSet >() ),
m_invocationRuleSet( make_shared< InvocationRuleSet >() ),
m_unificationRuleSet( make_shared< UnificationRuleSet >() ),
m_memManager( make_shared< CTMemoryManager >() )
{}
Env::~Env() {}
void Env::storeValue( const Term& idPat, const Term& contextIdPat, const Term& val )
{
storeValue( idPat, contextIdPat, make_shared< ValueProvider >(
[val]( const Env& e, const Term& identity, const Term& contextId, Term& result )
{
result = val;
return Status::Success;
} ) );
}
void Env::storeValue( const Term& idPat, const Term& contextIdPat, const ptr< ValueProvider >& valp )
{
m_valueStore = Merge( m_valueStore, VEC( idPat, contextIdPat ),
[valp]( auto&& oldValp )
{
if( !oldValp )
return valp;
// If another value provider was already registered with the same pattern,
// combine them through a lambda that will call them both and check for ambiguousness.
return make_shared< ValueProvider >( [oldValp, valp]( Env& e, const Term& identity, const Term& contextId, Term& result )
{
auto s1 = ( *oldValp )( e, identity, contextId, result );
if( s1 == Status::AmbiguousMatch )
return s1;
auto s2 = ( *valp )( e, identity, contextId, result );
if( s2 == Status::AmbiguousMatch )
return s2;
if( s1 == s2 )
{
if( s1 == Status::NoMatch )
return Status::NoMatch;
else
return Status::AmbiguousMatch;
}
return Status::Success;
} );
} );
++m_valueStoreVersion;
}
Env::Status Env::retrieveValue( const Term& id, const Term& contextId, Term& result )
{
MatchSolution bestSol;
ptr< ValueProvider > bestProvider;
bool ambiguous = false;
auto pat = VEC( id, contextId );
for( auto&& [s, provider] : Match( pat, m_valueStore ) )
{
if( !bestProvider || s > bestSol )
{
bestSol = s;
bestProvider = provider;
ambiguous = false;
continue;
}
if( s < bestSol )
continue;
ambiguous = true;
}
if( !bestProvider )
return Status::NoMatch;
if( ambiguous )
return Status::AmbiguousMatch;
return ( *bestProvider )( *this, id, contextId, result );
}
void Env::addVisibilityRule( const Term& toImport, const Term& destination, bool transitive, bool preserveDomain )
{
const auto& vec = *get< pvec >( destination );
auto prefixLength = vec.length().minLength();
// Create the pattern: it is the destination identity,
// followed by one or more elements.
auto vecPat = Vector::MakeAppend( vec, ANYTERM( _ ) );
vecPat.setRepetitionTerm( ANYTERM( _ ) );
auto pat = TERM( make_shared< Vector >( move( vecPat ) ) );
storeValue( pat, transitive ? ANYTERM( _ ) : destination, make_shared< ValueProvider >(
[toImport, prefixLength, preserveDomain]( Env& e, const Term& identity, const Term& contextId, Term& result )
{
auto newId = ConcatenateVectorTerms( toImport, DropVectorTerm( identity, prefixLength ) );
if( preserveDomain )
newId = InjectDomainIntoIdentity( newId, ExtractDomainFromIdentity( identity ) );
return e.retrieveValue( newId, contextId, result );
} ) );
}