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
# 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)

View file

@ -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(