Parser - Initial ugly impl of argument type resolution
This commit is contained in:
parent
3e184f5796
commit
84cdfa38de
2 changed files with 173 additions and 1 deletions
20
opast.hh
20
opast.hh
|
@ -253,6 +253,26 @@ class A_FuncNode : public A_Node
|
||||||
auto const* const ptr( locals_.get( id ) );
|
auto const* const ptr( locals_.get( id ) );
|
||||||
return ptr && ptr->argument;
|
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 >;
|
using P_InstrListNode = T_OwnPtr< T_InstrListNode >;
|
||||||
|
|
||||||
|
|
154
opparser.cc
154
opparser.cc
|
@ -174,6 +174,7 @@ struct T_ParserImpl_
|
||||||
bool checkInstructionRestrictions( ) noexcept;
|
bool checkInstructionRestrictions( ) noexcept;
|
||||||
bool collectGlobalTypes( ) noexcept;
|
bool collectGlobalTypes( ) noexcept;
|
||||||
bool checkLocalVariables( ) noexcept;
|
bool checkLocalVariables( ) noexcept;
|
||||||
|
bool checkArgumentTypes( ) noexcept;
|
||||||
bool checkIdentifierExpressions( ) noexcept;
|
bool checkIdentifierExpressions( ) noexcept;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
@ -288,6 +289,7 @@ void T_ParserImpl_::main(
|
||||||
&& checkInstructionRestrictions( )
|
&& checkInstructionRestrictions( )
|
||||||
&& checkLocalVariables( )
|
&& checkLocalVariables( )
|
||||||
&& collectGlobalTypes( )
|
&& collectGlobalTypes( )
|
||||||
|
&& checkArgumentTypes( )
|
||||||
&& checkIdentifierExpressions( );
|
&& checkIdentifierExpressions( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,6 +488,12 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
}
|
}
|
||||||
assert( dt != E_DataType::UNKNOWN );
|
assert( dt != E_DataType::UNKNOWN );
|
||||||
|
|
||||||
|
#ifdef INVASIVE_TRACES
|
||||||
|
esb << "id " << id << " as " << dt << " at " << location << '\n' << '\0';
|
||||||
|
printf( "%s" , esb.data( ) );
|
||||||
|
esb.clear( );
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( function.hasLocal( id ) ) {
|
if ( function.hasLocal( id ) ) {
|
||||||
if ( function.isArgument( id ) ) {
|
if ( function.isArgument( id ) ) {
|
||||||
errors.addNew( "trying to override argument",
|
errors.addNew( "trying to override argument",
|
||||||
|
@ -527,6 +535,150 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
||||||
return errors.empty( );
|
return errors.empty( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool T_ParserImpl_::checkArgumentTypes( ) noexcept
|
||||||
|
{
|
||||||
|
// Find functions for which arguments types need to be resolved
|
||||||
|
const auto nFunctions( output->root.nFunctions( ) );
|
||||||
|
bool argsResolved[ nFunctions ];
|
||||||
|
uint32_t nSolved = 0;
|
||||||
|
for ( auto i = 0u ; i < nFunctions ; i ++ ) {
|
||||||
|
auto& fn( output->root.function( i ) );
|
||||||
|
if ( fn.type( ) == A_Node::DECL_FN ) {
|
||||||
|
auto& rfn( dynamic_cast< T_FuncNode& >( fn ) );
|
||||||
|
argsResolved[ i ] = rfn.arguments( ) == 0;
|
||||||
|
} else {
|
||||||
|
argsResolved[ i ] = true;
|
||||||
|
}
|
||||||
|
if ( argsResolved[ i ] ) {
|
||||||
|
nSolved ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No functions use arguments -> we're done.
|
||||||
|
if ( nSolved == nFunctions ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all calls with arguments
|
||||||
|
T_MultiArray< T_CallInstrNode* > callInstuctions;
|
||||||
|
for ( auto i = 0u ; i < nFunctions ; i ++ ) {
|
||||||
|
callInstuctions.next( );
|
||||||
|
visitor.visit( output->root.function( i ) , [&]( A_Node& node , const bool exit ) {
|
||||||
|
if ( exit || node.type( ) != A_Node::OP_CALL ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& call( dynamic_cast< T_CallInstrNode& >( node ) );
|
||||||
|
if ( call.arguments( ) != 0 ) {
|
||||||
|
callInstuctions.add( &call );
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef INVASIVE_TRACES
|
||||||
|
T_StringBuilder tracer;
|
||||||
|
#define TRACE( x ) do { tracer.clear( ) << x << '\0'; printf( "%s\n" , tracer.data( ) ); } while (0)
|
||||||
|
#else
|
||||||
|
#define TRACE( x )
|
||||||
|
#endif
|
||||||
|
|
||||||
|
T_StringBuilder esb;
|
||||||
|
bool changed = true;
|
||||||
|
while ( changed ) {
|
||||||
|
changed = false;
|
||||||
|
|
||||||
|
// Go through all functions for which argument types have been
|
||||||
|
// resolved and check all calls.
|
||||||
|
for ( auto i = 0u ; i < nFunctions ; i ++ ) {
|
||||||
|
auto& f( output->root.function( i ) );
|
||||||
|
TRACE( "about to check function " << f.name( ) );
|
||||||
|
if ( !argsResolved[ i ] ) {
|
||||||
|
TRACE( " -> arguments not resolved, skipped" );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE( " -> " << callInstuctions.sizeOf( i ) << " calls w/ arguments" );
|
||||||
|
for ( auto c = 0u ; c < callInstuctions.sizeOf( i ) ; c ++ ) {
|
||||||
|
auto const* call( callInstuctions.get( i , c ) );
|
||||||
|
if ( ! call ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const& called( call->id( ) );
|
||||||
|
const auto calledIdx( output->root.functionIndex( called ) );
|
||||||
|
auto& calledFn( dynamic_cast< T_FuncNode& >(
|
||||||
|
output->root.function( calledIdx ) ) );
|
||||||
|
TRACE( " -> checking call to " << called << " (idx " << calledIdx
|
||||||
|
<< ") at " << call->location( ) );
|
||||||
|
assert( call->arguments( ) == calledFn.arguments( ) );
|
||||||
|
if ( argsResolved[ calledIdx ] ) {
|
||||||
|
TRACE( " argument types already resolved, checking" );
|
||||||
|
for ( auto a = 0u ; a < call->arguments( ) ; a ++ ) {
|
||||||
|
auto& arg( call->argument( a ) );
|
||||||
|
E_DataType ndt{ E_DataType::UNKNOWN };
|
||||||
|
if ( arg.type( ) == A_Node::EXPR_ID ) {
|
||||||
|
T_String const& id( dynamic_cast< T_IdentifierExprNode& >( arg ).id( ) );
|
||||||
|
if ( f.hasLocal( id ) ) {
|
||||||
|
ndt = f.getLocalType( id );
|
||||||
|
} else {
|
||||||
|
auto const* const ptr( output->types.get( id ) );
|
||||||
|
if ( ptr ) {
|
||||||
|
ndt = *ptr;
|
||||||
|
} else {
|
||||||
|
errors.addNew( "unknown identifier" ,
|
||||||
|
arg.location( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ndt = E_DataType::VARIABLE;
|
||||||
|
}
|
||||||
|
TRACE( " [" << a << "] " << ndt );
|
||||||
|
if ( ndt != E_DataType::UNKNOWN && calledFn.getLocalType( a ) != ndt ) {
|
||||||
|
esb << "argument " << ( a + 1 ) << " of function '"
|
||||||
|
<< called << "' should be a "
|
||||||
|
<< calledFn.getLocalType( a )
|
||||||
|
<< " but a " << ndt << " is being passed";
|
||||||
|
errors.addNew( std::move( esb ) , arg.location( ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = true;
|
||||||
|
} else {
|
||||||
|
TRACE( " resolving arguments" );
|
||||||
|
bool ok = true;
|
||||||
|
for ( auto a = 0u ; a < call->arguments( ) ; a ++ ) {
|
||||||
|
auto& arg( call->argument( a ) );
|
||||||
|
E_DataType ndt{ E_DataType::UNKNOWN };
|
||||||
|
if ( arg.type( ) == A_Node::EXPR_ID ) {
|
||||||
|
T_String const& id( dynamic_cast< T_IdentifierExprNode& >( arg ).id( ) );
|
||||||
|
if ( f.hasLocal( id ) ) {
|
||||||
|
ndt = f.getLocalType( id );
|
||||||
|
} else {
|
||||||
|
auto const* const ptr( output->types.get( id ) );
|
||||||
|
if ( ptr ) {
|
||||||
|
ndt = *ptr;
|
||||||
|
} else {
|
||||||
|
errors.addNew( "unknown identifier" ,
|
||||||
|
arg.location( ) );
|
||||||
|
ok = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ndt = E_DataType::VARIABLE;
|
||||||
|
}
|
||||||
|
TRACE( " [" << a << "] " << ndt );
|
||||||
|
calledFn.setLocalType( a , ndt );
|
||||||
|
}
|
||||||
|
argsResolved[ calledIdx ] = ok;
|
||||||
|
changed = changed || ok;
|
||||||
|
}
|
||||||
|
callInstuctions.get( i , c ) = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors.empty( );
|
||||||
|
}
|
||||||
|
|
||||||
bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept
|
bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept
|
||||||
{
|
{
|
||||||
uint32_t cfi;
|
uint32_t cfi;
|
||||||
|
@ -1059,7 +1211,7 @@ M_INSTR_( Pipeline )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& pipeline{ instructions.add< T_PipelineInstrNode >( input[ 0 ] ) };
|
auto& pipeline{ instructions.add< T_PipelineInstrNode >( input[ 1 ] ) };
|
||||||
pipeline.location( ) = input[ 0 ].location( );
|
pipeline.location( ) = input[ 0 ].location( );
|
||||||
|
|
||||||
const auto nMax{ std::min( input.size( ) , 8u ) };
|
const auto nMax{ std::min( input.size( ) , 8u ) };
|
||||||
|
|
Loading…
Reference in a new issue