#include "builtins/builtins.h"
#include "precedence.h"
#include "helpers.h"
using namespace empathy;
using namespace empathy::ir;
using namespace empathy::llr;
using namespace empathy::parse;
namespace empathy::builtins
{
void SetupLogicOps( Env& e )
{
CreatePrefixOp( e, "!"_sid, "operator_logical_not"_sid, precedence::UnaryOps,
ForType< bool >( []( auto&& operand ) -> Value
{
return BuildComputedValue( GetValueType< bool >(),
Xor( operand, ToValue( true ) ) );
} )
);
CreateLeftAssInfixOp( e, "|"_sid, "operator_logical_or"_sid, precedence::OrOp,
ForType< bool >( []( auto&& lhs, auto&& rhs ) -> Value
{
// Build a CFG that implements the control flow for
// shortcut evaluation.
auto cfg = make_shared< CFG >();
auto pLhsBB = cfg->createBB();
auto pRhsBB = cfg->createBB();
auto pEndBB = cfg->createBB();
// If the lhs is true, skip to the end directly.
// Otherwise, jump to the BB that computes rhs.
pLhsBB->setTerminator( CondBranch( lhs, pEndBB, pRhsBB ) );
auto rhsIndex = cfg->getNewTemporaryIndex();
pRhsBB->emplace_back( CreateTemporary( rhsIndex, rhs ) );
pRhsBB->setTerminator( Branch( pEndBB ) );
auto resultIndex = cfg->getNewTemporaryIndex();
// Build the Phi instruction that will collect the final result.
auto phi = Phi( *ValueFromIRExpr( GetValueType< bool >() ),
2, resultIndex );
// If coming directly from the lhs BB, we know the result is true.
phi.setIncoming( pLhsBB, ToValue( true ) );
// Otherwise, the result is whatever was computed by the rhs block.
phi.setIncoming( pRhsBB, BuildComputedValue( GetValueType< bool >(),
GetTemporary( rhsIndex ) ) );
pEndBB->emplace_back( move( phi ) );
// Build the result val which pulls the temporary created by the
// cfg above.
auto resultVal = BuildComputedValue( GetValueType< bool >(),
GetTemporary( resultIndex ) );
// Pachage all that in a ComplexValue, the parser will unpack
// it down the line and inline or execute our little cfg.
return ToValue(
ComplexValue( move( resultVal ), move( cfg ) ) );
} )
);
}
}