Goose  Artifact [e51c6bc5d2]

Artifact e51c6bc5d27491311384071f45249fb79a7adcb57cb2950bcaa8c3c9b69c3208:

  • File bs/sema/env.cpp — part of check-in [f18062b8da] at 2020-02-15 15:13:17 on branch trunk — Started to implement a virtual memory sub system for compilation time execution. (user: achavasse size: 3950)

#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 );
        } ) );
}