From 8806cd81d270f0534b6e4ddf8567001bf2a5d579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 11 Nov 2017 16:53:21 +0100 Subject: [PATCH] Parser - Finished type checks ... I think. Unless I forgot something, which is likely. --- demo.srd | 10 +-- opparser.cc | 204 +++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 153 insertions(+), 61 deletions(-) diff --git a/demo.srd b/demo.srd index c9b1d8e..cf76984 100644 --- a/demo.srd +++ b/demo.srd @@ -1,6 +1,6 @@ (init # Compute viewport size - (if (cmp-gt width height) + (if (cmp-gt $width $height) ( (set vp-height $height) (set vp-width (mul $height (div 16 9))) @@ -112,7 +112,7 @@ (fn dof-init () # Sampler used for the inputs - (sampler dof-sampler + (sampler smp-dof (mipmaps no) (wrapping clamp-edge) (sampling linear) @@ -176,18 +176,18 @@ (fn dof-render (in-image in-depth) (profiling "Depth of Field" - (use-texture 1 in-depth dof-sampler) + (use-texture 1 in-depth smp-dof) # First pass (call dof-set-uniforms prg-dof-pass1) - (use-texture 0 in-image dof-sampler) + (use-texture 0 in-image smp-dof) (use-pipeline pl-dof-pass1) (use-framebuffer rt-dof-pass1) (fullscreen) # Second pass (call dof-set-uniforms prg-dof-pass2) - (use-texture 0 tx-dof-pass1 dof-sampler) + (use-texture 0 tx-dof-pass1 smp-dof) (use-pipeline pl-dof-pass2) (use-framebuffer rt-dof-pass2) (viewport 0 0 $vp-width $vp-height) diff --git a/opparser.cc b/opparser.cc index dc2a247..dd7a8b3 100644 --- a/opparser.cc +++ b/opparser.cc @@ -178,7 +178,17 @@ struct T_ParserImpl_ bool collectGlobalTypes( ) noexcept; bool checkLocalVariables( ) noexcept; bool checkArgumentTypes( ) noexcept; - bool checkIdentifierExpressions( ) noexcept; + + bool checkIdentifiers( ) noexcept; + void checkIdentifier( + T_String const& id , + T_SRDLocation const& location , + const uint32_t funcIndex , + const E_DataType expected ) noexcept; + void ciInput( uint32_t funcIndex , + A_Node& input ) noexcept; + void ciIdentifier( uint32_t funcIndex , + A_Node& input ) noexcept; E_DataType getTypeOf( T_String const& name , A_FuncNode const* context ) const noexcept; @@ -296,7 +306,7 @@ void T_ParserImpl_::main( && checkLocalVariables( ) && collectGlobalTypes( ) && checkArgumentTypes( ) - && checkIdentifierExpressions( ); + && checkIdentifiers( ); } /*----------------------------------------------------------------------------*/ @@ -679,7 +689,9 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept return errors.empty( ); } -bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept +/*------------------------------------------------------------------------------*/ + +bool T_ParserImpl_::checkIdentifiers( ) noexcept { uint32_t cfi; T_StringBuilder esb; @@ -689,69 +701,149 @@ bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept if ( exit ) { return true; } + switch ( n.type( ) ) { - // 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( ) ); - } else if ( callInfo[ cfi ] & E_InstrRestriction::INIT ) { - errors.addNew( "input used in initialisation" , - e.location( ) ); - } + case A_Node::EXPR_INPUT: + ciInput( cfi , n ); return false; - } - if ( n.type( ) != A_Node::EXPR_ID ) { + case A_Node::EXPR_ID: + ciIdentifier( cfi , n ); + return false; + + case A_Node::OP_USE_FRAMEBUFFER: + { + auto& instr( dynamic_cast< T_UseInstrNode& >( n ) ); + checkIdentifier( instr.id( ) , instr.idLocation( ) , cfi , + E_DataType::FRAMEBUFFER ); + return false; + } + + case A_Node::OP_USE_PROGRAM: + { + auto& instr( dynamic_cast< T_UseInstrNode& >( n ) ); + checkIdentifier( instr.id( ) , instr.idLocation( ) , cfi , + E_DataType::PROGRAM ); + return false; + } + + case A_Node::OP_USE_PIPELINE: + { + auto& instr( dynamic_cast< T_UseInstrNode& >( n ) ); + checkIdentifier( instr.id( ) , instr.idLocation( ) , cfi , + E_DataType::PIPELINE ); + return false; + } + + case A_Node::OP_USE_TEXTURE: + { + auto& instr( dynamic_cast< T_UseTextureInstrNode& >( n ) ); + checkIdentifier( instr.id( ) , instr.idLocation( ) , cfi , + E_DataType::TEXTURE ); + checkIdentifier( instr.samplerId( ) , instr.samplerIdLocation( ) , + cfi , E_DataType::SAMPLER ); + return true; + } + + case A_Node::OP_ODBG: + { + auto& t( dynamic_cast< T_OutputDebugInstrNode& >( n ) ); + checkIdentifier( t.texture( ) , t.textureLocation( ) , cfi , + E_DataType::TEXTURE ); + return false; + } + + case A_Node::OP_UNIFORMS: + { + auto& t( dynamic_cast< T_UniformsInstrNode& >( n ) ); + checkIdentifier( t.progId( ) , t.progIdLocation( ) , cfi , + E_DataType::PROGRAM ); + return false; + } + + default: 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( ); } +void T_ParserImpl_::checkIdentifier( + T_String const& id , + T_SRDLocation const& location , + const uint32_t funcIndex , + const E_DataType expected ) noexcept +{ + const E_DataType dt{ getTypeOf( id , &output->root.function( funcIndex ) ) }; + + if ( dt == E_DataType::UNKNOWN ) { + errors.addNew( "unknown identifier" , location ); + } else if ( dt != expected ) { + T_StringBuilder esb; + esb << E_DataType::TEXTURE << " expected, " << dt << " found instead"; + errors.addNew( std::move( esb ) , location ); + } +} + +void T_ParserImpl_::ciInput( + const uint32_t funcIndex , + A_Node& input ) noexcept +{ + auto& e( dynamic_cast< T_InputExprNode& >( input ) ); + auto const* const t( output->types.get( e.id( ) ) ); + if ( !t ) { + errors.addNew( "no such input" , e.idLocation( ) ); + } else if ( *t != E_DataType::INPUT ) { + T_StringBuilder esb; + esb << "'" << e.id( ) << "' used as input but declared as a " + << *t; + errors.addNew( std::move( esb ) , e.idLocation( ) ); + } else if ( callInfo[ funcIndex ] & E_InstrRestriction::INIT ) { + errors.addNew( "input used in initialisation" , + e.location( ) ); + } +} + +void T_ParserImpl_::ciIdentifier( + const uint32_t funcIndex , + A_Node& input ) noexcept +{ + auto& e( dynamic_cast< T_IdentifierExprNode& >( input ) ); + E_DataType dt{ getTypeOf( e.id( ) , &output->root.function( funcIndex ) ) }; + + // Undefined identifiers + if ( dt == E_DataType::UNKNOWN ) { + errors.addNew( "unknown identifier" , e.location( ) ); + return; + } + + // Variables are fine + if ( dt == E_DataType::VARIABLE ) { + return; + } + + // Check builtins + if ( dt == E_DataType::BUILTIN ) { + if ( ( callInfo[ funcIndex ] & E_InstrRestriction::INIT ) + && e.id( ) == "time" ) { + errors.addNew( "'time' built-in used in initialisation" , + e.location( ) ); + } + return; + } + + // Allow other types to be used as an expression + // in the context of the call instruction. + if ( e.parent( ).type( ) != A_Node::OP_CALL ) { + T_StringBuilder esb; + esb << "'" << e.id( ) + << "' used as a variable but declared as a " + << dt; + errors.addNew( std::move( esb ) , e.location( ) ); + } +} + /*------------------------------------------------------------------------------*/ E_DataType T_ParserImpl_::getTypeOf(