summaryrefslogtreecommitdiff
path: root/source/slang/slang-serialize-ast.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/slang/slang-serialize-ast.cpp')
-rw-r--r--source/slang/slang-serialize-ast.cpp1608
1 files changed, 1471 insertions, 137 deletions
diff --git a/source/slang/slang-serialize-ast.cpp b/source/slang/slang-serialize-ast.cpp
index a7837edea..aad3bcc57 100644
--- a/source/slang/slang-serialize-ast.cpp
+++ b/source/slang/slang-serialize-ast.cpp
@@ -1,208 +1,1542 @@
// slang-serialize-ast.cpp
#include "slang-serialize-ast.h"
-#include "slang-ast-dump.h"
-#include "slang-ast-support-types.h"
-#include "slang-generated-ast-macro.h"
-#include "slang-generated-ast.h"
-#include "slang-serialize-ast-type-info.h"
-#include "slang-serialize-factory.h"
+#include "slang-ast-dispatch.h"
+#include "slang-compiler.h"
+#include "slang-diagnostics.h"
+#include "slang-mangle.h"
namespace Slang
{
+// TODO(tfoley): have the parser export this, or a utility function
+// for initializing a `SyntaxDecl` in the common case.
+//
+NodeBase* parseSimpleSyntax(Parser* parser, void* userData);
-// !!!!!!!!!!!!!!!!!!!!!! Generate fields for a type !!!!!!!!!!!!!!!!!!!!!!!!!!!
-static const SerialClass* _addClass(
- SerialClasses* serialClasses,
- ASTNodeType type,
- ASTNodeType super,
- const List<SerialField>& fields)
+struct ASTEncodingContext
{
- const SerialClass* superClass =
- serialClasses->getSerialClass(SerialTypeKind::NodeBase, SerialSubType(super));
- return serialClasses->add(
- SerialTypeKind::NodeBase,
- SerialSubType(type),
- fields.getBuffer(),
- fields.getCount(),
- superClass);
-}
+private:
+ Encoder* encoder;
+ struct UnhandledCase
+ {
+ };
+
+ typedef Int DeclID;
+ Dictionary<Decl*, DeclID> mapDeclToID;
+ List<Decl*> decls;
+
+ struct ImportedDeclInfo
+ {
+ Int moduleIndex = -1;
+ Decl* decl;
+ };
+ List<ImportedDeclInfo> importedDecls;
-#define SLANG_AST_ADD_SERIAL_FIELD(FIELD_NAME, TYPE, param) \
- fields.add(SerialField::make(#FIELD_NAME, &obj->FIELD_NAME));
+ typedef Int ValID;
+ Dictionary<Val*, ValID> mapValToID;
+ List<Val*> vals;
-// 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_ADD_SERIAL_CLASS(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \
- { \
- NAME* obj = SerialField::getPtr<NAME>(); \
- SLANG_UNUSED(obj); \
- fields.clear(); \
- SLANG_FIELDS_ASTNode_##NAME(SLANG_AST_ADD_SERIAL_FIELD, param) \
- _addClass(serialClasses, ASTNodeType::NAME, ASTNodeType::SUPER, fields); \
+ ModuleDecl* _module = nullptr;
+
+ SerialSourceLocWriter* _sourceLocWriter = nullptr;
+
+public:
+ ASTEncodingContext(Encoder* encoder, ModuleDecl* module, SerialSourceLocWriter* sourceLocWriter)
+ : encoder(encoder), _module(module), _sourceLocWriter(sourceLocWriter)
+ {
}
-struct ASTFieldAccess
-{
- static void calcClasses(SerialClasses* serialClasses)
+ template<typename T>
+ void encodeASTNodeContent(T* node)
{
- // Add NodeBase first, and specially handle so that we add a null super class
- serialClasses->add(
- SerialTypeKind::NodeBase,
- SerialSubType(ASTNodeType::NodeBase),
- nullptr,
- 0,
- nullptr);
+ Encoder::WithObject withObject(encoder);
- // Add the rest in order such that Super class is always added before its children
- List<SerialField> fields;
- SLANG_CHILDREN_ASTNode_NodeBase(SLANG_AST_ADD_SERIAL_CLASS, _)
+ ASTNodeDispatcher<T, void>::dispatch(node, [&](auto n) { _encodeDataOf(n); });
+ }
+
+ void flush()
+ {
+ auto containerChunk = encoder->getRIFFChunk();
+
+ RiffContainer::Chunk* declChunk = nullptr;
+ RiffContainer::Chunk* importedDeclChunk = nullptr;
+ RiffContainer::Chunk* valChunk = nullptr;
+ {
+ Encoder::WithArray withList(encoder);
+ declChunk = encoder->getRIFFChunk();
+ }
+ {
+ Encoder::WithArray withList(encoder);
+ importedDeclChunk = encoder->getRIFFChunk();
+ }
+ {
+ Encoder::WithArray withList(encoder);
+ valChunk = encoder->getRIFFChunk();
+ }
+ Int declIndex = 0;
+ Int importedDeclIndex = 0;
+ Int valIndex = 0;
+
+ bool done = false;
+ do
+ {
+ done = true;
+ while (declIndex < decls.getCount())
+ {
+ done = false;
+ encoder->setRIFFChunk(declChunk);
+ encodeASTNodeContent(decls[declIndex++]);
+ }
+ while (importedDeclIndex < importedDecls.getCount())
+ {
+ done = false;
+ encoder->setRIFFChunk(importedDeclChunk);
+ encodeImportedDecl(importedDecls[importedDeclIndex++]);
+ }
+ while (valIndex < vals.getCount())
+ {
+ done = false;
+ encoder->setRIFFChunk(valChunk);
+ encodeASTNodeContent(vals[valIndex++]);
+ }
+ } while (!done);
+
+ RiffContainer::calcAndSetSize(containerChunk);
+ encoder->setRIFFChunk(containerChunk);
+ }
+
+ ModuleDecl* findModuleForDecl(Decl* decl)
+ {
+ for (auto d = decl; d; d = d->parentDecl)
+ {
+ if (auto m = as<ModuleDecl>(d))
+ return m;
+ }
+ return nullptr;
}
-};
-// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ ModuleDecl* findModuleDeclWasImportedFrom(Decl* decl)
+ {
+ auto declModule = findModuleForDecl(decl);
+ if (declModule == nullptr)
+ return nullptr;
+ if (declModule == _module)
+ return nullptr;
+ return declModule;
+ }
+
+ DeclID getDeclID(Decl* decl)
+ {
+ SLANG_ASSERT(decl != nullptr);
+
+ if (auto found = mapDeclToID.tryGetValue(decl))
+ return *found;
+
+ // We need to detect whether the declaration is an
+ // imported one, or one from this module itself.
+ //
+ // Imported declarations need to be handled very
+ // differently, since they'll involve resolving
+ // references to those other modules, and the
+ // declarations within them.
+ //
+ if (auto importedFromModule = findModuleDeclWasImportedFrom(decl))
+ {
+ DeclID importedFromModuleDeclID = 0;
+ if (decl != importedFromModule)
+ {
+ importedFromModuleDeclID = getDeclID(importedFromModule);
+ }
+
+ DeclID id = ~importedDecls.getCount();
+ mapDeclToID.add(decl, id);
+
+ ImportedDeclInfo info;
+ info.moduleIndex = ~importedFromModuleDeclID;
+ info.decl = decl;
+ importedDecls.add(info);
+
+ return id;
+ }
+ else
+ {
+ DeclID id = decls.getCount();
+ decls.add(decl);
+ mapDeclToID.add(decl, id);
+
+ return id;
+ }
+ }
+
+ void encodePtr(Decl* decl)
+ {
+ DeclID id = getDeclID(decl);
+ encoder->encode(id);
+ }
+
+ ValID getValID(Val* val)
+ {
+ SLANG_ASSERT(val != nullptr);
+
+ if (auto found = mapValToID.tryGetValue(val))
+ return *found;
+
+ // In order to ensure that values can be fully constructed
+ // from the get-go (so that they will get cached correctly),
+ // we conspire to ensure that every value is preceded by
+ // all of its operands.
+ //
+ for (auto operand : val->m_operands)
+ {
+ switch (operand.kind)
+ {
+ default:
+ break;
+
+ case ValNodeOperandKind::ValNode:
+ if (auto operandNode = operand.values.nodeOperand)
+ {
+ SLANG_ASSERT(as<Val>(operandNode));
+ getValID(static_cast<Val*>(operandNode));
+ }
+ break;
+
+ case ValNodeOperandKind::ASTNode:
+ if (auto operandNode = operand.values.nodeOperand)
+ {
+ SLANG_ASSERT(as<Decl>(operandNode));
+ getDeclID(static_cast<Decl*>(operandNode));
+ }
+ break;
+ }
+ }
+ auto resolved = val->resolve();
+ if (resolved != val)
+ {
+ getValID(resolved);
+ }
+
+ ValID id = vals.getCount();
+ vals.add(val);
+ mapValToID.add(val, id);
+ return id;
+ }
+
+ void encodePtr(Val* val)
+ {
+ ValID id = getValID(val);
+ encoder->encode(id);
+ }
+
+ void encodeImportedDecl(ImportedDeclInfo const& info)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encode(info.moduleIndex);
+ auto decl = info.decl;
+ if (auto importedModuleDecl = as<ModuleDecl>(decl))
+ {
+ SLANG_ASSERT(info.moduleIndex == -1);
+ encode(importedModuleDecl->getName());
+ }
+ else
+ {
+ auto mangledName = getMangledName(getCurrentASTBuilder(), decl);
+ encode(mangledName);
+ }
+ }
+
+ void encodePtr(Modifier* modifier) { encodeASTNodeContent(modifier); }
+ void encodePtr(Expr* expr) { encodeASTNodeContent(expr); }
+ void encodePtr(Stmt* stmt) { encodeASTNodeContent(stmt); }
+
+ void encodePtr(Name* name) { encode(name->text); }
+
+ void encodePtr(MarkupEntry* entry)
+ {
+ // TODO: is this case needed?
+ SLANG_UNUSED(entry);
+ }
+
+ void encodePtr(DeclAssociationList* list)
+ {
+ // We serialize this as if it were a simple list
+ // of key-value pairs because... well... that's
+ // what it amounts to in practice.
+ //
+ Encoder::WithArray withArray(encoder);
+ for (auto association : list->associations)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encode(association->kind);
+ encode(association->decl);
+ }
+ }
+
+ void encodePtr(CandidateExtensionList* list) { encode(list->candidateExtensions); }
+
+ void encodePtr(WitnessTable* witnessTable)
+ {
+ Encoder::WithObject withObject(encoder);
+ encode(witnessTable->baseType);
+ encode(witnessTable->witnessedType);
+ encode(witnessTable->isExtern);
+
+ // TODO(tfoley): In theory we should be able to streamline
+ // this so that we only encode the requirements that we
+ // absolutely need to (which basically amounts to `associatedtype`
+ // requirements where the satisfying type is part of the public
+ // API of the type).
+ //
+ encode(witnessTable->m_requirementDictionary);
+ }
+
+ void encodeValue(RequirementWitness const& witness)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encodeEnum(witness.m_flavor);
+ switch (witness.m_flavor)
+ {
+ case RequirementWitness::Flavor::none:
+ break;
+
+ case RequirementWitness::Flavor::declRef:
+ encode(witness.m_declRef);
+ break;
+
+ case RequirementWitness::Flavor::val:
+ encode(witness.m_val);
+ break;
+
+ case RequirementWitness::Flavor::witnessTable:
+ encode((WitnessTable*)witness.m_obj.Ptr());
+ break;
+ }
+ }
+
+ void encodePtr(DiagnosticInfo* info) { encode(Int(info->id)); }
+
+ void encodePtr(DeclBase* declBase)
+ {
+ if (auto decl = as<Decl>(declBase))
+ {
+ encodePtr(decl);
+ }
+ else
+ {
+ encodeASTNodeContent(declBase);
+ }
+ }
+
+ void encodeValue(UnhandledCase);
+
+ void encodeValue(String const& value) { encoder->encode(value); }
+
+ void encodeValue(Token const& value)
+ {
+ encode(value.type);
+ encode(TokenFlags(value.flags & ~TokenFlag::Name));
+ encode(value.loc);
+ if (value.hasContent())
+ encoder->encodeString(value.getContent());
+ else
+ encode(nullptr);
+ }
+
+ void encodeValue(NameLoc const& value) { encode(value.name); }
+
+ void encodeValue(SemanticVersion value) { encoder->encode(value.toInteger()); }
+
+ void encodeValue(CapabilitySet const& value)
+ {
+ // While the `CapabilityTargetSets` type is a dictionary,
+ // in practice each entry already embeds its own key
+ // (the target atom), so we can encode this as just
+ // an array of the `CapabilityTargetSet` values.
+ //
+ Encoder::WithArray withArray(encoder);
+ for (auto pair : value.getCapabilityTargetSets())
+ {
+ encode(pair.second);
+ }
+ }
+
+ void encodeValue(CapabilityTargetSet const& value)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encode(value.target);
+
+ // Similar to the case for the `CapabilityTargetSets` above,
+ // each `CapabilityStageSet` already includes the stage atom,
+ // so we can simply encode the values from the dictionary.
+ //
+ Encoder::WithArray withArray(encoder);
+ for (auto pair : value.shaderStageSets)
+ {
+ encode(pair.second);
+ }
+ }
+
+ void encodeValue(CapabilityStageSet const& value)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encode(value.stage);
+ encode(value.atomSet);
+ }
+
+ void encodeValue(CapabilityAtomSet const& value)
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto rawAtom : value)
+ {
+ encode(CapabilityAtom(rawAtom));
+ }
+ }
-/* static */ void ASTSerialUtil::addSerialClasses(SerialClasses* serialClasses)
+ template<typename T>
+ void encodeValue(std::optional<T> const& value)
+ {
+ if (value)
+ encodeValue(*value);
+ else
+ encoder->encode(nullptr);
+ }
+
+ void encodeValue(SyntaxClass<NodeBase> const& value) { encode(value.getTag()); }
+
+ template<typename T>
+ void encodeValue(DeclRef<T> const& value)
+ {
+ encode((DeclRefBase*)value);
+ }
+
+ void encodeValue(ValNodeOperand value)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+
+ encodeEnum(value.kind);
+ switch (value.kind)
+ {
+ case ValNodeOperandKind::ConstantValue:
+ encode(value.values.intOperand);
+ break;
+
+ case ValNodeOperandKind::ValNode:
+ encode(static_cast<Val*>(value.values.nodeOperand));
+ break;
+
+ case ValNodeOperandKind::ASTNode:
+ {
+ if (auto decl = as<Decl>(value.values.nodeOperand))
+ {
+ encode(decl);
+ }
+ else
+ {
+ SLANG_UNEXPECTED("AST node operand of `Val` was expected to be a `Decl`");
+ }
+ }
+ break;
+ }
+ }
+
+ void encodeValue(TypeExp value) { encode(value.type); }
+
+ void encodeValue(QualType value)
+ {
+ Encoder::WithObject withObject(encoder);
+ encode(value.type);
+ encode(value.isLeftValue);
+ encode(value.hasReadOnlyOnTarget);
+ encode(value.isWriteOnly);
+ }
+
+ void encodeValue(MatrixCoord value)
+ {
+ Encoder::WithObject withObject(encoder);
+ encode(value.row);
+ encode(value.col);
+ }
+
+ void encodeValue(SPIRVAsmOperand::Flavor const& value) { encodeEnum(value); }
+
+ void encodeValue(SPIRVAsmOperand const& value)
+ {
+ Encoder::WithObject withObject(encoder);
+ encode(value.flavor);
+ encode(value.token);
+ encode(value.expr);
+ encode(value.bitwiseOrWith);
+ encode(value.knownValue);
+ encode(value.wrapInId);
+ encode(value.type);
+ }
+
+ void encodeValue(SPIRVAsmInst const& value)
+ {
+ Encoder::WithObject withObject(encoder);
+ encode(value.opcode);
+ encode(value.operands);
+ }
+
+
+ template<typename T, typename = std::enable_if_t<std::is_same_v<T, bool>>>
+ void encodeValue(T value)
+ {
+ encoder->encodeBool(value);
+ }
+
+ void encodeValue(Int32 value) { encoder->encode(value); }
+ void encodeValue(UInt32 value) { encoder->encode(value); }
+ void encodeValue(Int64 value) { encoder->encode(value); }
+ void encodeValue(UInt64 value) { encoder->encode(value); }
+ void encodeValue(float value) { encoder->encode(value); }
+ void encodeValue(double value) { encoder->encode(value); }
+
+ void encodeValue(uint8_t value) { encoder->encode(UInt32(value)); }
+
+ void encodeValue(nullptr_t) { encoder->encode(nullptr); }
+
+ template<typename T>
+ void encodeEnum(T value)
+ {
+ encoder->encode(Int32(value));
+ }
+
+ void encodeValue(DeclVisibility value) { encodeEnum(value); }
+ void encodeValue(BaseType value) { encodeEnum(value); }
+ void encodeValue(BuiltinRequirementKind value) { encodeEnum(value); }
+ void encodeValue(ASTNodeType value) { encodeEnum(value); }
+ void encodeValue(ImageFormat value) { encodeEnum(value); }
+ void encodeValue(TypeTag value) { encodeEnum(value); }
+ void encodeValue(TryClauseType value) { encodeEnum(value); }
+ void encodeValue(CapabilityAtom value) { encodeEnum(value); }
+ void encodeValue(DeclAssociationKind value) { encodeEnum(value); }
+ void encodeValue(TokenType value) { encodeEnum(value); }
+
+ void encodeValue(SourceLoc value)
+ {
+ if (!_sourceLocWriter)
+ {
+ encoder->encode(nullptr);
+ }
+ else
+ {
+ auto intermediate = _sourceLocWriter->addSourceLoc(value);
+ encoder->encode(intermediate);
+ }
+ }
+
+ template<typename T>
+ void encodeValue(T const* ptr)
+ {
+ if (!ptr)
+ {
+ encoder->encode(nullptr);
+ }
+ else
+ {
+ encodePtr(const_cast<T*>(ptr));
+ }
+ }
+
+ template<typename T>
+ void encodeValue(RefPtr<T> const& ptr)
+ {
+ if (!ptr)
+ {
+ encoder->encode(nullptr);
+ }
+ else
+ {
+ encodePtr(ptr.Ptr());
+ }
+ }
+
+ void encodeValue(Modifiers const& modifiers)
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto m : const_cast<Modifiers&>(modifiers))
+ {
+ encode(m);
+ }
+ }
+
+ template<typename T, int N>
+ void encodeValue(ShortList<T, N> const& array)
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto element : array)
+ {
+ encode(element);
+ }
+ }
+
+
+ template<typename T>
+ void encode(List<T> const& array)
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto element : array)
+ {
+ encode(element);
+ }
+ }
+
+ template<typename T, size_t N>
+ void encode(T const (&array)[N])
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto element : array)
+ {
+ encode(element);
+ }
+ }
+
+ template<typename K, typename V>
+ void encode(OrderedDictionary<K, V> const& dictionary)
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto p : dictionary)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encode(p.key);
+ encode(p.value);
+ }
+ }
+
+ template<typename K, typename V>
+ void encode(Dictionary<K, V> const& dictionary)
+ {
+ Encoder::WithArray withArray(encoder);
+ for (auto p : dictionary)
+ {
+ Encoder::WithKeyValuePair withPair(encoder);
+ encode(p.first);
+ encode(p.second);
+ }
+ }
+
+ template<typename T>
+ void encode(T const& value)
+ {
+ encodeValue(value);
+ }
+
+ // for each class of node, we generate
+ // code to recursively serialize each
+ // of its fields.
+
+#if 0 // FIDDLE TEMPLATE:
+%for _,T in ipairs(Slang.NodeBase.subclasses) do
+ void _encodeDataOf($T* obj)
+ {
+%if T.directSuperClass then
+ _encodeDataOf(static_cast<$(T.directSuperClass)*>(obj));
+%end
+%for _,f in ipairs(T.directFields) do
+ encode(obj->$f);
+%end
+ }
+%end
+#else // FIDDLE OUTPUT:
+#define FIDDLE_GENERATED_OUTPUT_ID 0
+#include "slang-serialize-ast.cpp.fiddle"
+#endif // FIDDLE END
+};
+
+void writeSerializedModuleAST(
+ Encoder* encoder,
+ ModuleDecl* moduleDecl,
+ SerialSourceLocWriter* sourceLocWriter)
{
- ASTFieldAccess::calcClasses(serialClasses);
+ Encoder::WithObject withObject(encoder);
+
+ // TODO: we should have a more careful pass here,
+ // where we only encode the public declarations
+ //
+
+ ASTEncodingContext context(encoder, moduleDecl, sourceLocWriter);
+ context.getDeclID(moduleDecl);
+ context.flush();
}
-/* static */ SlangResult ASTSerialUtil::testSerialize(
- NodeBase* node,
- RootNamePool* rootNamePool,
- SharedASTBuilder* sharedASTBuilder,
- SourceManager* sourceManager)
+struct ASTDecodingContext
{
- RefPtr<SerialClasses> classes;
+public:
+ ASTDecodingContext(
+ Linkage* linkage,
+ ASTBuilder* astBuilder,
+ DiagnosticSink* sink,
+ RiffContainer::Chunk* rootChunk,
+ SerialSourceLocReader* sourceLocReader,
+ SourceLoc requestingSourceLoc)
+ : _linkage(linkage)
+ , _astBuilder(astBuilder)
+ , _sink(sink)
+ , _rootChunk(static_cast<RiffContainer::ListChunk*>(rootChunk))
+ , _sourceLocReader(sourceLocReader)
+ , _requestingSourceLoc(requestingSourceLoc)
+ {
+ }
+
+ Linkage* _linkage = nullptr;
+ DiagnosticSink* _sink = nullptr;
+ SerialSourceLocReader* _sourceLocReader = nullptr;
+ SourceLoc _requestingSourceLoc;
+
+ SlangResult decodeAll()
+ {
+ auto cursor = _rootChunk->getFirstContainedChunk();
+
+ // There are a few different top-level chunks that
+ // hold different arrays that we need in order
+ // to decode the entire module hierarchy.
+ //
+ // Basically, these lists correspond to the kinds
+ // of nodes in the AST hierarchy for which back-references
+ // are allowed (all other nodes should, barring
+ // weird corner cases, form a single tree-structured
+ // ownership hierarchy, rooted at the `ModuleDecl`.
+ //
+
+ // First there is the list that actually encodes
+ // for the declarations in the module, including
+ // the `ModuleDecl` itself, which should be the
+ // first entry in the list.
+ //
+ auto declChunk = cursor;
+ cursor = cursor->m_next;
+
+ // Next there is a list of all the declarations
+ // referenced inside of the module that need to
+ // be imported in from outside.
+ //
+ auto importedDeclChunk = cursor;
+ cursor = cursor->m_next;
+
+ // Then there are all the `Val`-derived nodes that
+ // are needed by the module, which will need to be
+ // deduplicated so that they are unique within the
+ // current compilation context.
+ //
+ auto valChunk = cursor;
+ cursor = cursor->m_next;
+
+ // The process of decoding the module is then spread
+ // over a number of steps.
+ //
+ // The first step is to process all of the imported
+ // declarations, so that other nodes can refer to
+ // them.
+ //
+ SLANG_RETURN_ON_FAIL(decodeImportedDecls(importedDeclChunk));
+
+ // Next we process the declarations that are within
+ // the module itself, first creating an "empty shell"
+ // of each declaration that has the right size in
+ // memory (and the right `ASTNodeType` tag), so that
+ // we can wire up references to it (including circular
+ // references)... so long as nothing here tries to
+ // look *inside* the empty shell along the way.
+ //
+ SLANG_RETURN_ON_FAIL(createEmptyShells(declChunk));
+
+ // Once all the `Decl`s that might be needed have
+ // been allocated, we can process all the `Val`s
+ // that might reference those`Decl`s (and one another).
+ //
+ // The nature of the `Val` representation ensures
+ // that there cannot be cirularities in the references
+ // between `Val`s, and the encoding process will have
+ // sorted the entries so that a `Val` only ever appears
+ // *after* its operands.
+ //
+ SLANG_RETURN_ON_FAIL(decodeVals(valChunk));
+
+ // Once all the back-reference-able objects have been
+ // instantiated in memory, we can go back through the
+ // `Decl`s in the module and fill in those empty shells.
+ //
+ SLANG_RETURN_ON_FAIL(fillEmptyShells(declChunk));
+
+ // As a final pass, we perform any special cleanup actions
+ // that might be required to make the output valid for consumers.
+ //
+ // For example, this is where we set the `DeclCheckState` of everything
+ // we are loading to reflect the fact that everything we deserialize
+ // is (supposed to be) fully cheked.
+ //
+ SLANG_RETURN_ON_FAIL(cleanUpNodes());
+
+
+ return SLANG_OK;
+ }
+
+ typedef Int DeclID;
+ Decl* getDeclByID(DeclID id)
+ {
+ if (id >= 0)
+ {
+ return _decls[id];
+ }
+ else
+ {
+ return _importedDecls[~id];
+ }
+ }
+
+private:
+ struct UnhandledCase
+ {
+ };
+
+ ASTBuilder* _astBuilder = nullptr;
+ RiffContainer::ListChunk* _rootChunk = nullptr;
+
+ List<Decl*> _decls;
+ List<Decl*> _importedDecls;
+ List<Val*> _vals;
+
+ typedef Int ValID;
+ Val* getValByID(ValID id) { return _vals[id]; }
+
+ SlangResult decodeImportedDecls(RiffContainer::Chunk* importedDeclChunk)
+ {
+ Decoder decoder(importedDeclChunk);
+
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
+
+ Int moduleIndex;
+ decode(moduleIndex, decoder);
+
+ if (moduleIndex == -1)
+ {
+ Name* moduleName = nullptr;
+ decode(moduleName, decoder);
+
+ Decl* importedModule = getImportedModule(moduleName);
+ _importedDecls.add(importedModule);
+ }
+ else
+ {
+ auto importedFromModuleDecl = as<ModuleDecl>(_importedDecls[moduleIndex]);
+ auto importedFromModule = importedFromModuleDecl->module;
+
+ String mangledName;
+ decode(mangledName, decoder);
+
+ auto importedNode =
+ importedFromModule->findExportFromMangledName(mangledName.getUnownedSlice());
+ auto importedDecl = as<Decl>(importedNode);
+ _importedDecls.add(importedDecl);
+ }
+ }
+ return SLANG_OK;
+ }
+
+ ModuleDecl* getImportedModule(Name* moduleName)
+ {
+ Module* module = _linkage->findOrImportModule(moduleName, _requestingSourceLoc, _sink);
+ if (!module)
+ {
+ SLANG_ABORT_COMPILATION("failed to load an imported module during deserialization");
+ }
+
+ return module->getModuleDecl();
+ }
+
+ SlangResult decodeVals(RiffContainer::Chunk* valChunk)
+ {
+ Decoder decoder(valChunk);
+
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ Val* val = decodeValNode(decoder);
+ _vals.add(val);
+ }
+ return SLANG_OK;
+ }
- SerialClassesUtil::create(classes);
+ SlangResult createEmptyShells(RiffContainer::Chunk* declChunk)
+ {
+ Decoder decoder(declChunk);
+
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ ASTNodeType nodeType;
+
+ // Each of the declarations is expected to take
+ // the form of an object with a first field
+ // that holds the node type.
+ //
+ {
+ Decoder::WithObject withObject(decoder);
+ decode(nodeType, decoder);
+ }
+
+ auto emptyShell = createEmptyShell(nodeType);
+ auto declEmptyShell = as<Decl>(emptyShell);
+ _decls.add(declEmptyShell);
+ }
- List<uint8_t> contents;
+ return SLANG_OK;
+ }
+ Val* decodeValNode(Decoder& decoder)
{
- OwnedMemoryStream stream(FileAccess::ReadWrite);
+ Decoder::WithObject withObject(decoder);
- ModuleDecl* moduleDecl = as<ModuleDecl>(node);
- // Only serialize out things *in* this module
- ModuleSerialFilter filterStorage(moduleDecl);
+ ASTNodeType nodeType;
+ decode(nodeType, decoder);
- SerialFilter* filter = moduleDecl ? &filterStorage : nullptr;
+ ValNodeDesc desc;
+ desc.type = SyntaxClass<NodeBase>(nodeType);
- SerialWriter writer(classes, filter);
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ ValNodeOperand operand;
+ decode(operand, decoder);
+ desc.operands.add(operand);
+ }
- // Lets serialize it all
- writer.addPointer(node);
- // Let's stick it all in a stream
- writer.write(&stream);
+ desc.init();
- stream.swapContents(contents);
+ auto val = _astBuilder->_getOrCreateImpl(_Move(desc));
- NamePool namePool;
- namePool.setRootNamePool(rootNamePool);
+ // Values created during deserialization are
+ // not expected to ever resolve further, because
+ // they should be coming from fully checked code.
+ //
+ // val->resolve();
+ // val->_setUnique();
- ASTBuilder builder(sharedASTBuilder, "Serialize Check");
+ return val;
+ }
- SetASTBuilderContextRAII astBuilderRAII(&builder);
+ NodeBase* createEmptyShell(ASTNodeType nodeType)
+ {
+ return SyntaxClass<NodeBase>(nodeType).createInstance(_astBuilder);
+ }
- DefaultSerialObjectFactory objectFactory(&builder);
+ SlangResult fillEmptyShells(RiffContainer::Chunk* declChunk)
+ {
+ Index declIndex = 0;
- // We could now check that the loaded data matches
+ Decoder decoder(declChunk);
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ auto declEmptyShell = _decls[declIndex++];
+ decodeASTNodeContent(declEmptyShell, decoder);
+ }
+ return SLANG_OK;
+ }
+
+ SlangResult cleanUpNodes()
+ {
+ for (auto decl : _decls)
{
- const List<SerialInfo::Entry*>& writtenEntries = writer.getEntries();
- List<const SerialInfo::Entry*> readEntries;
+ decl->checkState = DeclCheckState::CapabilityChecked;
+ }
- SlangResult res = SerialReader::loadEntries(
- contents.getBuffer(),
- contents.getCount(),
- classes,
- readEntries);
- SLANG_UNUSED(res);
+ return SLANG_OK;
+ }
- SLANG_ASSERT(writtenEntries.getCount() == readEntries.getCount());
- // They should be identical up to the
- for (Index i = 1; i < readEntries.getCount(); ++i)
+ void assignGenericParameterIndices(GenericDecl* genericDecl)
+ {
+ int parameterCounter = 0;
+ for (auto m : genericDecl->members)
+ {
+ if (auto typeParam = as<GenericTypeParamDeclBase>(m))
+ {
+ typeParam->parameterIndex = parameterCounter++;
+ }
+ else if (auto valParam = as<GenericValueParamDecl>(m))
{
- auto writtenEntry = writtenEntries[i];
- auto readEntry = readEntries[i];
+ valParam->parameterIndex = parameterCounter++;
+ }
+ }
+ }
+
- const size_t writtenSize = writtenEntry->calcSize(classes);
- const size_t readSize = readEntry->calcSize(classes);
- SLANG_UNUSED(writtenSize);
- SLANG_UNUSED(readSize);
+ void cleanUpASTNode(NodeBase* node)
+ {
+ if (auto expr = as<Expr>(node))
+ {
+ expr->checked = true;
+ }
+ else if (auto genericDecl = as<GenericDecl>(node))
+ {
+ assignGenericParameterIndices(genericDecl);
+ }
+ else if (auto syntaxDecl = as<SyntaxDecl>(node))
+ {
+ syntaxDecl->parseCallback = &parseSimpleSyntax;
+ syntaxDecl->parseUserData = (void*)syntaxDecl->syntaxClass.getInfo();
+ }
+ else if (auto namespaceLikeDecl = as<NamespaceDeclBase>(node))
+ {
+ auto declScope = _astBuilder->create<Scope>();
+ declScope->containerDecl = namespaceLikeDecl;
+ namespaceLikeDecl->ownedScope = declScope;
+ }
+ }
+
+ void decodeASTNodeContent(NodeBase* node, Decoder& decoder)
+ {
+ Decoder::WithObject withObject(decoder);
- SLANG_ASSERT(readSize == writtenSize);
- // Check the payload is the same
- SLANG_ASSERT(memcmp(readEntry, writtenEntry, readSize) == 0);
+ ASTNodeDispatcher<NodeBase, void>::dispatch(
+ node,
+ [&](auto n) { _decodeDataOf(n, decoder); });
+
+ cleanUpASTNode(node);
+ }
+
+ DeclID decodeDeclID(Decoder& decoder)
+ {
+ DeclID result = decoder.decode<DeclID>();
+ return result;
+ }
+
+ ValID decodeValID(Decoder& decoder)
+ {
+ ValID result = decoder.decode<ValID>();
+ return result;
+ }
+
+ template<typename T>
+ void decodeASTNode(T*& node, Decoder& decoder)
+ {
+ ASTNodeType nodeType;
+ auto saved = decoder.getCursor();
+ {
+ Decoder::WithObject withObject(decoder);
+ decode(nodeType, decoder);
+ }
+ decoder.setCursor(saved);
+
+ auto shell = createEmptyShell(nodeType);
+ decodeASTNodeContent(shell, decoder);
+
+ node = as<T>(shell);
+ }
+
+ void decodePtr(Name*& name, Decoder& decoder, Name*)
+ {
+ String text;
+ decode(text, decoder);
+
+ name = _astBuilder->getNamePool()->getName(text);
+ }
+
+ void decodePtr(DeclAssociationList*& outList, Decoder& decoder, DeclAssociationList*)
+ {
+ // Mirroring the encoding logic, we decode this
+ // as a list of key-value pairs.
+ //
+ auto list = RefPtr(new DeclAssociationList());
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ auto association = RefPtr(new DeclAssociation());
+
+ Decoder::WithKeyValuePair withPair(decoder);
+ decode(association->kind, decoder);
+ decode(association->decl, decoder);
+
+ list->associations.add(association);
+ }
+
+ outList = list.detach();
+ }
+
+ void decodePtr(DiagnosticInfo const*& info, Decoder& decoder, DiagnosticInfo const*)
+ {
+ Int id;
+ decode(id, decoder);
+ info = getDiagnosticsLookup()->getDiagnosticById(id);
+ }
+
+ void decodePtr(MarkupEntry*& markupEntry, Decoder&, MarkupEntry*)
+ {
+ // TODO: is this case needed?
+ markupEntry = nullptr;
+ }
+
+ void decodePtr(CandidateExtensionList*& list, Decoder& decoder, CandidateExtensionList*)
+ {
+ auto result = RefPtr(new CandidateExtensionList());
+ decode(result->candidateExtensions, decoder);
+ list = result.detach();
+ }
+
+ void decodePtr(WitnessTable*& witnessTable, Decoder& decoder, WitnessTable*)
+ {
+ Decoder::WithObject withObject(decoder);
+ auto wt = RefPtr(new WitnessTable());
+ decode(wt->baseType, decoder);
+ decode(wt->witnessedType, decoder);
+ decode(wt->isExtern, decoder);
+ decode(wt->m_requirementDictionary, decoder);
+ witnessTable = wt.detach();
+ }
+
+ void decodeValue(RequirementWitness& witness, Decoder& decoder)
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
+ decodeEnum(witness.m_flavor, decoder);
+ switch (witness.m_flavor)
+ {
+ case RequirementWitness::Flavor::none:
+ break;
+
+ case RequirementWitness::Flavor::declRef:
+ decode(witness.m_declRef, decoder);
+ break;
+
+ case RequirementWitness::Flavor::val:
+ decode(witness.m_val, decoder);
+ break;
+
+ case RequirementWitness::Flavor::witnessTable:
+ {
+ RefPtr<WitnessTable> object;
+ decode(object, decoder);
+ witness.m_obj = object;
}
+ break;
}
+ }
- SerialReader reader(classes, nullptr);
+ template<typename T>
+ void decodePtr(T*& node, Decoder& decoder, Val*)
+ {
+ ValID id = decodeValID(decoder);
+ node = static_cast<T*>(getValByID(id));
+ }
+
+ template<typename T>
+ void decodePtr(T*& node, Decoder& decoder, Decl*)
+ {
+ DeclID id = decodeDeclID(decoder);
+ node = static_cast<T*>(getDeclByID(id));
+ }
+
+ template<typename T>
+ void decodePtr(T*& node, Decoder& decoder, DeclBase*)
+ {
+ if (decoder.getTag() == SerialBinary::kInt64FourCC)
+ {
+ DeclID id = decodeDeclID(decoder);
+ node = static_cast<T*>(getDeclByID(id));
+ }
+ else
{
+ decodeASTNode(node, decoder);
+ }
+ }
+
+ template<typename T>
+ void decodePtr(T*& node, Decoder& decoder, NodeBase*)
+ {
+ decodeASTNode(node, decoder);
+ }
+
+
+ void decodeValue(UnhandledCase, Decoder& decoder);
- SlangResult res = reader.load(contents.getBuffer(), contents.getCount(), &namePool);
- SLANG_UNUSED(res);
+ void decodeValue(String& value, Decoder& decoder) { value = decoder.decodeString(); }
+
+ void decodeValue(Token& value, Decoder& decoder)
+ {
+ decode(value.type, decoder);
+ decode(value.flags, decoder);
+ decode(value.loc, decoder);
+ if (decoder.decodeNull())
+ {
}
+ else
+ {
+ Name* name = nullptr;
+ decode(name, decoder);
+ value.setName(name);
+ }
+ }
+
+ void decodeValue(NameLoc& value, Decoder& decoder) { decode(value.name, decoder); }
- // Lets see what we have
- const ASTDumpUtil::Flags dumpFlags =
- ASTDumpUtil::Flag::HideSourceLoc | ASTDumpUtil::Flag::HideScope;
+ void decodeValue(SemanticVersion& value, Decoder& decoder)
+ {
+ SemanticVersion::IntegerType rawValue = decoder.decode<SemanticVersion::IntegerType>();
+ value.setFromInteger(rawValue);
+ }
- String readDump;
+ void decodeValue(CapabilitySet& value, Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
{
- SourceWriter sourceWriter(sourceManager, LineDirectiveMode::None, nullptr);
- ASTDumpUtil::dump(
- reader.getPointer(SerialIndex(1)).dynamicCast<NodeBase>(),
- ASTDumpUtil::Style::Hierachical,
- dumpFlags,
- &sourceWriter);
- readDump = sourceWriter.getContentAndClear();
+ CapabilityTargetSet targetSet;
+ decode(targetSet, decoder);
+ value.getCapabilityTargetSets()[targetSet.target] = targetSet;
}
- String origDump;
+ }
+
+ void decodeValue(CapabilityTargetSet& value, Decoder& decoder)
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
+ decode(value.target, decoder);
+
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
{
- SourceWriter sourceWriter(sourceManager, LineDirectiveMode::None, nullptr);
- ASTDumpUtil::dump(node, ASTDumpUtil::Style::Hierachical, dumpFlags, &sourceWriter);
- origDump = sourceWriter.getContentAndClear();
+ CapabilityStageSet stageSet;
+ decode(stageSet, decoder);
+ value.shaderStageSets[stageSet.stage] = stageSet;
}
+ }
- // Write out
- File::writeAllText("ast-read.ast-dump", readDump);
- File::writeAllText("ast-orig.ast-dump", origDump);
+ void decodeValue(CapabilityStageSet& value, Decoder& decoder)
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
+ decode(value.stage, decoder);
+ decode(value.atomSet, decoder);
+ }
- if (readDump != origDump)
+ void decodeValue(CapabilityAtomSet& value, Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
{
- return SLANG_FAIL;
+ CapabilityAtom atom;
+ decode(atom, decoder);
+ value.add(UInt(atom));
}
}
- return SLANG_OK;
-}
+ template<typename T>
+ void decodeValue(std::optional<T>& outValue, Decoder& decoder)
+ {
+ if (decoder.decodeNull())
+ {
+ outValue.reset();
+ }
+ else
+ {
+ T value;
+ decode(value, decoder);
+ outValue = value;
+ }
+ }
-/* static */ List<uint8_t> ASTSerialUtil::serializeAST(ModuleDecl* moduleDecl)
-{
- // TODO: we should store `classes` in GlobalSession to avoid recomputing them every time.
- RefPtr<SerialClasses> classes;
- SerialClassesUtil::create(classes);
+ void decodeValue(SyntaxClass<NodeBase>& syntaxClass, Decoder& decoder)
+ {
+ ASTNodeType nodeType;
+ decode(nodeType, decoder);
+ syntaxClass = SyntaxClass<NodeBase>(nodeType);
+ }
- List<uint8_t> contents;
- OwnedMemoryStream stream(FileAccess::ReadWrite);
+ template<typename T>
+ void decodeValue(DeclRef<T>& declRef, Decoder& decoder)
+ {
+ decode(declRef.declRefBase, decoder);
+ }
- // Only serialize out things *in* this module
- ModuleSerialFilter filterStorage(moduleDecl);
+ void decodeValue(ValNodeOperand& value, Decoder& decoder)
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
- SerialFilter* filter = moduleDecl ? &filterStorage : nullptr;
+ decodeEnum(value.kind, decoder);
+ switch (value.kind)
+ {
+ case ValNodeOperandKind::ConstantValue:
+ decode(value.values.intOperand, decoder);
+ break;
- SerialWriter writer(classes, filter);
+ case ValNodeOperandKind::ValNode:
+ {
+ Val* val = nullptr;
+ decode(val, decoder);
+ value.values.nodeOperand = val;
+ }
+ break;
- // Lets serialize it all
- writer.addPointer(moduleDecl);
- // Let's stick it all in a stream
- writer.write(&stream);
+ case ValNodeOperandKind::ASTNode:
+ {
+ Decl* decl = nullptr;
+ decode(decl, decoder);
+ value.values.nodeOperand = decl;
+ }
+ break;
+ }
+ }
+
+ void decodeValue(TypeExp& value, Decoder& decoder) { decode(value.type, decoder); }
+
+ void decodeValue(QualType& value, Decoder& decoder)
+ {
+ Decoder::WithObject withObject(decoder);
+ decode(value.type, decoder);
+ decode(value.isLeftValue, decoder);
+ decode(value.hasReadOnlyOnTarget, decoder);
+ decode(value.isWriteOnly, decoder);
+ }
+
+ void decodeValue(MatrixCoord& value, Decoder& decoder)
+ {
+ Decoder::WithObject withObject(decoder);
+ decode(value.row, decoder);
+ decode(value.col, decoder);
+ }
+
+ void decodeValue(SPIRVAsmOperand::Flavor& value, Decoder& decoder)
+ {
+ decodeEnum(value, decoder);
+ }
+
+ void decodeValue(SPIRVAsmOperand& value, Decoder& decoder)
+ {
+ Decoder::WithObject withObject(decoder);
+ decode(value.flavor, decoder);
+ decode(value.token, decoder);
+ decode(value.expr, decoder);
+ decode(value.bitwiseOrWith, decoder);
+ decode(value.knownValue, decoder);
+ decode(value.wrapInId, decoder);
+ decode(value.type, decoder);
+ }
+
+ void decodeValue(SPIRVAsmInst& value, Decoder& decoder)
+ {
+ Decoder::WithObject withObject(decoder);
+ decode(value.opcode, decoder);
+ decode(value.operands, decoder);
+ }
+
+
+ template<typename T>
+ void decodeEnum(T& value, Decoder& decoder)
+ {
+ value = T(decoder.decode<Int32>());
+ }
+
+ template<typename T>
+ void decodeSimpleValue(T& value, Decoder& decoder)
+ {
+ value = decoder.decode<T>();
+ }
+
+ void decodeValue(bool& value, Decoder& decoder) { value = decoder.decodeBool(); }
+ void decodeValue(Int32& value, Decoder& decoder) { decodeSimpleValue(value, decoder); }
+ void decodeValue(Int64& value, Decoder& decoder) { decodeSimpleValue(value, decoder); }
+ void decodeValue(UInt32& value, Decoder& decoder) { decodeSimpleValue(value, decoder); }
+ void decodeValue(UInt64& value, Decoder& decoder) { decodeSimpleValue(value, decoder); }
+ void decodeValue(float& value, Decoder& decoder) { decodeSimpleValue(value, decoder); }
+ void decodeValue(double& value, Decoder& decoder) { decodeSimpleValue(value, decoder); }
+
+ void decodeValue(uint8_t& value, Decoder& decoder)
+ {
+ value = uint8_t(decoder.decode<UInt32>());
+ }
+
+ void decodeValue(DeclVisibility& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(BaseType& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(BuiltinRequirementKind& value, Decoder& decoder)
+ {
+ decodeEnum(value, decoder);
+ }
+ void decodeValue(ASTNodeType& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(ImageFormat& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(TypeTag& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(TryClauseType& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(CapabilityAtom& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(PreferRecomputeAttribute::SideEffectBehavior& value, Decoder& decoder)
+ {
+ decodeEnum(value, decoder);
+ }
+ void decodeValue(LogicOperatorShortCircuitExpr::Flavor& value, Decoder& decoder)
+ {
+ decodeEnum(value, decoder);
+ }
+ void decodeValue(TreatAsDifferentiableExpr::Flavor& value, Decoder& decoder)
+ {
+ decodeEnum(value, decoder);
+ }
+ void decodeValue(DeclAssociationKind& value, Decoder& decoder) { decodeEnum(value, decoder); }
+ void decodeValue(TokenType& value, Decoder& decoder) { decodeEnum(value, decoder); }
+
+
+ void decodeValue(SourceLoc& value, Decoder& decoder)
+ {
+ if (!decoder.decodeNull())
+ {
+ SerialSourceLocData::SourceLoc intermediate;
+ decoder.decode(intermediate);
+
+ if (_sourceLocReader)
+ {
+ auto sourceLoc = _sourceLocReader->getSourceLoc(intermediate);
+ value = sourceLoc;
+ }
+ }
+ }
+
+ template<typename T>
+ void decodeValue(T*& ptr, Decoder& decoder)
+ {
+ if (decoder.decodeNull())
+ ptr = nullptr;
+ else
+ decodePtr(ptr, decoder, (T*)nullptr);
+ }
+
+ template<typename T>
+ void decodeValue(RefPtr<T>& ptr, Decoder& decoder)
+ {
+ if (decoder.decodeNull())
+ ptr = nullptr;
+ else
+ {
+ // Hi Future Tess,
+ //
+ // The next step here is decoding logic for `WitnessTable`s.
+ //
+
+ decodePtr(*ptr.writeRef(), decoder, (T*)nullptr);
+ }
+ }
+
+ void decodeValue(Modifiers& modifiers, Decoder& decoder)
+ {
+ Modifier** link = &modifiers.first;
+
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ Modifier* modifier = nullptr;
+ decode(modifier, decoder);
+
+ *link = modifier;
+ link = &modifier->next;
+ }
+ }
+
+ template<typename T, int N>
+ void decodeValue(ShortList<T, N>& array, Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ T element;
+ decode(element, decoder);
+ array.add(element);
+ }
+ }
- stream.swapContents(contents);
- return contents;
-}
+ template<typename T>
+ void decode(List<T>& array, Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ T element;
+ decode(element, decoder);
+ array.add(element);
+ }
+ }
+
+ template<typename T, size_t N>
+ void decode(T (&array)[N], Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ for (auto& element : array)
+ {
+ decode(element, decoder);
+ }
+ }
+
+ template<typename K, typename V>
+ void decode(OrderedDictionary<K, V>& dictionary, Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
+
+ K key;
+ V value;
+ decode(key, decoder);
+ decode(value, decoder);
+
+ dictionary.add(key, value);
+ }
+ }
+
+ template<typename K, typename V>
+ void decode(Dictionary<K, V>& dictionary, Decoder& decoder)
+ {
+ Decoder::WithArray withArray(decoder);
+ while (decoder.hasElements())
+ {
+ Decoder::WithKeyValuePair withPair(decoder);
+
+ K key;
+ V value;
+ decode(key, decoder);
+ decode(value, decoder);
+
+ dictionary.add(key, value);
+ }
+ }
+
+ template<typename T>
+ void decode(T& outValue, Decoder& decoder)
+ {
+ decodeValue(outValue, decoder);
+ }
+
+#if 0 // FIDDLE TEMPLATE:
+%for _,T in ipairs(Slang.NodeBase.subclasses) do
+ void _decodeDataOf($T* obj, Decoder& decoder)
+ {
+% if T.directSuperClass then
+ _decodeDataOf(static_cast<$(T.directSuperClass)*>(obj), decoder);
+% end
+% for _,f in ipairs(T.directFields) do
+ decode(obj->$f, decoder);
+% end
+ }
+%end
+#else // FIDDLE OUTPUT:
+#define FIDDLE_GENERATED_OUTPUT_ID 1
+#include "slang-serialize-ast.cpp.fiddle"
+#endif // FIDDLE END
+};
+
+ModuleDecl* readSerializedModuleAST(
+ Linkage* linkage,
+ ASTBuilder* astBuilder,
+ DiagnosticSink* sink,
+ RiffContainer::Chunk* chunk,
+ SerialSourceLocReader* sourceLocReader,
+ SourceLoc requestingSourceLoc)
+{
+ ASTDecodingContext
+ context(linkage, astBuilder, sink, chunk, sourceLocReader, requestingSourceLoc);
+ context.decodeAll();
+ auto node = context.getDeclByID(0);
+ auto moduleDecl = as<ModuleDecl>(node);
+ return moduleDecl;
+}
} // namespace Slang