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
|
||||
# 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)
|
||||
|
|
204
opparser.cc
204
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(
|
||||
|
|
Loading…
Reference in a new issue