Parser - Check local variable declarations
This commit is contained in:
parent
e21e5cefb2
commit
36a3e5e26f
3 changed files with 109 additions and 20 deletions
44
opast.cc
44
opast.cc
|
@ -315,6 +315,18 @@ A_FuncNode::A_FuncNode(
|
|||
instructions_( *this )
|
||||
{ }
|
||||
|
||||
T_Optional< T_SRDLocation > A_FuncNode::addLocalVariable(
|
||||
T_String const& name ,
|
||||
T_SRDLocation const& location ) noexcept
|
||||
{
|
||||
auto const* const pnp( locals_.get( name ) );
|
||||
if ( pnp ) {
|
||||
return pnp->location;
|
||||
}
|
||||
locals_.add( T_Local_{ name , location , false } );
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
/*= T_RootNode ===============================================================*/
|
||||
|
||||
|
@ -359,15 +371,28 @@ T_Optional< T_SRDLocation > T_FuncNode::addArgument(
|
|||
assert( token.type( ) == E_SRDTokenType::WORD );
|
||||
assert( token.hasLocation( ) );
|
||||
|
||||
const auto pnp( argNames_.indexOf( token.stringValue( ) ) );
|
||||
if ( pnp != -1 ) {
|
||||
return argLocations_[ pnp ];
|
||||
const auto pnp( locals_.indexOf( token.stringValue( ) ) );
|
||||
if ( pnp != T_HashIndex::INVALID_INDEX ) {
|
||||
return locals_[ pnp ].location;
|
||||
}
|
||||
argNames_.add( token.stringValue( ) );
|
||||
argLocations_.add( token.location( ) );
|
||||
locals_.add( T_Local_{ token.stringValue( ) , token.location( ) , true } );
|
||||
return {};
|
||||
}
|
||||
|
||||
uint32_t T_FuncNode::arguments( ) const noexcept
|
||||
{
|
||||
const auto n( locals_.size( ) );
|
||||
uint32_t na{ 0u };
|
||||
|
||||
for ( auto i = 0u ; i < n ; i ++ ) {
|
||||
if ( locals_[ i ].argument ) {
|
||||
na ++;
|
||||
}
|
||||
}
|
||||
|
||||
return na;
|
||||
}
|
||||
|
||||
|
||||
/*= T_PipelineInstrNode ======================================================*/
|
||||
|
||||
|
@ -551,13 +576,14 @@ T_Optional< T_SRDLocation > T_SamplerInstrNode::setLOD(
|
|||
|
||||
/*= T_LocalsInstrNode ===========================================================*/
|
||||
|
||||
bool T_LocalsInstrNode::addVariable(
|
||||
T_Optional< T_SRDLocation > T_LocalsInstrNode::addVariable(
|
||||
T_SRDToken const& token ) noexcept
|
||||
{
|
||||
if ( vars_.contains( token.stringValue( ) ) ) {
|
||||
return false;
|
||||
const auto pnp( vars_.indexOf( token.stringValue( ) ) );
|
||||
if ( pnp != -1 ) {
|
||||
return varLocs_[ pnp ];
|
||||
}
|
||||
vars_.add( token.stringValue( ) );
|
||||
varLocs_.add( token.location( ) );
|
||||
return true;
|
||||
return {};
|
||||
}
|
||||
|
|
35
opast.hh
35
opast.hh
|
@ -198,6 +198,27 @@ class A_FuncNode : public A_Node
|
|||
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
|
||||
|
@ -217,6 +238,10 @@ class A_FuncNode : public A_Node
|
|||
{ return instructions_; }
|
||||
T_InstrListNode const& instructions( ) const noexcept
|
||||
{ return instructions_; }
|
||||
|
||||
T_Optional< T_SRDLocation > addLocalVariable(
|
||||
T_String const& name ,
|
||||
T_SRDLocation const& location ) noexcept;
|
||||
};
|
||||
using P_InstrListNode = T_OwnPtr< T_InstrListNode >;
|
||||
|
||||
|
@ -293,10 +318,6 @@ class T_SpecialFuncNode : public A_FuncNode
|
|||
// 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
|
||||
|
@ -308,8 +329,7 @@ class T_FuncNode : public A_FuncNode
|
|||
T_Optional< T_SRDLocation > addArgument(
|
||||
T_SRDToken const& token ) noexcept;
|
||||
|
||||
uint32_t arguments( ) const noexcept
|
||||
{ return argNames_.size( ); }
|
||||
uint32_t arguments( ) const noexcept;
|
||||
};
|
||||
|
||||
|
||||
|
@ -407,7 +427,8 @@ class T_LocalsInstrNode : public A_InstructionNode
|
|||
: A_InstructionNode( OP_LOCALS , parent )
|
||||
{ }
|
||||
|
||||
bool addVariable( T_SRDToken const& token ) noexcept;
|
||||
T_Optional< T_SRDLocation > addVariable(
|
||||
T_SRDToken const& token ) noexcept;
|
||||
|
||||
uint32_t variables( ) const noexcept
|
||||
{ return vars_.size( ); }
|
||||
|
|
50
opparser.cc
50
opparser.cc
|
@ -171,6 +171,7 @@ struct T_ParserImpl_
|
|||
bool checkCalls( ) noexcept;
|
||||
bool checkInstructionRestrictions( ) noexcept;
|
||||
bool collectGlobalTypes( ) noexcept;
|
||||
bool checkLocalVariables( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
@ -282,7 +283,8 @@ void T_ParserImpl_::main(
|
|||
&& checkRequiredBlocks( input )
|
||||
&& checkCalls( )
|
||||
&& checkInstructionRestrictions( )
|
||||
&& collectGlobalTypes( );
|
||||
&& collectGlobalTypes( )
|
||||
&& checkLocalVariables( );
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
@ -458,6 +460,39 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
|||
return errors.empty( );
|
||||
}
|
||||
|
||||
bool T_ParserImpl_::checkLocalVariables( ) noexcept
|
||||
{
|
||||
uint32_t cfi;
|
||||
for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) {
|
||||
auto& function( output->root.function( cfi ) );
|
||||
T_StringBuilder esb;
|
||||
visitor.visit( function ,
|
||||
[&]( A_Node& n , const bool exit ) -> bool {
|
||||
if ( exit || n.type( ) != A_Node::OP_LOCALS ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto& locals( dynamic_cast< T_LocalsInstrNode& >( n ) );
|
||||
for ( auto i = 0u ; i < locals.variables( ) ; i ++ ) {
|
||||
auto prev{ function.addLocalVariable(
|
||||
locals.varName( i ) ,
|
||||
locals.varLocation( i ) ) };
|
||||
if ( !prev ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
esb << "duplicate local '" << locals.varName( i )
|
||||
<< "'; previous declaration at "
|
||||
<< *prev;
|
||||
errors.addNew( std::move( esb ) , locals.varLocation( i ) );
|
||||
}
|
||||
|
||||
return false;
|
||||
} );
|
||||
}
|
||||
return errors.empty( );
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------------*/
|
||||
|
||||
bool T_ParserImpl_::parseTopLevel(
|
||||
|
@ -830,15 +865,22 @@ M_INSTR_( Local )
|
|||
auto& instr{ instructions.add< T_LocalsInstrNode >( ) };
|
||||
instr.location( ) = input[ 0 ].location( );
|
||||
|
||||
T_StringBuilder sb;
|
||||
for ( auto i = 1u ; i < ni ; i ++ ) {
|
||||
auto const& token( input[ i ] );
|
||||
if ( token.type( ) != E_SRDTokenType::WORD ) {
|
||||
errors.addNew( "variable identifier expected" ,
|
||||
token.location( ) );
|
||||
} else if ( !instr.addVariable( token ) ) {
|
||||
errors.addNew( "duplicate variable identifier" ,
|
||||
token.location( ) );
|
||||
continue;
|
||||
}
|
||||
const auto prev{ instr.addVariable( token ) };
|
||||
if ( !prev ) {
|
||||
continue;
|
||||
}
|
||||
sb << "duplicate local '" << token.stringValue( )
|
||||
<< "'; previous declaration at "
|
||||
<< *prev;
|
||||
errors.addNew( std::move( sb ) , token.location( ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue