diff --git a/opast.cc b/opast.cc index 8d98a47..1e07155 100644 --- a/opast.cc +++ b/opast.cc @@ -129,14 +129,14 @@ T_Optional< T_SRDLocation > T_FuncNode::addArgument( T_PipelineInstrNode::T_PipelineInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken ) noexcept - : A_InstructionNode( OP_PIPELINE , parent ) , + : A_InstructionNode( OP_PIPELINE , parent , E_InstrRestriction::FRAME ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) { } T_PipelineInstrNode::T_PipelineInstrNode( T_InstrListNode& parent ) noexcept - : A_InstructionNode( OP_PIPELINE , parent ) , + : A_InstructionNode( OP_PIPELINE , parent , E_InstrRestriction::FRAME ) , id_( "*invalid*" ) , idLocation_{ } { } @@ -160,7 +160,7 @@ T_Optional< T_SRDLocation > T_PipelineInstrNode::addProgram( T_ProfileInstrNode::T_ProfileInstrNode( T_InstrListNode& parent , T_String const& text ) noexcept - : A_InstructionNode( OP_PROFILE , parent ) , + : A_InstructionNode( OP_PROFILE , parent , E_InstrRestriction::INIT ) , text_( text ) , instructions_( *this ) { } @@ -172,7 +172,7 @@ T_ProgramInstrNode::T_ProgramInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken , T_SRDToken const& pathToken ) noexcept - : A_InstructionNode( OP_PROGRAM , parent ) , + : A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) , path_( pathToken.stringValue( ) ) , @@ -197,7 +197,7 @@ T_TextureInstrNode::T_TextureInstrNode( T_InstrListNode& parent , T_SRDToken const& idToken , const E_TexType type ) noexcept - : A_InstructionNode( OP_PROGRAM , parent ) , + : A_InstructionNode( OP_PROGRAM , parent , E_InstrRestriction::FRAME ) , id_( idToken.stringValue( ) ) , idLocation_( idToken.location( ) ) , type_( type ) diff --git a/opast.hh b/opast.hh index a5171e5..1755b07 100644 --- a/opast.hh +++ b/opast.hh @@ -76,16 +76,38 @@ class A_Node /*----------------------------------------------------------------------------*/ +// 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( E_Type type , - A_Node& parent ) noexcept - : A_Node( type , &parent ) - {} + 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 { @@ -341,14 +363,14 @@ class T_InputInstrNode : public A_InstructionNode public: T_InputInstrNode( T_InstrListNode& parent , T_SRDToken const& tName ) noexcept - : A_InstructionNode( OP_INPUT , parent ) , + : A_InstructionNode( OP_INPUT , parent , E_InstrRestriction::FRAME ) , name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) ) {} T_InputInstrNode( T_InstrListNode& parent , T_SRDToken const& tName , T_SRDToken const& tDefault ) noexcept - : A_InstructionNode( OP_INPUT , parent ) , + : A_InstructionNode( OP_INPUT , parent , E_InstrRestriction::FRAME ) , name_( tName.stringValue( ) ) , nameLocation_( tName.location( ) ) , defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) ) {} diff --git a/parsercheck.cc b/parsercheck.cc index 98ffe42..e30495d 100644 --- a/parsercheck.cc +++ b/parsercheck.cc @@ -239,30 +239,54 @@ bool checkCalls( T_RootNode& root ) } return {}; } ); - enum class E_CallInfo_ { - INIT_CHECKED , FRAME_CHECKED , - INIT_CALLED , FRAME_CALLED - }; - using T_CallInfo_ = T_Flags< E_CallInfo_ , uint8_t >; - T_CallInfo_ callInfo[ calls.size( ) ]; + T_InstrRestriction callInfo[ calls.size( ) ]; callGraphVisitor.visit( root.functionIndex( "*init*" ) , [&]( uint32_t id , const bool exit ) -> bool { - if ( exit || callInfo[ id ] & E_CallInfo_::INIT_CALLED ) { + if ( exit || callInfo[ id ] & E_InstrRestriction::INIT ) { return false; } - callInfo[ id ] |= E_CallInfo_::INIT_CALLED; + callInfo[ id ] |= E_InstrRestriction::INIT; return true; } ); callGraphVisitor.visit( root.functionIndex( "*frame*" ) , [&]( uint32_t id , const bool exit ) -> bool { - if ( exit || callInfo[ id ] & E_CallInfo_::FRAME_CALLED ) { + if ( exit || callInfo[ id ] & E_InstrRestriction::FRAME ) { return false; } - callInfo[ id ] |= E_CallInfo_::FRAME_CALLED; + callInfo[ id ] |= E_InstrRestriction::FRAME; return true; } ); + for ( auto i = 0u ; i < root.nFunctions( ) ; i ++ ) { + visitor.visit( root.function( i ) , + [&]( A_Node& node , bool exit ) { + if ( exit ) { + return false; + } + + auto const* instr( dynamic_cast< A_InstructionNode const* >( &node ) ); + if ( instr && ( instr->restriction( ) & callInfo[ i ] ) ) { + T_StringBuilder sb; + sb << "instruction not allowed in " + << ( ( instr->restriction( ) & E_InstrRestriction::INIT ) + ? "initialisation" : "frame function" ); + errors.addNew( std::move( sb ) , instr->location( ) ); + } + return true; + } ); + } + + if ( !errors.empty( ) ) { + T_StringBuilder sb; + for ( auto const& err : errors ) { + WriteSRDError( sb , err ); + } + sb << "Parser failed\n" << '\0'; + fprintf( stderr , "%s" , sb.data( ) ); + return false; + } + T_StringBuilder sb; for ( auto callerId = 0u ; callerId < calls.size( ) ; callerId ++ ) { const auto nCallees( calls.sizeOf( callerId ) );