#pragma once #include "odbg.hh" #include #include namespace opast { using namespace ebcl; /*= BASE CLASS FOR AST NODES ===================================================*/ class T_RootNode; class A_Node { public: enum E_Type { ROOT , // Root node ILIST , // Instruction list // DECL_INIT , // Initialisation block DECL_FRAME , // Frame block DECL_FN , // Function // OP_CALL , // Function call OP_CLEAR , // Clear buffer OP_COND , // Conditional instruction OP_FRAMEBUFFER ,// Define framebuffer OP_FULLSCREEN , // Draw a fullscreen quad OP_INPUT , // Input declaration OP_LOCALS , // Declare local variables OP_MAINOUT , // Select the output buffer OP_ODBG , // Output debugging OP_PIPELINE , // Shader pipeline declaration OP_PROFILE , // Profiling block OP_PROGRAM , // Shader program declaration OP_SAMPLER , // Define sampler OP_SET , // Set instruction OP_TEXTURE , // Define texture OP_UNIFORMS , // Set uniforms OP_VIEWPORT , // Set viewport // "Use-" instructions OP_USE_FRAMEBUFFER , OP_USE_PIPELINE , OP_USE_PROGRAM , OP_USE_TEXTURE , // Unary operators EXPR_NEG , EXPR_INV , EXPR_NOT , EXPR_SIN , EXPR_COS , EXPR_TAN , EXPR_SQRT , EXPR_EXP , EXPR_LN , // Binary operators EXPR_ADD , EXPR_SUB , EXPR_MUL , EXPR_DIV , EXPR_POW , // Binary operators - comparisons EXPR_CMP_EQ , EXPR_CMP_NE , EXPR_CMP_GT , EXPR_CMP_GE , EXPR_CMP_LT , EXPR_CMP_LE , // EXPR_ID , // Variable access EXPR_INPUT , // Input value access EXPR_CONST , // Numeric constant // Technical nodes TN_CONDITION , // Expression for a conditional instruction TN_CASE , // Valued case for a conditional instruction TN_DEFAULT , // Default case for a conditional instruction TN_FBATT , // Framebuffer attachment TN_ARG , // Call argument }; private: const E_Type type_; A_Node* const parent_; T_SRDLocation location_; protected: explicit A_Node( const E_Type type , A_Node* const parent ) noexcept; public: virtual ~A_Node( ) = 0; E_Type type( ) const noexcept { return type_; } T_SRDLocation& location( ) noexcept { return location_; } T_SRDLocation const& location( ) const noexcept { return location_; } A_Node& parent( ) const noexcept { assert( parent_ ); return *parent_; } T_RootNode& root( ) const noexcept; }; // Browser function to be used with T_Visitor extern A_Node* ASTVisitorBrowser( A_Node& node , const uint32_t child ) noexcept; // Data types enum class E_DataType { UNKNOWN , BUILTIN , VARIABLE , FRAMEBUFFER , INPUT , PIPELINE , PROGRAM , SAMPLER , TEXTURE , }; M_LSHIFT_OP( T_StringBuilder , E_DataType ); /*= BASE STRUCTURES FOR INSTRUCTIONS =========================================*/ // Some instructions are restricted to either the initialisation code or the // frame code. enum class E_InstrRestriction { INIT , FRAME }; using T_InstrRestriction = T_Flags< E_InstrRestriction >; // Base class for instruction nodes class A_InstructionNode : public A_Node { private: const T_InstrRestriction restriction_; protected: A_InstructionNode( const E_Type type , A_Node& parent , T_InstrRestriction restriction = {} ) noexcept : A_Node( type , &parent ) , restriction_( restriction ) { assert( !restriction_.isSet({ E_InstrRestriction::INIT , E_InstrRestriction::FRAME }) ); } public: T_InstrRestriction restriction( ) const noexcept { return restriction_; } }; // Nodes that store lists of instructions class T_InstrListNode : public A_Node { private: T_Array< T_OwnPtr< A_InstructionNode > > instructions_; public: T_InstrListNode( A_Node& parent ) noexcept : A_Node( ILIST , &parent ) { } template< typename IType , typename... ArgTypes > IType& add( ArgTypes&&... args ); uint32_t size( ) const noexcept { return instructions_.size( ); } A_InstructionNode& node( const uint32_t index ) const noexcept { return *instructions_[ index ]; } }; template< typename IType , typename... ArgTypes > inline IType& T_InstrListNode::add( ArgTypes&&... args ) { instructions_.add( NewOwned< IType >( *this , std::forward< ArgTypes >( args ) ... ) ); return (IType&) *instructions_.last( ); } /*------------------------------------------------------------------------------*/ // Base class for expressions class A_ExpressionNode : public A_Node { protected: A_ExpressionNode( E_Type type , A_Node& parent ) noexcept : A_Node( type , &parent ) { } }; using P_ExpressionNode = T_OwnPtr< A_ExpressionNode >; // Technical node used for the arguments of various instructions class T_ArgumentNode : public A_Node { private: P_ExpressionNode expr_; public: T_ArgumentNode( A_Node& parent , P_ExpressionNode expr ) noexcept : A_Node( TN_ARG , &parent ) , expr_( std::move( expr ) ) { if ( expr_ ) { location( ) = expr_->location( ); } } A_ExpressionNode& expression( ) const noexcept { return *expr_; } bool isIdentifier( ) const noexcept { return expr_->type( ) == EXPR_ID; } }; using P_ArgumentNode = T_OwnPtr< T_ArgumentNode >; /*= FUNCTIONS AND ROOT NODES =================================================*/ // Function-like nodes class A_FuncNode : public A_Node { private: T_String name_; T_InstrListNode instructions_; protected: struct T_Local_ { T_String name; T_SRDLocation location; bool argument; E_DataType type{ E_DataType::UNKNOWN }; T_Local_( T_String const& name , T_SRDLocation const& location , const bool argument ) noexcept : name{ name } , location{ location } , argument{ argument } { } }; T_ObjectTable< T_String , T_Local_ > locals_{ []( T_Local_ const& l ) -> T_String { return l.name; } }; protected: // For init or frame entry points. // isInit = true => init entry point // isInit = false => frame entry point explicit A_FuncNode( bool isInit , T_RootNode* const parent ) noexcept; // For normal functions explicit A_FuncNode( T_String const& name , T_RootNode* const parent ) noexcept; public: T_String const& name( ) const noexcept { return name_; } T_InstrListNode& instructions( ) noexcept { return instructions_; } T_InstrListNode const& instructions( ) const noexcept { return instructions_; } // --------------------------------------------------------------------- T_Optional< T_SRDLocation > addLocalVariable( T_String const& name , T_SRDLocation const& location ) noexcept; uint32_t locals( ) const noexcept { return locals_.size( ); } bool hasLocal( T_String const& id ) const noexcept { return locals_.contains( id ); } bool isArgument( T_String const& id ) const noexcept { auto const* const ptr( locals_.get( id ) ); return ptr && ptr->argument; } uint32_t getLocalIndex( T_String const& name ) const noexcept { return locals_.indexOf( name ); } T_String const& getLocalName( const uint32_t index ) const noexcept { return locals_[ index ].name; } E_DataType getLocalType( T_String const& name ) const noexcept { return locals_.get( name )->type; } E_DataType getLocalType( const uint32_t index ) const noexcept { return locals_[ index ].type; } void setLocalType( const uint32_t index , const E_DataType type ) noexcept { locals_[ index ].type = type; } }; using P_InstrListNode = T_OwnPtr< T_InstrListNode >; /*----------------------------------------------------------------------------*/ // Root node, keeps track of the whole tree and related data (function table, // assets...) class T_RootNode : public A_Node { private: T_ObjectTable< T_String , T_OwnPtr< A_FuncNode > > functions_; public: T_RootNode( ) noexcept; // --------------------------------------------------------------------- // Return type for addFunction. We'll always return a reference to a // function node (which may or may not be the same as the initial one, // if there were duplicates), and we'll return the location of the // initial function in the case of a duplicate. struct T_AddFunctionResult { A_FuncNode& function; T_Optional< T_SRDLocation > dupLocation; T_AddFunctionResult( A_FuncNode& function ) noexcept : function{ function } , dupLocation{} {} T_AddFunctionResult( A_FuncNode& function , T_SRDLocation const& dupLocation ) noexcept : function{ function } , dupLocation{ dupLocation } {} }; // Attempts to add a function. If the function is already present in // the table, the result will be set up with the previous declaration's // location, and the specified function will not be modified (a duplicate // entry will be added to the table instead). T_AddFunctionResult addFunction( T_OwnPtr< A_FuncNode >& function ) noexcept; // --------------------------------------------------------------------- bool hasFunction( T_String const& name ) noexcept { return functions_.contains( name ); } bool hasInit( ) noexcept { return hasFunction( "*init*" ); } bool hasFrame( ) noexcept { return hasFunction( "*frame*" ); } uint32_t nFunctions( ) const noexcept { return functions_.size( ); } int32_t functionIndex( T_String const& name ) const noexcept { return functions_.indexOf( name ); } A_FuncNode& function( const uint32_t index ) const noexcept { return *functions_.values( )[ index ]; } }; /*----------------------------------------------------------------------------*/ // Init & frame functions class T_SpecialFuncNode : public A_FuncNode { public: T_SpecialFuncNode( bool isInit , T_RootNode& parent ) noexcept : A_FuncNode( isInit , &parent ) { } }; // Normal functions class T_FuncNode : public A_FuncNode { public: T_FuncNode( T_String const& name , T_RootNode& parent ) noexcept : A_FuncNode( name , &parent ) { } // Add an argument. If the argument is a duplicate, return the location // of the initial argument. T_Optional< T_SRDLocation > addArgument( T_SRDToken const& token ) noexcept; uint32_t arguments( ) const noexcept; }; /*= GENERAL / FLOW CONTROL INSTRUCTIONS ========================================*/ // Function call class T_CallInstrNode : public A_InstructionNode { private: T_String id_; T_SRDLocation idLocation_; T_AutoArray< P_ArgumentNode , 8 > arguments_; public: T_CallInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept : A_InstructionNode( OP_CALL , parent ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) { } void addArgument( P_ExpressionNode expr ) noexcept { if ( expr ) { arguments_.add( NewOwned< T_ArgumentNode >( *this , std::move( expr ) ) ); } } T_String const& id( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } uint32_t arguments( ) const noexcept { return arguments_.size( ); } T_ArgumentNode& argument( const uint32_t index ) const noexcept { return *arguments_[ index ]; } }; // Conditional instruction class T_CondInstrNode : public A_InstructionNode { public: class T_Expression : public A_Node { private: P_ExpressionNode expression_; public: T_Expression( T_CondInstrNode& parent , P_ExpressionNode expr ) : A_Node( TN_CONDITION , &parent ) , expression_( std::move( expr ) ) { } A_ExpressionNode& expression( ) const noexcept { return *expression_; } }; class T_ValuedCase : public A_Node { private: int64_t value_; P_InstrListNode instructions_; public: T_ValuedCase( T_CondInstrNode& parent , const int64_t value , P_InstrListNode il ) : A_Node( TN_CASE , &parent ) , value_( value ) , instructions_( std::move( il ) ) { } int64_t value( ) const noexcept { return value_; } T_InstrListNode& instructions( ) const noexcept { return *instructions_; } }; class T_DefaultCase : public A_Node { private: P_InstrListNode instructions_; public: T_DefaultCase( T_CondInstrNode& parent , P_InstrListNode il ) : A_Node( TN_DEFAULT , &parent ) , instructions_( std::move( il ) ) { } T_InstrListNode& instructions( ) const noexcept { return *instructions_; } }; private: T_OwnPtr< T_Expression > expression_; T_ObjectTable< int64_t , T_OwnPtr< T_ValuedCase > > cases_{ []( T_OwnPtr< T_ValuedCase > const& c ) -> int64_t { return c->value( ); } }; T_OwnPtr< T_DefaultCase > defaultCase_; public: explicit T_CondInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_COND , parent ) { } void setExpression( P_ExpressionNode expression ) noexcept; bool hasExpression( ) const noexcept { return bool( expression_ ); } T_Expression& expression( ) const noexcept { return *expression_; } void setCase( const int64_t value , P_InstrListNode instrList ) noexcept; void rmCase( const int64_t value ) noexcept { cases_.remove( value ); } uint32_t nCases( ) const noexcept { return cases_.size( ); } T_Array< int64_t > cases( ) const noexcept { return cases_.keys( ); } bool hasCase( const int64_t value ) const noexcept { return cases_.contains( value ); } T_ValuedCase& getCase( const int64_t value ) const noexcept { return **cases_.get( value ); } T_ValuedCase& getCaseByIndex( const uint32_t index ) const noexcept { return *cases_[ index ]; } void setDefaultCase( P_InstrListNode defaultCase ) noexcept; bool hasDefaultCase( ) const noexcept { return bool( defaultCase_ ); } T_DefaultCase& defaultCase( ) const noexcept { return *defaultCase_; } }; // Local variable declarations class T_LocalsInstrNode : public A_InstructionNode { private: T_AutoArray< T_String , 8 > vars_; T_AutoArray< T_SRDLocation , 8 > varLocs_; public: T_LocalsInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_LOCALS , parent ) { } T_Optional< T_SRDLocation > addVariable( T_SRDToken const& token ) noexcept; uint32_t variables( ) const noexcept { return vars_.size( ); } T_String const& varName( const uint32_t index ) const noexcept { return vars_[ index ]; } T_SRDLocation const& varLocation( const uint32_t index ) const noexcept { return varLocs_[ index ]; } }; // Setting a global variable class T_SetInstrNode : public A_InstructionNode { private: T_String id_; T_SRDLocation idLocation_; P_ExpressionNode expression_; public: T_SetInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept : A_InstructionNode( OP_SET , parent ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) { } T_String const& id( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } void setExpression( P_ExpressionNode expression ) noexcept { expression_ = std::move( expression ); } bool hasExpression( ) const noexcept { return bool( expression_ ); } A_ExpressionNode& expression( ) const noexcept { return *expression_; } }; /*= RESOURCE DEFINITION INSTRUCTIONS =========================================*/ // Base class class A_ResourceDefInstrNode : public A_InstructionNode { private: T_String id_; T_SRDLocation idLocation_; E_DataType dataType_; protected: A_ResourceDefInstrNode( const E_Type type , T_InstrListNode& parent , T_SRDToken const& identifier , const E_DataType dataType ) noexcept : A_InstructionNode( type , parent , E_InstrRestriction::FRAME ) , id_( identifier.stringValue( ) ) , idLocation_( identifier.location( ) ) , dataType_( dataType ) { } public: T_String const& id( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } E_DataType dataType( ) const noexcept { return dataType_; } }; /*------------------------------------------------------------------------------*/ // Framebuffer definition instruction class T_FramebufferInstrNode : public A_ResourceDefInstrNode { public: class T_Attachment : public A_Node { private: bool depth_; T_String id_; P_ArgumentNode lod_; public: T_Attachment( T_FramebufferInstrNode& parent , const bool depth , T_SRDToken const& texId , P_ExpressionNode lod = { } ) noexcept : A_Node( TN_FBATT , &parent ) , depth_( depth ) , id_( texId.stringValue( ) ) { location() = texId.location( ); if ( lod ) { lod_ = NewOwned< T_ArgumentNode >( *this , std::move( lod ) ); } } bool isDepth( ) const noexcept { return depth_; } T_String const& id( ) const noexcept { return id_; } T_ArgumentNode* lod( ) const noexcept { return lod_.get( ); } }; private: T_AutoArray< T_OwnPtr< T_Attachment > , 16 > colorAttachments_; T_OwnPtr< T_Attachment > depthAttachment_; bool hasAttachment( T_String const& name ) const noexcept; public: T_FramebufferInstrNode( T_InstrListNode& parent , T_SRDToken const& identifier ) noexcept : A_ResourceDefInstrNode( OP_FRAMEBUFFER , parent , identifier , E_DataType::FRAMEBUFFER ) { } // --------------------------------------------------------------------- bool addColorAttachment( T_SRDToken const& id , P_ExpressionNode lod = {} ) noexcept; uint32_t colorAttachments( ) const noexcept { return colorAttachments_.size( ); } T_Attachment& colorAttachment( const uint32_t index ) const noexcept { return *colorAttachments_[ index ]; } // --------------------------------------------------------------------- bool setDepthAttachment( T_SRDToken const& token , P_ExpressionNode lod = {} ) noexcept; T_Attachment* depthAttachment( ) const noexcept { return depthAttachment_.get( ); } }; // Input declaration class T_InputInstrNode : public A_ResourceDefInstrNode { private: float defValue_; T_SRDLocation dvLocation_; public: T_InputInstrNode( T_InstrListNode& parent , T_SRDToken const& tName ) noexcept : A_ResourceDefInstrNode( OP_INPUT , parent , tName , E_DataType::INPUT ) {} T_InputInstrNode( T_InstrListNode& parent , T_SRDToken const& tName , T_SRDToken const& tDefault ) noexcept : A_ResourceDefInstrNode( OP_INPUT , parent , tName , E_DataType::INPUT ) , defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) ) {} float defValue( ) const noexcept { return defValue_; } T_SRDLocation const& defValueLocation( ) const noexcept { return dvLocation_; } }; // Pipeline declaration instruction class T_PipelineInstrNode : public A_ResourceDefInstrNode { private: T_StaticArray< T_String , 6 > pids_; T_StaticArray< T_SRDLocation , 6 > pidLocations_; public: T_PipelineInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept : A_ResourceDefInstrNode( OP_PIPELINE , parent , idToken , E_DataType::PIPELINE ) { } // Add a program identifier. The token is assumed to be a valid word, // and the list of programs is assumed not to be full. If the identifer // is already in the pipeline's list, the location of the first // occurrence will be returned. T_Optional< T_SRDLocation > addProgram( T_SRDToken const& pidToken ) noexcept; uint32_t size( ) const noexcept { return pids_.size( ); } T_String const& program( const uint32_t index ) const noexcept { return pids_[ index ]; } T_SRDLocation const& pLocation( const uint32_t index ) const noexcept { return pidLocations_[ index ]; } }; // Program loader instruction class T_ProgramInstrNode : public A_ResourceDefInstrNode { private: T_String path_; T_SRDLocation pathLocation_; public: T_ProgramInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken , T_SRDToken const& pathToken ) noexcept : A_ResourceDefInstrNode( OP_PROGRAM , parent , idToken , E_DataType::PROGRAM ) , path_( pathToken.stringValue( ) ) , pathLocation_( pathToken.location( ) ) { } T_String const& path( ) const noexcept { return path_; } T_SRDLocation const& pathLocation( ) const noexcept { return pathLocation_; } }; // Sampler definition class T_SamplerInstrNode : public A_ResourceDefInstrNode { private: struct T_Sampling_ { T_SRDLocation location; E_TexSampling mode; }; struct T_Mipmaps_ { T_SRDLocation location; T_Optional< E_TexSampling > mode; }; struct T_Wrapping_ { T_SRDLocation location; E_TexWrap mode; }; struct T_LOD_ { T_SRDLocation location; P_ArgumentNode min; P_ArgumentNode max; }; T_Optional< T_Sampling_ > sampling_; T_Optional< T_Mipmaps_ > mipmaps_; T_Optional< T_Wrapping_ > wrapping_; T_Optional< T_LOD_ > lod_; public: T_SamplerInstrNode( T_InstrListNode& parent , T_SRDToken const& id ) noexcept : A_ResourceDefInstrNode( OP_SAMPLER , parent , id , E_DataType::SAMPLER ) { } // Attempt to set sampling mode, mipmap mode, wrapping mode or // LOD minimal/maximal, returning the location of the previous // definition if there was one. T_Optional< T_SRDLocation > setSampling( E_TexSampling mode , T_SRDLocation const& location ) noexcept; T_Optional< T_SRDLocation > setMipmapSampling( E_TexSampling mode , T_SRDLocation const& location ) noexcept; T_Optional< T_SRDLocation > setNoMipmap( T_SRDLocation const& location ) noexcept; T_Optional< T_SRDLocation > setWrapping( E_TexWrap mode , T_SRDLocation const& location ) noexcept; T_Optional< T_SRDLocation > setLOD( T_SRDLocation const& location , P_ExpressionNode min , P_ExpressionNode max ) noexcept; // Get either the defined values or the defaults E_TexSampling sampling( ) const noexcept { return sampling_ ? sampling_->mode : E_TexSampling::NEAREST; } T_Optional< E_TexSampling > mipmap( ) const noexcept { return mipmaps_ ? mipmaps_->mode : T_Optional< E_TexSampling >{}; } E_TexWrap wrapping( ) const noexcept { return wrapping_ ? wrapping_->mode : E_TexWrap::REPEAT; } T_ArgumentNode* minLod( ) const noexcept { return lod_ ? lod_->min.get( ) : nullptr; } T_ArgumentNode* maxLod( ) const noexcept { return lod_ ? lod_->max.get( ) : nullptr; } }; // Texture definition class T_TextureInstrNode : public A_ResourceDefInstrNode { private: E_TexType type_; P_ArgumentNode width_; P_ArgumentNode height_; P_ArgumentNode lods_; public: T_TextureInstrNode( T_InstrListNode& parent , T_SRDToken const& id , E_TexType type ) noexcept : A_ResourceDefInstrNode( OP_TEXTURE , parent , id , E_DataType::TEXTURE ) , type_( type ) { } E_TexType texType( ) const noexcept { return type_; } void setWidth( P_ExpressionNode width ) noexcept { if ( width ) { width_ = NewOwned< T_ArgumentNode >( *this , std::move( width ) ); } } void setHeight( P_ExpressionNode height ) noexcept { if ( height ) { height_ = NewOwned< T_ArgumentNode >( *this , std::move( height ) ); } } void setLODs( P_ExpressionNode lods ) noexcept { if ( lods ) { lods_ = NewOwned< T_ArgumentNode >( *this , std::move( lods ) ); } } bool hasWidth( ) const noexcept { return bool( width_ ); } T_ArgumentNode& width( ) const noexcept { return *width_; } bool hasHeight( ) const noexcept { return bool( height_ ); } T_ArgumentNode& height( ) const noexcept { return *height_; } T_ArgumentNode* lods( ) const noexcept { return lods_.get( ); } }; /*= TOOL CONTROL INSTRUCTIONS ==================================================*/ // Output debugging class T_OutputDebugInstrNode : public A_InstructionNode { private: T_String idTexture_; T_SRDLocation locTexture_; E_ODbgMode mode_; T_SRDLocation locMode_; T_String description_; T_SRDLocation locDescription_; public: T_OutputDebugInstrNode( T_InstrListNode& parent , T_SRDToken const& texture , const E_ODbgMode mode , T_SRDLocation const& modeLocation , T_SRDToken const& description ) noexcept; T_String const& texture( ) const noexcept { return idTexture_; } T_SRDLocation const& textureLocation( ) const noexcept { return locTexture_; } E_ODbgMode mode( ) const noexcept { return mode_; } T_SRDLocation const& modeLocation( ) const noexcept { return locMode_; } T_String const& description( ) const noexcept { return description_; } T_SRDLocation const& descriptionLocation( ) const noexcept { return locDescription_; } }; // Profiling instruction class T_ProfileInstrNode : public A_InstructionNode { private: T_String text_; T_InstrListNode instructions_; public: T_ProfileInstrNode( T_InstrListNode& parent , T_String const& text ) noexcept : A_InstructionNode( OP_PROFILE , parent , E_InstrRestriction::INIT ) , text_( text ) , instructions_( *this ) { } T_String const& text( ) const { return text_; } T_InstrListNode& instructions( ) noexcept { return instructions_; } T_InstrListNode const& instructions( ) const noexcept { return instructions_; } }; /*= RENDERING INSTRUCTIONS =====================================================*/ // Clear instruction class T_ClearInstrNode : public A_InstructionNode { private: T_StaticArray< P_ArgumentNode , 4 > components_; public: T_ClearInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_CLEAR , parent , E_InstrRestriction::INIT ) { } void addComponent( P_ExpressionNode expr ) noexcept { if ( expr ) { components_.add( NewOwned< T_ArgumentNode >( *this , std::move( expr ) ) ); } } uint32_t components( ) const noexcept { return components_.size( ); } T_ArgumentNode& component( const uint32_t index ) const noexcept { return *components_[ index ]; } }; // Fullscreen quad instruction class T_FullscreenInstrNode : public A_InstructionNode { public: T_FullscreenInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_FULLSCREEN , parent , E_InstrRestriction::INIT ) { } }; // Main output selection class T_MainOutputInstrNode : public A_InstructionNode { public: T_MainOutputInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_MAINOUT , parent , E_InstrRestriction::INIT ) { } }; // Uniform setting instruction class T_UniformsInstrNode : public A_InstructionNode { private: bool integers_; T_String progId_; T_SRDLocation progIdLocation_; uint32_t uloc_; T_SRDLocation ulocLocation_; T_StaticArray< P_ArgumentNode , 4 > values_; public: T_UniformsInstrNode( T_InstrListNode& parent , const bool integers , T_SRDToken const& prog , T_SRDToken const& loc ) noexcept : A_InstructionNode( OP_UNIFORMS , parent ) , integers_( integers ) , progId_( prog.stringValue( ) ) , progIdLocation_( prog.location( ) ) , uloc_( loc.longValue( ) ) , ulocLocation_( loc.location( ) ) { } bool integers( ) const noexcept { return integers_; } T_String const& progId( ) const noexcept { return progId_; } T_SRDLocation const& progIdLocation( ) const noexcept { return progIdLocation_; } uint32_t uloc( ) const noexcept { return uloc_; } T_SRDLocation const& ulocLocation( ) const noexcept { return ulocLocation_; } void addValue( P_ExpressionNode value ) noexcept { if ( value ) { values_.add( NewOwned< T_ArgumentNode >( *this , std::move( value ) ) ); } } uint32_t values( ) const noexcept { return values_.size( ); } T_ArgumentNode& value( const uint32_t index ) const noexcept { return *values_[ index ]; } }; // Use-* instructions (framebuffers, programs, pipelines) // Also serves as the base for use-texture class T_UseInstrNode : public A_InstructionNode { public: enum E_Type { FRAMEBUFFER , PIPELINE , PROGRAM , TEXTURE }; private: T_String id_; T_SRDLocation idLocation_; public: T_UseInstrNode( T_InstrListNode& parent , const E_Type type , T_SRDToken const& identifier ) noexcept : A_InstructionNode( ([type]() { switch ( type ) { case FRAMEBUFFER: return OP_USE_FRAMEBUFFER; case PIPELINE: return OP_USE_PIPELINE; case PROGRAM: return OP_USE_PROGRAM; case TEXTURE: return OP_USE_TEXTURE; } std::abort( ); } )( ) , parent ) , id_( identifier.stringValue( ) ) , idLocation_( identifier.location( ) ) { } T_String const& id( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } }; // Texture/sampler use instructions class T_UseTextureInstrNode : public T_UseInstrNode { private: uint32_t bank_; T_SRDLocation bankLocation_; T_String samplerId_; T_SRDLocation samplerIdLocation_; public: T_UseTextureInstrNode( T_InstrListNode& parent , T_SRDToken const& bank , T_SRDToken const& identifier , T_SRDToken const& sampler ) noexcept : T_UseInstrNode( parent , TEXTURE , identifier ) , bank_( bank.longValue( ) ) , bankLocation_( bank.location( ) ) , samplerId_( sampler.stringValue( ) ) , samplerIdLocation_( sampler.location( ) ) { } uint32_t bank( ) const noexcept { return bank_; } T_SRDLocation const& bankLocation( ) const noexcept { return bankLocation_; } T_String const& samplerId( ) const noexcept { return samplerId_; } T_SRDLocation const& samplerIdLocation( ) const noexcept { return samplerIdLocation_; } }; // Viewport instruction class T_ViewportInstrNode : public A_InstructionNode { public: enum E_Parameter { PX , PY , PWIDTH , PHEIGHT }; private: P_ArgumentNode parameters_[ 4 ]; public: T_ViewportInstrNode( T_InstrListNode& parent ) noexcept : A_InstructionNode( OP_VIEWPORT , parent , E_InstrRestriction::INIT ) { } void setParameter( const E_Parameter p , P_ExpressionNode value ) noexcept { if ( value ) { parameters_[ int( p ) ] = NewOwned< T_ArgumentNode >( *this , std::move( value ) ); } } bool hasParameter( const E_Parameter p ) const noexcept { return bool( parameters_[ int( p ) ] ); } T_ArgumentNode& parameter( const E_Parameter p ) const noexcept { return *parameters_[ int( p ) ]; } }; /*= EXPRESSIONS ==============================================================*/ // A constant value class T_ConstantExprNode : public A_ExpressionNode { private: bool wasFloat_; double vFloat_; int64_t vInt_; public: T_ConstantExprNode( A_Node& parent , T_SRDToken const& token ) noexcept : A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( token.type( ) == E_SRDTokenType::FLOAT ) , vFloat_( token.floatValue( ) ) , vInt_( token.longValue( ) ) { location( ) = token.location( ); } T_ConstantExprNode( A_Node& parent , int64_t value ) noexcept : A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( false ) , vFloat_( value ) , vInt_( value ) { } T_ConstantExprNode( A_Node& parent , double value ) noexcept : A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( true ) , vFloat_( value ) , vInt_( (int64_t) value ) { } bool wasFloat( ) const noexcept { return wasFloat_; } double floatValue( ) const noexcept { return vFloat_; } int64_t intValue( ) const noexcept { return vInt_; } }; // An identifier used in an expression class T_IdentifierExprNode : public A_ExpressionNode { private: T_String id_; public: T_IdentifierExprNode( A_Node& parent , T_SRDToken const& token ) noexcept : T_IdentifierExprNode( parent , token.stringValue( ) ) { location( ) = token.location( ); } T_IdentifierExprNode( A_Node& parent , T_String const& id ) noexcept : A_ExpressionNode( EXPR_ID , parent ) , id_( id ) { } T_String const& id( ) const noexcept { return id_; } }; // Access to an input value class T_InputExprNode : public A_ExpressionNode { private: T_String id_; T_SRDLocation idLocation_; public: T_InputExprNode( A_Node& parent , T_SRDToken const& token ) noexcept : A_ExpressionNode( EXPR_INPUT , parent ) , id_( token.stringValue( ) ) , idLocation_( token.location( ) ) { } T_String const& id( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } }; // A unary operator class T_UnaryOperatorNode : public A_ExpressionNode { public: enum E_Operator { NEG , INV , NOT , SIN , COS , TAN , SQRT , EXP , LN }; private: E_Operator op_; P_ExpressionNode argument_; public: T_UnaryOperatorNode( A_Node& parent , const E_Operator op ) noexcept; E_Operator op( ) const noexcept { return op_; } void setArgument( P_ExpressionNode argument ) noexcept { argument_ = std::move( argument ); } bool hasArgument( ) const noexcept { return bool( argument_ ); } A_ExpressionNode const& argument( ) const noexcept { return *argument_; } A_ExpressionNode& argument( ) noexcept { return *argument_; } }; // A binary operator class T_BinaryOperatorNode : public A_ExpressionNode { public: enum E_Operator { ADD , SUB , MUL , DIV , POW , CMP_EQ , CMP_NE , CMP_GT , CMP_GE , CMP_LT , CMP_LE , }; private: E_Operator op_; P_ExpressionNode left_; P_ExpressionNode right_; public: T_BinaryOperatorNode( A_Node& parent , const E_Operator op ) noexcept; E_Operator op( ) const noexcept { return op_; } void setLeft( P_ExpressionNode left ) noexcept { left_ = std::move( left ); } void setRight( P_ExpressionNode right ) noexcept { right_ = std::move( right ); } bool hasLeft( ) const noexcept { return bool( left_ ); } bool hasRight( ) const noexcept { return bool( right_ ); } A_ExpressionNode const& left( ) const noexcept { return *left_; } A_ExpressionNode& left( ) noexcept { return *left_; } A_ExpressionNode const& right( ) const noexcept { return *right_; } A_ExpressionNode& right( ) noexcept { return *right_; } }; /*= PARSER ===================================================================*/ // Parser output. Consists in a root node as well as other details (table of // constants, data types, etc...) struct T_ParserOutput { T_RootNode root; T_KeyValueTable< T_String , E_DataType > types; }; // The actual parser class T_Parser : public A_PrivateImplementation { private: T_Array< T_SRDError > errors_; T_OwnPtr< T_ParserOutput > output_; public: T_Parser( ) noexcept; bool parse( T_SRDList const& input ) noexcept; T_Array< T_SRDError > const& errors( ) const noexcept { return errors_; } T_OwnPtr< T_ParserOutput > result( ) noexcept { return std::move( output_ ); } }; } // namespace opast