337 lines
7.8 KiB
C++
337 lines
7.8 KiB
C++
#include "externals.hh"
|
|
#include "opast.hh"
|
|
#include <ebcl/Algorithms.hh>
|
|
|
|
using namespace ebcl;
|
|
using namespace opast;
|
|
|
|
|
|
/*= A_Node ===================================================================*/
|
|
|
|
A_Node::A_Node( const E_Type type ,
|
|
A_Node* const parent ) noexcept
|
|
: type_( type ) , parent_( parent )
|
|
{
|
|
assert( ( type == ROOT && !parent ) || ( type != ROOT && parent ) );
|
|
}
|
|
|
|
A_Node::~A_Node( ) { }
|
|
|
|
T_RootNode& A_Node::root( ) const noexcept
|
|
{
|
|
A_Node const* node( this );
|
|
while ( node->parent_ ) {
|
|
node = node->parent_;
|
|
}
|
|
assert( node );
|
|
assert( node->type_ == ROOT );
|
|
return *dynamic_cast< T_RootNode* >(
|
|
const_cast< A_Node* >( node ) );
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
A_Node* opast::ASTVisitorBrowser(
|
|
A_Node& node ,
|
|
const uint32_t child ) noexcept
|
|
{
|
|
switch ( node.type( ) ) {
|
|
|
|
// Root node
|
|
case A_Node::ROOT: {
|
|
auto& n( (T_RootNode&) node );
|
|
if ( child < n.nFunctions( ) ) {
|
|
return &n.function( child );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Functions / special blocks
|
|
case A_Node::DECL_FN: case A_Node::DECL_INIT: case A_Node::DECL_FRAME:
|
|
if ( child == 0 ) {
|
|
auto& n( (A_FuncNode&) node );
|
|
return &n.instructions( );
|
|
}
|
|
break;
|
|
|
|
// Instruction list
|
|
case A_Node::ILIST: {
|
|
auto& n( (T_InstrListNode&) node );
|
|
if ( child < n.size( ) ) {
|
|
return &n.node( child );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Unary operators
|
|
case A_Node::EXPR_NEG: case A_Node::EXPR_INV:
|
|
case A_Node::EXPR_NOT: case A_Node::EXPR_SIN:
|
|
case A_Node::EXPR_COS: case A_Node::EXPR_TAN:
|
|
case A_Node::EXPR_SQRT: case A_Node::EXPR_EXP:
|
|
case A_Node::EXPR_LN:
|
|
{
|
|
auto& n( (T_UnaryOperatorNode&) node );
|
|
if ( child == 0 && n.hasArgument( ) ) {
|
|
return &n.argument( );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Binary operators
|
|
case A_Node::EXPR_ADD: case A_Node::EXPR_SUB:
|
|
case A_Node::EXPR_MUL: case A_Node::EXPR_DIV:
|
|
case A_Node::EXPR_POW:
|
|
case A_Node::EXPR_CMP_EQ: case A_Node::EXPR_CMP_NE:
|
|
case A_Node::EXPR_CMP_GT: case A_Node::EXPR_CMP_GE:
|
|
case A_Node::EXPR_CMP_LT: case A_Node::EXPR_CMP_LE:
|
|
{
|
|
auto& n( (T_BinaryOperatorNode&) node );
|
|
if ( child == 0 && n.hasLeft( ) ) {
|
|
return &n.left( );
|
|
}
|
|
if ( child < 2 && n.hasRight( ) ) {
|
|
return &n.right( );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Nodes that do not have children
|
|
case A_Node::EXPR_ID: case A_Node::EXPR_CONST:
|
|
case A_Node::EXPR_INPUT:
|
|
case A_Node::OP_PROGRAM: case A_Node::OP_PIPELINE:
|
|
case A_Node::OP_INPUT: case A_Node::OP_FULLSCREEN:
|
|
case A_Node::OP_USE_FRAMEBUFFER: case A_Node::OP_USE_PIPELINE:
|
|
case A_Node::OP_USE_PROGRAM: case A_Node::OP_USE_TEXTURE:
|
|
break;
|
|
|
|
// Profile instruction
|
|
case A_Node::OP_PROFILE:
|
|
if ( child == 0 ) {
|
|
return &( ((T_ProfileInstrNode&) node).instructions( ) );
|
|
}
|
|
break;
|
|
|
|
// Call instruction
|
|
case A_Node::OP_CALL:
|
|
{
|
|
auto& n( (T_CallInstrNode&) node );
|
|
if ( child < n.arguments( ) ) {
|
|
return &n.argument( child );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Conditional instruction
|
|
case A_Node::OP_COND:
|
|
{
|
|
auto& n( (T_CondInstrNode&) node );
|
|
auto c = child;
|
|
if ( n.hasExpression( ) ) {
|
|
if ( c == 0 ) {
|
|
return &n.expression( );
|
|
}
|
|
c --;
|
|
}
|
|
if ( !n.cases( ).empty( ) ) {
|
|
if ( c < n.cases( ).size( ) ) {
|
|
return &n.getCase( n.cases( )[ c ] );
|
|
}
|
|
c -= n.cases( ).size( );
|
|
}
|
|
if ( n.hasDefaultCase( ) && c == 0 ) {
|
|
return &n.defaultCase( );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Set instruction
|
|
case A_Node::OP_SET:
|
|
if ( child == 0 ) {
|
|
auto& n( (T_SetInstrNode&) node );
|
|
if ( n.hasExpression( ) ) {
|
|
return &n.expression( );
|
|
}
|
|
}
|
|
break;
|
|
|
|
// Texture instruction
|
|
case A_Node::OP_TEXTURE:
|
|
{
|
|
auto& n( (T_TextureInstrNode&) node );
|
|
auto c = child;
|
|
if ( n.hasWidth( ) ) {
|
|
if ( c == 0 ) {
|
|
return &n.width( );
|
|
}
|
|
c --;
|
|
}
|
|
if ( n.hasHeight( ) && c == 0 ) {
|
|
return &n.height( );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Uniforms instruction
|
|
case A_Node::OP_UNIFORMS:
|
|
{
|
|
auto& n( (T_UniformsInstrNode&) node );
|
|
if ( child < n.values( ) ) {
|
|
return &n.value( child );
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Viewport instruction
|
|
case A_Node::OP_VIEWPORT:
|
|
{
|
|
auto& n( (T_ViewportInstrNode&) node );
|
|
auto c = child;
|
|
for ( int i = 0 ; i < 4 ; i ++ ) {
|
|
T_ViewportInstrNode::E_Parameter p{
|
|
T_ViewportInstrNode::E_Parameter( i ) };
|
|
if ( n.hasParameter( p ) ) {
|
|
if ( c == 0 ) {
|
|
return &n.parameter( p );
|
|
}
|
|
c --;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
/*= A_FuncNode ===============================================================*/
|
|
|
|
A_FuncNode::A_FuncNode(
|
|
const bool isInit ,
|
|
T_RootNode* const root ) noexcept
|
|
: A_Node( isInit ? DECL_INIT : DECL_FRAME , root ) ,
|
|
name_( isInit ? "*init*" : "*frame*" ) ,
|
|
instructions_( *this )
|
|
{ }
|
|
|
|
A_FuncNode::A_FuncNode(
|
|
T_String const& name ,
|
|
T_RootNode* const root ) noexcept
|
|
: A_Node( DECL_FN , root ) , name_( name ) ,
|
|
instructions_( *this )
|
|
{ }
|
|
|
|
|
|
/*= T_RootNode ===============================================================*/
|
|
|
|
T_RootNode::T_RootNode( ) noexcept
|
|
: A_Node( ROOT , nullptr ) , functions_(
|
|
[]( T_OwnPtr< A_FuncNode > const& f ) {
|
|
return f->name( );
|
|
} )
|
|
{ }
|
|
|
|
T_RootNode::T_AddFunctionResult T_RootNode::addFunction(
|
|
T_OwnPtr< A_FuncNode >& function ) noexcept
|
|
{
|
|
T_String const& fn( function->name( ) );
|
|
auto const* const pf( functions_.get( fn ) );
|
|
if ( !pf ) {
|
|
auto* const rv( function.get( ) );
|
|
functions_.add( std::move( function ) );
|
|
return *rv;
|
|
}
|
|
|
|
T_String dfn;
|
|
uint32_t dupCtr( 0 );
|
|
do {
|
|
T_StringBuilder fnsb;
|
|
fnsb << fn << " dup " << dupCtr ++;
|
|
dfn = std::move( fnsb );
|
|
} while ( functions_.contains( dfn ) );
|
|
|
|
T_OwnPtr< A_FuncNode > df( NewOwned< T_FuncNode >( dfn , *this ) );
|
|
auto* const rv( df.get( ) );
|
|
functions_.add( std::move( df ) );
|
|
return T_AddFunctionResult{ *rv , (*pf)->location( ) };
|
|
}
|
|
|
|
|
|
/*= T_FuncNode ===============================================================*/
|
|
|
|
T_Optional< T_SRDLocation > T_FuncNode::addArgument(
|
|
T_SRDToken const& token ) noexcept
|
|
{
|
|
assert( token.type( ) == E_SRDTokenType::WORD );
|
|
assert( token.hasLocation( ) );
|
|
|
|
const auto pnp( argNames_.indexOf( token.stringValue( ) ) );
|
|
if ( pnp != -1 ) {
|
|
return argLocations_[ pnp ];
|
|
}
|
|
argNames_.add( token.stringValue( ) );
|
|
argLocations_.add( token.location( ) );
|
|
return {};
|
|
}
|
|
|
|
|
|
/*= T_PipelineInstrNode ======================================================*/
|
|
|
|
T_Optional< T_SRDLocation > T_PipelineInstrNode::addProgram(
|
|
T_SRDToken const& pidToken ) noexcept
|
|
{
|
|
T_String const& name( pidToken.stringValue( ) );
|
|
const auto pIndex( pids_.indexOf( name ) );
|
|
if ( pIndex != -1 ) {
|
|
return pidLocations_[ pIndex ];
|
|
}
|
|
pids_.add( name );
|
|
pidLocations_.add( pidToken.location( ) );
|
|
return {};
|
|
}
|
|
|
|
|
|
/*= T_UnaryOperatorNode ======================================================*/
|
|
|
|
T_UnaryOperatorNode::T_UnaryOperatorNode(
|
|
A_Node& parent ,
|
|
const E_Operator op ) noexcept
|
|
: A_ExpressionNode( ([op]() {
|
|
switch ( op ) {
|
|
case NEG: return EXPR_NEG;
|
|
case INV: return EXPR_INV;
|
|
case NOT: return EXPR_NOT;
|
|
case SIN: return EXPR_SIN;
|
|
case COS: return EXPR_COS;
|
|
case TAN: return EXPR_TAN;
|
|
case SQRT: return EXPR_SQRT;
|
|
case EXP: return EXPR_EXP;
|
|
case LN: return EXPR_LN;
|
|
}
|
|
std::abort( );
|
|
})( ) , parent ) , op_( op )
|
|
{ }
|
|
|
|
|
|
/*= T_BinaryOperatorNode =====================================================*/
|
|
|
|
T_BinaryOperatorNode::T_BinaryOperatorNode(
|
|
A_Node& parent ,
|
|
const E_Operator op ) noexcept
|
|
: A_ExpressionNode( ([op]() {
|
|
switch ( op ) {
|
|
case ADD: return EXPR_ADD;
|
|
case SUB: return EXPR_SUB;
|
|
case MUL: return EXPR_MUL;
|
|
case DIV: return EXPR_DIV;
|
|
case POW: return EXPR_POW;
|
|
case CMP_EQ: return EXPR_CMP_EQ;
|
|
case CMP_NE: return EXPR_CMP_NE;
|
|
case CMP_GT: return EXPR_CMP_GT;
|
|
case CMP_GE: return EXPR_CMP_GE;
|
|
case CMP_LT: return EXPR_CMP_LT;
|
|
case CMP_LE: return EXPR_CMP_LE;
|
|
}
|
|
std::abort( );
|
|
})( ) , parent ) , op_( op )
|
|
{ }
|