#include "builtins/builtins.h"
#include "precedence.h"
#include "builtins/helpers.h"
using namespace goose;
using namespace goose::eir;
using namespace goose::parse;
using namespace goose::builtins;
namespace goose::builtins
{
void SetupWhereOp( Env& e )
{
auto wherePrecedence = []( const Parser& p ) -> optional< uint32_t >
{
auto lastVal = p.peekLastValue();
if( !lastVal )
return nullopt;
if( !IsType( p.context(), *lastVal ) )
return nullopt;
if( !GetTypePredicates( *lastVal ) )
return nullopt;
return precedence::VerificationPredicate;
};
auto parseWhere = []( Parser& p, LocationId locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
auto next = p.resolver()->lookAheadUnresolved();
if( !next )
{
dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "'[' expected after 'where'.", 0 );
return false;
}
auto decomp = Decompose( next->first, Val< Delimiter >() );
if( !decomp || *decomp != Delimiter::OpenBracket )
{
dm.emitSyntaxErrorMessage( p.resolver()->currentLocation(), "'[' expected after 'where'.", 0 );
return false;
}
auto type = *p.popValue();
auto preds = *GetTypePredicates( type );
if( preds )
preds = make_shared< TypePredicates >( *preds );
else
{
preds = make_shared< TypePredicates >();
auto& c = p.context();
// Create a new identity for the predicates, which imports everything from the parent identity
// and also makes @val visible as a placeholder for the type's value.
preds->m_identity = VEC( Env::NewUniqueId() );
c.env()->addVisibilityRule( c.identity(), preds->m_identity );
auto typeTerm = ValueToEIR( type );
auto name = "@val"_sid;
auto valuePlaceholderIdentity = AppendToVectorTerm( preds->m_identity, TERM( name ) );
c.env()->storeValue( valuePlaceholderIdentity, ANYTERM( _ ),
ValueToEIR( BuildComputedValue( typeTerm, cir::Placeholder( typeTerm, name ) ) ) );
}
preds->m_unparsedPredicates.emplace_back();
auto& toks = preds->m_unparsedPredicates.back();
auto g = p.resolver()->consumeUnit();
// Strip the start and end brackets
auto beg = g.begin();
advance( beg, 1 );
move( beg, g.end(), back_inserter( toks ) );
auto loc = Location::CreateSpanningLocation( type.locationId(), toks.back().second );
toks.resize( toks.size() - 1 );
p.pushValue( Value( type.type(), InjectPredicatesIntoStdType( type.val(), preds ) )
.setLocationId( loc ) );
return true;
};
RegisterRule( e, "where"_sid, Rule( wherePrecedence, parseWhere ) );
}
}