summaryrefslogtreecommitdiffstats
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/slang/slang-ast-base.h2
-rw-r--r--source/slang/slang-ast-modifier.h17
-rw-r--r--source/slang/slang-ast-reflect.h3
-rw-r--r--source/slang/slang-ast-serialize.cpp1289
-rw-r--r--source/slang/slang-ast-serialize.h254
-rw-r--r--source/slang/slang-ast-support-types.h16
-rw-r--r--source/slang/slang-diagnostic-defs.h174
-rw-r--r--source/slang/slang-diagnostics.cpp141
-rw-r--r--source/slang/slang-diagnostics.h1
-rw-r--r--source/slang/slang.cpp13
-rw-r--r--source/slang/slang.vcxproj2
-rw-r--r--source/slang/slang.vcxproj.filters6
12 files changed, 1790 insertions, 128 deletions
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index 27ac8a437..847dada03 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -275,7 +275,7 @@ class Modifier : public SyntaxNode
Modifier* next = nullptr;
// The keyword that was used to introduce t that was used to name this modifier.
- Name* name;
+ Name* name = nullptr;
Name* getName() { return name; }
NameLoc getNameAndLoc() { return NameLoc(name, loc); }
diff --git a/source/slang/slang-ast-modifier.h b/source/slang/slang-ast-modifier.h
index 30ef1f921..1cbfab7c3 100644
--- a/source/slang/slang-ast-modifier.h
+++ b/source/slang/slang-ast-modifier.h
@@ -814,23 +814,6 @@ class HLSLTriangleAdjModifier : public HLSLGeometryShaderInputPrimitiveTypeModif
SLANG_CLASS(HLSLTriangleAdjModifier)
};
-
-// A modifier to be attached to syntax after we've computed layout
-class ComputedLayoutModifier : public Modifier
-{
- SLANG_CLASS(ComputedLayoutModifier)
-
- RefPtr<Layout> layout;
-};
-
-
-class TupleVarModifier : public Modifier
-{
- SLANG_CLASS(TupleVarModifier)
-
-// TupleFieldModifier* tupleField = nullptr;
-};
-
// A modifier to indicate that a constructor/initializer can be used
// to perform implicit type conversion, and to specify the cost of
// the conversion, if applied.
diff --git a/source/slang/slang-ast-reflect.h b/source/slang/slang-ast-reflect.h
index 8df8dbc38..3b055cc87 100644
--- a/source/slang/slang-ast-reflect.h
+++ b/source/slang/slang-ast-reflect.h
@@ -20,7 +20,8 @@
SLANG_FORCE_INLINE static bool isDerivedFrom(ASTNodeType type) { return int(type) >= int(kType) && int(type) <= int(ASTNodeType::LAST); } \
SLANG_CLASS_REFLECT_SUPER_##TYPE(SUPER) \
friend class ASTBuilder; \
- friend struct ASTConstructAccess;
+ friend struct ASTConstructAccess; \
+ friend struct ASTFieldAccess;
// Macro definitions - use the SLANG_ASTNode_ definitions to invoke the IMPL to produce the code
// injected into AST classes
diff --git a/source/slang/slang-ast-serialize.cpp b/source/slang/slang-ast-serialize.cpp
new file mode 100644
index 000000000..411e7a7ad
--- /dev/null
+++ b/source/slang/slang-ast-serialize.cpp
@@ -0,0 +1,1289 @@
+// slang-ast-serialize.cpp
+#include "slang-ast-serialize.h"
+
+#include "slang-ast-generated.h"
+#include "slang-ast-generated-macro.h"
+
+#include "slang-compiler.h"
+#include "slang-type-layout.h"
+
+#include "slang-ast-support-types.h"
+
+#include "../core/slang-byte-encode-util.h"
+
+namespace Slang {
+
+
+// Things stored as references:
+//
+// NodeBase derived types
+// Array
+//
+// RefObject derived types:
+//
+// Breadcrumb
+// StringRepresentation
+// Scope
+
+
+
+// Helpers to convert fields treated as values
+
+class ASTSerialReader;
+class ASTSerialWriter;
+
+template <typename NATIVE_TYPE, typename SERIAL_TYPE>
+static void _toSerialValue(ASTSerialWriter* writer, const NATIVE_TYPE& src, SERIAL_TYPE& dst)
+{
+ ASTSerialTypeInfo<NATIVE_TYPE>::toSerial(writer, &src, &dst);
+}
+
+template <typename SERIAL_TYPE, typename NATIVE_TYPE>
+static void _toNativeValue(ASTSerialReader* reader, const SERIAL_TYPE& src, NATIVE_TYPE& dst)
+{
+ ASTSerialTypeInfo<NATIVE_TYPE>::toNative(reader, &src, &dst);
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Serial <-> Native conversion !!!!!!!!!!!!!!!!!!!!!!!!
+
+
+// We need to have a way to map between the two.
+// If no mapping is needed, (just a copy), then we don't bother with the functions
+template <typename T>
+struct ASTSerialBasicTypeInfo
+{
+ typedef T NativeType;
+ typedef T SerialType;
+
+ // We want the alignment to be the same as the size of the type for basic types
+ // NOTE! Might be different from SLANG_ALIGN_OF(SerialType)
+ enum { SerialAlignment = sizeof(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial) { SLANG_UNUSED(writer); *(T*)serial = *(const T*)native; }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native) { SLANG_UNUSED(reader); *(T*)native = *(const T*)serial; }
+
+ static const ASTSerialType* getType()
+ {
+ static const ASTSerialType type = { sizeof(SerialType), uint8_t(SerialAlignment), &toSerial, &toNative };
+ return &type;
+ }
+};
+
+template <typename NATIVE_T, typename SERIAL_T>
+struct ASTSerialConvertTypeInfo
+{
+ typedef NATIVE_T NativeType;
+ typedef SERIAL_T SerialType;
+
+ enum { SerialAlignment = ASTSerialBasicTypeInfo<SERIAL_T>::SerialAlignment };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial) { SLANG_UNUSED(writer); *(SERIAL_T*)serial = SERIAL_T(*(const NATIVE_T*)native); }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native) { SLANG_UNUSED(reader); *(NATIVE_T*)native = NATIVE_T(*(const SERIAL_T*)serial); }
+};
+
+template <typename T>
+struct ASTSerialIdentityTypeInfo
+{
+ typedef T NativeType;
+ typedef T SerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial) { SLANG_UNUSED(writer); *(T*)serial = *(const T*)native; }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native) { SLANG_UNUSED(reader); *(T*)native = *(const T*)serial; }
+};
+
+// Don't need to convert the index type
+
+template <>
+struct ASTSerialTypeInfo<ASTSerialIndex> : public ASTSerialIdentityTypeInfo<ASTSerialIndex> {};
+
+// Implement for Basic Types
+
+template <>
+struct ASTSerialTypeInfo<uint8_t> : public ASTSerialBasicTypeInfo<uint8_t> {};
+template <>
+struct ASTSerialTypeInfo<uint16_t> : public ASTSerialBasicTypeInfo<uint16_t> {};
+template <>
+struct ASTSerialTypeInfo<uint32_t> : public ASTSerialBasicTypeInfo<uint32_t> {};
+template <>
+struct ASTSerialTypeInfo<uint64_t> : public ASTSerialBasicTypeInfo<uint64_t> {};
+
+template <>
+struct ASTSerialTypeInfo<int8_t> : public ASTSerialBasicTypeInfo<int8_t> {};
+template <>
+struct ASTSerialTypeInfo<int16_t> : public ASTSerialBasicTypeInfo<int16_t> {};
+template <>
+struct ASTSerialTypeInfo<int32_t> : public ASTSerialBasicTypeInfo<int32_t> {};
+template <>
+struct ASTSerialTypeInfo<int64_t> : public ASTSerialBasicTypeInfo<int64_t> {};
+
+template <>
+struct ASTSerialTypeInfo<float> : public ASTSerialBasicTypeInfo<float> {};
+template <>
+struct ASTSerialTypeInfo<double> : public ASTSerialBasicTypeInfo<double> {};
+
+// SamplerStateFlavor
+
+template <>
+struct ASTSerialTypeInfo<SamplerStateFlavor> : public ASTSerialConvertTypeInfo<SamplerStateFlavor, uint8_t> {};
+
+// TextureFlavor
+
+template <>
+struct ASTSerialTypeInfo<TextureFlavor>
+{
+ typedef TextureFlavor NativeType;
+ typedef uint16_t SerialType;
+ enum { SerialAlignment = sizeof(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial) { SLANG_UNUSED(writer); *(SerialType*)serial = ((const NativeType*)native)->flavor; }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native) { SLANG_UNUSED(reader); ((NativeType*)native)->flavor = *(const SerialType*)serial; }
+};
+
+// Fixed arrays
+
+template <typename T, size_t N>
+struct ASTSerialTypeInfo<T[N]>
+{
+ typedef ASTSerialTypeInfo<T> ElementASTSerialType;
+ typedef typename ElementASTSerialType::SerialType SerialElementType;
+
+ typedef T NativeType[N];
+ typedef SerialElementType SerialType[N];
+
+ enum { SerialAlignment = ASTSerialTypeInfo<T>::SerialAlignment };
+
+ static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ {
+ SerialElementType* serial = (SerialElementType*)outSerial;
+ const T* native = (const T*)inNative;
+ for (Index i = 0; i < Index(N); ++i)
+ {
+ ElementASTSerialType::toSerial(writer, native + i, serial + i);
+ }
+ }
+ static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ {
+ const SerialElementType* serial = (const SerialElementType*)inSerial;
+ T* native = (T*)outNative;
+ for (Index i = 0; i < Index(N); ++i)
+ {
+ ElementASTSerialType::toNative(reader, serial + i, native + i);
+ }
+ }
+};
+
+// Special case bool - as we can't rely on size alignment
+template <>
+struct ASTSerialTypeInfo<bool>
+{
+ typedef bool NativeType;
+ typedef uint8_t SerialType;
+
+ enum { SerialAlignment = sizeof(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ {
+ SLANG_UNUSED(writer);
+ *(SerialType*)outSerial = *(const NativeType*)inNative ? 1 : 0;
+ }
+ static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ {
+ SLANG_UNUSED(reader);
+ *(NativeType*)outNative = (*(const SerialType*)inSerial) != 0;
+ }
+};
+
+
+// Pointer
+// Could handle different pointer base types with some more template magic here, but instead went with Pointer type to keep
+// things simpler.
+template <typename T>
+struct ASTSerialTypeInfo<T*>
+{
+ typedef T* NativeType;
+ typedef ASTSerialIndex SerialType;
+
+ enum
+ {
+ SerialAlignment = SLANG_ALIGN_OF(SerialType)
+ };
+
+ static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ {
+ *(SerialType*)outSerial = writer->addPointer(*(T**)inNative);
+ }
+ static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ {
+ *(T**)outNative = reader->getPointer(*(const SerialType*)inSerial).dynamicCast<T>();
+ }
+};
+
+struct ASTSerialDeclRefBaseTypeInfo
+{
+ typedef DeclRefBase NativeType;
+ struct SerialType
+ {
+ ASTSerialIndex substitutions;
+ ASTSerialIndex decl;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ {
+ SerialType& serial = *(SerialType*)outSerial;
+ const NativeType& native = *(const NativeType*)inNative;
+
+ serial.decl = writer->addPointer(native.decl);
+ serial.substitutions = writer->addPointer(native.substitutions.substitutions);
+ }
+ static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ {
+ DeclRefBase& native = *(DeclRefBase*)(outNative);
+ const SerialType& serial = *(const SerialType*)inSerial;
+
+ native.decl = reader->getPointer(serial.decl).dynamicCast<Decl>();
+ native.substitutions.substitutions = reader->getPointer(serial.substitutions).dynamicCast<Substitutions>();
+ }
+ static const ASTSerialType* getType()
+ {
+ static const ASTSerialType type = { sizeof(SerialType), uint8_t(SerialAlignment), &toSerial, &toNative };
+ return &type;
+ }
+};
+
+template <typename T>
+struct ASTSerialTypeInfo<DeclRef<T>> : public ASTSerialDeclRefBaseTypeInfo {};
+
+// MatrixCoord can just go as is
+template <>
+struct ASTSerialTypeInfo<MatrixCoord> : ASTSerialIdentityTypeInfo<MatrixCoord> {};
+
+// SourceLoc
+
+// Make the type exposed, so we can look for it if we want to remap.
+template <>
+struct ASTSerialTypeInfo<SourceLoc>
+{
+ typedef SourceLoc NativeType;
+ typedef ASTSerialSourceLoc SerialType;
+ enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialSourceLoc) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ {
+ *(SerialType*)outSerial = writer->addSourceLoc(*(const NativeType*)inNative);
+ }
+ static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ {
+ *(NativeType*)outNative = reader->getSourceLoc(*(const SerialType*)inSerial);
+ }
+};
+
+// List
+template <typename T, typename ALLOCATOR>
+struct ASTSerialTypeInfo<List<T, ALLOCATOR>>
+{
+ typedef List<T, ALLOCATOR> NativeType;
+ typedef ASTSerialIndex SerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ dst = writer->addArray(src.getBuffer(), src.getCount());
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& dst = *(NativeType*)native;
+ auto& src = *(const SerialType*)serial;
+
+ reader->getArray(src, dst);
+ }
+};
+
+// Dictionary
+template <typename KEY, typename VALUE>
+struct ASTSerialTypeInfo<Dictionary<KEY, VALUE>>
+{
+ typedef Dictionary<KEY, VALUE> NativeType;
+ struct SerialType
+ {
+ ASTSerialIndex keys; ///< Index an array
+ ASTSerialIndex values; ///< Index an array
+ };
+
+ typedef typename ASTSerialTypeInfo<KEY>::SerialType KeySerialType;
+ typedef typename ASTSerialTypeInfo<VALUE>::SerialType ValueSerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialIndex) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ List<KeySerialType> keys;
+ List<ValueSerialType> values;
+
+ Index count = Index(src.Count());
+ keys.setCount(count);
+ values.setCount(count);
+
+ Index i = 0;
+ for (const auto& pair : src)
+ {
+ ASTSerialTypeInfo<KEY>::toSerial(writer, &pair.Key, &keys[i]);
+ ASTSerialTypeInfo<VALUE>::toSerial(writer, &pair.Value, &values[i]);
+ i++;
+ }
+
+ dst.keys = writer->addArray(keys.getBuffer(), count);
+ dst.values = writer->addArray(values.getBuffer(), count);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ // Clear it
+ dst = NativeType();
+
+ List<KEY> keys;
+ List<VALUE> values;
+
+ reader->getArray(src.keys, keys);
+ reader->getArray(src.values, values);
+
+ SLANG_ASSERT(keys.getCount() == values.getCount());
+
+ const Index count = keys.getCount();
+ for (Index i = 0; i < count; ++i)
+ {
+ dst.Add(keys[i], values[i]);
+ }
+ }
+};
+
+// SyntaxClass<T>
+template <typename T>
+struct ASTSerialTypeInfo<SyntaxClass<T>>
+{
+ typedef SyntaxClass<T> NativeType;
+ typedef uint16_t SerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ SLANG_UNUSED(writer);
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+ dst = SerialType(src.classInfo->m_classId);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ SLANG_UNUSED(reader);
+ auto& src = *(const SerialType*)native;
+ auto& dst = *(NativeType*)serial;
+ dst.classInfo = ReflectClassInfo::getInfo(ASTNodeType(src));
+ }
+};
+
+// Handle RefPtr - just convert into * to do the conversion
+template <typename T>
+struct ASTSerialTypeInfo<RefPtr<T>>
+{
+ typedef RefPtr<T> NativeType;
+ typedef typename ASTSerialTypeInfo<T*>::SerialType SerialType;
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ T* obj = src;
+ ASTSerialTypeInfo<T*>::toSerial(writer, &obj, serial);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ T* obj = nullptr;
+ ASTSerialTypeInfo<T*>::toNative(reader, serial, &obj);
+ *(NativeType*)native = obj;
+ }
+};
+
+// QualType
+
+template <>
+struct ASTSerialTypeInfo<QualType>
+{
+ typedef QualType NativeType;
+ struct SerialType
+ {
+ ASTSerialIndex type;
+ uint8_t isLeftValue;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialIndex) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* inNative, void* outSerial)
+ {
+ auto dst = (SerialType*)outSerial;
+ auto src = (const NativeType*)inNative;
+ dst->isLeftValue = src->isLeftValue ? 1 : 0;
+ dst->type = writer->addPointer(src->type);
+ }
+ static void toNative(ASTSerialReader* reader, const void* inSerial, void* outNative)
+ {
+ auto src = (const SerialType*)inSerial;
+ auto dst = (NativeType*)outNative;
+ dst->type = reader->getPointer(src->type).dynamicCast<Type>();
+ dst->isLeftValue = src->isLeftValue != 0;
+ }
+};
+
+
+// LookupResult::Breadcrumb
+template <>
+struct ASTSerialTypeInfo<LookupResultItem::Breadcrumb>
+{
+ typedef LookupResultItem::Breadcrumb NativeType;
+ struct SerialType
+ {
+ NativeType::Kind kind;
+ NativeType::ThisParameterMode thisParameterMode;
+ ASTSerialTypeInfo<DeclRef<Decl>>::SerialType declRef;
+ ASTSerialTypeInfo<RefPtr<NativeType>> next;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ dst.kind = src.kind;
+ dst.thisParameterMode = src.thisParameterMode;
+ _toSerialValue(writer, src.declRef, dst.declRef);
+ _toSerialValue(writer, src.next, dst.next);
+ }
+
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& dst = *(NativeType*)native;
+ auto& src = *(const SerialType*)serial;
+
+ dst.kind = src.kind;
+ dst.thisParameterMode = src.thisParameterMode;
+ _toNativeValue(reader, src.declRef, dst.declRef);
+ _toNativeValue(reader, src.next, dst.next);
+ }
+};
+
+// LookupResultItem
+template <>
+struct ASTSerialTypeInfo<LookupResultItem>
+{
+ typedef LookupResultItem NativeType;
+ struct SerialType
+ {
+ ASTSerialTypeInfo<DeclRef<Decl>>::SerialType declRef;
+ ASTSerialTypeInfo<RefPtr<NativeType::Breadcrumb>> breadcrumbs;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ _toSerialValue(writer, src.declRef, dst.declRef);
+ _toSerialValue(writer, src.breadcrumbs, dst.breadcrumbs);
+ }
+
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& dst = *(NativeType*)native;
+ auto& src = *(const SerialType*)serial;
+
+ _toNativeValue(reader, src.declRef, dst.declRef);
+ _toNativeValue(reader, src.breadcrumbs, dst.breadcrumbs);
+ }
+};
+
+// LookupResult
+template <>
+struct ASTSerialTypeInfo<LookupResult>
+{
+ typedef LookupResult NativeType;
+ typedef ASTSerialIndex SerialType;
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ if (src.isOverloaded())
+ {
+ // Save off as an array
+ dst = writer->addArray(src.items.getBuffer(), src.items.getCount());
+ }
+ else if (src.item.declRef.getDecl())
+ {
+ dst = writer->addArray(&src.item, 1);
+ }
+ else
+ {
+ dst = ASTSerialIndex(0);
+ }
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& dst = *(NativeType*)native;
+ auto& src = *(const SerialType*)serial;
+
+ // Initialize
+ dst = NativeType();
+
+ List<LookupResultItem> items;
+ reader->getArray(src, items);
+
+ if (items.getCount() == 1)
+ {
+ dst.item = items[0];
+ }
+ else
+ {
+ dst.items.swapWith(items);
+ // We have to set item such that it is valid/member of items, if items is non empty
+ dst.item = dst.items[0];
+ }
+ }
+};
+
+
+// GlobalGenericParamSubstitution::ConstraintArg
+template <>
+struct ASTSerialTypeInfo<GlobalGenericParamSubstitution::ConstraintArg>
+{
+ typedef GlobalGenericParamSubstitution::ConstraintArg NativeType;
+ struct SerialType
+ {
+ ASTSerialIndex decl;
+ ASTSerialIndex val;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialIndex) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& dst = *(SerialType*)serial;
+ auto& src = *(const NativeType*)native;
+
+ dst.decl = writer->addPointer(src.decl);
+ dst.val = writer->addPointer(src.val);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ dst.decl = reader->getPointer(src.decl).dynamicCast<Decl>();
+ dst.val = reader->getPointer(src.val).dynamicCast<Val>();
+ }
+};
+
+// ExpandedSpecializationArg
+template <>
+struct ASTSerialTypeInfo<ExpandedSpecializationArg>
+{
+ typedef ExpandedSpecializationArg NativeType;
+ struct SerialType
+ {
+ ASTSerialIndex val;
+ ASTSerialIndex witness;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialIndex) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& dst = *(SerialType*)serial;
+ auto& src = *(const NativeType*)native;
+
+ dst.witness = writer->addPointer(src.witness);
+ dst.val = writer->addPointer(src.val);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ dst.witness = reader->getPointer(src.witness).dynamicCast<Val>();
+ dst.val = reader->getPointer(src.val).dynamicCast<Val>();
+ }
+};
+
+// TypeExp
+template <>
+struct ASTSerialTypeInfo<TypeExp>
+{
+ typedef TypeExp NativeType;
+ struct SerialType
+ {
+ ASTSerialIndex type;
+ ASTSerialIndex expr;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(ASTSerialIndex) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& dst = *(SerialType*)serial;
+ auto& src = *(const NativeType*)native;
+
+ dst.type = writer->addPointer(src.type);
+ dst.expr = writer->addPointer(src.exp);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ dst.type = reader->getPointer(src.type).dynamicCast<Type>();
+ dst.exp = reader->getPointer(src.type).dynamicCast<Expr>();
+ }
+};
+
+// DeclCheckStateExt
+template <>
+struct ASTSerialTypeInfo<DeclCheckStateExt>
+{
+ typedef DeclCheckStateExt NativeType;
+ typedef DeclCheckStateExt::RawType SerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ SLANG_UNUSED(writer);
+ *(SerialType*)serial = (*(const NativeType*)native).getRaw();
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ SLANG_UNUSED(reader);
+ (*(NativeType*)serial).setRaw(*(const SerialType*)native);
+ }
+};
+
+// Modifiers
+template <>
+struct ASTSerialTypeInfo<Modifiers>
+{
+ typedef Modifiers NativeType;
+ typedef ASTSerialIndex SerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ // We need to make into an array
+ List<ASTSerialIndex> modifierIndices;
+ for (Modifier* modifier : *(NativeType*)native)
+ {
+ modifierIndices.add(writer->addPointer(modifier));
+ }
+ *(SerialType*)serial = writer->addArray(modifierIndices.getBuffer(), modifierIndices.getCount());
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ List<Modifier*> modifiers;
+ reader->getArray(*(const SerialType*)serial, modifiers);
+
+ Modifier* prev = nullptr;
+ for (Modifier* modifier : modifiers)
+ {
+ if (prev)
+ {
+ prev->next = modifier;
+ }
+ }
+
+ NativeType& dst = *(NativeType*)native;
+ dst.first = modifiers.getCount() > 0 ? modifiers[0] : nullptr;
+ }
+};
+
+// ImageFormat
+template <>
+struct ASTSerialTypeInfo<ImageFormat> : public ASTSerialConvertTypeInfo<ImageFormat, uint8_t> {};
+
+// Stage
+template <>
+struct ASTSerialTypeInfo<Stage> : public ASTSerialConvertTypeInfo<Stage, uint8_t> {};
+
+// TokenType
+template <>
+struct ASTSerialTypeInfo<TokenType> : public ASTSerialConvertTypeInfo<TokenType, uint8_t> {};
+
+// BaseType
+template <>
+struct ASTSerialTypeInfo<BaseType> : public ASTSerialConvertTypeInfo<BaseType, uint8_t> {};
+
+// SemanticVersion
+template <>
+struct ASTSerialTypeInfo<SemanticVersion> : public ASTSerialIdentityTypeInfo<SemanticVersion> {};
+
+// ASTNodeType
+template <>
+struct ASTSerialTypeInfo<ASTNodeType> : public ASTSerialConvertTypeInfo<ASTNodeType, uint16_t> {};
+
+// String
+template <>
+struct ASTSerialTypeInfo<String>
+{
+ typedef String NativeType;
+ typedef ASTSerialIndex SerialType;
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ *(SerialType*)serial = writer->addString(src);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+ dst = reader->getString(src);
+ }
+};
+
+// Token
+template <>
+struct ASTSerialTypeInfo<Token>
+{
+ typedef Token NativeType;
+ struct SerialType
+ {
+ ASTSerialTypeInfo<BaseType>::SerialType type;
+ ASTSerialTypeInfo<SourceLoc>::SerialType loc;
+ ASTSerialIndex name;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ ASTSerialTypeInfo<TokenType>::toSerial(writer, &src.type, &dst.type);
+ ASTSerialTypeInfo<SourceLoc>::toSerial(writer, &src.loc, &dst.loc);
+ dst.name = writer->addName(src.getName());
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ dst.flags = 0;
+ dst.charsNameUnion.chars = nullptr;
+
+ ASTSerialTypeInfo<TokenType>::toNative(reader, &src.type, &dst.type);
+ ASTSerialTypeInfo<SourceLoc>::toNative(reader, &src.loc, &dst.loc);
+
+ if (src.name != ASTSerialIndex(0))
+ {
+ dst.charsNameUnion.name = reader->getName(src.name);
+ dst.flags |= TokenFlag::Name;
+ }
+ }
+};
+
+// NameLoc
+template <>
+struct ASTSerialTypeInfo<NameLoc>
+{
+ typedef NameLoc NativeType;
+ struct SerialType
+ {
+ ASTSerialTypeInfo<SourceLoc>::SerialType loc;
+ ASTSerialIndex name;
+ };
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+
+ dst.name = writer->addName(src.name);
+ ASTSerialTypeInfo<SourceLoc>::toSerial(writer, &src.loc, &dst.loc);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ dst.name = reader->getName(src.name);
+ ASTSerialTypeInfo<SourceLoc>::toNative(reader, &src.loc, &dst.loc);
+ }
+};
+
+// DiagnosticInfo
+template <>
+struct ASTSerialTypeInfo<const DiagnosticInfo*>
+{
+ typedef const DiagnosticInfo* NativeType;
+ typedef ASTSerialIndex SerialType;
+
+ enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) };
+
+ static void toSerial(ASTSerialWriter* writer, const void* native, void* serial)
+ {
+ auto& src = *(const NativeType*)native;
+ auto& dst = *(SerialType*)serial;
+ dst = src ? writer->addString(UnownedStringSlice(src->name)) : ASTSerialIndex(0);
+ }
+ static void toNative(ASTSerialReader* reader, const void* serial, void* native)
+ {
+ auto& src = *(const SerialType*)serial;
+ auto& dst = *(NativeType*)native;
+
+ if (src == ASTSerialIndex(0))
+ {
+ dst = nullptr;
+ }
+ else
+ {
+ dst = findDiagnosticByName(reader->getStringSlice(src));
+ }
+ }
+};
+
+// !!!!!!!!!!!!!!!!!!!!! ASTSerialGetType<T> !!!!!!!!!!!!!!!!!!!!!!!!!!!
+// Getting the type info, let's use a static variable to hold the state to keep simple
+
+template <typename T>
+struct ASTSerialGetType
+{
+ static const ASTSerialType* getType()
+ {
+ typedef ASTSerialTypeInfo<T> Info;
+ static const ASTSerialType type = { sizeof(typename Info::SerialType), uint8_t(Info::SerialAlignment), &Info::toSerial, &Info::toNative };
+ return &type;
+ }
+};
+
+// Special case DeclRef, because it always uses the same type
+template <typename T>
+struct ASTSerialGetType<DeclRef<T>>
+{
+ static const ASTSerialType* getType() { return ASTSerialDeclRefBaseTypeInfo::getType(); }
+};
+
+// !!!!!!!!!!!!!!!!!!!!!! Generate fields for a type !!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+template <typename T>
+ASTSerialField _calcField(const char* name, T& in)
+{
+ uint8_t* ptr = &reinterpret_cast<uint8_t&>(in);
+
+ ASTSerialField field;
+ field.name = name;
+ field.type = ASTSerialGetType<T>::getType();
+ // This only works because we in is an offset from 1
+ field.nativeOffset = uint32_t(size_t(ptr) - 1);
+ field.serialOffset = 0;
+ return field;
+}
+
+static ASTSerialClass _makeClass(MemoryArena* arena, ASTNodeType type, const List<ASTSerialField>& fields)
+{
+ ASTSerialClass cls = {};
+ cls.type = type;
+ cls.fieldsCount = fields.getCount();
+ cls.fields = arena->allocateAndCopyArray(fields.getBuffer(), fields.getCount());
+ return cls;
+}
+
+#define SLANG_AST_SERIAL_FIELD(FIELD_NAME, TYPE, param) fields.add(_calcField(#FIELD_NAME, obj->FIELD_NAME));
+
+// Note that the obj point is not nullptr, because some compilers notice this is 'indexing from null'
+// and warn/error. So we offset from 1.
+#define SLANG_AST_SERIAL_MAKE_CLASS(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \
+{ \
+ NAME* obj = (NAME*)1; \
+ SLANG_UNUSED(obj); \
+ fields.clear(); \
+ SLANG_FIELDS_ASTNode_##NAME(SLANG_AST_SERIAL_FIELD, param) \
+ outClasses[Index(ASTNodeType::NAME)] = _makeClass(arena, ASTNodeType::NAME, fields); \
+}
+
+struct ASTFieldAccess
+{
+ static void calcClasses(MemoryArena* arena, ASTSerialClass outClasses[Index(ASTNodeType::CountOf)])
+ {
+ List<ASTSerialField> fields;
+ SLANG_ALL_ASTNode_NodeBase(SLANG_AST_SERIAL_MAKE_CLASS, _)
+ }
+};
+
+ASTSerialClasses::ASTSerialClasses():
+ m_arena(2048)
+{
+ memset(m_classes, 0, sizeof(m_classes));
+ ASTFieldAccess::calcClasses(&m_arena, m_classes);
+
+ // Now work out the layout
+ for (Index i = 0; i < SLANG_COUNT_OF(m_classes); ++i)
+ {
+ // Set up each class in order, from lowest to highest index
+ // Doing so means super class is always setup
+ ASTSerialClass& serialClass = m_classes[i];
+
+ const ReflectClassInfo* info = ReflectClassInfo::getInfo(serialClass.type);
+
+ size_t maxAlignment = 1;
+ size_t offset = 0;
+
+ const ReflectClassInfo* superInfo = info->m_superClass;
+ if (superInfo)
+ {
+ ASTSerialClass& superSerialInfo = m_classes[superInfo->m_classId];
+
+ // If it's been setup, then alignment must be non zero.
+ // The ordering of ASTNodeType, should mean type have larger ASTNodeType greater than supers ASTNodeType.
+ SLANG_ASSERT(superSerialInfo.alignment != 0);
+
+ // Must be a power of 2
+ SLANG_ASSERT((superSerialInfo.alignment & (superSerialInfo.alignment - 1)) == 0);
+
+ maxAlignment = superSerialInfo.alignment;
+ offset = superSerialInfo.size;
+
+ // Check it is correctly aligned
+ SLANG_ASSERT((offset & (maxAlignment - 1)) == 0);
+ }
+
+ // Okay, go through fields setting their offset
+ ASTSerialField* field = serialClass.fields;
+ for (Index j = 0; j < serialClass.fieldsCount; j++)
+ {
+ size_t alignment = field->type->serialAlignment;
+ // Make sure the offset is aligned for the field requirement
+ offset = (offset + alignment - 1) & ~(alignment - 1);
+
+ // Save the field offset
+ field->serialOffset = uint32_t(offset);
+
+ // Move past the field
+ offset += field->type->serialSizeInBytes;
+
+ // Calc the maximum alignment
+ maxAlignment = (alignment > maxAlignment) ? alignment : maxAlignment;
+ }
+
+ // Align with maximum alignment
+ offset += (offset + maxAlignment - 1) & ~(maxAlignment - 1);
+
+ serialClass.alignment = uint8_t(maxAlignment);
+ serialClass.size = uint32_t(offset);
+ }
+}
+
+
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ASTSerialWriter::ASTSerialWriter(ASTSerialClasses* classes) :
+ m_arena(2048),
+ m_classes(classes)
+{
+ // 0 is always the null pointer
+ m_entries.add(nullptr);
+ m_ptrMap.Add(nullptr, 0);
+}
+
+ASTSerialIndex ASTSerialWriter::addPointer(const NodeBase* node)
+{
+ // Null is always 0
+ if (node == nullptr)
+ {
+ return ASTSerialIndex(0);
+ }
+ // Look up in the map
+ Index* indexPtr = m_ptrMap.TryGetValue(node);
+ if (indexPtr)
+ {
+ return ASTSerialIndex(*indexPtr);
+ }
+
+ const ASTSerialClass* serialClass = m_classes->getSerialClass(node->astNodeType);
+
+ typedef ASTSerialInfo::NodeEntry NodeEntry;
+
+ NodeEntry* nodeEntry = (NodeEntry*)m_arena.allocateAligned(sizeof(NodeEntry) + serialClass->size, 8);
+
+ nodeEntry->type = ASTSerialInfo::Type::Node;
+ nodeEntry->astNodeType = uint16_t(node->astNodeType);
+ nodeEntry->nextAlignment = 0;
+
+ auto index = _add(node, nodeEntry);
+
+ uint8_t* serialPayload = (uint8_t*)(nodeEntry + 1);
+
+ while (serialClass)
+ {
+ for (Index i = 0; i < serialClass->fieldsCount; ++i)
+ {
+ auto field = serialClass->fields[i];
+ // Work out the offsets
+ auto srcField = ((const uint8_t*)node) + field.nativeOffset;
+ auto dstField = serialPayload + field.serialOffset;
+
+ field.type->toSerialFunc(this, srcField, dstField);
+ }
+ // Get the super class
+ const ReflectClassInfo* reflectInfo = ReflectClassInfo::getInfo(serialClass->type);
+ const ReflectClassInfo* superReflectInfo = reflectInfo->m_superClass;
+
+ serialClass = superReflectInfo ? m_classes->getSerialClass(ASTNodeType(superReflectInfo->m_classId)) : nullptr;
+ }
+
+ return index;
+}
+
+ASTSerialIndex ASTSerialWriter::addPointer(const RefObject* obj)
+{
+ // Null is always 0
+ if (obj == nullptr)
+ {
+ return ASTSerialIndex(0);
+ }
+ // Look up in the map
+ Index* indexPtr = m_ptrMap.TryGetValue(obj);
+ if (indexPtr)
+ {
+ return ASTSerialIndex(*indexPtr);
+ }
+
+ if (auto stringRep = dynamicCast<StringRepresentation>(obj))
+ {
+ ASTSerialIndex index = addString(StringRepresentation::asSlice(stringRep));
+ m_ptrMap.Add(obj, Index(index));
+ return index;
+ }
+ else if (auto breadcrumb = dynamicCast<LookupResultItem::Breadcrumb>(obj))
+ {
+ typedef ASTSerialTypeInfo<LookupResultItem::Breadcrumb> TypeInfo;
+ typedef ASTSerialInfo::RefObjectEntry RefObjectEntry;
+
+ RefObjectEntry* refEntry = (RefObjectEntry*)m_arena.allocateAligned(sizeof(RefObjectEntry) + sizeof(TypeInfo::SerialType), 8);
+
+ refEntry->type = ASTSerialInfo::Type::RefObject;
+ refEntry->subType = RefObjectEntry::SubType::Breadcrumb;
+
+ auto index = _add(breadcrumb, refEntry);
+
+ // Do any conversion
+ TypeInfo::toSerial(this, breadcrumb, refEntry + 1);
+ return index;
+ }
+ else if (auto name = dynamicCast<const Name>(obj))
+ {
+ return addName(name);
+ }
+ else if (auto scope = dynamicCast<Scope>(obj))
+ {
+ // We don't serialize scope
+ return ASTSerialIndex(0);
+ }
+ else if (auto module = dynamicCast<Module>(obj))
+ {
+ // We don't serialize Module
+ return ASTSerialIndex(0);
+ }
+
+ SLANG_ASSERT(!"Unhandled type");
+ return ASTSerialIndex(0);
+}
+
+ASTSerialIndex ASTSerialWriter::addString(const UnownedStringSlice& slice)
+{
+ typedef ByteEncodeUtil Util;
+ typedef ASTSerialInfo::StringEntry StringEntry;
+
+ if (slice.getLength() == 0)
+ {
+ return ASTSerialIndex(0);
+ }
+
+ Index newIndex = m_entries.getCount();
+
+ Index* indexPtr = m_sliceMap.TryGetValueOrAdd(slice, newIndex);
+ if (indexPtr)
+ {
+ return ASTSerialIndex(*indexPtr);
+ }
+
+ // Okay we need to add the string
+
+ uint8_t encodeBuf[Util::kMaxLiteEncodeUInt32];
+ const int encodeCount = Util::encodeLiteUInt32(uint32_t(slice.getLength()), encodeBuf);
+
+ StringEntry* entry = (StringEntry*)m_arena.allocateUnaligned(sizeof(StringEntry) + encodeCount + slice.getLength());
+ entry->nextAlignment = 0;
+ entry->type = ASTSerialInfo::Type::String;
+
+ uint8_t* dst = (uint8_t*)(entry + 1);
+ for (int i = 0; i < encodeCount; ++i)
+ {
+ dst[i] = encodeBuf[i];
+ }
+
+ memcpy(dst + encodeCount, slice.begin(), slice.getLength());
+
+ m_entries.add(entry);
+ return ASTSerialIndex(newIndex);
+}
+
+
+ASTSerialIndex ASTSerialWriter::addString(const String& in)
+{
+ return addPointer(in.getStringRepresentation());
+}
+
+ASTSerialIndex ASTSerialWriter::addName(const Name* name)
+{
+ if (name == nullptr)
+ {
+ return ASTSerialIndex(0);
+ }
+
+ // Look it up
+ Index* indexPtr = m_ptrMap.TryGetValue(name);
+ if (indexPtr)
+ {
+ return ASTSerialIndex(*indexPtr);
+ }
+
+ ASTSerialIndex index = addString(name->text);
+ m_ptrMap.Add(name, Index(index));
+ return index;
+}
+
+ASTSerialSourceLoc ASTSerialWriter::addSourceLoc(SourceLoc sourceLoc)
+{
+ SLANG_UNUSED(sourceLoc);
+ return 0;
+}
+
+ASTSerialIndex ASTSerialWriter::_addArray(size_t elementSize, const void* elements, Index elementCount)
+{
+ typedef ASTSerialInfo::ArrayEntry Entry;
+
+ if (elementCount == 0)
+ {
+ return ASTSerialIndex(0);
+ }
+
+ size_t payloadSize = elementCount * elementSize;
+
+ Entry* entry = (Entry*)m_arena.allocateAligned(sizeof(Entry) + payloadSize, 8);
+
+ entry->type = ASTSerialInfo::Type::Array;
+ entry->nextAlignment = 0;
+ entry->elementSize = uint16_t(elementSize);
+ entry->elementCount = uint32_t(elementCount);
+
+ memcpy(entry + 1, elements, payloadSize);
+
+ m_entries.add(entry);
+ ASTSerialIndex index = ASTSerialIndex(m_entries.getCount() - 1);
+
+ // We don't add to a pointer map, because arrays are not shared
+
+ // Do the conversion
+
+ return index;
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialReader !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+ASTSerialPointer ASTSerialReader::getPointer(ASTSerialIndex index)
+{
+ SLANG_UNUSED(index);
+ return ASTSerialPointer();
+}
+
+String ASTSerialReader::getString(ASTSerialIndex index)
+{
+ SLANG_UNUSED(index);
+ return String();
+}
+
+Name* ASTSerialReader::getName(ASTSerialIndex index)
+{
+ if (index == ASTSerialIndex(0))
+ {
+ return nullptr;
+ }
+ return nullptr;
+}
+
+UnownedStringSlice ASTSerialReader::getStringSlice(ASTSerialIndex index)
+{
+ SLANG_UNUSED(index);
+ return UnownedStringSlice();
+}
+
+SourceLoc ASTSerialReader::getSourceLoc(ASTSerialSourceLoc loc)
+{
+ SLANG_UNUSED(loc);
+ return SourceLoc();
+}
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerializeUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+/* static */SlangResult ASTSerializeUtil::selfTest()
+{
+ RefPtr<ASTSerialClasses> classes = new ASTSerialClasses;
+
+ {
+ struct Thing
+ {
+ Module* node;
+ };
+ Thing thing;
+
+ //Pointer pointer(thing.node);
+
+ auto field = _calcField("node", thing.node);
+
+
+ const ASTSerialType* type = ASTSerialGetType<Type*>::getType();
+ SLANG_UNUSED(type);
+ }
+
+ {
+ const ASTSerialType* type = ASTSerialGetType<int[10]>::getType();
+ SLANG_UNUSED(type);
+ }
+
+ {
+ const ASTSerialType* type = ASTSerialGetType<bool[3]>::getType();
+ SLANG_UNUSED(type);
+ }
+
+ {
+ const ASTSerialType* type = ASTSerialGetType<Type*[3]>::getType();
+ SLANG_UNUSED(type);
+ }
+
+ return SLANG_OK;
+}
+
+
+} // namespace Slang
diff --git a/source/slang/slang-ast-serialize.h b/source/slang/slang-ast-serialize.h
new file mode 100644
index 000000000..a20da2e37
--- /dev/null
+++ b/source/slang/slang-ast-serialize.h
@@ -0,0 +1,254 @@
+// slang-ast-serialize.h
+#ifndef SLANG_AST_SERIALIZE_H
+#define SLANG_AST_SERIALIZE_H
+
+#include <type_traits>
+
+#include "slang-ast-support-types.h"
+#include "slang-ast-all.h"
+
+namespace Slang
+{
+
+// Type used to implement mechanisms to convert to and from serial types.
+template <typename T>
+struct ASTSerialTypeInfo;
+
+struct ASTSerialInfo
+{
+ enum class Type : uint8_t
+ {
+ String, ///< String
+ Node, ///< NodeBase derived
+ RefObject, ///< RefObject derived types
+ Array, ///< Array
+ };
+
+ struct Entry
+ {
+ Type type;
+ uint8_t nextAlignment; ///< Alignment of next entry
+ };
+
+ struct StringEntry : Entry
+ {
+ };
+
+ struct NodeEntry : Entry
+ {
+ uint16_t astNodeType;
+ uint32_t _pad0;
+ };
+
+ struct RefObjectEntry : Entry
+ {
+ enum class SubType : uint8_t
+ {
+ Breadcrumb,
+ };
+ SubType subType;
+ uint32_t _pad0;
+ };
+
+ struct ArrayEntry : Entry
+ {
+ uint16_t elementSize;
+ uint32_t elementCount;
+ };
+};
+
+enum class ASTSerialIndex : uint32_t;
+typedef uint32_t ASTSerialSourceLoc;
+
+/* A type to convert pointers into types such that they can be passed around to readers/writers without
+having to know the specific type. If there was a base class that all the serialized types derived from,
+that was dynamically castable this would not be necessary */
+struct ASTSerialPointer
+{
+ enum class Kind
+ {
+ Unknown,
+ RefObject,
+ NodeBase
+ };
+
+ // Helpers so we can choose what kind of pointer we have based on the (unused) type of the pointer passed in
+ SLANG_FORCE_INLINE RefObject* _get(const RefObject*) { return m_kind == Kind::RefObject ? reinterpret_cast<RefObject*>(m_ptr) : nullptr; }
+ SLANG_FORCE_INLINE NodeBase* _get(const NodeBase*) { return m_kind == Kind::NodeBase ? reinterpret_cast<NodeBase*>(m_ptr) : nullptr; }
+
+ template <typename T>
+ T* dynamicCast()
+ {
+ return Slang::dynamicCast<T>(_get((T*)nullptr));
+ }
+
+ ASTSerialPointer() :
+ m_kind(Kind::Unknown),
+ m_ptr(nullptr)
+ {
+ }
+
+ ASTSerialPointer(RefObject* in) :
+ m_kind(Kind::RefObject),
+ m_ptr((void*)in)
+ {
+ }
+ ASTSerialPointer(NodeBase* in) :
+ m_kind(Kind::NodeBase),
+ m_ptr((void*)in)
+ {
+ }
+
+ static Kind getKind(const RefObject*) { return Kind::RefObject; }
+ static Kind getKind(const NodeBase*) { return Kind::NodeBase; }
+
+ Kind m_kind;
+ void* m_ptr;
+};
+
+
+/* This class is the interface used by toNative implementations to recreate a type */
+class ASTSerialReader : public RefObject
+{
+public:
+
+ ASTSerialPointer getPointer(ASTSerialIndex index);
+ template <typename T>
+ void getArray(ASTSerialIndex index, List<T>& outArray);
+ String getString(ASTSerialIndex index);
+ Name* getName(ASTSerialIndex index);
+ UnownedStringSlice getStringSlice(ASTSerialIndex index);
+ SourceLoc getSourceLoc(ASTSerialSourceLoc loc);
+};
+
+// ---------------------------------------------------------------------------
+template <typename T>
+void ASTSerialReader::getArray(ASTSerialIndex index, List<T>& outArray)
+{
+ SLANG_UNUSED(index);
+ outArray.clear();
+}
+
+class ASTSerialClasses;
+
+/* This is a class used tby toSerial implementations to turn native type into the serial type */
+class ASTSerialWriter : public RefObject
+{
+public:
+ ASTSerialIndex addPointer(const NodeBase* ptr);
+ ASTSerialIndex addPointer(const RefObject* ptr);
+
+ template <typename T>
+ ASTSerialIndex addArray(const T* in, Index count);
+
+ ASTSerialIndex addString(const UnownedStringSlice& slice);
+ ASTSerialIndex addString(const String& in);
+ ASTSerialIndex addName(const Name* name);
+ ASTSerialSourceLoc addSourceLoc(SourceLoc sourceLoc);
+
+ ASTSerialWriter(ASTSerialClasses* classes);
+
+protected:
+
+ ASTSerialIndex _addArray(size_t elementSize, const void* elements, Index elementCount);
+
+ ASTSerialIndex _add(const void* nativePtr, ASTSerialInfo::Entry* entry)
+ {
+ m_entries.add(entry);
+ // Okay I need to allocate space for this
+ ASTSerialIndex index = ASTSerialIndex(m_entries.getCount() - 1);
+ // Add to the map
+ m_ptrMap.Add(nativePtr, Index(index));
+ return index;
+ }
+
+ Dictionary<const void*, Index> m_ptrMap; // Maps a pointer to an entry index
+
+ // NOTE! Assumes the content stays in scope!
+ Dictionary<UnownedStringSlice, Index> m_sliceMap;
+
+ List<ASTSerialInfo::Entry*> m_entries; ///< The entries
+ MemoryArena m_arena; ///< Holds the payloads
+ ASTSerialClasses* m_classes;
+};
+
+// ---------------------------------------------------------------------------
+template <typename T>
+ASTSerialIndex ASTSerialWriter::addArray(const T* in, Index count)
+{
+ typedef ASTSerialTypeInfo<T> ElementTypeInfo;
+ typedef typename ElementTypeInfo::SerialType ElementSerialType;
+
+ if (std::is_same<T, ElementSerialType>::value)
+ {
+ // If they are the same we can just write out
+ return _addArray(sizeof(T), in, count);
+ }
+ else
+ {
+ // Else we need to convert
+ List<ElementSerialType> work;
+ work.setCount(count);
+
+ for (Index i = 0; i < count; ++i)
+ {
+ ElementTypeInfo::toSerial(this, &in[i], &work[i]);
+ }
+ return _addArray(sizeof(ElementSerialType), in, count);
+ }
+}
+
+struct ASTSerialType
+{
+ typedef void(*ToSerialFunc)(ASTSerialWriter* writer, const void* src, void* dst);
+ typedef void(*ToNativeFunc)(ASTSerialReader* reader, const void* src, void* dst);
+
+ size_t serialSizeInBytes;
+ uint8_t serialAlignment;
+ ToSerialFunc toSerialFunc;
+ ToNativeFunc toNativeFunc;
+};
+
+struct ASTSerialField
+{
+ const char* name; ///< The name of the field
+ const ASTSerialType* type; ///< The type of the field
+ uint32_t nativeOffset; ///< Offset to field from base of type
+ uint32_t serialOffset; ///< Offset in serial type
+};
+
+
+struct ASTSerialClass
+{
+ ASTNodeType type;
+ uint8_t alignment;
+ ASTSerialField* fields;
+ Index fieldsCount;
+ uint32_t size;
+};
+
+// An instance could be shared across Sessions, but for simplicity of life time
+// here we don't deal with that
+class ASTSerialClasses : public RefObject
+{
+public:
+
+ const ASTSerialClass* getSerialClass(ASTNodeType type) const { return &m_classes[Index(type)]; }
+
+ /// Ctor
+ ASTSerialClasses();
+
+protected:
+ MemoryArena m_arena;
+
+ ASTSerialClass m_classes[Index(ASTNodeType::CountOf)];
+};
+
+struct ASTSerializeUtil
+{
+ static SlangResult selfTest();
+};
+
+} // namespace Slang
+
+#endif
diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h
index 66144eaed..6fe8781c5 100644
--- a/source/slang/slang-ast-support-types.h
+++ b/source/slang/slang-ast-support-types.h
@@ -393,12 +393,13 @@ namespace Slang
struct DeclCheckStateExt
{
public:
+ typedef uint8_t RawType;
DeclCheckStateExt() {}
DeclCheckStateExt(DeclCheckState state)
: m_raw(uint8_t(state))
{}
- enum : uint8_t
+ enum : RawType
{
/// A flag to indicate that a declaration is being checked.
///
@@ -412,7 +413,7 @@ namespace Slang
DeclCheckState getState() const { return DeclCheckState(m_raw & ~kBeingCheckedBit); }
void setState(DeclCheckState state)
{
- m_raw = (m_raw & kBeingCheckedBit) | uint8_t(state);
+ m_raw = (m_raw & kBeingCheckedBit) | RawType(state);
}
bool isBeingChecked() const { return (m_raw & kBeingCheckedBit) != 0; }
@@ -428,8 +429,11 @@ namespace Slang
return getState() >= state;
}
+ RawType getRaw() const { return m_raw; }
+ void setRaw(RawType raw) { m_raw = raw; }
+
private:
- uint8_t m_raw = 0;
+ RawType m_raw = 0;
};
void addModifier(
@@ -1179,12 +1183,16 @@ namespace Slang
// in the case where the result is overloaded.
struct LookupResult
{
- // The one item that was found, in the smple case
+ // The one item that was found, in the simple 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.
+ //
+ // Additionally, if `items` is used, then `item` *must* hold an item that
+ // is also in the items list (typically the first entry), as an invariant.
+ // Otherwise isValid/begin will not function correctly.
List<LookupResultItem> items;
// Was at least one result found?
diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h
index f6d38889b..5349f0e30 100644
--- a/source/slang/slang-diagnostic-defs.h
+++ b/source/slang/slang-diagnostic-defs.h
@@ -22,7 +22,7 @@
// -1 - Notes that decorate another diagnostic.
//
-DIAGNOSTIC(-1, Note, alsoSeePipelineDefinition, "also see pipeline definition");
+DIAGNOSTIC(-1, Note, alsoSeePipelineDefinition, "also see pipeline definition")
DIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseNameNotAccessible, "implicit parameter matching failed because the component of the same name is not accessible from '$0'.\ncheck if you have declared necessary requirements and properly used the 'public' qualifier.")
DIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseShaderDoesNotDefineComponent, "implicit parameter matching failed because shader '$0' does not define component '$1'.")
DIAGNOSTIC(-1, Note, implicitParameterMatchingFailedBecauseTypeMismatch, "implicit parameter matching failed because the component of the same name does not match parameter type '$0'.")
@@ -62,25 +62,25 @@ DIAGNOSTIC( 8, Error, outputPathsImplyDifferentFormats,
"the output paths '$0' and '$1' require different code-generation targets")
DIAGNOSTIC( 10, Error, explicitOutputPathsAndMultipleTargets, "canot use both explicit output paths ('-o') and multiple targets ('-target')")
-DIAGNOSTIC( 11, Error, glslIsNotSupported, "the Slang compiler does not support GLSL as a source language");
-DIAGNOSTIC( 12, Error, cannotDeduceSourceLanguage, "can't deduce language for input file '$0'");
-DIAGNOSTIC( 13, Error, unknownCodeGenerationTarget, "unknown code generation target '$0'");
-DIAGNOSTIC( 14, Error, unknownProfile, "unknown profile '$0'");
-DIAGNOSTIC( 15, Error, unknownStage, "unknown stage '$0'");
-DIAGNOSTIC( 16, Error, unknownPassThroughTarget, "unknown pass-through target '$0'");
-DIAGNOSTIC( 17, Error, unknownCommandLineOption, "unknown command-line option '$0'");
-DIAGNOSTIC( 18, Error, unknownFileSystemOption, "unknown file-system option '$0'");
-DIAGNOSTIC( 19, Error, unknownSourceLanguage, "unknown source language '$0'");
-
-DIAGNOSTIC( 20, Error, entryPointsNeedToBeAssociatedWithTranslationUnits, "when using multiple source files, entry points must be specified after their corresponding source file(s)");
-DIAGNOSTIC( 21, Error, expectedArgumentForOption, "expected an argument for command-line option '$0'");
-
-DIAGNOSTIC( 24, Error, unknownLineDirectiveMode, "unknown '#line' directive mode '$0'");
-DIAGNOSTIC( 25, Error, unknownFloatingPointMode, "unknown floating-point mode '$0'");
-DIAGNOSTIC( 26, Error, unknownOptimiziationLevel, "unknown optimization level '$0'");
-DIAGNOSTIC( 27, Error, unknownDebugInfoLevel, "unknown debug info level '$0'");
-
-DIAGNOSTIC( 28, Error, unableToGenerateCodeForTarget, "unable to generate code for target '$0'");
+DIAGNOSTIC( 11, Error, glslIsNotSupported, "the Slang compiler does not support GLSL as a source language")
+DIAGNOSTIC( 12, Error, cannotDeduceSourceLanguage, "can't deduce language for input file '$0'")
+DIAGNOSTIC( 13, Error, unknownCodeGenerationTarget, "unknown code generation target '$0'")
+DIAGNOSTIC( 14, Error, unknownProfile, "unknown profile '$0'")
+DIAGNOSTIC( 15, Error, unknownStage, "unknown stage '$0'")
+DIAGNOSTIC( 16, Error, unknownPassThroughTarget, "unknown pass-through target '$0'")
+DIAGNOSTIC( 17, Error, unknownCommandLineOption, "unknown command-line option '$0'")
+DIAGNOSTIC( 18, Error, unknownFileSystemOption, "unknown file-system option '$0'")
+DIAGNOSTIC( 19, Error, unknownSourceLanguage, "unknown source language '$0'")
+
+DIAGNOSTIC( 20, Error, entryPointsNeedToBeAssociatedWithTranslationUnits, "when using multiple source files, entry points must be specified after their corresponding source file(s)")
+DIAGNOSTIC( 21, Error, expectedArgumentForOption, "expected an argument for command-line option '$0'")
+
+DIAGNOSTIC( 24, Error, unknownLineDirectiveMode, "unknown '#line' directive mode '$0'")
+DIAGNOSTIC( 25, Error, unknownFloatingPointMode, "unknown floating-point mode '$0'")
+DIAGNOSTIC( 26, Error, unknownOptimiziationLevel, "unknown optimization level '$0'")
+DIAGNOSTIC( 27, Error, unknownDebugInfoLevel, "unknown debug info level '$0'")
+
+DIAGNOSTIC( 28, Error, unableToGenerateCodeForTarget, "unable to generate code for target '$0'")
DIAGNOSTIC( 30, Warning, sameStageSpecifiedMoreThanOnce, "the stage '$0' was specified more than once for entry point '$1'")
DIAGNOSTIC( 31, Error, conflictingStagesForEntryPoint, "conflicting stages have been specified for entry point '$0'")
@@ -109,27 +109,27 @@ DIAGNOSTIC( 70, Error, cannotMatchOutputFileToEntryPoint, "the output path '$
DIAGNOSTIC( 80, Error, duplicateOutputPathsForEntryPointAndTarget, "multiple output paths have been specified entry point '$0' on target '$1'")
-DIAGNOSTIC( 82, Error, unableToWriteReproFile, "unable to write repro file '%0'");
-DIAGNOSTIC( 83, Error, unableToWriteModuleContainer, "unable to write module container '%0'");
-DIAGNOSTIC( 84, Error, unableToReadModuleContainer, "unable to read module container '%0'");
-DIAGNOSTIC( 85, Error, unableToAddReferenceToModuleContainer, "unable to add a reference to a module container");
-DIAGNOSTIC( 86, Error, unableToCreateModuleContainer, "unable to create module container");
+DIAGNOSTIC( 82, Error, unableToWriteReproFile, "unable to write repro file '%0'")
+DIAGNOSTIC( 83, Error, unableToWriteModuleContainer, "unable to write module container '%0'")
+DIAGNOSTIC( 84, Error, unableToReadModuleContainer, "unable to read module container '%0'")
+DIAGNOSTIC( 85, Error, unableToAddReferenceToModuleContainer, "unable to add a reference to a module container")
+DIAGNOSTIC( 86, Error, unableToCreateModuleContainer, "unable to create module container")
-DIAGNOSTIC( 87, Error, unableToSetDefaultDownstreamCompiler, "unable to set default downstream compiler for source language '%0' to '%1'");
+DIAGNOSTIC( 87, Error, unableToSetDefaultDownstreamCompiler, "unable to set default downstream compiler for source language '%0' to '%1'")
//
// 1xxxx - Lexical analysis
//
-DIAGNOSTIC(10000, Error, illegalCharacterPrint, "illegal character '$0'");
-DIAGNOSTIC(10000, Error, illegalCharacterHex, "illegal character (0x$0)");
-DIAGNOSTIC(10001, Error, illegalCharacterLiteral, "illegal character literal");
+DIAGNOSTIC(10000, Error, illegalCharacterPrint, "illegal character '$0'")
+DIAGNOSTIC(10000, Error, illegalCharacterHex, "illegal character (0x$0)")
+DIAGNOSTIC(10001, Error, illegalCharacterLiteral, "illegal character literal")
DIAGNOSTIC(10002, Warning, octalLiteral, "'0' prefix indicates octal literal")
DIAGNOSTIC(10003, Error, invalidDigitForBase, "invalid digit for base-$1 literal: '$0'")
-DIAGNOSTIC(10004, Error, endOfFileInLiteral, "end of file in literal");
-DIAGNOSTIC(10005, Error, newlineInLiteral, "newline in literal");
+DIAGNOSTIC(10004, Error, endOfFileInLiteral, "end of file in literal")
+DIAGNOSTIC(10005, Error, newlineInLiteral, "newline in literal")
//
// 15xxx - Preprocessing
@@ -151,11 +151,11 @@ DIAGNOSTIC(15103, Error, unexpectedTokensAfterDirective, "unexpected tokens foll
// 152xx - preprocessor expressions
-DIAGNOSTIC(15200, Error, expectedTokenInPreprocessorExpression, "expected '$0' in preprocessor expression");
-DIAGNOSTIC(15201, Error, syntaxErrorInPreprocessorExpression, "syntax error in preprocessor expression");
-DIAGNOSTIC(15202, Error, divideByZeroInPreprocessorExpression, "division by zero in preprocessor expression");
-DIAGNOSTIC(15203, Error, expectedTokenInDefinedExpression, "expected '$0' in 'defined' expression");
-DIAGNOSTIC(15204, Warning, directiveExpectsExpression, "'$0' directive requires an expression");
+DIAGNOSTIC(15200, Error, expectedTokenInPreprocessorExpression, "expected '$0' in preprocessor expression")
+DIAGNOSTIC(15201, Error, syntaxErrorInPreprocessorExpression, "syntax error in preprocessor expression")
+DIAGNOSTIC(15202, Error, divideByZeroInPreprocessorExpression, "division by zero in preprocessor expression")
+DIAGNOSTIC(15203, Error, expectedTokenInDefinedExpression, "expected '$0' in 'defined' expression")
+DIAGNOSTIC(15204, Warning, directiveExpectsExpression, "'$0' directive requires an expression")
DIAGNOSTIC(15205, Warning, undefinedIdentifierInPreprocessorExpression, "undefined identifier '$0' in preprocessor expression will evaluate to zero")
DIAGNOSTIC(-1, Note, seeOpeningToken, "see opening '$0'")
@@ -190,22 +190,22 @@ DIAGNOSTIC(15901, Warning, userDefinedWarning, "#warning: $0")
// 2xxxx - Parsing
//
-DIAGNOSTIC(20003, Error, unexpectedToken, "unexpected $0");
-DIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenType, "unexpected $0, expected $1");
-DIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenName, "unexpected $0, expected '$1'");
-
-DIAGNOSTIC(0, Error, tokenNameExpectedButEOF, "\"$0\" expected but end of file encountered.");
-DIAGNOSTIC(0, Error, tokenTypeExpectedButEOF, "$0 expected but end of file encountered.");
-DIAGNOSTIC(20001, Error, tokenNameExpected, "\"$0\" expected");
-DIAGNOSTIC(20001, Error, tokenNameExpectedButEOF2, "\"$0\" expected but end of file encountered.");
-DIAGNOSTIC(20001, Error, tokenTypeExpected, "$0 expected");
-DIAGNOSTIC(20001, Error, tokenTypeExpectedButEOF2, "$0 expected but end of file encountered.");
-DIAGNOSTIC(20001, Error, typeNameExpectedBut, "unexpected $0, expected type name");
-DIAGNOSTIC(20001, Error, typeNameExpectedButEOF, "type name expected but end of file encountered.");
-DIAGNOSTIC(20001, Error, unexpectedEOF, " Unexpected end of file.");
-DIAGNOSTIC(20002, Error, syntaxError, "syntax error.");
+DIAGNOSTIC(20003, Error, unexpectedToken, "unexpected $0")
+DIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenType, "unexpected $0, expected $1")
+DIAGNOSTIC(20001, Error, unexpectedTokenExpectedTokenName, "unexpected $0, expected '$1'")
+
+DIAGNOSTIC(0, Error, tokenNameExpectedButEOF, "\"$0\" expected but end of file encountered.")
+DIAGNOSTIC(0, Error, tokenTypeExpectedButEOF, "$0 expected but end of file encountered.")
+DIAGNOSTIC(20001, Error, tokenNameExpected, "\"$0\" expected")
+DIAGNOSTIC(20001, Error, tokenNameExpectedButEOF2, "\"$0\" expected but end of file encountered.")
+DIAGNOSTIC(20001, Error, tokenTypeExpected, "$0 expected")
+DIAGNOSTIC(20001, Error, tokenTypeExpectedButEOF2, "$0 expected but end of file encountered.")
+DIAGNOSTIC(20001, Error, typeNameExpectedBut, "unexpected $0, expected type name")
+DIAGNOSTIC(20001, Error, typeNameExpectedButEOF, "type name expected but end of file encountered.")
+DIAGNOSTIC(20001, Error, unexpectedEOF, " Unexpected end of file.")
+DIAGNOSTIC(20002, Error, syntaxError, "syntax error.")
DIAGNOSTIC(20004, Error, unexpectedTokenExpectedComponentDefinition, "unexpected token '$0', only component definitions are allowed in a shader scope.")
-DIAGNOSTIC(20008, Error, invalidOperator, "invalid operator '$0'.");
+DIAGNOSTIC(20008, Error, invalidOperator, "invalid operator '$0'.")
DIAGNOSTIC(20011, Error, unexpectedColon, "unexpected ':'.")
DIAGNOSTIC(20012, Error, invalidSPIRVVersion, "Expecting SPIR-V version as either 'major.minor', or quoted if has patch (eg for SPIR-V 1.2, '1.2' or \"1.2\"')")
DIAGNOSTIC(20013, Error, invalidCUDASMVersion, "Expecting CUDA SM version as either 'major.minor', or quoted if has patch (eg for '7.0' or \"7.0\"')")
@@ -234,10 +234,10 @@ DIAGNOSTIC(30019, Error, typeMismatch, "expected an expression of type '$0', got
DIAGNOSTIC(30020, Error, importOperatorReturnTypeMismatch, "import operator should return '$1', but the expression has type '$0''. do you forget 'project'?")
DIAGNOSTIC(30021, Error, noApplicationFunction, "$0: no overload takes arguments ($1)")
DIAGNOSTIC(30022, Error, invalidTypeCast, "invalid type cast between \"$0\" and \"$1\".")
-DIAGNOSTIC(30023, Error, typeHasNoPublicMemberOfName, "\"$0\" does not have public member \"$1\".");
+DIAGNOSTIC(30023, Error, typeHasNoPublicMemberOfName, "\"$0\" does not have public member \"$1\".")
DIAGNOSTIC(30025, Error, invalidArraySize, "array size must be larger than zero.")
DIAGNOSTIC(30026, Error, returnInComponentMustComeLast, "'return' can only appear as the last statement in component definition.")
-DIAGNOSTIC(30027, Error, noMemberOfNameInType, "'$0' is not a member of '$1'.");
+DIAGNOSTIC(30027, Error, noMemberOfNameInType, "'$0' is not a member of '$1'.")
DIAGNOSTIC(30028, Error, forPredicateTypeError, "'for': predicate expression must evaluate to bool.")
DIAGNOSTIC(30030, Error, projectionOutsideImportOperator, "'project': invalid use outside import operator.")
DIAGNOSTIC(30031, Error, projectTypeMismatch, "'project': expression must evaluate to record type '$0'.")
@@ -272,7 +272,7 @@ DIAGNOSTIC(31000, Error, unknownAttributeName, "unknown attribute '$0'")
DIAGNOSTIC(31001, Error, attributeArgumentCountMismatch, "attribute '$0' expects $1 arguments ($2 provided)")
DIAGNOSTIC(31002, Error, attributeNotApplicable, "attribute '$0' is not valid here")
-DIAGNOSTIC(31003, Error, badlyDefinedPatchConstantFunc, "hull shader '$0' has has badly defined 'patchconstantfunc' attribute.");
+DIAGNOSTIC(31003, Error, badlyDefinedPatchConstantFunc, "hull shader '$0' has has badly defined 'patchconstantfunc' attribute.")
DIAGNOSTIC(31004, Error, expectedSingleIntArg, "attribute '$0' expects a single int argument")
DIAGNOSTIC(31005, Error, expectedSingleStringArg, "attribute '$0' expects a single string argument")
@@ -305,19 +305,19 @@ DIAGNOSTIC(39999, Error, variableUsedInItsOwnDefinition, "the initial-value expr
DIAGNOSTIC(30400, Error, genericTypeNeedsArgs, "generic type '$0' used without argument")
// 305xx: initializer lists
-DIAGNOSTIC(30500, Error, tooManyInitializers, "too many initializers (expected $0, got $1)");
-DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'");
-DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'");
-DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows");
+DIAGNOSTIC(30500, Error, tooManyInitializers, "too many initializers (expected $0, got $1)")
+DIAGNOSTIC(30501, Error, cannotUseInitializerListForArrayOfUnknownSize, "cannot use initializer list for array of statically unknown size '$0'")
+DIAGNOSTIC(30502, Error, cannotUseInitializerListForVectorOfUnknownSize, "cannot use initializer list for vector of statically unknown size '$0'")
+DIAGNOSTIC(30503, Error, cannotUseInitializerListForMatrixOfUnknownSize, "cannot use initializer list for matrix of statically unknown size '$0' rows")
DIAGNOSTIC(30504, Error, cannotUseInitializerListForType, "cannot use initializer list for type '$0'")
// 306xx: variables
-DIAGNOSTIC(30600, Error, varWithoutTypeMustHaveInitializer, "a variable declaration without an initial-value expression must be given an explicit type");
+DIAGNOSTIC(30600, Error, varWithoutTypeMustHaveInitializer, "a variable declaration without an initial-value expression must be given an explicit type")
DIAGNOSTIC(30610, Error, ambiguousDefaultInitializerForType, "more than one default initializer was found for type '$0'")
// 307xx: parameters
-DIAGNOSTIC(30700, Error, outputParameterCannotHaveDefaultValue, "an 'out' or 'inout' parameter cannot have a default-value expression");
+DIAGNOSTIC(30700, Error, outputParameterCannotHaveDefaultValue, "an 'out' or 'inout' parameter cannot have a default-value expression")
// 308xx: inheritance
DIAGNOSTIC(30810, Error, baseOfInterfaceMustBeInterface, "interface '$0' cannot inherit from non-interface type '$1'")
@@ -354,10 +354,10 @@ DIAGNOSTIC(39999, Error, expectedAGeneric, "expected a generic when using '<...>
DIAGNOSTIC(39999, Error, genericArgumentInferenceFailed, "could not specialize generic for arguments of type $0")
DIAGNOSTIC(39999, Note, genericSignatureTried, "see declaration of $0")
-DIAGNOSTIC(39999, Error, ambiguousReference, "ambiguous reference to '$0'");
-DIAGNOSTIC(39999, Error, ambiguousExpression, "ambiguous reference");
+DIAGNOSTIC(39999, Error, ambiguousReference, "ambiguous reference to '$0'")
+DIAGNOSTIC(39999, Error, ambiguousExpression, "ambiguous reference")
-DIAGNOSTIC(39999, Error, declarationDidntDeclareAnything, "declaration does not declare anything");
+DIAGNOSTIC(39999, Error, declarationDidntDeclareAnything, "declaration does not declare anything")
DIAGNOSTIC(39999, Error, expectedPrefixOperator, "function called as prefix operator was not declared `__prefix`")
DIAGNOSTIC(39999, Error, expectedPostfixOperator, "function called as postfix operator was not declared `__postfix`")
@@ -403,7 +403,7 @@ DIAGNOSTIC(38022, Error, cannotSpecializeGlobalGenericToItself, "the global type
DIAGNOSTIC(38023, Error, cannotSpecializeGlobalGenericToAnotherGenericParam, "the global type parameter '$0' cannot be specialized using another global type parameter ('$1')")
-DIAGNOSTIC(38024, Error, invalidDispatchThreadIDType, "parameter with SV_DispatchThreadID must be either scalar or vector (1 to 3) of uint/int but is $0");
+DIAGNOSTIC(38024, Error, invalidDispatchThreadIDType, "parameter with SV_DispatchThreadID must be either scalar or vector (1 to 3) of uint/int but is $0")
DIAGNOSTIC(-1, Note, noteWhenCompilingEntryPoint, "when compiling entry point '$0'")
@@ -446,10 +446,10 @@ DIAGNOSTIC(39016, Error, globalUniformsNotSupported, "'$0' is implicitly a globa
DIAGNOSTIC(39017, Error, tooManyShaderRecordConstantBuffers, "can have at most one 'shader record' attributed constant buffer; found $0.")
-DIAGNOSTIC(39018, Error, typeParametersNotAllowedOnEntryPointGlobal, "local-root-signature shader parameter '$0' at global scope must not include existential/interface types");
+DIAGNOSTIC(39018, Error, typeParametersNotAllowedOnEntryPointGlobal, "local-root-signature shader parameter '$0' at global scope must not include existential/interface types")
DIAGNOSTIC(39019, Warning, vkIndexWithoutVkLocation, "ignoring '[[vk::index(...)]]` attribute without a corresponding '[[vk::location(...)]]' attribute")
-DIAGNOSTIC(39020, Error, mixingImplicitAndExplicitBindingForVaryingParams, "mixing explicit and implicit bindings for varying parameters is not supported (see '$0' and '$1')");
+DIAGNOSTIC(39020, Error, mixingImplicitAndExplicitBindingForVaryingParams, "mixing explicit and implicit bindings for varying parameters is not supported (see '$0' and '$1')")
//
// 4xxxx - IL code generation.
@@ -479,7 +479,7 @@ DIAGNOSTIC(41010, Warning, missingReturn, "control flow may reach end of non-'vo
// 5xxxx - Target code generation.
//
-DIAGNOSTIC(50010, Internal, missingExistentialBindingsForParameter, "missing argument for existential parameter slot");
+DIAGNOSTIC(50010, Internal, missingExistentialBindingsForParameter, "missing argument for existential parameter slot")
DIAGNOSTIC(50020, Error, invalidTessCoordType, "TessCoord must have vec2 or vec3 type.")
DIAGNOSTIC(50020, Error, invalidFragCoordType, "FragCoord must be a vec4.")
@@ -487,51 +487,51 @@ DIAGNOSTIC(50020, Error, invalidInvocationIdType, "InvocationId must have
DIAGNOSTIC(50020, Error, invalidThreadIdType, "ThreadId must have int type.")
DIAGNOSTIC(50020, Error, invalidPrimitiveIdType, "PrimitiveId must have int type.")
DIAGNOSTIC(50020, Error, invalidPatchVertexCountType, "PatchVertexCount must have int type.")
-DIAGNOSTIC(50022, Error, worldIsNotDefined, "world '$0' is not defined.");
-DIAGNOSTIC(50023, Error, stageShouldProvideWorldAttribute, "'$0' should provide 'World' attribute.");
+DIAGNOSTIC(50022, Error, worldIsNotDefined, "world '$0' is not defined.")
+DIAGNOSTIC(50023, Error, stageShouldProvideWorldAttribute, "'$0' should provide 'World' attribute.")
DIAGNOSTIC(50040, Error, componentHasInvalidTypeForPositionOutput, "'$0': component used as 'loc' output must be of vec4 type.")
DIAGNOSTIC(50041, Error, componentNotDefined, "'$0': component not defined.")
-DIAGNOSTIC(50052, Error, domainShaderRequiresControlPointCount, "'DomainShader' requires attribute 'ControlPointCount'.");
+DIAGNOSTIC(50052, Error, domainShaderRequiresControlPointCount, "'DomainShader' requires attribute 'ControlPointCount'.")
DIAGNOSTIC(50052, Error, hullShaderRequiresControlPointCount, "'HullShader' requires attribute 'ControlPointCount'.")
-DIAGNOSTIC(50052, Error, hullShaderRequiresControlPointWorld, "'HullShader' requires attribute 'ControlPointWorld'.");
-DIAGNOSTIC(50052, Error, hullShaderRequiresCornerPointWorld, "'HullShader' requires attribute 'CornerPointWorld'.");
-DIAGNOSTIC(50052, Error, hullShaderRequiresDomain, "'HullShader' requires attribute 'Domain'.");
+DIAGNOSTIC(50052, Error, hullShaderRequiresControlPointWorld, "'HullShader' requires attribute 'ControlPointWorld'.")
+DIAGNOSTIC(50052, Error, hullShaderRequiresCornerPointWorld, "'HullShader' requires attribute 'CornerPointWorld'.")
+DIAGNOSTIC(50052, Error, hullShaderRequiresDomain, "'HullShader' requires attribute 'Domain'.")
DIAGNOSTIC(50052, Error, hullShaderRequiresInputControlPointCount, "'HullShader' requires attribute 'InputControlPointCount'.")
DIAGNOSTIC(50052, Error, hullShaderRequiresOutputTopology, "'HullShader' requires attribute 'OutputTopology'.")
DIAGNOSTIC(50052, Error, hullShaderRequiresPartitioning, "'HullShader' requires attribute 'Partitioning'.")
-DIAGNOSTIC(50052, Error, hullShaderRequiresPatchWorld, "'HullShader' requires attribute 'PatchWorld'.");
+DIAGNOSTIC(50052, Error, hullShaderRequiresPatchWorld, "'HullShader' requires attribute 'PatchWorld'.")
DIAGNOSTIC(50052, Error, hullShaderRequiresTessLevelInner, "'HullShader' requires attribute 'TessLevelInner'.")
DIAGNOSTIC(50052, Error, hullShaderRequiresTessLevelOuter, "'HullShader' requires attribute 'TessLevelOuter'.")
-DIAGNOSTIC(50053, Error, invalidTessellationDomian, "'Domain' should be either 'triangles' or 'quads'.");
-DIAGNOSTIC(50053, Error, invalidTessellationOutputTopology, "'OutputTopology' must be one of: 'point', 'line', 'triangle_cw', or 'triangle_ccw'.");
+DIAGNOSTIC(50053, Error, invalidTessellationDomian, "'Domain' should be either 'triangles' or 'quads'.")
+DIAGNOSTIC(50053, Error, invalidTessellationOutputTopology, "'OutputTopology' must be one of: 'point', 'line', 'triangle_cw', or 'triangle_ccw'.")
DIAGNOSTIC(50053, Error, invalidTessellationPartitioning, "'Partitioning' must be one of: 'integer', 'pow2', 'fractional_even', or 'fractional_odd'.")
DIAGNOSTIC(50053, Error, invalidTessellationDomain, "'Domain' should be either 'triangles' or 'quads'.")
DIAGNOSTIC(50082, Error, importingFromPackedBufferUnsupported, "importing type '$0' from PackedBuffer is not supported by the GLSL backend.")
DIAGNOSTIC(51090, Error, cannotGenerateCodeForExternComponentType, "cannot generate code for extern component type '$0'.")
DIAGNOSTIC(51091, Error, typeCannotBePlacedInATexture, "type '$0' cannot be placed in a texture.")
-DIAGNOSTIC(51092, Error, stageDoesntHaveInputWorld, "'$0' doesn't appear to have any input world");
+DIAGNOSTIC(51092, Error, stageDoesntHaveInputWorld, "'$0' doesn't appear to have any input world")
-DIAGNOSTIC(52000, Error, multiLevelBreakUnsupported, "control flow appears to require multi-level `break`, which Slang does not yet support");
+DIAGNOSTIC(52000, Error, multiLevelBreakUnsupported, "control flow appears to require multi-level `break`, which Slang does not yet support")
-DIAGNOSTIC(52001, Warning, dxilNotFound, "dxil shared library not found, so 'dxc' output cannot be signed! Shader code will not be runnable in non-development environments.");
+DIAGNOSTIC(52001, Warning, dxilNotFound, "dxil shared library not found, so 'dxc' output cannot be signed! Shader code will not be runnable in non-development environments.")
-DIAGNOSTIC(52002, Error, passThroughCompilerNotFound, "Could not find a suitable pass-through compiler for '$0'.");
-DIAGNOSTIC(52003, Error, cppCompilerNotFound, "Could not find a suitable C/C++ compiler for '$0'.");
+DIAGNOSTIC(52002, Error, passThroughCompilerNotFound, "Could not find a suitable pass-through compiler for '$0'.")
+DIAGNOSTIC(52003, Error, cppCompilerNotFound, "Could not find a suitable C/C++ compiler for '$0'.")
-DIAGNOSTIC(52004, Error, unableToWriteFile, "Unable to write file '$0'");
-DIAGNOSTIC(52005, Error, unableToReadFile, "Unable to read file '$0'");
+DIAGNOSTIC(52004, Error, unableToWriteFile, "Unable to write file '$0'")
+DIAGNOSTIC(52005, Error, unableToReadFile, "Unable to read file '$0'")
// 99999 - Internal compiler errors, and not-yet-classified diagnostics.
DIAGNOSTIC(99999, Internal, unimplemented, "unimplemented feature in Slang compiler: $0")
DIAGNOSTIC(99999, Internal, unexpected, "unexpected condition encountered in Slang compiler: $0")
DIAGNOSTIC(99999, Internal, internalCompilerError, "Slang internal compiler error")
-DIAGNOSTIC(99999, Error, compilationAborted, "Slang compilation aborted due to internal error");
-DIAGNOSTIC(99999, Error, compilationAbortedDueToException, "Slang compilation aborted due to an exception of $0: $1");
-DIAGNOSTIC(99999, Note, noteLocationOfInternalError, "the Slang compiler threw an exception while working on code near this location");
-DIAGNOSTIC(99999, Internal, serialDebugVerificationFailed, "Verification of serial debug information failed.");
+DIAGNOSTIC(99999, Error, compilationAborted, "Slang compilation aborted due to internal error")
+DIAGNOSTIC(99999, Error, compilationAbortedDueToException, "Slang compilation aborted due to an exception of $0: $1")
+DIAGNOSTIC(99999, Note, noteLocationOfInternalError, "the Slang compiler threw an exception while working on code near this location")
+DIAGNOSTIC(99999, Internal, serialDebugVerificationFailed, "Verification of serial debug information failed.")
#undef DIAGNOSTIC
diff --git a/source/slang/slang-diagnostics.cpp b/source/slang/slang-diagnostics.cpp
index a46e0515b..d16e8e84e 100644
--- a/source/slang/slang-diagnostics.cpp
+++ b/source/slang/slang-diagnostics.cpp
@@ -3,6 +3,9 @@
#include "slang-name.h"
+#include "../core/slang-memory-arena.h"
+#include "../core/slang-dictionary.h"
+
#include <assert.h>
#ifdef _WIN32
@@ -268,34 +271,136 @@ void DiagnosticSink::diagnoseRaw(
namespace Diagnostics
{
-#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, messageFormat };
+#define DIAGNOSTIC(id, severity, name, messageFormat) const DiagnosticInfo name = { id, Severity::severity, #name, messageFormat };
#include "slang-diagnostic-defs.h"
+#undef DIAGNOSTIC
}
-DiagnosticInfo const* findDiagnosticByName(UnownedStringSlice const& name)
+static const DiagnosticInfo* const kAllDiagnostics[] =
{
- // TODO: We should eventually have a more formal system for associating individual
- // diagnostics, or groups of diagnostics, with user-exposed names for use when
- // enabling/disabling warnings (or turning warnings into errors, etc.).
- //
- // For now we build an ad hoc mapping from string names to corresponding single
- // diagnostics (not groups).
- //
- static const struct
+#define DIAGNOSTIC(id, severity, name, messageFormat) &Diagnostics::name,
+#include "slang-diagnostic-defs.h"
+#undef DIAGNOSTIC
+};
+
+class DiagnosticsLookup : public RefObject
+{
+public:
+ const DiagnosticInfo* findDiagostic(const UnownedStringSlice& slice) const
+ {
+ const Index* indexPtr = m_map.TryGetValue(slice);
+ return indexPtr ? kAllDiagnostics[*indexPtr] : nullptr;
+ }
+ Index _findDiagnosticIndex(const UnownedStringSlice& slice) const
{
- char const* name;
- DiagnosticInfo const* diagnostic;
- } kDiagnostics[] =
+ const Index* indexPtr = m_map.TryGetValue(slice);
+ return indexPtr ? *indexPtr : 0;
+ }
+ static DiagnosticsLookup* getSingleton()
+ {
+ static RefPtr<DiagnosticsLookup> singleton = new DiagnosticsLookup;
+ return singleton;
+ }
+
+ typedef uint8_t CharFlags;
+ struct CharFlag
{
- { "overlapping-bindings", &Diagnostics::parameterBindingsOverlap },
+ enum Enum : CharFlags
+ {
+ Upper = 0x1,
+ Lower = 0x2,
+ };
};
- for( auto& entry : kDiagnostics )
+ static CharFlags _classifyChar(char c)
+ {
+ CharFlags flags = 0;
+ flags |= (c >= 'a' && c <= 'z') ? CharFlag::Lower : 0;
+ flags |= (c >= 'A' && c <= 'Z') ? CharFlag::Upper : 0;
+ return flags;
+ }
+protected:
+ void _add(const char* name, Index index)
+ {
+ m_map.Add(UnownedStringSlice(name), index);
+
+ // Add a dashed version
+ {
+ m_work.Clear();
+
+ CharFlags prevFlags = 0;
+ for (const char* cur = name; *cur; cur++)
+ {
+ char c = *cur;
+ const CharFlags flags = _classifyChar(c);
+
+ if (flags & CharFlag::Upper)
+ {
+ if (prevFlags & CharFlag::Lower)
+ {
+ // If we go from lower to upper, insert a dash. aA -> a-a
+ m_work << '-';
+ }
+ else if (prevFlags & CharFlag::Upper)
+ {
+ // Could be an acronym, if the next character is lower, we need to insert a - here
+ if (_classifyChar(cur[1]) & CharFlag::Lower)
+ {
+ m_work << '-';
+ }
+ }
+ // Make it lower
+ c = c - 'A' + 'a';
+ }
+ m_work << c;
+
+ prevFlags = flags;
+ }
+
+ UnownedStringSlice dashSlice(m_arena.allocateString(m_work.getBuffer(), m_work.getLength()), m_work.getLength());
+ m_map.AddIfNotExists(dashSlice, index);
+ }
+ }
+ void _addAlias(const char* name, const char* diagnosticName)
+ {
+ const Index index = _findDiagnosticIndex(UnownedStringSlice(diagnosticName));
+ SLANG_ASSERT(index >= 0);
+ if (index >= 0)
+ {
+ _add(name, index);
+ }
+ }
+ DiagnosticsLookup();
+
+ StringBuilder m_work;
+ Dictionary<UnownedStringSlice, Index> m_map;
+ MemoryArena m_arena;
+};
+
+DiagnosticsLookup::DiagnosticsLookup():
+ m_arena(2048)
+{
+ // TODO: We should eventually have a more formal system for associating individual
+ // diagnostics, or groups of diagnostics, with user-exposed names for use when
+ // enabling/disabling warnings (or turning warnings into errors, etc.).
+ //
+ // For now we build a map from diagnostic name to it's entry. Two entries are typically
+ // added - the 'original name' as associated with the diagnostic in lowerCamel, and
+ // a dashified version.
+
+ for (Index i = 0; i < SLANG_COUNT_OF(kAllDiagnostics); ++i)
{
- if( name == entry.name )
- return entry.diagnostic;
+ const DiagnosticInfo* diagnostic = kAllDiagnostics[i];
+ _add(diagnostic->name, i);
}
- return nullptr;
+
+ // Add any aliases
+ _addAlias("overlappingBindings", "parameterBindingsOverlap");
+}
+
+DiagnosticInfo const* findDiagnosticByName(UnownedStringSlice const& name)
+{
+ return DiagnosticsLookup::getSingleton()->findDiagostic(name);
}
diff --git a/source/slang/slang-diagnostics.h b/source/slang/slang-diagnostics.h
index 1056cf2eb..caaba4033 100644
--- a/source/slang/slang-diagnostics.h
+++ b/source/slang/slang-diagnostics.h
@@ -40,6 +40,7 @@ namespace Slang
{
int id;
Severity severity;
+ char const* name; ///< Unique name
char const* messageFormat;
};
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 5279b2a40..7c535d64b 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -15,6 +15,7 @@
#include "slang-type-layout.h"
#include "slang-ast-dump.h"
+#include "slang-ast-serialize.h"
#include "slang-repro.h"
@@ -1074,6 +1075,18 @@ void FrontEndCompileRequest::parseTranslationUnit(
File::writeAllText(fileName, writer.getContent());
}
}
+
+#if 0
+ // Test serialization
+ {
+ RefPtr<ASTSerialClasses> classes = new ASTSerialClasses;
+ ASTSerialWriter writer(classes);
+
+ // Lets serialize it all
+ writer.addPointer(translationUnit->getModuleDecl());
+ }
+#endif
+
}
}
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index 3be09765d..5850bc2b8 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -198,6 +198,7 @@
<ClInclude Include="slang-ast-generated-macro.h" />
<ClInclude Include="slang-ast-generated.h" />
<ClInclude Include="slang-ast-modifier.h" />
+ <ClInclude Include="slang-ast-serialize.h" />
<ClInclude Include="slang-ast-stmt.h" />
<ClInclude Include="slang-ast-support-types.h" />
<ClInclude Include="slang-ast-type.h" />
@@ -279,6 +280,7 @@
<ClCompile Include="slang-ast-decl.cpp" />
<ClCompile Include="slang-ast-dump.cpp" />
<ClCompile Include="slang-ast-reflect.cpp" />
+ <ClCompile Include="slang-ast-serialize.cpp" />
<ClCompile Include="slang-ast-substitutions.cpp" />
<ClCompile Include="slang-ast-type.cpp" />
<ClCompile Include="slang-ast-val.cpp" />
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 64f912110..fdc1bf45d 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -45,6 +45,9 @@
<ClInclude Include="slang-ast-modifier.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-ast-serialize.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-ast-stmt.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -284,6 +287,9 @@
<ClCompile Include="slang-ast-reflect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="slang-ast-serialize.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ast-substitutions.cpp">
<Filter>Source Files</Filter>
</ClCompile>