Parser - Finished type checks
... I think. Unless I forgot something, which is likely.
This commit is contained in:
parent
773efeff54
commit
8806cd81d2
2 changed files with 153 additions and 61 deletions
10
demo.srd
10
demo.srd
|
@ -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)
|
||||||
|
|
204
opparser.cc
204
opparser.cc
|
@ -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,69 +701,149 @@ 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 ) );
|
|
||||||
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( ) );
|
|
||||||
}
|
|
||||||
return false;
|
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;
|
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( );
|
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(
|
E_DataType T_ParserImpl_::getTypeOf(
|
||||||
|
|
Loading…
Reference in a new issue