demotool/opast.hh

1360 lines
34 KiB
C++

#pragma once
#include "odbg.hh"
#include <ebcl/SRDData.hh>
#include <ebcl/Sets.hh>
namespace opast {
using namespace ebcl;
/*= BASE CLASS FOR AST NODES ===================================================*/
class T_RootNode;
class A_Node
{
public:
enum E_Type {
ROOT , // Root node
ILIST , // Instruction list
//
DECL_INIT , // Initialisation block
DECL_FRAME , // Frame block
DECL_FN , // Function
//
OP_CALL , // Function call
OP_CLEAR , // Clear buffer
OP_COND , // Conditional instruction
OP_FRAMEBUFFER ,// Define framebuffer
OP_FULLSCREEN , // Draw a fullscreen quad
OP_INPUT , // Input declaration
OP_LOCALS , // Declare local variables
OP_MAINOUT , // Select the output buffer
OP_ODBG , // Output debugging
OP_PIPELINE , // Shader pipeline declaration
OP_PROFILE , // Profiling block
OP_PROGRAM , // Shader program declaration
OP_SAMPLER , // Define sampler
OP_SET , // Set instruction
OP_TEXTURE , // Define texture
OP_UNIFORMS , // Set uniforms
OP_VIEWPORT , // Set viewport
// "Use-<obj type>" instructions
OP_USE_FRAMEBUFFER ,
OP_USE_PIPELINE ,
OP_USE_PROGRAM ,
OP_USE_TEXTURE ,
// Unary operators
EXPR_NEG , EXPR_INV , EXPR_NOT ,
EXPR_SIN , EXPR_COS , EXPR_TAN ,
EXPR_SQRT , EXPR_EXP , EXPR_LN ,
// Binary operators
EXPR_ADD , EXPR_SUB ,
EXPR_MUL , EXPR_DIV ,
EXPR_POW ,
// Binary operators - comparisons
EXPR_CMP_EQ , EXPR_CMP_NE ,
EXPR_CMP_GT , EXPR_CMP_GE ,
EXPR_CMP_LT , EXPR_CMP_LE ,
//
EXPR_ID , // Variable access
EXPR_INPUT , // Input value access
EXPR_CONST , // Numeric constant
// Technical nodes
TN_CONDITION , // Expression for a conditional instruction
TN_CASE , // Valued case for a conditional instruction
TN_DEFAULT , // Default case for a conditional instruction
TN_FBATT , // Framebuffer attachment
TN_ARG , // Call argument
};
private:
const E_Type type_;
A_Node* const parent_;
T_SRDLocation location_;
protected:
explicit A_Node( const E_Type type ,
A_Node* const parent ) noexcept;
public:
virtual ~A_Node( ) = 0;
E_Type type( ) const noexcept
{ return type_; }
T_SRDLocation& location( ) noexcept
{ return location_; }
T_SRDLocation const& location( ) const noexcept
{ return location_; }
A_Node& parent( ) const noexcept
{ assert( parent_ ); return *parent_; }
T_RootNode& root( ) const noexcept;
};
// Browser function to be used with T_Visitor
extern A_Node* ASTVisitorBrowser(
A_Node& node ,
const uint32_t child ) noexcept;
// Data types
enum class E_DataType {
UNKNOWN ,
BUILTIN ,
VARIABLE ,
FRAMEBUFFER ,
INPUT ,
PIPELINE ,
PROGRAM ,
SAMPLER ,
TEXTURE ,
};
M_LSHIFT_OP( T_StringBuilder , E_DataType );
/*= BASE STRUCTURES FOR INSTRUCTIONS =========================================*/
// Some instructions are restricted to either the initialisation code or the
// frame code.
enum class E_InstrRestriction
{
INIT , FRAME
};
using T_InstrRestriction = T_Flags< E_InstrRestriction >;
// Base class for instruction nodes
class A_InstructionNode : public A_Node
{
private:
const T_InstrRestriction restriction_;
protected:
A_InstructionNode( const E_Type type ,
A_Node& parent ,
T_InstrRestriction restriction = {} ) noexcept
: A_Node( type , &parent ) ,
restriction_( restriction )
{
assert( !restriction_.isSet({
E_InstrRestriction::INIT ,
E_InstrRestriction::FRAME }) );
}
public:
T_InstrRestriction restriction( ) const noexcept
{ return restriction_; }
};
// Nodes that store lists of instructions
class T_InstrListNode : public A_Node
{
private:
T_Array< T_OwnPtr< A_InstructionNode > > instructions_;
public:
T_InstrListNode( A_Node& parent ) noexcept
: A_Node( ILIST , &parent ) { }
template<
typename IType ,
typename... ArgTypes
> IType& add( ArgTypes&&... args );
uint32_t size( ) const noexcept
{ return instructions_.size( ); }
A_InstructionNode& node( const uint32_t index ) const noexcept
{ return *instructions_[ index ]; }
};
template<
typename IType ,
typename... ArgTypes
> inline IType& T_InstrListNode::add(
ArgTypes&&... args )
{
instructions_.add( NewOwned< IType >( *this ,
std::forward< ArgTypes >( args ) ... ) );
return (IType&) *instructions_.last( );
}
/*------------------------------------------------------------------------------*/
// Base class for expressions
class A_ExpressionNode : public A_Node
{
protected:
A_ExpressionNode( E_Type type ,
A_Node& parent ) noexcept
: A_Node( type , &parent )
{ }
};
using P_ExpressionNode = T_OwnPtr< A_ExpressionNode >;
// Technical node used for the arguments of various instructions
class T_ArgumentNode : public A_Node
{
private:
P_ExpressionNode expr_;
public:
T_ArgumentNode( A_Node& parent ,
P_ExpressionNode expr ) noexcept
: A_Node( TN_ARG , &parent ) ,
expr_( std::move( expr ) )
{
if ( expr_ ) {
location( ) = expr_->location( );
}
}
A_ExpressionNode& expression( ) const noexcept
{ return *expr_; }
bool isIdentifier( ) const noexcept
{ return expr_->type( ) == EXPR_ID; }
};
using P_ArgumentNode = T_OwnPtr< T_ArgumentNode >;
/*= FUNCTIONS AND ROOT NODES =================================================*/
// Function-like nodes
class A_FuncNode : public A_Node
{
private:
T_String name_;
T_InstrListNode instructions_;
protected:
struct T_Local_
{
T_String name;
T_SRDLocation location;
bool argument;
E_DataType type{ E_DataType::UNKNOWN };
T_Local_( T_String const& name ,
T_SRDLocation const& location ,
const bool argument ) noexcept
: name{ name } , location{ location } ,
argument{ argument }
{ }
};
T_ObjectTable< T_String , T_Local_ > locals_{
[]( T_Local_ const& l ) -> T_String {
return l.name;
}
};
protected:
// For init or frame entry points.
// isInit = true => init entry point
// isInit = false => frame entry point
explicit A_FuncNode( bool isInit ,
T_RootNode* const parent ) noexcept;
// For normal functions
explicit A_FuncNode( T_String const& name ,
T_RootNode* const parent ) noexcept;
public:
T_String const& name( ) const noexcept
{ return name_; }
T_InstrListNode& instructions( ) noexcept
{ return instructions_; }
T_InstrListNode const& instructions( ) const noexcept
{ return instructions_; }
// ---------------------------------------------------------------------
T_Optional< T_SRDLocation > addLocalVariable(
T_String const& name ,
T_SRDLocation const& location ) noexcept;
uint32_t locals( ) const noexcept
{ return locals_.size( ); }
bool hasLocal( T_String const& id ) const noexcept
{ return locals_.contains( id ); }
bool isArgument( T_String const& id ) const noexcept
{
auto const* const ptr( locals_.get( id ) );
return ptr && ptr->argument;
}
uint32_t getLocalIndex(
T_String const& name ) const noexcept
{ return locals_.indexOf( name ); }
T_String const& getLocalName(
const uint32_t index ) const noexcept
{ return locals_[ index ].name; }
E_DataType getLocalType(
T_String const& name ) const noexcept
{ return locals_.get( name )->type; }
E_DataType getLocalType(
const uint32_t index ) const noexcept
{ return locals_[ index ].type; }
void setLocalType(
const uint32_t index ,
const E_DataType type ) noexcept
{ locals_[ index ].type = type; }
};
using P_InstrListNode = T_OwnPtr< T_InstrListNode >;
/*----------------------------------------------------------------------------*/
// Root node, keeps track of the whole tree and related data (function table,
// assets...)
class T_RootNode : public A_Node
{
private:
T_ObjectTable< T_String , T_OwnPtr< A_FuncNode > > functions_;
public:
T_RootNode( ) noexcept;
// ---------------------------------------------------------------------
// Return type for addFunction. We'll always return a reference to a
// function node (which may or may not be the same as the initial one,
// if there were duplicates), and we'll return the location of the
// initial function in the case of a duplicate.
struct T_AddFunctionResult
{
A_FuncNode& function;
T_Optional< T_SRDLocation > dupLocation;
T_AddFunctionResult( A_FuncNode& function ) noexcept
: function{ function } , dupLocation{}
{}
T_AddFunctionResult( A_FuncNode& function ,
T_SRDLocation const& dupLocation ) noexcept
: function{ function } , dupLocation{ dupLocation }
{}
};
// Attempts to add a function. If the function is already present in
// the table, the result will be set up with the previous declaration's
// location, and the specified function will not be modified (a duplicate
// entry will be added to the table instead).
T_AddFunctionResult addFunction(
T_OwnPtr< A_FuncNode >& function ) noexcept;
// ---------------------------------------------------------------------
bool hasFunction( T_String const& name ) noexcept
{ return functions_.contains( name ); }
bool hasInit( ) noexcept
{ return hasFunction( "*init*" ); }
bool hasFrame( ) noexcept
{ return hasFunction( "*frame*" ); }
uint32_t nFunctions( ) const noexcept
{ return functions_.size( ); }
int32_t functionIndex( T_String const& name ) const noexcept
{ return functions_.indexOf( name ); }
A_FuncNode& function( const uint32_t index ) const noexcept
{ return *functions_.values( )[ index ]; }
};
/*----------------------------------------------------------------------------*/
// Init & frame functions
class T_SpecialFuncNode : public A_FuncNode
{
public:
T_SpecialFuncNode(
bool isInit ,
T_RootNode& parent ) noexcept
: A_FuncNode( isInit , &parent )
{ }
};
// Normal functions
class T_FuncNode : public A_FuncNode
{
public:
T_FuncNode( T_String const& name ,
T_RootNode& parent ) noexcept
: A_FuncNode( name , &parent )
{ }
// Add an argument. If the argument is a duplicate, return the location
// of the initial argument.
T_Optional< T_SRDLocation > addArgument(
T_SRDToken const& token ) noexcept;
uint32_t arguments( ) const noexcept;
};
/*= GENERAL / FLOW CONTROL INSTRUCTIONS ========================================*/
// Function call
class T_CallInstrNode : public A_InstructionNode
{
private:
T_String id_;
T_SRDLocation idLocation_;
T_AutoArray< P_ArgumentNode , 8 > arguments_;
public:
T_CallInstrNode( T_InstrListNode& parent ,
T_SRDToken const& idToken ) noexcept
: A_InstructionNode( OP_CALL , parent ) ,
id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) )
{ }
void addArgument( P_ExpressionNode expr ) noexcept
{
if ( expr ) {
arguments_.add( NewOwned< T_ArgumentNode >(
*this , std::move( expr ) ) );
}
}
T_String const& id( ) const noexcept
{ return id_; }
T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
uint32_t arguments( ) const noexcept
{ return arguments_.size( ); }
T_ArgumentNode& argument( const uint32_t index ) const noexcept
{ return *arguments_[ index ]; }
};
// Conditional instruction
class T_CondInstrNode : public A_InstructionNode
{
public:
class T_Expression : public A_Node
{
private:
P_ExpressionNode expression_;
public:
T_Expression( T_CondInstrNode& parent ,
P_ExpressionNode expr )
: A_Node( TN_CONDITION , &parent ) ,
expression_( std::move( expr ) )
{ }
A_ExpressionNode& expression( ) const noexcept
{ return *expression_; }
};
class T_ValuedCase : public A_Node
{
private:
int64_t value_;
P_InstrListNode instructions_;
public:
T_ValuedCase( T_CondInstrNode& parent ,
const int64_t value ,
P_InstrListNode il )
: A_Node( TN_CASE , &parent ) ,
value_( value ) ,
instructions_( std::move( il ) )
{ }
int64_t value( ) const noexcept
{ return value_; }
T_InstrListNode& instructions( ) const noexcept
{ return *instructions_; }
};
class T_DefaultCase : public A_Node
{
private:
P_InstrListNode instructions_;
public:
T_DefaultCase( T_CondInstrNode& parent ,
P_InstrListNode il )
: A_Node( TN_DEFAULT , &parent ) ,
instructions_( std::move( il ) )
{ }
T_InstrListNode& instructions( ) const noexcept
{ return *instructions_; }
};
private:
T_OwnPtr< T_Expression > expression_;
T_ObjectTable< int64_t , T_OwnPtr< T_ValuedCase > > cases_{
[]( T_OwnPtr< T_ValuedCase > const& c ) -> int64_t {
return c->value( );
}
};
T_OwnPtr< T_DefaultCase > defaultCase_;
public:
explicit T_CondInstrNode( T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_COND , parent )
{ }
void setExpression( P_ExpressionNode expression ) noexcept;
bool hasExpression( ) const noexcept
{ return bool( expression_ ); }
T_Expression& expression( ) const noexcept
{ return *expression_; }
void setCase( const int64_t value ,
P_InstrListNode instrList ) noexcept;
void rmCase( const int64_t value ) noexcept
{ cases_.remove( value ); }
uint32_t nCases( ) const noexcept
{ return cases_.size( ); }
T_Array< int64_t > cases( ) const noexcept
{ return cases_.keys( ); }
bool hasCase( const int64_t value ) const noexcept
{ return cases_.contains( value ); }
T_ValuedCase& getCase( const int64_t value ) const noexcept
{ return **cases_.get( value ); }
T_ValuedCase& getCaseByIndex(
const uint32_t index ) const noexcept
{ return *cases_[ index ]; }
void setDefaultCase( P_InstrListNode defaultCase ) noexcept;
bool hasDefaultCase( ) const noexcept
{ return bool( defaultCase_ ); }
T_DefaultCase& defaultCase( ) const noexcept
{ return *defaultCase_; }
};
// Local variable declarations
class T_LocalsInstrNode : public A_InstructionNode
{
private:
T_AutoArray< T_String , 8 > vars_;
T_AutoArray< T_SRDLocation , 8 > varLocs_;
public:
T_LocalsInstrNode( T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_LOCALS , parent )
{ }
T_Optional< T_SRDLocation > addVariable(
T_SRDToken const& token ) noexcept;
uint32_t variables( ) const noexcept
{ return vars_.size( ); }
T_String const& varName(
const uint32_t index ) const noexcept
{ return vars_[ index ]; }
T_SRDLocation const& varLocation(
const uint32_t index ) const noexcept
{ return varLocs_[ index ]; }
};
// Setting a global variable
class T_SetInstrNode : public A_InstructionNode
{
private:
T_String id_;
T_SRDLocation idLocation_;
P_ExpressionNode expression_;
public:
T_SetInstrNode( T_InstrListNode& parent ,
T_SRDToken const& idToken ) noexcept
: A_InstructionNode( OP_SET , parent ) ,
id_( idToken.stringValue( ) ) ,
idLocation_( idToken.location( ) )
{ }
T_String const& id( ) const noexcept
{ return id_; }
T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
void setExpression( P_ExpressionNode expression ) noexcept
{ expression_ = std::move( expression ); }
bool hasExpression( ) const noexcept
{ return bool( expression_ ); }
A_ExpressionNode& expression( ) const noexcept
{ return *expression_; }
};
/*= RESOURCE DEFINITION INSTRUCTIONS =========================================*/
// Base class
class A_ResourceDefInstrNode : public A_InstructionNode
{
private:
T_String id_;
T_SRDLocation idLocation_;
E_DataType dataType_;
protected:
A_ResourceDefInstrNode(
const E_Type type ,
T_InstrListNode& parent ,
T_SRDToken const& identifier ,
const E_DataType dataType ) noexcept
: A_InstructionNode( type , parent , E_InstrRestriction::FRAME ) ,
id_( identifier.stringValue( ) ) ,
idLocation_( identifier.location( ) ) ,
dataType_( dataType )
{ }
public:
T_String const& id( ) const noexcept
{ return id_; }
T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
E_DataType dataType( ) const noexcept
{ return dataType_; }
};
/*------------------------------------------------------------------------------*/
// Framebuffer definition instruction
class T_FramebufferInstrNode : public A_ResourceDefInstrNode
{
public:
class T_Attachment : public A_Node
{
private:
bool depth_;
T_String id_;
P_ArgumentNode lod_;
public:
T_Attachment( T_FramebufferInstrNode& parent ,
const bool depth ,
T_SRDToken const& texId ,
P_ExpressionNode lod = { } ) noexcept
: A_Node( TN_FBATT , &parent ) ,
depth_( depth ) ,
id_( texId.stringValue( ) )
{
location() = texId.location( );
if ( lod ) {
lod_ = NewOwned< T_ArgumentNode >( *this ,
std::move( lod ) );
}
}
bool isDepth( ) const noexcept
{ return depth_; }
T_String const& id( ) const noexcept
{ return id_; }
T_ArgumentNode* lod( ) const noexcept
{ return lod_.get( ); }
};
private:
T_AutoArray< T_OwnPtr< T_Attachment > , 16 > colorAttachments_;
T_OwnPtr< T_Attachment > depthAttachment_;
bool hasAttachment( T_String const& name ) const noexcept;
public:
T_FramebufferInstrNode( T_InstrListNode& parent ,
T_SRDToken const& identifier ) noexcept
: A_ResourceDefInstrNode( OP_FRAMEBUFFER , parent ,
identifier , E_DataType::FRAMEBUFFER )
{ }
// ---------------------------------------------------------------------
bool addColorAttachment( T_SRDToken const& id ,
P_ExpressionNode lod = {} ) noexcept;
uint32_t colorAttachments( ) const noexcept
{ return colorAttachments_.size( ); }
T_Attachment& colorAttachment(
const uint32_t index ) const noexcept
{ return *colorAttachments_[ index ]; }
// ---------------------------------------------------------------------
bool setDepthAttachment( T_SRDToken const& token ,
P_ExpressionNode lod = {} ) noexcept;
T_Attachment* depthAttachment( ) const noexcept
{ return depthAttachment_.get( ); }
};
// Input declaration
class T_InputInstrNode : public A_ResourceDefInstrNode
{
private:
float defValue_;
T_SRDLocation dvLocation_;
public:
T_InputInstrNode( T_InstrListNode& parent ,
T_SRDToken const& tName ) noexcept
: A_ResourceDefInstrNode( OP_INPUT , parent ,
tName , E_DataType::INPUT )
{}
T_InputInstrNode( T_InstrListNode& parent ,
T_SRDToken const& tName ,
T_SRDToken const& tDefault ) noexcept
: A_ResourceDefInstrNode( OP_INPUT , parent ,
tName , E_DataType::INPUT ) ,
defValue_( tDefault.floatValue( ) ) , dvLocation_( tDefault.location( ) )
{}
float defValue( ) const noexcept
{ return defValue_; }
T_SRDLocation const& defValueLocation( ) const noexcept
{ return dvLocation_; }
};
// Pipeline declaration instruction
class T_PipelineInstrNode : public A_ResourceDefInstrNode
{
private:
T_StaticArray< T_String , 6 > pids_;
T_StaticArray< T_SRDLocation , 6 > pidLocations_;
public:
T_PipelineInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& idToken ) noexcept
: A_ResourceDefInstrNode( OP_PIPELINE , parent ,
idToken , E_DataType::PIPELINE )
{ }
// Add a program identifier. The token is assumed to be a valid word,
// and the list of programs is assumed not to be full. If the identifer
// is already in the pipeline's list, the location of the first
// occurrence will be returned.
T_Optional< T_SRDLocation > addProgram(
T_SRDToken const& pidToken ) noexcept;
uint32_t size( ) const noexcept
{ return pids_.size( ); }
T_String const& program( const uint32_t index ) const noexcept
{ return pids_[ index ]; }
T_SRDLocation const& pLocation( const uint32_t index ) const noexcept
{ return pidLocations_[ index ]; }
};
// Program loader instruction
class T_ProgramInstrNode : public A_ResourceDefInstrNode
{
private:
T_String path_;
T_SRDLocation pathLocation_;
public:
T_ProgramInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& idToken ,
T_SRDToken const& pathToken ) noexcept
: A_ResourceDefInstrNode( OP_PROGRAM , parent ,
idToken , E_DataType::PROGRAM ) ,
path_( pathToken.stringValue( ) ) ,
pathLocation_( pathToken.location( ) )
{ }
T_String const& path( ) const noexcept
{ return path_; }
T_SRDLocation const& pathLocation( ) const noexcept
{ return pathLocation_; }
};
// Sampler definition
class T_SamplerInstrNode : public A_ResourceDefInstrNode
{
private:
struct T_Sampling_
{
T_SRDLocation location;
E_TexSampling mode;
};
struct T_Mipmaps_
{
T_SRDLocation location;
T_Optional< E_TexSampling > mode;
};
struct T_Wrapping_
{
T_SRDLocation location;
E_TexWrap mode;
};
struct T_LOD_
{
T_SRDLocation location;
P_ExpressionNode min;
P_ExpressionNode max;
};
T_Optional< T_Sampling_ > sampling_;
T_Optional< T_Mipmaps_ > mipmaps_;
T_Optional< T_Wrapping_ > wrapping_;
T_Optional< T_LOD_ > lod_;
public:
T_SamplerInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& id ) noexcept
: A_ResourceDefInstrNode( OP_SAMPLER , parent ,
id , E_DataType::SAMPLER )
{ }
// Attempt to set sampling mode, mipmap mode, wrapping mode or
// LOD minimal/maximal, returning the location of the previous
// definition if there was one.
T_Optional< T_SRDLocation > setSampling(
E_TexSampling mode ,
T_SRDLocation const& location ) noexcept;
T_Optional< T_SRDLocation > setMipmapSampling(
E_TexSampling mode ,
T_SRDLocation const& location ) noexcept;
T_Optional< T_SRDLocation > setNoMipmap(
T_SRDLocation const& location ) noexcept;
T_Optional< T_SRDLocation > setWrapping(
E_TexWrap mode ,
T_SRDLocation const& location ) noexcept;
T_Optional< T_SRDLocation > setLOD(
T_SRDLocation const& location ,
P_ExpressionNode min ,
P_ExpressionNode max ) noexcept;
// Get either the defined values or the defaults
E_TexSampling sampling( ) const noexcept
{ return sampling_ ? sampling_->mode : E_TexSampling::NEAREST; }
T_Optional< E_TexSampling > mipmap( ) const noexcept
{ return mipmaps_ ? mipmaps_->mode : T_Optional< E_TexSampling >{}; }
E_TexWrap wrapping( ) const noexcept
{ return wrapping_ ? wrapping_->mode : E_TexWrap::REPEAT; }
A_ExpressionNode* minLod( ) const noexcept
{ return lod_ ? lod_->min.get( ) : nullptr; }
A_ExpressionNode* maxLod( ) const noexcept
{ return lod_ ? lod_->max.get( ) : nullptr; }
};
// Texture definition
class T_TextureInstrNode : public A_ResourceDefInstrNode
{
private:
E_TexType type_;
P_ArgumentNode width_;
P_ArgumentNode height_;
P_ArgumentNode lods_;
public:
T_TextureInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& id ,
E_TexType type ) noexcept
: A_ResourceDefInstrNode( OP_TEXTURE , parent ,
id , E_DataType::TEXTURE ) ,
type_( type )
{ }
E_TexType texType( ) const noexcept
{ return type_; }
void setWidth( P_ExpressionNode width ) noexcept
{
if ( width ) {
width_ = NewOwned< T_ArgumentNode >(
*this , std::move( width ) );
}
}
void setHeight( P_ExpressionNode height ) noexcept
{
if ( height ) {
height_ = NewOwned< T_ArgumentNode >(
*this , std::move( height ) );
}
}
void setLODs( P_ExpressionNode lods ) noexcept
{
if ( lods ) {
lods_ = NewOwned< T_ArgumentNode >(
*this , std::move( lods ) );
}
}
bool hasWidth( ) const noexcept
{ return bool( width_ ); }
T_ArgumentNode& width( ) const noexcept
{ return *width_; }
bool hasHeight( ) const noexcept
{ return bool( height_ ); }
T_ArgumentNode& height( ) const noexcept
{ return *height_; }
T_ArgumentNode* lods( ) const noexcept
{ return lods_.get( ); }
};
/*= TOOL CONTROL INSTRUCTIONS ==================================================*/
// Output debugging
class T_OutputDebugInstrNode : public A_InstructionNode
{
private:
T_String idTexture_;
T_SRDLocation locTexture_;
E_ODbgMode mode_;
T_SRDLocation locMode_;
T_String description_;
T_SRDLocation locDescription_;
public:
T_OutputDebugInstrNode(
T_InstrListNode& parent ,
T_SRDToken const& texture ,
const E_ODbgMode mode ,
T_SRDLocation const& modeLocation ,
T_SRDToken const& description ) noexcept;
T_String const& texture( ) const noexcept
{ return idTexture_; }
T_SRDLocation const& textureLocation( ) const noexcept
{ return locTexture_; }
E_ODbgMode mode( ) const noexcept
{ return mode_; }
T_SRDLocation const& modeLocation( ) const noexcept
{ return locMode_; }
T_String const& description( ) const noexcept
{ return description_; }
T_SRDLocation const& descriptionLocation( ) const noexcept
{ return locDescription_; }
};
// Profiling instruction
class T_ProfileInstrNode : public A_InstructionNode
{
private:
T_String text_;
T_InstrListNode instructions_;
public:
T_ProfileInstrNode(
T_InstrListNode& parent ,
T_String const& text ) noexcept
: A_InstructionNode( OP_PROFILE , parent , E_InstrRestriction::INIT ) ,
text_( text ) ,
instructions_( *this )
{ }
T_String const& text( ) const
{ return text_; }
T_InstrListNode& instructions( ) noexcept
{ return instructions_; }
T_InstrListNode const& instructions( ) const noexcept
{ return instructions_; }
};
/*= RENDERING INSTRUCTIONS =====================================================*/
// Clear instruction
class T_ClearInstrNode : public A_InstructionNode
{
private:
T_StaticArray< P_ArgumentNode , 4 > components_;
public:
T_ClearInstrNode( T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_CLEAR , parent ,
E_InstrRestriction::INIT )
{ }
void addComponent( P_ExpressionNode expr ) noexcept
{
if ( expr ) {
components_.add( NewOwned< T_ArgumentNode >(
*this , std::move( expr ) ) );
}
}
uint32_t components( ) const noexcept
{ return components_.size( ); }
T_ArgumentNode& component( const uint32_t index ) const noexcept
{ return *components_[ index ]; }
};
// Fullscreen quad instruction
class T_FullscreenInstrNode : public A_InstructionNode
{
public:
T_FullscreenInstrNode( T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_FULLSCREEN , parent , E_InstrRestriction::INIT )
{ }
};
// Main output selection
class T_MainOutputInstrNode : public A_InstructionNode
{
public:
T_MainOutputInstrNode( T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_MAINOUT , parent , E_InstrRestriction::INIT )
{ }
};
// Uniform setting instruction
class T_UniformsInstrNode : public A_InstructionNode
{
private:
bool integers_;
T_String progId_;
T_SRDLocation progIdLocation_;
uint32_t uloc_;
T_SRDLocation ulocLocation_;
T_StaticArray< P_ExpressionNode , 4 > values_;
public:
T_UniformsInstrNode( T_InstrListNode& parent ,
const bool integers ,
T_SRDToken const& prog ,
T_SRDToken const& loc ) noexcept
: A_InstructionNode( OP_UNIFORMS , parent ) , integers_( integers ) ,
progId_( prog.stringValue( ) ) , progIdLocation_( prog.location( ) ) ,
uloc_( loc.longValue( ) ) , ulocLocation_( loc.location( ) )
{ }
bool integers( ) const noexcept
{ return integers_; }
T_String const& progId( ) const noexcept
{ return progId_; }
T_SRDLocation const& progIdLocation( ) const noexcept
{ return progIdLocation_; }
uint32_t uloc( ) const noexcept
{ return uloc_; }
T_SRDLocation const& ulocLocation( ) const noexcept
{ return ulocLocation_; }
void addValue( P_ExpressionNode value ) noexcept
{
if ( value ) {
values_.add( std::move( value ) );
}
}
uint32_t values( ) const noexcept
{ return values_.size( ); }
A_ExpressionNode& value( const uint32_t index ) const noexcept
{ return *values_[ index ]; }
};
// Use-* instructions (framebuffers, programs, pipelines)
// Also serves as the base for use-texture
class T_UseInstrNode : public A_InstructionNode
{
public:
enum E_Type {
FRAMEBUFFER , PIPELINE , PROGRAM , TEXTURE
};
private:
T_String id_;
T_SRDLocation idLocation_;
public:
T_UseInstrNode( T_InstrListNode& parent ,
const E_Type type ,
T_SRDToken const& identifier ) noexcept
: A_InstructionNode( ([type]() {
switch ( type ) {
case FRAMEBUFFER: return OP_USE_FRAMEBUFFER;
case PIPELINE: return OP_USE_PIPELINE;
case PROGRAM: return OP_USE_PROGRAM;
case TEXTURE: return OP_USE_TEXTURE;
}
std::abort( );
} )( ) , parent ) ,
id_( identifier.stringValue( ) ) ,
idLocation_( identifier.location( ) )
{ }
T_String const& id( ) const noexcept
{ return id_; }
T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
};
// Texture/sampler use instructions
class T_UseTextureInstrNode : public T_UseInstrNode
{
private:
uint32_t bank_;
T_SRDLocation bankLocation_;
T_String samplerId_;
T_SRDLocation samplerIdLocation_;
public:
T_UseTextureInstrNode( T_InstrListNode& parent ,
T_SRDToken const& bank ,
T_SRDToken const& identifier ,
T_SRDToken const& sampler ) noexcept
: T_UseInstrNode( parent , TEXTURE , identifier ) ,
bank_( bank.longValue( ) ) ,
bankLocation_( bank.location( ) ) ,
samplerId_( sampler.stringValue( ) ) ,
samplerIdLocation_( sampler.location( ) )
{ }
uint32_t bank( ) const noexcept
{ return bank_; }
T_SRDLocation const& bankLocation( ) const noexcept
{ return bankLocation_; }
T_String const& samplerId( ) const noexcept
{ return samplerId_; }
T_SRDLocation const& samplerIdLocation( ) const noexcept
{ return samplerIdLocation_; }
};
// Viewport instruction
class T_ViewportInstrNode : public A_InstructionNode
{
public:
enum E_Parameter {
PX , PY , PWIDTH , PHEIGHT
};
private:
P_ExpressionNode parameters_[ 4 ];
public:
T_ViewportInstrNode( T_InstrListNode& parent ) noexcept
: A_InstructionNode( OP_VIEWPORT , parent ,
E_InstrRestriction::INIT )
{ }
void setParameter( const E_Parameter p , P_ExpressionNode height ) noexcept
{ parameters_[ int( p ) ] = std::move( height ); }
bool hasParameter( const E_Parameter p ) const noexcept
{ return bool( parameters_[ int( p ) ] ); }
A_ExpressionNode& parameter( const E_Parameter p ) const noexcept
{ return *parameters_[ int( p ) ]; }
};
/*= EXPRESSIONS ==============================================================*/
// A constant value
class T_ConstantExprNode : public A_ExpressionNode
{
private:
bool wasFloat_;
double vFloat_;
int64_t vInt_;
public:
T_ConstantExprNode( A_Node& parent ,
T_SRDToken const& token ) noexcept
: A_ExpressionNode( EXPR_CONST , parent ) ,
wasFloat_( token.type( ) == E_SRDTokenType::FLOAT ) ,
vFloat_( token.floatValue( ) ) ,
vInt_( token.longValue( ) )
{ location( ) = token.location( ); }
T_ConstantExprNode( A_Node& parent ,
int64_t value ) noexcept
: A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( false ) ,
vFloat_( value ) , vInt_( value )
{ }
T_ConstantExprNode( A_Node& parent ,
double value ) noexcept
: A_ExpressionNode( EXPR_CONST , parent ) , wasFloat_( true ) ,
vFloat_( value ) , vInt_( (int64_t) value )
{ }
bool wasFloat( ) const noexcept
{ return wasFloat_; }
double floatValue( ) const noexcept
{ return vFloat_; }
int64_t intValue( ) const noexcept
{ return vInt_; }
};
// An identifier used in an expression
class T_IdentifierExprNode : public A_ExpressionNode
{
private:
T_String id_;
public:
T_IdentifierExprNode( A_Node& parent ,
T_SRDToken const& token ) noexcept
: T_IdentifierExprNode( parent , token.stringValue( ) )
{ location( ) = token.location( ); }
T_IdentifierExprNode( A_Node& parent ,
T_String const& id ) noexcept
: A_ExpressionNode( EXPR_ID , parent ) , id_( id )
{ }
T_String const& id( ) const noexcept
{ return id_; }
};
// Access to an input value
class T_InputExprNode : public A_ExpressionNode
{
private:
T_String id_;
T_SRDLocation idLocation_;
public:
T_InputExprNode( A_Node& parent ,
T_SRDToken const& token ) noexcept
: A_ExpressionNode( EXPR_INPUT , parent ) ,
id_( token.stringValue( ) ) ,
idLocation_( token.location( ) )
{ }
T_String const& id( ) const noexcept
{ return id_; }
T_SRDLocation const& idLocation( ) const noexcept
{ return idLocation_; }
};
// A unary operator
class T_UnaryOperatorNode : public A_ExpressionNode
{
public:
enum E_Operator {
NEG , INV , NOT ,
SIN , COS , TAN ,
SQRT , EXP , LN
};
private:
E_Operator op_;
P_ExpressionNode argument_;
public:
T_UnaryOperatorNode(
A_Node& parent ,
const E_Operator op ) noexcept;
E_Operator op( ) const noexcept
{ return op_; }
void setArgument( P_ExpressionNode argument ) noexcept
{ argument_ = std::move( argument ); }
bool hasArgument( ) const noexcept
{ return bool( argument_ ); }
A_ExpressionNode const& argument( ) const noexcept
{ return *argument_; }
A_ExpressionNode& argument( ) noexcept
{ return *argument_; }
};
// A binary operator
class T_BinaryOperatorNode : public A_ExpressionNode
{
public:
enum E_Operator {
ADD , SUB ,
MUL , DIV ,
POW ,
CMP_EQ , CMP_NE ,
CMP_GT , CMP_GE ,
CMP_LT , CMP_LE ,
};
private:
E_Operator op_;
P_ExpressionNode left_;
P_ExpressionNode right_;
public:
T_BinaryOperatorNode(
A_Node& parent ,
const E_Operator op ) noexcept;
E_Operator op( ) const noexcept
{ return op_; }
void setLeft( P_ExpressionNode left ) noexcept
{ left_ = std::move( left ); }
void setRight( P_ExpressionNode right ) noexcept
{ right_ = std::move( right ); }
bool hasLeft( ) const noexcept
{ return bool( left_ ); }
bool hasRight( ) const noexcept
{ return bool( right_ ); }
A_ExpressionNode const& left( ) const noexcept
{ return *left_; }
A_ExpressionNode& left( ) noexcept
{ return *left_; }
A_ExpressionNode const& right( ) const noexcept
{ return *right_; }
A_ExpressionNode& right( ) noexcept
{ return *right_; }
};
/*= PARSER ===================================================================*/
// Parser output. Consists in a root node as well as other details (table of
// constants, data types, etc...)
struct T_ParserOutput
{
T_RootNode root;
T_KeyValueTable< T_String , E_DataType > types;
};
// The actual parser
class T_Parser : public A_PrivateImplementation
{
private:
T_Array< T_SRDError > errors_;
T_OwnPtr< T_ParserOutput > output_;
public:
T_Parser( ) noexcept;
bool parse( T_SRDList const& input ) noexcept;
T_Array< T_SRDError > const& errors( ) const noexcept
{ return errors_; }
T_OwnPtr< T_ParserOutput > result( ) noexcept
{ return std::move( output_ ); }
};
} // namespace opast