#ifndef GOOSE_EIR_VALUE_H
#define GOOSE_EIR_VALUE_H
namespace goose::cir
{
class Instruction;
using InstrSeq = list< Instruction >;
}
namespace goose::eir
{
class Value;
class ValuePattern;
extern const Term& TypeType();
extern Term ValueToEIR( const Value& v );
extern optional< Value > EIRToValue( const Term& t );
extern Term ValueToEIR( const ValuePattern& v );
extern optional< ValuePattern > EIRToValuePattern( const Term& t );
class Value
{
public:
Value() = default;
template< typename T, typename VL >
Value( T&& type, VL&& valOrCIR, LocationId loc = LocationId() ) :
m_type( forward< T >( type ) ),
m_valOrCIR( forward< VL >( valOrCIR ) ),
m_locationId( loc )
{}
const auto& type() const { return m_type; }
const auto& payload() const { return m_valOrCIR; }
const auto& val() const { return get< Term >( m_valOrCIR ); }
auto& type() { return m_type; }
auto& val() { return get< Term >( m_valOrCIR ); }
const ptr< cir::InstrSeq >& cir() const
{
static ptr< cir::InstrSeq > null;
const auto* ppCir = get_if< ptr< cir::InstrSeq > >( &m_valOrCIR );
if( !ppCir )
return null;
return *ppCir;
}
ptr< cir::InstrSeq >& cir()
{
static ptr< cir::InstrSeq > null;
auto* ppCir = get_if< ptr< cir::InstrSeq > >( &m_valOrCIR );
if( !ppCir )
return null;
return *ppCir;
}
template< typename T >
void setCIR( T&& pInstrSeq )
{
m_valOrCIR = forward< T >( pInstrSeq );
}
auto locationId() const { return m_locationId; }
auto&& setLocationId( LocationId id )
{
if( !m_locationId.isPoison() )
m_locationId = id;
return *this;
}
bool isPoison() const { return m_locationId.isPoison(); }
auto&& setPoison() { m_locationId.setPoison(); return *this; }
bool isConstant() const { return holds_alternative< Term >( m_valOrCIR ); }
bool isType() const;
bool isMetaType() const;
friend ostream& operator<<( ostream& out, const Value& val )
{
return out << ValueToEIR( val );
}
bool operator==( const Value& rhs ) const
{
return m_type == rhs.m_type && m_valOrCIR == rhs.m_valOrCIR;
}
bool operator!=( const Value& rhs ) const
{
return m_type != rhs.m_type || m_valOrCIR != rhs.m_valOrCIR;
}
bool operator<( const Value& rhs ) const
{
if( m_type != rhs.m_type )
return m_type < rhs.m_type;
return m_valOrCIR < rhs.m_valOrCIR;
}
private:
Term m_type;
variant< Term, ptr< cir::InstrSeq > > m_valOrCIR;
LocationId m_locationId = LocationId::Poison();
};
class ValuePattern
{
public:
template< typename S, typename T, typename V >
ValuePattern( S&& sort, T&& type, V&& v, LocationId locationId = LocationId() ) :
m_sort( forward< T >( sort ) ),
m_type( forward< T >( type ) ),
m_val( forward< V >( v ) ),
m_locationId( locationId )
{}
auto locationId() const { return m_locationId; }
auto&& setLocationId( LocationId id )
{
if( !m_locationId.isPoison() )
m_locationId = id;
return *this;
}
bool isPoison() const { return m_locationId.isPoison(); }
void setPoison() { m_locationId.setPoison(); }
const auto& sort() const { return m_sort; }
const auto& type() const { return m_type; }
const auto& val() const { return m_val; }
auto& sort() { return m_sort; }
auto& type() { return m_type; }
auto& val() { return m_val; }
private:
Term m_sort;
Term m_type;
Term m_val;
LocationId m_locationId = 0;
};
// A generic poisoned value of "type" type.
extern const Value& PoisonType();
// A generic poisoned value of "poisontype" type.
extern const Value& PoisonValue();
using ValueVec = llvm::SmallVector< Value, 4 >;
}
#endif