Parser - Finished type checks

... I think. Unless I forgot something, which is likely.
This commit is contained in:
Emmanuel BENOîT 2017-11-11 16:53:21 +01:00
parent 773efeff54
commit 8806cd81d2
2 changed files with 153 additions and 61 deletions

View file

@ -1,6 +1,6 @@
(init (init
# Compute viewport size # Compute viewport size
(if (cmp-gt width height) (if (cmp-gt $width $height)
( (
(set vp-height $height) (set vp-height $height)
(set vp-width (mul $height (div 16 9))) (set vp-width (mul $height (div 16 9)))
@ -112,7 +112,7 @@
(fn dof-init () (fn dof-init ()
# Sampler used for the inputs # Sampler used for the inputs
(sampler dof-sampler (sampler smp-dof
(mipmaps no) (mipmaps no)
(wrapping clamp-edge) (wrapping clamp-edge)
(sampling linear) (sampling linear)
@ -176,18 +176,18 @@
(fn dof-render (in-image in-depth) (fn dof-render (in-image in-depth)
(profiling "Depth of Field" (profiling "Depth of Field"
(use-texture 1 in-depth dof-sampler) (use-texture 1 in-depth smp-dof)
# First pass # First pass
(call dof-set-uniforms prg-dof-pass1) (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-pipeline pl-dof-pass1)
(use-framebuffer rt-dof-pass1) (use-framebuffer rt-dof-pass1)
(fullscreen) (fullscreen)
# Second pass # Second pass
(call dof-set-uniforms prg-dof-pass2) (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-pipeline pl-dof-pass2)
(use-framebuffer rt-dof-pass2) (use-framebuffer rt-dof-pass2)
(viewport 0 0 $vp-width $vp-height) (viewport 0 0 $vp-width $vp-height)

View file

@ -178,7 +178,17 @@ struct T_ParserImpl_
bool collectGlobalTypes( ) noexcept; bool collectGlobalTypes( ) noexcept;
bool checkLocalVariables( ) noexcept; bool checkLocalVariables( ) noexcept;
bool checkArgumentTypes( ) 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 , E_DataType getTypeOf( T_String const& name ,
A_FuncNode const* context ) const noexcept; A_FuncNode const* context ) const noexcept;
@ -296,7 +306,7 @@ void T_ParserImpl_::main(
&& checkLocalVariables( ) && checkLocalVariables( )
&& collectGlobalTypes( ) && collectGlobalTypes( )
&& checkArgumentTypes( ) && checkArgumentTypes( )
&& checkIdentifierExpressions( ); && checkIdentifiers( );
} }
/*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/
@ -679,7 +689,9 @@ bool T_ParserImpl_::checkArgumentTypes( ) noexcept
return errors.empty( ); return errors.empty( );
} }
bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept /*------------------------------------------------------------------------------*/
bool T_ParserImpl_::checkIdentifiers( ) noexcept
{ {
uint32_t cfi; uint32_t cfi;
T_StringBuilder esb; T_StringBuilder esb;
@ -689,67 +701,147 @@ bool T_ParserImpl_::checkIdentifierExpressions( ) noexcept
if ( exit ) { if ( exit ) {
return true; return true;
} }
switch ( n.type( ) ) {
// Check get-input expressions case A_Node::EXPR_INPUT:
if ( n.type( ) == A_Node::EXPR_INPUT ) { ciInput( cfi , n );
auto& e( dynamic_cast< T_InputExprNode& >( n ) ); return false;
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;
}
} );
}
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( ) ) ); auto const* const t( output->types.get( e.id( ) ) );
if ( !t ) { if ( !t ) {
errors.addNew( "no such input" , e.idLocation( ) ); errors.addNew( "no such input" , e.idLocation( ) );
} else if ( *t != E_DataType::INPUT ) { } else if ( *t != E_DataType::INPUT ) {
T_StringBuilder esb;
esb << "'" << e.id( ) << "' used as input but declared as a " esb << "'" << e.id( ) << "' used as input but declared as a "
<< *t; << *t;
errors.addNew( std::move( esb ) , e.idLocation( ) ); errors.addNew( std::move( esb ) , e.idLocation( ) );
} else if ( callInfo[ cfi ] & E_InstrRestriction::INIT ) { } else if ( callInfo[ funcIndex ] & E_InstrRestriction::INIT ) {
errors.addNew( "input used in initialisation" , errors.addNew( "input used in initialisation" ,
e.location( ) ); e.location( ) );
} }
return false; }
}
if ( n.type( ) != A_Node::EXPR_ID ) { void T_ParserImpl_::ciIdentifier(
return true; 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 ) ) };
// Check use of identifiers in expressions // Undefined identifiers
auto& e( dynamic_cast< T_IdentifierExprNode& >( n ) ); if ( dt == E_DataType::UNKNOWN ) {
auto const* const gType{ output->types.get( e.id( ) ) }; errors.addNew( "unknown identifier" , e.location( ) );
if ( gType ) { return;
// FIXME handle aliases }
// Variables are fine // Variables are fine
if ( *gType == E_DataType::VARIABLE ) { if ( dt == E_DataType::VARIABLE ) {
return false; return;
} }
// Check builtins // Check builtins
if ( *gType == E_DataType::BUILTIN ) { if ( dt == E_DataType::BUILTIN ) {
if ( ( callInfo[ cfi ] & E_InstrRestriction::INIT ) if ( ( callInfo[ funcIndex ] & E_InstrRestriction::INIT )
&& e.id( ) == "time" ) { && e.id( ) == "time" ) {
errors.addNew( "'time' built-in used in initialisation" , errors.addNew( "'time' built-in used in initialisation" ,
e.location( ) ); e.location( ) );
} }
return false; return;
} }
// We'll allow other types to be used in an expression // Allow other types to be used as an expression
// in the context of the call instruction. // in the context of the call instruction.
if ( e.parent( ).type( ) == A_Node::OP_CALL ) { if ( e.parent( ).type( ) != A_Node::OP_CALL ) {
return false; T_StringBuilder esb;
} esb << "'" << e.id( )
<< "' used as a variable but declared as a "
esb << "'" << e.id( ) << "' used as a variable but declared as a " << dt;
<< *gType;
errors.addNew( std::move( esb ) , e.location( ) ); errors.addNew( std::move( esb ) , e.location( ) );
return false;
} }
// FIXME check locals
return false;
} );
}
return errors.empty( );
} }
/*------------------------------------------------------------------------------*/ /*------------------------------------------------------------------------------*/