#include "builtins/builtins.h"
#include "parse/parse.h"
#include "precedence.h"
#include "builtins/helpers.h"
using namespace empathy;
using namespace empathy::ir;
using namespace empathy::parse;
namespace empathy::builtins
{
void SetupWhileStmt( Env& e )
{
auto handleWhile = []( Parser& p, uint32_t locationId, uint32_t prec )
{
auto& dm = DiagnosticsManager::GetInstance();
if( p.isInParenExpr() )
{
dm.emitSyntaxErrorMessage( locationId, "the while statement is not allowed here.", 0 );
return false;
}
auto pPrecBB = p.currentBB();
auto np = p.makeNestedParser();
if( !np.parseExpression( precedence::IfStmt ) )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the while statement.", 0 );
return false;
}
auto condVal = np.popValue();
if( !condVal )
{
dm.emitSyntaxErrorMessage( locationId, "expected an expression following the while statement.", 0 );
return false;
}
const auto& context = p.resolver()->context();
auto converted = ConvertValueToType( context, *condVal, GetValueType< bool >() );
if( holds_alternative< ValUnifyError >( converted ) )
{
switch( get< ValUnifyError >( converted ) )
{
// If the condition is invalid, bail out and mark the current
// diagnostics context as bust to avoid spamming cascading errors.
case ValUnifyError::NoSolution:
dm.emitSyntaxErrorMessage( condVal->locationId(), "the while condition can't be converted to a bool." );
break;
case ValUnifyError::Ambiguous:
dm.emitSyntaxErrorMessage( condVal->locationId(), "ambiguous while condition bool conversion." );
break;
}
return false;
}
auto pHeaderBB = p.cfg()->createBB();
auto pBodyBB = ParseSubStatement( p, precedence::IfStmt );
if( !pBodyBB )
{
dm.emitSyntaxErrorMessage( p.resolver()->getCurrentLocation(), "expected a statement after the while condition.", 0 );
return false;
}
// Retrieve the final block of the loop body, if any
auto pBodySuccBB = p.currentBB();
ptr< llr::BasicBlock > pSuccBB = p.cfg()->createBB();
// Jump unconditionally from the pred block to the loop header.
pPrecBB->setTerminator( llr::Branch( pHeaderBB ) );
// Emit the conditional branch that will either run an iteration of the loop or exit to the succ bb.
pHeaderBB->setTerminator( llr::CondBranch(
get< Value >( converted ),
pBodyBB, pSuccBB ) );
// Jump from the end of the body BB back to the loop header
pBodySuccBB->setTerminator( llr::Branch( pHeaderBB ) );
p.setCurrentBB( pSuccBB );
return true;
};
Rule r( handleWhile );
auto ruleVal = ToValue( move( r ) );
auto ruleTerm = ValueToIRExpr( ruleVal );
e.storeValue( AppendToVectorTerm( RootIdentity(), TSID( while ) ), ANYTERM( _ ), ruleTerm );
}
}