From 949e4099ecd45ebf3ca95162647adf664de75d96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 11 Nov 2017 10:17:35 +0100 Subject: [PATCH] Parser - Type checking for inputs and global identifiers --- opparser.cc | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/opparser.cc b/opparser.cc index ca7339a..b91ce80 100644 --- a/opparser.cc +++ b/opparser.cc @@ -149,8 +149,10 @@ struct T_ParserImpl_ T_OwnPtr< T_ParserOutput >& output; T_Array< T_SRDError >& errors; - T_Visitor< A_Node > visitor{ opast::ASTVisitorBrowser }; T_MultiArray< uint32_t > calls; + T_Array< T_InstrRestriction > callInfo; + + T_Visitor< A_Node > visitor{ opast::ASTVisitorBrowser }; T_Visitor< uint32_t , uint32_t > callGraphVisitor{ [this]( uint32_t v , uint32_t child ) -> T_Optional< uint32_t > { const uint32_t nc( calls.sizeOf( v ) ); @@ -172,6 +174,7 @@ struct T_ParserImpl_ bool checkInstructionRestrictions( ) noexcept; bool collectGlobalTypes( ) noexcept; bool checkLocalVariables( ) noexcept; + bool checkIdentifierExpressions( ) noexcept; // --------------------------------------------------------------------- @@ -284,7 +287,8 @@ void T_ParserImpl_::main( && checkCalls( ) && checkInstructionRestrictions( ) && collectGlobalTypes( ) - && checkLocalVariables( ); + && checkLocalVariables( ) + && checkIdentifierExpressions( ); } /*----------------------------------------------------------------------------*/ @@ -350,7 +354,9 @@ bool T_ParserImpl_::checkCalls( ) noexcept bool T_ParserImpl_::checkInstructionRestrictions( ) noexcept { - T_InstrRestriction callInfo[ calls.size( ) ]; + callInfo.clear( ); + callInfo.resize( calls.size( ) ); + callGraphVisitor.visit( output->root.functionIndex( "*init*" ) , [&]( uint32_t id , const bool exit ) -> bool { if ( exit || callInfo[ id ] & E_InstrRestriction::INIT ) { @@ -463,9 +469,9 @@ bool T_ParserImpl_::collectGlobalTypes( ) noexcept bool T_ParserImpl_::checkLocalVariables( ) noexcept { uint32_t cfi; + T_StringBuilder esb; 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 ) { @@ -493,6 +499,77 @@ bool T_ParserImpl_::checkLocalVariables( ) noexcept return errors.empty( ); } +bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept +{ + uint32_t cfi; + T_StringBuilder esb; + for ( cfi = 0 ; cfi < output->root.nFunctions( ) ; cfi ++ ) { + auto& function( output->root.function( cfi ) ); + visitor.visit( function , + [&]( A_Node& n , const bool exit ) -> bool { + if ( exit ) { + return true; + } + + // Check get-input expressions + if ( n.type( ) == A_Node::EXPR_INPUT ) { + auto& e( dynamic_cast< T_InputExprNode& >( n ) ); + auto const* const t( output->types.get( e.id( ) ) ); + if ( !t ) { + errors.addNew( "no such input" , e.idLocation( ) ); + } else if ( *t != E_DataType::INPUT ) { + esb << "'" << e.id( ) << "' used as input but declared as a " + << *t; + errors.addNew( std::move( esb ) , e.idLocation( ) ); + } + return false; + } + + if ( n.type( ) != A_Node::EXPR_ID ) { + return true; + } + + // Check use of identifiers in expressions + auto& e( dynamic_cast< T_IdentifierExprNode& >( n ) ); + auto const* const gType{ output->types.get( e.id( ) ) }; + if ( gType ) { + // FIXME handle aliases + + // Variables are fine + if ( *gType == E_DataType::VARIABLE ) { + return false; + } + + // Check builtins + if ( *gType == E_DataType::BUILTIN ) { + if ( ( callInfo[ cfi ] & E_InstrRestriction::INIT ) + && e.id( ) == "time" ) { + errors.addNew( "'time' built-in used in initialisation" , + e.location( ) ); + } + return false; + } + + // We'll allow other types to be used in an expression + // in the context of the call instruction. + if ( e.parent( ).type( ) == A_Node::OP_CALL ) { + return false; + } + + esb << "'" << e.id( ) << "' used as a variable but declared as a " + << *gType; + errors.addNew( std::move( esb ) , e.location( ) ); + return false; + } + + // FIXME check locals + + return false; + } ); + } + return errors.empty( ); +} + /*------------------------------------------------------------------------------*/ bool T_ParserImpl_::parseTopLevel(