#include "externals.hh" #include "opast.hh" #include 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_FRAMEBUFFER: case A_Node::OP_ODBG: // 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; } // Sampler definition may have LOD expressions case A_Node::OP_SAMPLER: { auto& n( (T_SamplerInstrNode&) node ); auto c = child; if ( n.minLod( ) ) { if ( c == 0 ) { return n.minLod( ); } c--; } if ( n.maxLod( ) && c == 0 ) { return n.maxLod( ); } 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 ) { } /*= T_FramebufferInstrNode ===================================================*/ bool T_FramebufferInstrNode::addColorAttachment( T_SRDToken const& id ) noexcept { if ( idColorAttachments_.contains( id.stringValue( ) ) || idDepthAttachment_ == id.stringValue( ) ) { return false; } idColorAttachments_.add( id.stringValue( ) ); locColorAttachments_.add( id.location( ) ); return true; } bool T_FramebufferInstrNode::setDepthAttachment( T_SRDToken const& token ) noexcept { if ( idDepthAttachment_ || idColorAttachments_.contains( token.stringValue( ) ) ) { return false; } idDepthAttachment_ = token.stringValue( ); locDepthAttachment_ = token.location( ); return true; } /*= T_OutputDebugInstrNode ===================================================*/ T_OutputDebugInstrNode::T_OutputDebugInstrNode( T_InstrListNode& parent , T_SRDToken const& texture , const E_ODbgMode mode , T_SRDLocation const& modeLocation , T_SRDToken const& description ) noexcept : A_InstructionNode( OP_ODBG , parent ) , idTexture_( texture.stringValue( ) ) , locTexture_( texture.location( ) ) , mode_( mode ) , locMode_( modeLocation ) , description_( description.stringValue( ) ) , locDescription_( description.location( ) ) { } /*= T_SamplerInstrNode =========================================================*/ T_Optional< T_SRDLocation > T_SamplerInstrNode::setSampling( E_TexSampling mode , T_SRDLocation const& location ) noexcept { if ( sampling_ ) { return sampling_->location; } sampling_ = T_Sampling_{ location , mode }; return {}; } T_Optional< T_SRDLocation > T_SamplerInstrNode::setMipmapSampling( E_TexSampling mode , T_SRDLocation const& location ) noexcept { if ( mipmaps_ ) { return mipmaps_->location; } mipmaps_ = T_Mipmaps_{ location , mode }; return {}; } T_Optional< T_SRDLocation > T_SamplerInstrNode::setNoMipmap( T_SRDLocation const& location ) noexcept { if ( mipmaps_ ) { return mipmaps_->location; } mipmaps_ = T_Mipmaps_{ location , {} }; return {}; } T_Optional< T_SRDLocation > T_SamplerInstrNode::setWrapping( E_TexWrap mode , T_SRDLocation const& location ) noexcept { if ( wrapping_ ) { return wrapping_->location; } wrapping_ = T_Wrapping_{ location , mode }; return {}; } T_Optional< T_SRDLocation > T_SamplerInstrNode::setLOD( T_SRDLocation const& location , P_ExpressionNode min , P_ExpressionNode max ) noexcept { if ( lod_ ) { return lod_->location; } lod_ = T_LOD_{ location , std::move( min ) , std::move( max ) }; return {}; }