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 ) );
|
||||
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 >;
|
||||
|
||||
|
|
154
opparser.cc
154
opparser.cc
|
@ -174,6 +174,7 @@ struct T_ParserImpl_
|
|||
bool checkInstructionRestrictions( ) noexcept;
|
||||
bool collectGlobalTypes( ) noexcept;
|
||||
bool checkLocalVariables( ) noexcept;
|
||||
bool checkArgumentTypes( ) noexcept;
|
||||
bool checkIdentifierExpressions( ) noexcept;
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
@ -288,6 +289,7 @@ void T_ParserImpl_::main(
|
|||
&& checkInstructionRestrictions( )
|
||||
&& checkLocalVariables( )
|
||||
&& collectGlobalTypes( )
|
||||
&& checkArgumentTypes( )
|
||||
&& checkIdentifierExpressions( );
|
||||
}
|
||||
|
||||
|
@ -486,6 +488,12 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
|||
}
|
||||
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.isArgument( id ) ) {
|
||||
errors.addNew( "trying to override argument",
|
||||
|
@ -527,6 +535,150 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept
|
|||
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
|
||||
{
|
||||
uint32_t cfi;
|
||||
|
@ -1059,7 +1211,7 @@ M_INSTR_( Pipeline )
|
|||
return;
|
||||
}
|
||||
|
||||
auto& pipeline{ instructions.add< T_PipelineInstrNode >( input[ 0 ] ) };
|
||||
auto& pipeline{ instructions.add< T_PipelineInstrNode >( input[ 1 ] ) };
|
||||
pipeline.location( ) = input[ 0 ].location( );
|
||||
|
||||
const auto nMax{ std::min( input.size( ) , 8u ) };
|
||||
|
|
Loading…
Reference in a new issue