#pragma once //#ifndef REAL_BUILD # include "externals.hh" //#endif #include namespace opast { using namespace ebcl; 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_PIPELINE , // Shader pipeline declaration OP_PROFILE , // Profiling block OP_PROGRAM , // Shader program declaration OP_SET , // Set instruction // 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_CONST , // Numeric constant }; 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; }; /*----------------------------------------------------------------------------*/ // Base class for instruction nodes class A_InstructionNode : public A_Node { protected: A_InstructionNode( E_Type type , A_Node& parent ) noexcept : A_Node( type , &parent ) {} }; // 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; template< typename IType , typename... ArgTypes > IType& add( ArgTypes&&... args ); }; 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( ); } /*----------------------------------------------------------------------------*/ // Function-like nodes class A_FuncNode : public A_Node { private: T_String name_; T_InstrListNode instructions_; 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_; } }; // 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*" ); } }; /*----------------------------------------------------------------------------*/ // Init & frame functions class T_SpecialFuncNode : public A_FuncNode { public: T_SpecialFuncNode( bool isInit , T_RootNode& parent ) noexcept; }; // Normal functions class T_FuncNode : public A_FuncNode { private: T_AutoArray< T_String , 8 > argNames_; T_AutoArray< T_SRDLocation , 8 > argLocations_; public: T_FuncNode( T_String const& name , T_RootNode& parent ) noexcept; // 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; }; /*----------------------------------------------------------------------------*/ // Base class for expressions class A_ExpressionNode : public A_Node { protected: A_ExpressionNode( E_Type type , A_Node& parent ) noexcept : A_Node( type , &parent ) { } }; /*============================================================================*/ // Pipeline declaration instruction class T_PipelineInstrNode : public A_InstructionNode { private: T_String id_; T_SRDLocation idLocation_; T_StaticArray< T_String , 6 > pids_; T_StaticArray< T_SRDLocation , 6 > pidLocations_; public: T_PipelineInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept; explicit T_PipelineInstrNode( T_InstrListNode& parent ) noexcept; // 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 ]; } }; // 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; T_String const& text( ) const { return text_; } T_InstrListNode& instructions( ) noexcept { return instructions_; } T_InstrListNode const& instructions( ) const noexcept { return instructions_; } }; // Program loader instruction class T_ProgramInstrNode : public A_InstructionNode { private: T_String id_; T_SRDLocation idLocation_; T_String path_; T_SRDLocation pathLocation_; public: T_ProgramInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken , T_SRDToken const& pathToken ) noexcept; }; // Setting a global variable class T_SetInstrNode : public A_InstructionNode { private: T_String id_; T_SRDLocation idLocation_; T_OwnPtr< A_ExpressionNode > expression_; public: T_SetInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept; T_String const& identifier( ) const noexcept { return id_; } T_SRDLocation const& idLocation( ) const noexcept { return idLocation_; } void setExpression( T_OwnPtr< A_ExpressionNode > expression ) noexcept { expression_ = std::move( expression ); } bool hasExpression( ) const noexcept { return bool( expression_ ); } A_ExpressionNode const& expression( ) const noexcept { return *expression_; } A_ExpressionNode& expression( ) noexcept { return *expression_; } }; /*============================================================================*/ // 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; T_ConstantExprNode( A_Node& parent , int64_t value ) noexcept; T_ConstantExprNode( A_Node& parent , double value ) noexcept; 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( A_Node& parent , T_String const& id ) noexcept; T_String const& id( ) const noexcept { return id_; } }; // 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_; T_OwnPtr< A_ExpressionNode > argument_; public: T_UnaryOperatorNode( A_Node& parent , const E_Operator op ) noexcept; E_Operator op( ) const noexcept { return op_; } void setArgument( T_OwnPtr< A_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_; T_OwnPtr< A_ExpressionNode > left_; T_OwnPtr< A_ExpressionNode > right_; public: T_BinaryOperatorNode( A_Node& parent , const E_Operator op ) noexcept; E_Operator op( ) const noexcept { return op_; } void setLeft( T_OwnPtr< A_ExpressionNode > left ) noexcept { left_ = std::move( left ); } void setRight( T_OwnPtr< A_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_; } }; /*============================================================================*/ class T_Parser : public A_PrivateImplementation { private: T_Array< T_SRDError > errors_; T_OwnPtr< T_RootNode > rootNode_; public: T_Parser( ) noexcept; bool parse( T_SRDList const& input ) noexcept; T_Array< T_SRDError > const& errors( ) const noexcept { return errors_; } T_OwnPtr< T_RootNode > result( ) noexcept { return std::move( rootNode_ ); } }; } // namespace opast