#include "builtins/builtins.h"
#include "parse/parse.h"
using namespace empathy::builtins;
using namespace empathy::llr;
using namespace empathy::parse;
namespace empathy::builtins
{
const Term& LocalVar::PatternTypeT::GetPattern()
{
static auto pattern = GetValueType< LocalVar >( MkHole( "T"_sid ) );
return pattern;
}
Value DeclareLocalVar( Parser& p, const Term& type, StringId name, const optional< Value >& initializer )
{
auto cfgId = p.cfg()->uniqueId();
auto index = p.cfg()->getNewTemporaryIndex();
LocalVar lv( type, cfgId, index );
auto bb = p.currentBB();
bb->emplace_back( AllocVar( *ValueFromIRExpr( type ), cfgId, index ) );
if( initializer )
{
p.pushValue( InvokeOverloadSet( p.resolver()->context(),
p.resolver()->context().env()->extInitializeLocalVar(),
MakeTuple( ToValue( lv ), *initializer ) ) );
}
else
{
p.pushValue( InvokeOverloadSet( p.resolver()->context(),
p.resolver()->context().env()->extInitializeLocalVar(),
MakeTuple( ToValue( lv ) ) ) );
}
auto locVar = ToValue( lv );
auto identity = AppendToVectorTerm( p.resolver()->context().identity(), name );
p.resolver()->context().env()->storeValue( identity, ANYTERM( _ ),
ValueToIRExpr( locVar ) );
p.resolver()->clearLookAheadCache();
return locVar;
}
Value DeclareLocalVarWithTypeInference( Parser& p, const Term& typeTExpr, StringId name, const Value& initVal )
{
const auto& c = p.resolver()->context();
// To infer the type and obtain a suitable initialization function,
// we want the declaration to behave as if it were the following function call:
// Params: ( $T, _ ( LocalVar[$T], initVal ) initFunc )
// Args: ( pat, InitializeLocalVar )
//
// Where pat is the TNamedDecl's type pattern and initVal is the initialization
// expression.
// We construct the above expressions and unify them. The best solution (if any)
// will give us the wanted type and the function to invoke to initialize it.
// Create the _ texpr.
static auto anyTVar = ValueToIRExpr( ToValue( TVar( "_"_sid ) ) );
// The $T texpr.
static auto TTVar = ValueToIRExpr( ToValue( TVar( "T"_sid ) ) );
// Create the LocalVar[$T] param.
auto locVarPatParam = ValueToIRExpr( ToValue( TNamedDecl( GetValueType< LocalVar >( TTVar ), "lv"_sid ) ) );
auto initValPattern = ValueToIRExpr( ValuePattern( TSID( constant ), initVal.type(), MkHole( "_"_sid ) ) );
// Create the _ ( LocalVar[pat], initType ) initFunc param.
auto initFuncTFTParam = ValueToIRExpr( ToValue(
TNamedDecl( ValueToIRExpr( ToValue( TFuncType( DomainAny(), anyTVar, VEC( move( locVarPatParam ), move( initValPattern ) ) ) ) ),
"initFunc"_sid ) ) );
// Create our parameter list pattern.
auto paramPat = VEC(
*BuildTemplateSignature( c, TTVar ),
*BuildTemplateSignature( c, initFuncTFTParam )
);
// Create our arg list patter,.
auto args = VEC(
*BuildTemplateArgPattern( c, typeTExpr ),
ValueToIRExpr( ToValue( c.env()->extInitializeLocalVar() ) )
);
optional< UnificationContext > bestUC;
optional< Term > bestSol;
bool ambiguous = false;
for( auto&& [s, uc] : FullUnify( paramPat, args, c ) )
{
if( !bestSol || uc.score() > bestUC->score() )
{
bestUC = uc;
bestSol = s;
ambiguous = false;
continue;
}
if( uc.score() < bestUC->score() )
continue;
if( s != bestSol )
ambiguous = true;
}
if( ambiguous )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"ambiguous variable type inference." );
return PoisonValue();
}
if( !bestSol )
{
// TODO display details
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
"variable initialization type mismatch." );
return PoisonValue();
}
auto ppCallPat = Postprocess( *bestSol, *bestUC );
if( !ppCallPat )
return PoisonValue();
// Perform the setup of the type template expression. This will create local bindings
// for tvars ($whatever), if any, making them available for further use.
TemplateSetup( c, *bestUC, typeTExpr );
auto callDecomp = Decompose( *ppCallPat,
Vec(
SubTerm(), // locvar
SubTerm() // initializer
)
);
auto&& [type, initializer] = *callDecomp;
auto initializerVal = *ValueFromIRExpr( initializer );
auto cfgId = p.cfg()->uniqueId();
auto index = p.cfg()->getNewTemporaryIndex();
LocalVar lv( type, cfgId, index );
auto bb = p.currentBB();
bb->emplace_back( AllocVar( *ValueFromIRExpr( lv.type() ), cfgId, index ) );
p.pushValue( ResolveInvocation( c, GetInvocationRule( *c.env(), initializerVal ), initializerVal,
MakeTuple( ToValue( lv ), initVal ) ) );
auto locVar = ToValue( lv );
auto identity = AppendToVectorTerm( p.resolver()->context().identity(), name );
p.resolver()->context().env()->storeValue( identity, ANYTERM( _ ),
ValueToIRExpr( locVar ) );
p.resolver()->clearLookAheadCache();
return locVar;
}
}
namespace empathy::ir
{
const Term& Bridge< LocalVarType >::Type()
{
return TypeType();
}
Value Bridge< LocalVarType >::ToValue( const LocalVarType& t )
{
return Value( Type(), TVEC( TSID( local_var ), t.type() ) );
}
Value Bridge< LocalVarType >::ToValue( const Term& type )
{
return Value( Type(), TVEC( TSID( local_var ), type ) );
}
optional< LocalVarType > Bridge< LocalVarType >::FromValue( const Value& v )
{
auto result = Decompose( v.val(),
Vec(
Lit( "local_var"_sid ),
SubTerm()
)
);
if( !result )
return nullopt;
auto&& [type] = *result;
return LocalVarType( move( type ) );
}
Term Bridge< LocalVar >::Type( const Term& type )
{
return ValueToIRExpr( ToValue< LocalVarType >( type ) );
}
Value Bridge< LocalVar >::ToValue( const LocalVar& lv )
{
return Value( Type( lv.type() ), VEC( TERM( lv.cfgId() ), TERM( lv.index() ) ) );
}
optional< LocalVar > Bridge< LocalVar >::FromValue( const Value& v )
{
auto t = FromValue< LocalVarType >( *ValueFromIRExpr( v.type() ) );
if( !t )
return nullopt;
auto result = Decompose( v.val(),
Vec(
Val< uint32_t >(),
Val< uint32_t >()
)
);
if( !result )
return nullopt;
auto&& [cfgId,index] = *result;
return LocalVar( move( t->type() ), cfgId, index );
}
}