summaryrefslogtreecommitdiff
path: root/source/slang/slang-ast-decl.h
blob: 5b596ded0255191c919218d66125184d5031e3fd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
// slang-decl-defs.h

#pragma once

#include "slang-ast-base.h"

namespace Slang {

// Syntax class definitions for declarations.

// A group of declarations that should be treated as a unit
class DeclGroup: public DeclBase
{
    SLANG_AST_CLASS(DeclGroup)

    List<Decl*> decls;
};


// A "container" decl is a parent to other declarations
class ContainerDecl: public Decl
{
    SLANG_ABSTRACT_AST_CLASS(ContainerDecl)

    List<Decl*> members;

    template<typename T>
    FilteredMemberList<T> getMembersOfType()
    {
        return FilteredMemberList<T>(members);
    }

    bool isMemberDictionaryValid() const { return dictionaryLastCount == members.getCount(); }

    void invalidateMemberDictionary() { dictionaryLastCount = -1; }

    SLANG_UNREFLECTED   // We don't want to reflect the following fields

    // Denotes how much of Members has been placed into the dictionary/transparentMembers.
    // If this value equals the Members.getCount(), the dictionary is completely full and valid.
    // If it's >= 0, then the Members after dictionaryLastCount are all that need to be added.
    // If it < 0 it means that the dictionary/transparentMembers is invalid and needs to be recreated.
    Index dictionaryLastCount = 0;

    // Dictionary for looking up members by name.
    // This is built on demand before performing lookup.
    Dictionary<Name*, Decl*> memberDictionary;
    
    // A list of transparent members, to be used in lookup
    // Note: this is only valid if `memberDictionaryIsValid` is true
    List<TransparentMemberInfo> transparentMembers;
};

// Base class for all variable declarations
class VarDeclBase : public Decl
{
    SLANG_ABSTRACT_AST_CLASS(VarDeclBase)

    // type of the variable
    TypeExp type;

    Type* getType() { return type.type; }

    // Initializer expression (optional)
    Expr* initExpr = nullptr;
};

// Ordinary potentially-mutable variables (locals, globals, and member variables)
class VarDecl : public VarDeclBase
{
    SLANG_AST_CLASS(VarDecl)
};

// A variable declaration that is always immutable (whether local, global, or member variable)
class LetDecl : public VarDecl
{
    SLANG_AST_CLASS(LetDecl)
};

// 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
{
    SLANG_ABSTRACT_AST_CLASS(AggTypeDeclBase);
};

// An extension to apply to an existing type
class ExtensionDecl : public AggTypeDeclBase
{
    SLANG_AST_CLASS(ExtensionDecl)

    TypeExp targetType;
};

// Declaration of a type that represents some sort of aggregate
class AggTypeDecl : public  AggTypeDeclBase
{
    SLANG_ABSTRACT_AST_CLASS(AggTypeDecl)

    FilteredMemberList<VarDecl> getFields()
    {
        return getMembersOfType<VarDecl>();
    }
};

class StructDecl: public AggTypeDecl
{
    SLANG_AST_CLASS(StructDecl);
};

class ClassDecl : public AggTypeDecl
{
    SLANG_AST_CLASS(ClassDecl)
};


// TODO: Is it appropriate to treat an `enum` as an aggregate type?
// Most code that looks for, e.g., conformances assumes user-defined
// types are all `AggTypeDecl`, so this is the right choice for now
// if we want `enum` types to be able to implement interfaces, etc.
//
class EnumDecl : public AggTypeDecl
{
    SLANG_AST_CLASS(EnumDecl)

    Type* tagType = nullptr;
};

// A single case in an enum.
//
// E.g., in a declaration like:
//
//      enum Color { Red = 0, Green, Blue };
//
// The `Red = 0` is the declaration of the `Red`
// case, with `0` as an explicit expression for its
// _tag value_.
//
class EnumCaseDecl : public Decl
{
    SLANG_AST_CLASS(EnumCaseDecl)

    // type of the parent `enum`
    TypeExp type;

    Type* getType() { return type.type; }

    // Tag value
    Expr* tagExpr = nullptr;
};

// An interface which other types can conform to
class InterfaceDecl : public  AggTypeDecl
{
    SLANG_AST_CLASS(InterfaceDecl)
};


class TypeConstraintDecl : public  Decl
{
    SLANG_ABSTRACT_AST_CLASS(TypeConstraintDecl)

    const TypeExp& getSup() const;
    // Overrides should be public so base classes can access
    // Implement _getSupOverride on derived classes to change behavior of getSup, as if getSup is virtual
    const TypeExp& _getSupOverride() const;
};

// A kind of pseudo-member that represents an explicit
// or implicit inheritance relationship.
//
class InheritanceDecl : public TypeConstraintDecl
{
    SLANG_AST_CLASS(InheritanceDecl)

    // The type expression as written
    TypeExp base;

    // After checking, this dictionary will map members
    // required by the base type to their concrete
    // implementations in the type that contains
    // this inheritance declaration.
    RefPtr<WitnessTable> witnessTable;

    // Overrides should be public so base classes can access
    const TypeExp& _getSupOverride() const { return base; }
};

// TODO: may eventually need sub-classes for explicit/direct vs. implicit/indirect inheritance


// A declaration that represents a simple (non-aggregate) type
//
// TODO: probably all types will be aggregate decls eventually,
// so that we can easily store conformances/constraints on type variables
class SimpleTypeDecl : public Decl
{
    SLANG_ABSTRACT_AST_CLASS(SimpleTypeDecl)
};

// A `typedef` declaration
class TypeDefDecl : public SimpleTypeDecl
{
    SLANG_AST_CLASS(TypeDefDecl)
   
    TypeExp type;
};

class TypeAliasDecl : public TypeDefDecl
{
    SLANG_AST_CLASS(TypeAliasDecl)
};

// An 'assoctype' declaration, it is a container of inheritance clauses
class AssocTypeDecl : public AggTypeDecl
{
    SLANG_AST_CLASS(AssocTypeDecl)
};

// A 'type_param' declaration, which defines a generic
// entry-point parameter. Is a container of GenericTypeConstraintDecl
class GlobalGenericParamDecl : public AggTypeDecl
{
    SLANG_AST_CLASS(GlobalGenericParamDecl)
};

// A `__generic_value_param` declaration, which defines an existential
// value parameter (not a type parameter.
class GlobalGenericValueParamDecl : public VarDeclBase
{
    SLANG_AST_CLASS(GlobalGenericValueParamDecl)
};

// A scope for local declarations (e.g., as part of a statement)
class ScopeDecl : public  ContainerDecl
{
    SLANG_AST_CLASS(ScopeDecl)
};

// A function/initializer/subscript parameter (potentially mutable)
class ParamDecl : public VarDeclBase
{
    SLANG_AST_CLASS(ParamDecl)
};

// A parameter of a function declared in "modern" types (immutable unless explicitly `out` or `inout`)
class ModernParamDecl : public ParamDecl
{
    SLANG_AST_CLASS(ModernParamDecl)
};

// Base class for things that have parameter lists and can thus be applied to arguments ("called")
class CallableDecl : public ContainerDecl
{
    SLANG_ABSTRACT_AST_CLASS(CallableDecl)

    FilteredMemberList<ParamDecl> getParameters()
    {
        return getMembersOfType<ParamDecl>();
    }

    TypeExp returnType;

    // Fields related to redeclaration, so that we
    // can support multiple specialized variations
    // of the "same" logical function.
    //
    // This should also help us to support redeclaration
    // of functions when handling HLSL/GLSL.

    // The "primary" declaration of the function, which will
    // be used whenever we need to unique things.
    CallableDecl* primaryDecl = nullptr;

    // The next declaration of the "same" function (that is,
    // with the same `primaryDecl`).
    CallableDecl* nextDecl = nullptr;
};

// Base class for callable things that may also have a body that is evaluated to produce their result
class FunctionDeclBase : public CallableDecl
{
    SLANG_ABSTRACT_AST_CLASS(FunctionDeclBase)

    Stmt* body = nullptr;
};

// A constructor/initializer to create instances of a type
class ConstructorDecl : public FunctionDeclBase
{
    SLANG_AST_CLASS(ConstructorDecl)
};

// A subscript operation used to index instances of a type
class SubscriptDecl : public CallableDecl
{
    SLANG_AST_CLASS(SubscriptDecl)
};

    /// A property declaration that abstracts over storage with a getter/setter/etc.
class PropertyDecl : public ContainerDecl
{
    SLANG_AST_CLASS(PropertyDecl)

    TypeExp type;
};

// An "accessor" for a subscript or property
class AccessorDecl : public FunctionDeclBase
{
    SLANG_AST_CLASS(AccessorDecl)
};

class GetterDecl : public AccessorDecl
{
    SLANG_AST_CLASS(GetterDecl)
};
class SetterDecl : public AccessorDecl
{
    SLANG_AST_CLASS(SetterDecl)
};
class RefAccessorDecl : public AccessorDecl
{
    SLANG_AST_CLASS(RefAccessorDecl)
};

class FuncDecl : public FunctionDeclBase
{
    SLANG_AST_CLASS(FuncDecl)
};

class NamespaceDeclBase : public ContainerDecl
{
    SLANG_AST_CLASS(NamespaceDeclBase)
};

    // A `namespace` declaration inside some module, that provides
    // a named scope for declarations inside it.
    //
    // Note: Multiple `namespace` declarations with the same name
    // in a given module/file will be collapsed into a single
    // `NamespaceDecl` during parsing, so this declaration does
    // not directly represent what is present in the input syntax.
    //
class NamespaceDecl : public NamespaceDeclBase
{
    SLANG_AST_CLASS(NamespaceDecl)
};

    // A "module" of code (essentially, a single translation unit)
    // that provides a scope for some number of declarations.
class ModuleDecl : public NamespaceDeclBase
{
    SLANG_AST_CLASS(ModuleDecl)
    // The API-level module that this declaration belong to.
    //
    // This field allows lookup of the `Module` based on a
    // declaration nested under a `ModuleDecl` by following
    // its chain of parents.
    //
    Module* module = nullptr;

    SLANG_UNREFLECTED

        /// Map a type to the list of extensions of that type (if any) declared in this module
        ///
        /// This mapping is filled in during semantic checking, as `ExtensionDecl`s get checked.
        ///
    Dictionary<AggTypeDecl*, RefPtr<CandidateExtensionList>> mapTypeToCandidateExtensions;
};

    /// A declaration that brings members of another declaration or namespace into scope
class UsingDecl : public Decl
{
    SLANG_AST_CLASS(UsingDecl)

        /// An expression that identifies the entity (e.g., a namespace) to be brought into `scope`
    Expr* arg = nullptr;

    SLANG_UNREFLECTED
        /// The scope that the entity named by `arg` will be brought into
    Scope* scope = nullptr;
};

class ImportDecl : public Decl
{
    SLANG_AST_CLASS(ImportDecl)

    // The name of the module we are trying to import
    NameLoc moduleNameAndLoc;
    
    // The module that actually got imported
    ModuleDecl* importedModuleDecl = nullptr;

    SLANG_UNREFLECTED
    // The scope that we want to import into
    Scope* scope = nullptr;
};

// A generic declaration, parameterized on types/values
class GenericDecl : public ContainerDecl
{
    SLANG_AST_CLASS(GenericDecl)
    // The decl that is genericized...
    Decl* inner = nullptr;
};

class GenericTypeParamDecl : public SimpleTypeDecl
{
    SLANG_AST_CLASS(GenericTypeParamDecl)
    // 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;
};

// A constraint placed as part of a generic declaration
class GenericTypeConstraintDecl : public TypeConstraintDecl
{
    SLANG_AST_CLASS(GenericTypeConstraintDecl)

    // 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 super-type, respectively.
    TypeExp sub;
    TypeExp sup;

    // Overrides should be public so base classes can access
    const TypeExp& _getSupOverride() const { return sup; }
};

class GenericValueParamDecl : public VarDeclBase
{
    SLANG_AST_CLASS(GenericValueParamDecl)
};

// 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
{
    SLANG_AST_CLASS(EmptyDecl)
};

// A declaration used by the implementation to put syntax keywords
// into the current scope.
//
class SyntaxDecl : public Decl
{
    SLANG_AST_CLASS(SyntaxDecl)

    // What type of syntax node will be produced when parsing with this keyword?
    SyntaxClass<NodeBase> syntaxClass;

    SLANG_UNREFLECTED

    // Callback to invoke in order to parse syntax with this keyword.
    SyntaxParseCallback  parseCallback = nullptr;
    void*                parseUserData = nullptr;
};

// A declaration of an attribute to be used with `[name(...)]` syntax.
//
class AttributeDecl : public ContainerDecl
{
    SLANG_AST_CLASS(AttributeDecl)
    // What type of syntax node will be produced to represent this attribute.
    SyntaxClass<NodeBase> syntaxClass;
};

} // namespace Slang