#ifndef RASTER_RENDERER_SYNTAX_H #define RASTER_RENDERER_SYNTAX_H #include "../core/basic.h" #include "Lexer.h" #include "Profile.h" #include "../../Slang.h" #include namespace Slang { class SyntaxVisitor; class FunctionSyntaxNode; class SyntaxNodeBase : public RefObject { public: CodePosition Position; }; // // Other modifiers may have more elaborate data, and so // are represented as heap-allocated objects, in a linked // list. // class Modifier : public SyntaxNodeBase { public: // Next modifier in linked list of modifiers on same piece of syntax RefPtr next; // The token that was used to name this modifier. Token nameToken; }; #define SIMPLE_MODIFIER(NAME) \ class NAME##Modifier : public Modifier {} SIMPLE_MODIFIER(Uniform); SIMPLE_MODIFIER(In); SIMPLE_MODIFIER(Out); SIMPLE_MODIFIER(Const); SIMPLE_MODIFIER(Instance); SIMPLE_MODIFIER(Builtin); SIMPLE_MODIFIER(Inline); SIMPLE_MODIFIER(Public); SIMPLE_MODIFIER(Require); SIMPLE_MODIFIER(Param); SIMPLE_MODIFIER(Extern); SIMPLE_MODIFIER(Input); SIMPLE_MODIFIER(Transparent); SIMPLE_MODIFIER(FromStdLib); SIMPLE_MODIFIER(Prefix); SIMPLE_MODIFIER(Postfix); #undef SIMPLE_MODIFIER enum class IntrinsicOp { Unknown = 0, #define INTRINSIC(NAME) NAME, #include "intrinsic-defs.h" }; IntrinsicOp findIntrinsicOp(char const* name); // Base class for modifiers that mark something as "intrinsic" // and thus lacking a direct implementation in the language. class IntrinsicModifierBase : public Modifier { }; // A modifier that marks something as one of a small set of // truly intrinsic operations that the compiler knows about // directly. class IntrinsicOpModifier : public IntrinsicModifierBase { public: // token that names the intrinsic op Token opToken; // The opcode for the intrinsic operation IntrinsicOp op = IntrinsicOp::Unknown; }; // A modifier that marks something as an intrinsic function, // for some subset of targets. class TargetIntrinsicModifier : public IntrinsicModifierBase { public: // Token that names the target that the operation // is an intrisic for. Token targetToken; // A custom definition for the operation Token definitionToken; }; class InOutModifier : public OutModifier {}; // This is a special sentinel modifier that gets added // to the list when we have multiple variable declarations // all sharing the same modifiers: // // static uniform int a : FOO, *b : register(x0); // // In this case both `a` and `b` share the syntax // for part of their modifier list, but then have // their own modifiers as well: // // a: SemanticModifier("FOO") --> SharedModifiers --> StaticModifier --> UniformModifier // / // b: RegisterModifier("x0") / // class SharedModifiers : public Modifier {}; // A GLSL `layout` modifier // // We use a distinct modifier for each key that // appears within the `layout(...)` construct, // and each key might have an optional value token. // // TODO: We probably want a notion of "modifier groups" // so that we can recover good source location info // for modifiers that were part of the same vs. // different constructs. class GLSLLayoutModifier : public Modifier { public: // THe token used to introduce the modifier is stored // as the `nameToken` field. // TODO: may want to accept a full expression here Token valToken; }; // We divide GLSL `layout` modifiers into those we have parsed // (in the sense of having some notion of their semantics), and // those we have not. class GLSLParsedLayoutModifier : public GLSLLayoutModifier {}; class GLSLUnparsedLayoutModifier : public GLSLLayoutModifier {}; // Specific cases for known GLSL `layout` modifiers that we need to work with class GLSLConstantIDLayoutModifier : public GLSLParsedLayoutModifier {}; class GLSLBindingLayoutModifier : public GLSLParsedLayoutModifier {}; class GLSLSetLayoutModifier : public GLSLParsedLayoutModifier {}; class GLSLLocationLayoutModifier : public GLSLParsedLayoutModifier {}; // A catch-all for single-keyword modifiers class SimpleModifier : public Modifier {}; // Some GLSL-specific modifiers class GLSLBufferModifier : public SimpleModifier {}; class GLSLWriteOnlyModifier : public SimpleModifier {}; class GLSLReadOnlyModifier : public SimpleModifier {}; class GLSLPatchModifier : public SimpleModifier {}; // Indicates that this is a variable declaration that corresponds to // a parameter block declaration in the source program. class ImplicitParameterBlockVariableModifier : public Modifier {}; // Indicates that this is a type that corresponds to the element // type of a parameter block declaration in the source program. class ImplicitParameterBlockElementTypeModifier : public Modifier {}; // An HLSL semantic class HLSLSemantic : public Modifier { public: Token name; }; // An HLSL semantic that affects layout class HLSLLayoutSemantic : public HLSLSemantic { public: Token registerName; Token componentMask; }; // An HLSL `register` semantic class HLSLRegisterSemantic : public HLSLLayoutSemantic { }; // TODO(tfoley): `packoffset` class HLSLPackOffsetSemantic : public HLSLLayoutSemantic { }; // An HLSL semantic that just associated a declaration with a semantic name class HLSLSimpleSemantic : public HLSLSemantic { }; // GLSL // Directives that came in via the preprocessor, but // that we need to keep around for later steps class GLSLPreprocessorDirective : public Modifier { }; // A GLSL `#version` directive class GLSLVersionDirective : public GLSLPreprocessorDirective { public: // Token giving the version number to use Token versionNumberToken; // Optional token giving the sub-profile to be used Token glslProfileToken; }; // A GLSL `#extension` directive class GLSLExtensionDirective : public GLSLPreprocessorDirective { public: // Token giving the version number to use Token extensionNameToken; // Optional token giving the sub-profile to be used Token dispositionToken; }; class ParameterBlockReflectionName : public Modifier { public: Token nameToken; }; // Helper class for iterating over a list of heap-allocated modifiers struct ModifierList { struct Iterator { Modifier* current; Modifier* operator*() { return current; } void operator++() { current = current->next.Ptr(); } bool operator!=(Iterator other) { return current != other.current; }; Iterator() : current(nullptr) {} Iterator(Modifier* modifier) : current(modifier) {} }; ModifierList() : modifiers(nullptr) {} ModifierList(Modifier* modifiers) : modifiers(modifiers) {} Iterator begin() { return Iterator(modifiers); } Iterator end() { return Iterator(nullptr); } Modifier* modifiers; }; // Helper class for iterating over heap-allocated modifiers // of a specific type. template struct FilteredModifierList { struct Iterator { Modifier* current; T* operator*() { return (T*)current; } void operator++() { current = Adjust(current->next.Ptr()); } bool operator!=(Iterator other) { return current != other.current; }; Iterator() : current(nullptr) {} Iterator(Modifier* modifier) : current(modifier) {} }; FilteredModifierList() : modifiers(nullptr) {} FilteredModifierList(Modifier* modifiers) : modifiers(Adjust(modifiers)) {} Iterator begin() { return Iterator(modifiers); } Iterator end() { return Iterator(nullptr); } static Modifier* Adjust(Modifier* modifier) { Modifier* m = modifier; for (;;) { if (!m) return m; if (dynamic_cast(m)) return m; m = m->next.Ptr(); } } Modifier* modifiers; }; // A set of modifiers attached to a syntax node struct Modifiers { // The first modifier in the linked list of heap-allocated modifiers RefPtr first; template FilteredModifierList getModifiersOfType() { return FilteredModifierList(first.Ptr()); } // Find the first modifier of a given type, or return `nullptr` if none is found. template T* findModifier() { return *getModifiersOfType().begin(); } template bool hasModifier() { return findModifier() != nullptr; } FilteredModifierList::Iterator begin() { return FilteredModifierList::Iterator(first.Ptr()); } FilteredModifierList::Iterator end() { return FilteredModifierList::Iterator(nullptr); } }; enum class BaseType { // Note(tfoley): These are ordered in terms of promotion rank, so be vareful when messing with this Void = 0, Bool, Int, UInt, UInt64, Float, #if 0 Texture2D = 48, TextureCube = 49, Texture2DArray = 50, Texture2DShadow = 51, TextureCubeShadow = 52, Texture2DArrayShadow = 53, Texture3D = 54, SamplerState = 4096, SamplerComparisonState = 4097, Error = 16384, #endif }; class Decl; class StructSyntaxNode; class BasicExpressionType; class ArrayExpressionType; class TypeDefDecl; class DeclRefType; class NamedExpressionType; class TypeType; class GenericDeclRefType; class VectorExpressionType; class MatrixExpressionType; class ArithmeticExpressionType; class GenericDecl; class Substitutions; class TextureType; class SamplerStateType; // A compile-time constant value (usually a type) class Val : public RefObject { public: // construct a new value by applying a set of parameter // substitutions to this one RefPtr Substitute(Substitutions* subst); // Lower-level interface for substition. Like the basic // `Substitute` above, but also takes a by-reference // integer parameter that should be incremented when // returning a modified value (this can help the caller // decide whether they need to do anything). virtual RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff); virtual bool EqualsVal(Val* val) = 0; virtual String ToString() = 0; virtual int GetHashCode() = 0; bool operator == (const Val & v) { return EqualsVal(const_cast(&v)); } }; // A compile-time integer (may not have a specific concrete value) class IntVal : public Val { }; // Try to extract a simple integer value from an `IntVal`. // This fill assert-fail if the object doesn't represent a literal value. int GetIntVal(RefPtr val); // Trivial case of a value that is just a constant integer class ConstantIntVal : public IntVal { public: int value; ConstantIntVal(int value) : value(value) {} virtual bool EqualsVal(Val* val) override; virtual String ToString() override; virtual int GetHashCode() override; }; // TODO(tfoley): classes for more general compile-time integers, // including references to template parameters // A type, representing a classifier for some term in the AST. // // Types can include "sugar" in that they may refer to a // `typedef` which gives them a good name when printed as // part of diagnostic messages. // // In order to operation on types, though, we often want // to look past any sugar, and operate on an underlying // "canonical" type. The reprsentation caches a pointer to // a canonical type on every type, so we can easily // operate on the raw representation when needed. class ExpressionType : public Val { public: static RefPtr Error; static RefPtr initializerListType; static RefPtr Overloaded; static Dictionary> sBuiltinTypes; static Dictionary sMagicDecls; // Note: just exists to make sure we can clean up // canonical types we create along the way static List> sCanonicalTypes; static ExpressionType* GetBool(); static ExpressionType* GetFloat(); static ExpressionType* GetInt(); static ExpressionType* GetUInt(); static ExpressionType* GetVoid(); static ExpressionType* getInitializerListType(); static ExpressionType* GetError(); public: virtual String ToString() = 0; bool Equals(ExpressionType * type); bool Equals(RefPtr type); bool IsVectorType() { return As() != nullptr; } bool IsArray() { return As() != nullptr; } template T* As() { return dynamic_cast(GetCanonicalType()); } // Convenience/legacy wrappers for `As<>` ArithmeticExpressionType * AsArithmeticType() { return As(); } BasicExpressionType * AsBasicType() { return As(); } VectorExpressionType * AsVectorType() { return As(); } MatrixExpressionType * AsMatrixType() { return As(); } ArrayExpressionType * AsArrayType() { return As(); } DeclRefType* AsDeclRefType() { return As(); } NamedExpressionType* AsNamedType(); bool IsTextureOrSampler(); bool IsTexture() { return As() != nullptr; } bool IsSampler() { return As() != nullptr; } bool IsStruct(); bool IsClass(); static void Init(); static void Finalize(); ExpressionType* GetCanonicalType(); virtual RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff) override; virtual bool EqualsVal(Val* val) override; protected: virtual bool EqualsImpl(ExpressionType * type) = 0; virtual ExpressionType* CreateCanonicalType() = 0; ExpressionType* canonicalType = nullptr; }; // A substitution represents a binding of certain // type-level variables to concrete argument values class Substitutions : public RefObject { public: // The generic declaration that defines the // parametesr we are binding to arguments GenericDecl* genericDecl; // The actual values of the arguments List> args; // Any further substitutions, relating to outer generic declarations RefPtr outer; // Apply a set of substitutions to the bindings in this substitution RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff); // Check if these are equivalent substitutiosn to another set bool Equals(Substitutions* subst); bool operator == (const Substitutions & subst) { return Equals(const_cast(&subst)); } int GetHashCode() const { int rs = 0; for (auto && v : args) { rs ^= v->GetHashCode(); rs *= 16777619; } return rs; } }; class SyntaxNode : public SyntaxNodeBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) = 0; }; class ContainerDecl; class SpecializeModifier; // Represents how much checking has been applied to a declaration. enum class DeclCheckState : uint8_t { // The declaration has been parsed, but not checked Unchecked, // We are in the process of checking the declaration "header" // (those parts of the declaration needed in order to // reference it) CheckingHeader, // We are done checking the declaration header. CheckedHeader, // We have checked the declaration fully. Checked, }; // A syntax node which can have modifiers appled class ModifiableSyntaxNode : public SyntaxNode { public: Modifiers modifiers; template FilteredModifierList GetModifiersOfType() { return FilteredModifierList(modifiers.first.Ptr()); } // Find the first modifier of a given type, or return `nullptr` if none is found. template T* FindModifier() { return *GetModifiersOfType().begin(); } template bool HasModifier() { return FindModifier() != nullptr; } }; void addModifier( RefPtr syntax, RefPtr modifier); // An intermediate type to represent either a single declaration, or a group of declarations class DeclBase : public ModifiableSyntaxNode { public: }; class Decl : public DeclBase { public: ContainerDecl* ParentDecl = nullptr; Token Name; String const& getName() { return Name.Content; } Token const& getNameToken() { return Name; } DeclCheckState checkState = DeclCheckState::Unchecked; // The next declaration defined in the same container with the same name Decl* nextInContainerWithSameName = nullptr; bool IsChecked(DeclCheckState state) { return checkState >= state; } void SetCheckState(DeclCheckState state) { assert(state >= checkState); checkState = state; } }; struct QualType { RefPtr type; bool IsLeftValue; QualType() : IsLeftValue(false) {} QualType(RefPtr type) : type(type) , IsLeftValue(false) {} QualType(ExpressionType* type) : type(type) , IsLeftValue(false) {} void operator=(RefPtr t) { *this = QualType(t); } void operator=(ExpressionType* t) { *this = QualType(t); } ExpressionType* Ptr() { return type.Ptr(); } operator RefPtr() { return type; } RefPtr operator->() { return type; } }; class ExpressionSyntaxNode : public SyntaxNode { public: QualType Type; ExpressionSyntaxNode() {} }; // A reference to a declaration, which may include // substitutions for generic parameters. struct DeclRefBase { typedef Decl DeclType; // The underlying declaration Decl* decl = nullptr; Decl* getDecl() const { return decl; } // Optionally, a chain of substititions to perform RefPtr substitutions; DeclRefBase() {} DeclRefBase(Decl* decl, RefPtr substitutions) : decl(decl) , substitutions(substitutions) {} // Apply substitutions to a type or ddeclaration RefPtr Substitute(RefPtr type) const; DeclRefBase Substitute(DeclRefBase declRef) const; // Apply substitutions to an expression RefPtr Substitute(RefPtr expr) const; // Apply substitutions to this declaration reference DeclRefBase SubstituteImpl(Substitutions* subst, int* ioDiff); // Check if this is an equivalent declaration reference to another bool Equals(DeclRefBase const& declRef) const; bool operator == (const DeclRefBase& other) const { return Equals(other); } // Convenience accessors for common properties of declarations String const& GetName() const; DeclRefBase GetParent() const; int GetHashCode() const; }; template struct DeclRef : DeclRefBase { typedef T DeclType; DeclRef() {} DeclRef(T* decl, RefPtr substitutions) : DeclRefBase(decl, substitutions) {} template DeclRef(DeclRef const& other, typename EnableIf::Value, void>::type* = 0) : DeclRefBase(other.decl, other.substitutions) { } // "dynamic cast" to a more specific declaration reference type template DeclRef As() const { DeclRef result; result.decl = dynamic_cast(decl); result.substitutions = substitutions; return result; } T* getDecl() const { return (T*)decl; } operator T*() const { return getDecl(); } // static DeclRef unsafeInit(DeclRefBase const& declRef) { return DeclRef((T*) declRef.decl, declRef.substitutions); } RefPtr Substitute(RefPtr type) const { return DeclRefBase::Substitute(type); } RefPtr Substitute(RefPtr expr) const { return DeclRefBase::Substitute(expr); } // Apply substitutions to a type or ddeclaration template DeclRef Substitute(DeclRef declRef) const { return DeclRef::unsafeInit(DeclRefBase::Substitute(declRef)); } // Apply substitutions to this declaration reference DeclRef SubstituteImpl(Substitutions* subst, int* ioDiff) { return DeclRef::unsafeInit(DeclRefBase::SubstituteImpl(subst, ioDiff)); } DeclRef GetParent() const { return DeclRef::unsafeInit(DeclRefBase::GetParent()); } }; // The type of a reference to an overloaded name class OverloadGroupType : public ExpressionType { public: virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; // The type of an initializer-list expression (before it has // been coerced to some other type) class InitializerListType : public ExpressionType { public: virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; // The type of an expression that was erroneous class ErrorType : public ExpressionType { public: virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; // A type that takes the form of a reference to some declaration class DeclRefType : public ExpressionType { public: DeclRef declRef; virtual String ToString() override; virtual RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff) override; static DeclRefType* Create(DeclRef declRef); protected: DeclRefType() {} DeclRefType(DeclRef declRef) : declRef(declRef) {} virtual int GetHashCode() override; virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; }; // Base class for types that can be used in arithmetic expressions class ArithmeticExpressionType : public DeclRefType { public: virtual BasicExpressionType* GetScalarType() = 0; }; class FunctionDeclBase; class BasicExpressionType : public ArithmeticExpressionType { public: BaseType BaseType; BasicExpressionType() { BaseType = Slang::BaseType::Int; } BasicExpressionType(Slang::BaseType baseType) { BaseType = baseType; } virtual Slang::String ToString() override; protected: virtual BasicExpressionType* GetScalarType() override; virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; }; class TextureTypeBase : public DeclRefType { public: // The type that results from fetching an element from this texture RefPtr elementType; // Bits representing the kind of texture type we are looking at // (e.g., `Texture2DMS` vs. `TextureCubeArray`) typedef uint16_t Flavor; Flavor flavor; enum { // Mask for the overall "shape" of the texture ShapeMask = SLANG_RESOURCE_BASE_SHAPE_MASK, // Flag for whether the shape has "array-ness" ArrayFlag = SLANG_TEXTURE_ARRAY_FLAG, // Whether or not the texture stores multiple samples per pixel MultisampleFlag = SLANG_TEXTURE_MULTISAMPLE_FLAG, // Whether or not this is a shadow texture // // TODO(tfoley): is this even meaningful/used? // ShadowFlag = 0x80, }; enum Shape : uint8_t { Shape1D = SLANG_TEXTURE_1D, Shape2D = SLANG_TEXTURE_2D, Shape3D = SLANG_TEXTURE_3D, ShapeCube = SLANG_TEXTURE_CUBE, Shape1DArray = Shape1D | ArrayFlag, Shape2DArray = Shape2D | ArrayFlag, // No Shape3DArray ShapeCubeArray = ShapeCube | ArrayFlag, }; Shape GetBaseShape() const { return Shape(flavor & ShapeMask); } bool isArray() const { return (flavor & ArrayFlag) != 0; } bool isMultisample() const { return (flavor & MultisampleFlag) != 0; } // bool isShadow() const { return (flavor & ShadowFlag) != 0; } SlangResourceShape getShape() const { return flavor & 0xFF; } SlangResourceAccess getAccess() const { return (flavor >> 8) & 0xFF; } TextureTypeBase( Flavor flavor, RefPtr elementType) : elementType(elementType) , flavor(flavor) {} }; class TextureType : public TextureTypeBase { public: TextureType( Flavor flavor, RefPtr elementType) : TextureTypeBase(flavor, elementType) {} }; // This is a base type for texture/sampler pairs, // as they exist in, e.g., GLSL class TextureSamplerType : public TextureTypeBase { public: TextureSamplerType( Flavor flavor, RefPtr elementType) : TextureTypeBase(flavor, elementType) {} }; // This is a base type for `image*` types, as they exist in GLSL class GLSLImageType : public TextureTypeBase { public: GLSLImageType( Flavor flavor, RefPtr elementType) : TextureTypeBase(flavor, elementType) {} }; class SamplerStateType : public DeclRefType { public: // What flavor of sampler state is this enum class Flavor : uint8_t { SamplerState, SamplerComparisonState, }; Flavor flavor; }; // Other cases of generic types known to the compiler class BuiltinGenericType : public DeclRefType { public: RefPtr elementType; }; // Types that behave like pointers, in that they can be // dereferenced (implicitly) to access members defined // in the element type. class PointerLikeType : public BuiltinGenericType {}; // Generic types used in existing Slang code // TODO(tfoley): check that these are actually working right... class PatchType : public PointerLikeType {}; class StorageBufferType : public BuiltinGenericType {}; class UniformBufferType : public PointerLikeType {}; class PackedBufferType : public BuiltinGenericType {}; // HLSL buffer-type resources class HLSLBufferType : public BuiltinGenericType {}; class HLSLRWBufferType : public BuiltinGenericType {}; class HLSLStructuredBufferType : public BuiltinGenericType {}; class HLSLRWStructuredBufferType : public BuiltinGenericType {}; class UntypedBufferResourceType : public DeclRefType {}; class HLSLByteAddressBufferType : public UntypedBufferResourceType {}; class HLSLRWByteAddressBufferType : public UntypedBufferResourceType {}; class HLSLAppendStructuredBufferType : public BuiltinGenericType {}; class HLSLConsumeStructuredBufferType : public BuiltinGenericType {}; class HLSLPatchType : public DeclRefType { public: ExpressionType* getElementType(); IntVal* getElementCount(); }; class HLSLInputPatchType : public HLSLPatchType {}; class HLSLOutputPatchType : public HLSLPatchType {}; // HLSL geometry shader output stream types class HLSLStreamOutputType : public BuiltinGenericType {}; class HLSLPointStreamType : public HLSLStreamOutputType {}; class HLSLLineStreamType : public HLSLStreamOutputType {}; class HLSLTriangleStreamType : public HLSLStreamOutputType {}; // class GLSLInputAttachmentType : public DeclRefType {}; // Base class for types used when desugaring parameter block // declarations, includeing HLSL `cbuffer` or GLSL `uniform` blocks. class ParameterBlockType : public PointerLikeType {}; class UniformParameterBlockType : public ParameterBlockType {}; class VaryingParameterBlockType : public ParameterBlockType {}; // Type for HLSL `cbuffer` declarations, and `ConstantBuffer` // ALso used for GLSL `uniform` blocks. class ConstantBufferType : public UniformParameterBlockType {}; // Type for HLSL `tbuffer` declarations, and `TextureBuffer` class TextureBufferType : public UniformParameterBlockType {}; // Type for GLSL `in` and `out` blocks class GLSLInputParameterBlockType : public VaryingParameterBlockType {}; class GLSLOutputParameterBlockType : public VaryingParameterBlockType {}; // Type for GLLSL `buffer` blocks class GLSLShaderStorageBufferType : public UniformParameterBlockType {}; class ArrayExpressionType : public ExpressionType { public: RefPtr BaseType; RefPtr ArrayLength; virtual Slang::String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; // The "type" of an expression that resolves to a type. // For example, in the expression `float(2)` the sub-expression, // `float` would have the type `TypeType(float)`. class TypeType : public ExpressionType { public: TypeType(RefPtr type) : type(type) {} // The type that this is the type of... RefPtr type; virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; class GenericDecl; // A vector type, e.g., `vector` class VectorExpressionType : public ArithmeticExpressionType { public: #if 0 VectorExpressionType( RefPtr elementType, RefPtr elementCount) : elementType(elementType) , elementCount(elementCount) {} #endif // The type of vector elements. // As an invariant, this should be a basic type or an alias. RefPtr elementType; // The number of elements RefPtr elementCount; virtual String ToString() override; protected: virtual BasicExpressionType* GetScalarType() override; }; // A matrix type, e.g., `matrix` class MatrixExpressionType : public ArithmeticExpressionType { public: // TODO: consider adding these back for convenience, // with a way to initialize them on-demand from the // real storage (which is in the `DeclRefType` #if 0 // The type of vector elements. // As an invariant, this should be a basic type or an alias. RefPtr elementType; // The type of the matrix rows RefPtr rowType; // The number of rows and columns RefPtr rowCount; RefPtr colCount; #endif ExpressionType* getElementType(); IntVal* getRowCount(); IntVal* getColumnCount(); virtual String ToString() override; protected: virtual BasicExpressionType* GetScalarType() override; }; inline BaseType GetVectorBaseType(VectorExpressionType* vecType) { return vecType->elementType->AsBasicType()->BaseType; } inline int GetVectorSize(VectorExpressionType* vecType) { auto constantVal = vecType->elementCount.As(); if (constantVal) return constantVal->value; // TODO: what to do in this case? return 0; } class ContainerDecl; // A group of declarations that should be treated as a unit class DeclGroup : public DeclBase { public: List> decls; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; template struct FilteredMemberList { typedef RefPtr Element; FilteredMemberList() : mBegin(NULL) , mEnd(NULL) {} explicit FilteredMemberList( List const& list) : mBegin(Adjust(list.begin(), list.end())) , mEnd(list.end()) {} struct Iterator { Element* mCursor; Element* mEnd; bool operator!=(Iterator const& other) { return mCursor != other.mCursor; } void operator++() { mCursor = Adjust(mCursor + 1, mEnd); } RefPtr& operator*() { return *(RefPtr*)mCursor; } }; Iterator begin() { Iterator iter = { mBegin, mEnd }; return iter; } Iterator end() { Iterator iter = { mEnd, mEnd }; return iter; } static Element* Adjust(Element* cursor, Element* end) { while (cursor != end) { if ((*cursor).As()) return cursor; cursor++; } return cursor; } // TODO(tfoley): It is ugly to have these. // We should probably fix the call sites instead. RefPtr& First() { return *begin(); } int Count() { int count = 0; for (auto iter : (*this)) { (void)iter; count++; } return count; } List> ToArray() { List> result; for (auto element : (*this)) { result.Add(element); } return result; } Element* mBegin; Element* mEnd; }; struct TransparentMemberInfo { // The declaration of the transparent member Decl* decl; }; // A "container" decl is a parent to other declarations class ContainerDecl : public Decl { public: List> Members; template FilteredMemberList getMembersOfType() { return FilteredMemberList(Members); } // Dictionary for looking up members by name. // This is built on demand before performing lookup. Dictionary memberDictionary; // Whether the `memberDictionary` is valid. // Should be set to `false` if any members get added/remoed. bool memberDictionaryIsValid = false; // A list of transparent members, to be used in lookup // Note: this is only valid if `memberDictionaryIsValid` is true List transparentMembers; }; template struct FilteredMemberRefList { List> const& decls; RefPtr substitutions; FilteredMemberRefList( List> const& decls, RefPtr substitutions) : decls(decls) , substitutions(substitutions) {} int Count() const { int count = 0; for (auto d : *this) count++; return count; } List> ToArray() const { List> result; for (auto d : *this) result.Add(d); return result; } struct Iterator { FilteredMemberRefList const* list; RefPtr* ptr; RefPtr* end; Iterator() : list(nullptr), ptr(nullptr) {} Iterator( FilteredMemberRefList const* list, RefPtr* ptr, RefPtr* end) : list(list) , ptr(ptr) , end(end) {} bool operator!=(Iterator other) { return ptr != other.ptr; } void operator++() { ptr = list->Adjust(ptr + 1, end); } DeclRef operator*() { return DeclRef((T*) ptr->Ptr(), list->substitutions); } }; Iterator begin() const { return Iterator(this, Adjust(decls.begin(), decls.end()), decls.end()); } Iterator end() const { return Iterator(this, decls.end(), decls.end()); } RefPtr* Adjust(RefPtr* ptr, RefPtr* end) const { while (ptr != end) { DeclRef declRef(ptr->Ptr(), substitutions); if (declRef.As()) return ptr; ptr++; } return end; } }; inline FilteredMemberRefList getMembers(DeclRef const& declRef) { return FilteredMemberRefList(declRef.getDecl()->Members, declRef.substitutions); } template inline FilteredMemberRefList getMembersOfType(DeclRef const& declRef) { return FilteredMemberRefList(declRef.getDecl()->Members, declRef.substitutions); } // // Type Expressions // // A "type expression" is a term that we expect to resolve to a type during checking. // We store both the original syntax and the resolved type here. struct TypeExp { TypeExp() {} TypeExp(TypeExp const& other) : exp(other.exp) , type(other.type) {} explicit TypeExp(RefPtr exp) : exp(exp) {} TypeExp(RefPtr exp, RefPtr type) : exp(exp) , type(type) {} RefPtr exp; RefPtr type; bool Equals(ExpressionType* other) { return type->Equals(other); } bool Equals(RefPtr other) { return type->Equals(other.Ptr()); } ExpressionType* Ptr() { return type.Ptr(); } operator RefPtr() { return type; } ExpressionType* operator->() { return Ptr(); } TypeExp Accept(SyntaxVisitor* visitor); }; // // Declarations // // Base class for all variable-like declarations class VarDeclBase : public Decl { public: // Type of the variable TypeExp Type; ExpressionType* getType() { return Type.type.Ptr(); } // Initializer expression (optional) RefPtr Expr; }; inline RefPtr GetType(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->Type); } inline RefPtr getInitExpr(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->Expr); } // A field of a `struct` type class StructField : public VarDeclBase { public: StructField() {} virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // An `AggTypeDeclBase` captures the shared functionality // between true aggregate type declarations and extension // declarations: // // - Both can container members (they are `ContainerDecl`s) // - Both can have declared bases // - Both expose a `this` variable in their body // class AggTypeDeclBase : public ContainerDecl { public: }; // An extension to apply to an existing type class ExtensionDecl : public AggTypeDeclBase { public: TypeExp targetType; // next extension attached to the same nominal type ExtensionDecl* nextCandidateExtension = nullptr; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; inline RefPtr GetTargetType(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->targetType); } // Declaration of a type that represents some sort of aggregate class AggTypeDecl : public AggTypeDeclBase { public: // extensions that might apply to this declaration ExtensionDecl* candidateExtensions = nullptr; FilteredMemberList GetFields() { return getMembersOfType(); } StructField* FindField(String name) { for (auto field : GetFields()) { if (field->Name.Content == name) return field.Ptr(); } return nullptr; } int FindFieldIndex(String name) { int index = 0; for (auto field : GetFields()) { if (field->Name.Content == name) return index; index++; } return -1; } }; inline ExtensionDecl* GetCandidateExtensions(DeclRef const& declRef) { return declRef.getDecl()->candidateExtensions; } class StructSyntaxNode : public AggTypeDecl { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; inline FilteredMemberRefList GetFields(DeclRef const& declRef) { return getMembersOfType(declRef); } class ClassSyntaxNode : public AggTypeDecl { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // An interface which other types can conform to class InterfaceDecl : public AggTypeDecl { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A kind of pseudo-member that represents an explicit // or implicit inheritance relationship. // class InheritanceDecl : public Decl { public: // The type expression as written TypeExp base; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; inline RefPtr getBaseType(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->base.type); } // TODO: may eventually need sub-classes for explicit/direct vs. implicit/indirect inheritance // A declaration that represents a simple (non-aggregate) type class SimpleTypeDecl : public Decl { }; // A `typedef` declaration class TypeDefDecl : public SimpleTypeDecl { public: TypeExp Type; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; inline RefPtr GetType(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->Type); } // A type alias of some kind (e.g., via `typedef`) class NamedExpressionType : public ExpressionType { public: NamedExpressionType(DeclRef declRef) : declRef(declRef) {} DeclRef declRef; virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; class StatementSyntaxNode : public ModifiableSyntaxNode { public: }; // A scope for local declarations (e.g., as part of a statement) class ScopeDecl : public ContainerDecl { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class ScopeStmt : public StatementSyntaxNode { public: RefPtr scopeDecl; }; class BlockStatementSyntaxNode : public ScopeStmt { public: List> Statements; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class UnparsedStmt : public StatementSyntaxNode { public: // The tokens that were contained between `{` and `}` List tokens; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class ParameterSyntaxNode : public VarDeclBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // Base class for things that have parameter lists and can thus be applied to arguments ("called") class CallableDecl : public ContainerDecl { public: FilteredMemberList GetParameters() { return getMembersOfType(); } TypeExp ReturnType; }; inline RefPtr GetResultType(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->ReturnType.type.Ptr()); } inline FilteredMemberRefList GetParameters(DeclRef const& declRef) { return getMembersOfType(declRef); } // Base class for callable things that may also have a body that is evaluated to produce their result class FunctionDeclBase : public CallableDecl { public: RefPtr Body; }; // Function types are currently used for references to symbols that name // either ordinary functions, or "component functions." // We do not directly store a representation of the type, and instead // use a reference to the symbol to stand in for its logical type class FuncType : public ExpressionType { public: DeclRef declRef; virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual ExpressionType* CreateCanonicalType() override; virtual int GetHashCode() override; }; // A constructor/initializer to create instances of a type class ConstructorDecl : public FunctionDeclBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A subscript operation used to index instances of a type class SubscriptDecl : public CallableDecl { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // An "accessor" for a subscript or property class AccessorDecl : public FunctionDeclBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class GetterDecl : public AccessorDecl { }; class SetterDecl : public AccessorDecl { }; // class FunctionSyntaxNode : public FunctionDeclBase { public: String InternalName; bool IsInline() { return HasModifier(); } bool IsExtern() { return HasModifier(); } virtual RefPtr Accept(SyntaxVisitor * visitor) override; FunctionSyntaxNode() { } }; struct Scope : public RefObject { // The parent of this scope (where lookup should go if nothing is found locally) RefPtr parent; // The next sibling of this scope (a peer for lookup) RefPtr nextSibling; // The container to use for lookup // // Note(tfoley): This is kept as an unowned pointer // so that a scope can't keep parts of the AST alive, // but the opposite it allowed. ContainerDecl* containerDecl; }; // Base class for expressions that will reference declarations class DeclRefExpr : public ExpressionSyntaxNode { public: // The scope in which to perform lookup RefPtr scope; // The declaration of the symbol being referenced DeclRef declRef; // The name of the symbol being referenced String name; }; class VarExpressionSyntaxNode : public DeclRefExpr { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // Masks to be applied when lookup up declarations enum class LookupMask : uint8_t { Type = 0x1, Function = 0x2, Value = 0x4, All = Type | Function | Value, }; // Represents one item found during lookup struct LookupResultItem { // Sometimes lookup finds an item, but there were additional // "hops" taken to reach it. We need to remember these steps // so that if/when we consturct a full expression we generate // appropriate AST nodes for all the steps. // // We build up a list of these "breadcrumbs" while doing // lookup, and store them alongside each item found. class Breadcrumb : public RefObject { public: enum class Kind { Member, // A member was references Deref, // A value with pointer(-like) type was dereferenced }; Kind kind; DeclRef declRef; RefPtr next; Breadcrumb(Kind kind, DeclRef declRef, RefPtr next) : kind(kind) , declRef(declRef) , next(next) {} }; // A properly-specialized reference to the declaration that was found. DeclRef declRef; // Any breadcrumbs needed in order to turn that declaration // reference into a well-formed expression. // // This is unused in the simple case where a declaration // is being referenced directly (rather than through // transparent members). RefPtr breadcrumbs; LookupResultItem() = default; explicit LookupResultItem(DeclRef declRef) : declRef(declRef) {} LookupResultItem(DeclRef declRef, RefPtr breadcrumbs) : declRef(declRef) , breadcrumbs(breadcrumbs) {} }; // Result of looking up a name in some lexical/semantic environment. // Can be used to enumerate all the declarations matching that name, // in the case where the result is overloaded. struct LookupResult { // The one item that was found, in the smple case LookupResultItem item; // All of the items that were found, in the complex case. // Note: if there was no overloading, then this list isn't // used at all, to avoid allocation. List items; // Was at least one result found? bool isValid() const { return item.declRef.getDecl() != nullptr; } bool isOverloaded() const { return items.Count() > 1; } }; class SemanticsVisitor; struct LookupRequest { SemanticsVisitor* semantics = nullptr; RefPtr scope = nullptr; RefPtr endScope = nullptr; LookupMask mask = LookupMask::All; }; // An expression that references an overloaded set of declarations // having the same name. class OverloadedExpr : public ExpressionSyntaxNode { public: // Optional: the base expression is this overloaded result // arose from a member-reference expression. RefPtr base; // The lookup result that was ambiguous LookupResult lookupResult2; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; typedef double FloatingPointLiteralValue; class ConstantExpressionSyntaxNode : public ExpressionSyntaxNode { public: enum class ConstantType { Int, Bool, Float }; ConstantType ConstType; union { int IntValue; FloatingPointLiteralValue FloatValue; }; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; enum class Operator { Neg, Not, BitNot, PreInc, PreDec, PostInc, PostDec, Mul, Div, Mod, Add, Sub, Lsh, Rsh, Eql, Neq, Greater, Less, Geq, Leq, BitAnd, BitXor, BitOr, And, Or, Sequence, Select, Assign = 200, AddAssign, SubAssign, MulAssign, DivAssign, ModAssign, LshAssign, RshAssign, OrAssign, AndAssign, XorAssign, }; String GetOperatorFunctionName(Operator op); String OperatorToString(Operator op); // An initializer list, e.g. `{ 1, 2, 3 }` class InitializerListExpr : public ExpressionSyntaxNode { public: List> args; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A base expression being applied to arguments: covers // both ordinary `()` function calls and `<>` generic application class AppExprBase : public ExpressionSyntaxNode { public: RefPtr FunctionExpr; List> Arguments; }; class InvokeExpressionSyntaxNode : public AppExprBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class OperatorExpressionSyntaxNode : public InvokeExpressionSyntaxNode { public: // Operator Operator; // void SetOperator(RefPtr scope, Slang::Operator op); virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class InfixExpr : public OperatorExpressionSyntaxNode {}; class PrefixExpr : public OperatorExpressionSyntaxNode {}; class PostfixExpr : public OperatorExpressionSyntaxNode {}; class IndexExpressionSyntaxNode : public ExpressionSyntaxNode { public: RefPtr BaseExpression; RefPtr IndexExpression; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class MemberExpressionSyntaxNode : public DeclRefExpr { public: RefPtr BaseExpression; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class SwizzleExpr : public ExpressionSyntaxNode { public: RefPtr base; int elementCount; int elementIndices[4]; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A dereference of a pointer or pointer-like type class DerefExpr : public ExpressionSyntaxNode { public: RefPtr base; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class TypeCastExpressionSyntaxNode : public ExpressionSyntaxNode { public: TypeExp TargetType; RefPtr Expression; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class SelectExpressionSyntaxNode : public OperatorExpressionSyntaxNode { public: }; class EmptyStatementSyntaxNode : public StatementSyntaxNode { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class DiscardStatementSyntaxNode : public StatementSyntaxNode { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; struct Variable : public VarDeclBase { virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class VarDeclrStatementSyntaxNode : public StatementSyntaxNode { public: RefPtr decl; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A "module" of code (essentiately, a single translation unit) // that provides a scope for some number of declarations. class ProgramSyntaxNode : public ContainerDecl { public: // Access members of specific types FilteredMemberList GetFunctions() { return getMembersOfType(); } FilteredMemberList GetClasses() { return getMembersOfType(); } FilteredMemberList GetStructs() { return getMembersOfType(); } FilteredMemberList GetTypeDefs() { return getMembersOfType(); } virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class ImportDecl : public Decl { public: // The name of the module we are trying to import Token nameToken; // The scope that we want to import into RefPtr scope; // The module that actually got imported RefPtr importedModuleDecl; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class IfStatementSyntaxNode : public StatementSyntaxNode { public: RefPtr Predicate; RefPtr PositiveStatement; RefPtr NegativeStatement; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A statement that can be escaped with a `break` class BreakableStmt : public ScopeStmt {}; class SwitchStmt : public BreakableStmt { public: RefPtr condition; RefPtr body; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A statement that is expected to appear lexically nested inside // some other construct, and thus needs to keep track of the // outer statement that it is associated with... class ChildStmt : public StatementSyntaxNode { public: StatementSyntaxNode* parentStmt = nullptr; }; // a `case` or `default` statement inside a `switch` // // Note(tfoley): A correct AST for a C-like language would treat // these as a labelled statement, and so they would contain a // sub-statement. I'm leaving that out for now for simplicity. class CaseStmtBase : public ChildStmt { public: }; // a `case` statement inside a `switch` class CaseStmt : public CaseStmtBase { public: RefPtr expr; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // a `default` statement inside a `switch` class DefaultStmt : public CaseStmtBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A statement that represents a loop, and can thus be escaped with a `continue` class LoopStmt : public BreakableStmt {}; class ForStatementSyntaxNode : public LoopStmt { public: RefPtr InitialStatement; RefPtr SideEffectExpression, PredicateExpression; RefPtr Statement; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class WhileStatementSyntaxNode : public LoopStmt { public: RefPtr Predicate; RefPtr Statement; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class DoWhileStatementSyntaxNode : public LoopStmt { public: RefPtr Statement; RefPtr Predicate; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // The case of child statements that do control flow relative // to their parent statement. class JumpStmt : public ChildStmt { public: StatementSyntaxNode* parentStmt = nullptr; }; class BreakStatementSyntaxNode : public JumpStmt { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class ContinueStatementSyntaxNode : public JumpStmt { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class ReturnStatementSyntaxNode : public StatementSyntaxNode { public: RefPtr Expression; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; class ExpressionStatementSyntaxNode : public StatementSyntaxNode { public: RefPtr Expression; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // Note(tfoley): Moved this further down in the file because it depends on // `ExpressionSyntaxNode` and a forward reference just isn't good enough // for `RefPtr`. // class GenericAppExpr : public AppExprBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // An expression representing re-use of the syntax for a type in more // than once conceptually-distinct declaration class SharedTypeExpr : public ExpressionSyntaxNode { public: // The underlying type expression that we want to share TypeExp base; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A modifier that indicates a built-in base type (e.g., `float`) class BuiltinTypeModifier : public Modifier { public: BaseType tag; }; // A modifier that indicates a built-in type that isn't a base type (e.g., `vector`) // // TODO(tfoley): This deserves a better name than "magic" class MagicTypeModifier : public Modifier { public: String name; uint32_t tag; }; // Modifiers that affect the storage layout for matrices class MatrixLayoutModifier : public Modifier {}; // Modifiers that specify row- and column-major layout, respectively class RowMajorLayoutModifier : public MatrixLayoutModifier {}; class ColumnMajorLayoutModifier : public MatrixLayoutModifier {}; // The HLSL flavor of those modifiers class HLSLRowMajorLayoutModifier : public RowMajorLayoutModifier {}; class HLSLColumnMajorLayoutModifier : public ColumnMajorLayoutModifier {}; // The GLSL flavor of those modifiers // // Note(tfoley): The GLSL versions of these modifiers are "backwards" // in the sense that when a GLSL programmer requests row-major layout, // we actually interpret that as requesting column-major. This makes // sense because we interpret matrix conventions backwards from how // GLSL specifies them. class GLSLRowMajorLayoutModifier : public ColumnMajorLayoutModifier {}; class GLSLColumnMajorLayoutModifier : public RowMajorLayoutModifier {}; // More HLSL Keyword // HLSL `nointerpolation` modifier class HLSLNoInterpolationModifier : public Modifier {}; // HLSL `linear` modifier class HLSLLinearModifier : public Modifier {}; // HLSL `sample` modifier class HLSLSampleModifier : public Modifier {}; // HLSL `centroid` modifier class HLSLCentroidModifier : public Modifier {}; // HLSL `precise` modifier class HLSLPreciseModifier : public Modifier {}; // HLSL `shared` modifier (which is used by the effect system, // and shouldn't be confused with `groupshared`) class HLSLEffectSharedModifier : public Modifier {}; // HLSL `groupshared` modifier class HLSLGroupSharedModifier : public Modifier {}; // HLSL `static` modifier (probably doesn't need to be // treated as HLSL-specific) class HLSLStaticModifier : public Modifier {}; // HLSL `uniform` modifier (distinct meaning from GLSL // use of the keyword) class HLSLUniformModifier : public Modifier {}; // HLSL `volatile` modifier (ignored) class HLSLVolatileModifier : public Modifier {}; // An HLSL `[name(arg0, ...)]` style attribute. class HLSLAttribute : public Modifier { public: Token nameToken; List> args; }; // An HLSL `[name(...)]` attribute that hasn't undergone // any semantic analysis. // After analysis, this might be transformed into a more specific case. class HLSLUncheckedAttribute : public HLSLAttribute { public: }; // An HLSL `[numthreads(x,y,z)]` attribute class HLSLNumThreadsAttribute : public HLSLAttribute { public: // The number of threads to use along each axis int32_t x; int32_t y; int32_t z; }; // HLSL modifiers for geometry shader input topology class HLSLGeometryShaderInputPrimitiveTypeModifier : public Modifier {}; class HLSLPointModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; class HLSLLineModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; class HLSLTriangleModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; class HLSLLineAdjModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; class HLSLTriangleAdjModifier : public HLSLGeometryShaderInputPrimitiveTypeModifier {}; // // A generic declaration, parameterized on types/values class GenericDecl : public ContainerDecl { public: // The decl that is genericized... RefPtr inner; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; inline Decl* GetInner(DeclRef const& declRef) { // TODO: Should really return a `DeclRef` for the inner // declaration, and not just a raw pointer return declRef.getDecl()->inner.Ptr(); } // The "type" of an expression that names a generic declaration. class GenericDeclRefType : public ExpressionType { public: GenericDeclRefType(DeclRef declRef) : declRef(declRef) {} DeclRef declRef; DeclRef const& GetDeclRef() const { return declRef; } virtual String ToString() override; protected: virtual bool EqualsImpl(ExpressionType * type) override; virtual int GetHashCode() override; virtual ExpressionType* CreateCanonicalType() override; }; class GenericTypeParamDecl : public SimpleTypeDecl { public: // The bound for the type parameter represents a trait that any // type used as this parameter must conform to // TypeExp bound; // The "initializer" for the parameter represents a default value TypeExp initType; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // A constraint placed as part of a generic declaration class GenericTypeConstraintDecl : public Decl { public: // A type constraint like `T : U` is constraining `T` to be "below" `U` // on a lattice of types. This may not be a subtyping relationship // per se, but it makes sense to use that terminology here, so we // think of these fields as the sub-type and sup-ertype, respectively. TypeExp sub; TypeExp sup; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; inline RefPtr GetSub(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->sub); } inline RefPtr GetSup(DeclRef const& declRef) { return declRef.Substitute(declRef.getDecl()->sup); } class GenericValueParamDecl : public VarDeclBase { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // The logical "value" of a rererence to a generic value parameter class GenericParamIntVal : public IntVal { public: DeclRef declRef; GenericParamIntVal(DeclRef declRef) : declRef(declRef) {} virtual bool EqualsVal(Val* val) override; virtual String ToString() override; virtual int GetHashCode() override; virtual RefPtr SubstituteImpl(Substitutions* subst, int* ioDiff) override; }; // Declaration of a user-defined modifier class ModifierDecl : public Decl { public: // The name of the C++ class to instantiate // (this is a reference to a class in the compiler source code, // and not the user's source code) Token classNameToken; virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // An empty declaration (which might still have modifiers attached). // // An empty declaration is uncommon in HLSL, but // in GLSL it is often used at the global scope // to declare metadata that logically belongs // to the entry point, e.g.: // // layout(local_size_x = 16) in; // class EmptyDecl : public Decl { public: virtual RefPtr Accept(SyntaxVisitor * visitor) override; }; // class SyntaxVisitor { protected: DiagnosticSink * sink = nullptr; DiagnosticSink* getSink() { return sink; } SourceLanguage sourceLanguage = SourceLanguage::Unknown; public: void setSourceLanguage(SourceLanguage language) { sourceLanguage = language; } SyntaxVisitor(DiagnosticSink * sink) : sink(sink) {} virtual ~SyntaxVisitor() { } virtual RefPtr VisitProgram(ProgramSyntaxNode* program) { for (auto & m : program->Members) m = m->Accept(this).As(); return program; } virtual void visitImportDecl(ImportDecl * decl) = 0; virtual RefPtr VisitFunction(FunctionSyntaxNode* func) { func->ReturnType = func->ReturnType.Accept(this); for (auto & member : func->Members) member = member->Accept(this).As(); if (func->Body) func->Body = func->Body->Accept(this).As(); return func; } virtual RefPtr VisitScopeDecl(ScopeDecl* decl) { // By default don't visit children, because they will always // be encountered in the ordinary flow of the corresponding statement. return decl; } virtual RefPtr VisitStruct(StructSyntaxNode * s) { for (auto & f : s->Members) f = f->Accept(this).As(); return s; } virtual RefPtr VisitClass(ClassSyntaxNode * s) { for (auto & f : s->Members) f = f->Accept(this).As(); return s; } virtual RefPtr VisitGenericDecl(GenericDecl * decl) { for (auto & m : decl->Members) m = m->Accept(this).As(); decl->inner = decl->inner->Accept(this).As(); return decl; } virtual RefPtr VisitTypeDefDecl(TypeDefDecl* decl) { decl->Type = decl->Type.Accept(this); return decl; } virtual RefPtr VisitDiscardStatement(DiscardStatementSyntaxNode * stmt) { return stmt; } virtual RefPtr VisitStructField(StructField * f) { f->Type = f->Type.Accept(this); return f; } virtual RefPtr VisitBlockStatement(BlockStatementSyntaxNode* stmt) { for (auto & s : stmt->Statements) s = s->Accept(this).As(); return stmt; } virtual RefPtr VisitBreakStatement(BreakStatementSyntaxNode* stmt) { return stmt; } virtual RefPtr VisitContinueStatement(ContinueStatementSyntaxNode* stmt) { return stmt; } virtual RefPtr VisitDoWhileStatement(DoWhileStatementSyntaxNode* stmt) { if (stmt->Predicate) stmt->Predicate = stmt->Predicate->Accept(this).As(); if (stmt->Statement) stmt->Statement = stmt->Statement->Accept(this).As(); return stmt; } virtual RefPtr VisitEmptyStatement(EmptyStatementSyntaxNode* stmt) { return stmt; } virtual RefPtr VisitForStatement(ForStatementSyntaxNode* stmt) { if (stmt->InitialStatement) stmt->InitialStatement = stmt->InitialStatement->Accept(this).As(); if (stmt->PredicateExpression) stmt->PredicateExpression = stmt->PredicateExpression->Accept(this).As(); if (stmt->SideEffectExpression) stmt->SideEffectExpression = stmt->SideEffectExpression->Accept(this).As(); if (stmt->Statement) stmt->Statement = stmt->Statement->Accept(this).As(); return stmt; } virtual RefPtr VisitIfStatement(IfStatementSyntaxNode* stmt) { if (stmt->Predicate) stmt->Predicate = stmt->Predicate->Accept(this).As(); if (stmt->PositiveStatement) stmt->PositiveStatement = stmt->PositiveStatement->Accept(this).As(); if (stmt->NegativeStatement) stmt->NegativeStatement = stmt->NegativeStatement->Accept(this).As(); return stmt; } virtual RefPtr VisitSwitchStmt(SwitchStmt* stmt) { if (stmt->condition) stmt->condition = stmt->condition->Accept(this).As(); if (stmt->body) stmt->body = stmt->body->Accept(this).As(); return stmt; } virtual RefPtr VisitCaseStmt(CaseStmt* stmt) { if (stmt->expr) stmt->expr = stmt->expr->Accept(this).As(); return stmt; } virtual RefPtr VisitDefaultStmt(DefaultStmt* stmt) { return stmt; } virtual RefPtr VisitReturnStatement(ReturnStatementSyntaxNode* stmt) { if (stmt->Expression) stmt->Expression = stmt->Expression->Accept(this).As(); return stmt; } virtual RefPtr VisitVarDeclrStatement(VarDeclrStatementSyntaxNode* stmt) { stmt->decl = stmt->decl->Accept(this).As(); return stmt; } virtual RefPtr VisitWhileStatement(WhileStatementSyntaxNode* stmt) { if (stmt->Predicate) stmt->Predicate = stmt->Predicate->Accept(this).As(); if (stmt->Statement) stmt->Statement = stmt->Statement->Accept(this).As(); return stmt; } virtual RefPtr VisitExpressionStatement(ExpressionStatementSyntaxNode* stmt) { if (stmt->Expression) stmt->Expression = stmt->Expression->Accept(this).As(); return stmt; } virtual RefPtr VisitOperatorExpression(OperatorExpressionSyntaxNode* expr) { for (auto && child : expr->Arguments) child->Accept(this); return expr; } virtual RefPtr VisitConstantExpression(ConstantExpressionSyntaxNode* expr) { return expr; } virtual RefPtr VisitIndexExpression(IndexExpressionSyntaxNode* expr) { if (expr->BaseExpression) expr->BaseExpression = expr->BaseExpression->Accept(this).As(); if (expr->IndexExpression) expr->IndexExpression = expr->IndexExpression->Accept(this).As(); return expr; } virtual RefPtr VisitMemberExpression(MemberExpressionSyntaxNode * stmt) { if (stmt->BaseExpression) stmt->BaseExpression = stmt->BaseExpression->Accept(this).As(); return stmt; } virtual RefPtr VisitSwizzleExpression(SwizzleExpr * expr) { if (expr->base) expr->base->Accept(this); return expr; } virtual RefPtr VisitInvokeExpression(InvokeExpressionSyntaxNode* stmt) { stmt->FunctionExpr->Accept(this); for (auto & arg : stmt->Arguments) arg = arg->Accept(this).As(); return stmt; } virtual RefPtr VisitTypeCastExpression(TypeCastExpressionSyntaxNode * stmt) { if (stmt->Expression) stmt->Expression = stmt->Expression->Accept(this).As(); return stmt->Expression; } virtual RefPtr VisitVarExpression(VarExpressionSyntaxNode* expr) { return expr; } virtual RefPtr VisitParameter(ParameterSyntaxNode* param) { return param; } virtual RefPtr VisitGenericApp(GenericAppExpr* type) { return type; } virtual RefPtr VisitDeclrVariable(Variable* dclr) { if (dclr->Expr) dclr->Expr = dclr->Expr->Accept(this).As(); return dclr; } virtual TypeExp VisitTypeExp(TypeExp const& typeExp) { TypeExp result = typeExp; result.exp = typeExp.exp->Accept(this).As(); if (auto typeType = result.exp->Type.type.As()) { result.type = typeType->type; } return result; } virtual void VisitExtensionDecl(ExtensionDecl* /*decl*/) {} virtual void VisitConstructorDecl(ConstructorDecl* /*decl*/) {} virtual void visitSubscriptDecl(SubscriptDecl* decl) = 0; virtual void visitAccessorDecl(AccessorDecl* decl) = 0; virtual void visitInterfaceDecl(InterfaceDecl* /*decl*/) = 0; virtual void visitInheritanceDecl(InheritanceDecl* /*decl*/) = 0; virtual RefPtr VisitSharedTypeExpr(SharedTypeExpr* typeExpr) { return typeExpr; } virtual void VisitDeclGroup(DeclGroup* declGroup) { for (auto decl : declGroup->decls) { decl->Accept(this); } } virtual RefPtr visitInitializerListExpr(InitializerListExpr* expr) = 0; }; // Note(tfoley): These logically belong to `ExpressionType`, // but order-of-declaration stuff makes that tricky // // TODO(tfoley): These should really belong to the compilation context! // void RegisterBuiltinDecl( RefPtr decl, RefPtr modifier); void RegisterMagicDecl( RefPtr decl, RefPtr modifier); // Look up a magic declaration by its name RefPtr findMagicDecl( String const& name); // Create an instance of a syntax class by name SyntaxNodeBase* createInstanceOfSyntaxClassByName( String const& name); } // namespace Slang #endif