diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2020-10-06 17:07:22 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-06 14:07:22 -0700 |
| commit | 4ad2e52662a00f7d8b25be6d451bba33ba62947f (patch) | |
| tree | abd70777a73037c44e40d182e332c7a19c60e779 | |
| parent | 8a70e20df6f47678c146eb29f89655aa734f97c7 (diff) | |
Use Reflection for (Serial)RefObject Serialization (#1567)
* First pass at generalizing serializer.
* Split out ReflectClassInfo
* Use the general ReflectClassInfo
* Fix some typos in debug generalized serialization.
* Add calculation of classIds.
Make distinct addCopy/add on SerialClasses.
* Write up of more generalized serialization
* WIP to transition from ASTSerialReader/Writer etc to generalized SerialReader/Writer and associated types.
* Improvements to SerialExtraObjects.
Keep RefObjects in scope in factory
* Compiles with Serial refactor - doesn't quite work yet.
* First pass serialization appears to work with refector.
* Split out type info for general slang types.
* Split out slang-serialize-misc-type-info.h
* DebugSerialData -> SerialSourecLocData
DebugSerialReader -> SerialSourceLocReader
DebugSerialWriter -> SerialSourceLocWriter
* Remove unused template that only compiles on VS.
* Fix warning around unused function on non-VS.
* Improve output of type names that are in scopes in C++ extractor.
Update premake5.lua to run generation for RefObject derived types.
* C++ extractor working on RefObject type.
* Split out serialization functionality that spans different types into slang-serialization-factory.cpp/.h
Put AST type info into header.
Removed RefObjectSerialSubType - use RefObjectType
Add filtering for RefObject derived types
Remove construction and filteringhacks.
* Set up field serialization for SerialRefObject derived types.
* Fix template problem compiling on Clang/Gcc
* Work in progress to make Value types work.
* Added slang-value-reflect.cpp
25 files changed, 1292 insertions, 897 deletions
diff --git a/premake5.lua b/premake5.lua index 3dcb5dd2e..0d3887986 100644 --- a/premake5.lua +++ b/premake5.lua @@ -269,7 +269,12 @@ function dumpTable(o) return s .. '} ' end - +function getExecutableSuffix() + if(os.target() == "windows") then + return ".exe" + end + return "" +end -- -- We are now going to start defining the projects, where -- each project builds some binary artifact (an executable, @@ -768,6 +773,40 @@ tool "gfx" -- might be able to do pic(true) buildoptions{"-fPIC"} + +function runCPPExtractor(sourcePath, name, inputFiles, stripPrefix, typeName, markSuffix) + + local generatedName = "slang-" .. name .. "-generated.h" + local generatedMacroName = "slang-" .. name .. "-generated-macro.h" + + local options = { "-strip-prefix", stripPrefix, "-reflect-type", typeName, " ", "-o", "slang-" .. name .. "-generated", "-output-fields", "-mark-suffix", markSuffix} + + -- Specify the actual command to run for this action. + -- + -- Note that we use a single-quoted Lua string and wrap the path + -- to the `slang-cpp-extractor` command in double quotes to avoid + -- confusing the Windows shell. It seems that Premake outputs that + -- path with forward slashes, which confused the shell if we don't + -- quote the executable path. + + local buildcmd = '"%{cfg.targetdir}/slang-cpp-extractor" -d ' .. sourcePath .. " " .. table.concat(inputFiles, " ") .. " " .. table.concat(options, " ") + + buildcommands { buildcmd } + + -- Specify the files output by the extactor - so custom action will run when these files are needed. + -- + buildoutputs { sourcePath .. generatedName, sourcePath .. generatedMacroName} + + -- Make it depend on the extractor tool itself + local buildInputTable = { "%{cfg.targetdir}/slang-cpp-extractor" .. getExecutableSuffix() } + for key, inputFile in ipairs(inputFiles) do + table.insert(buildInputTable, sourcePath .. "/" .. inputFile) + end + + -- + buildinputs(buildInputTable) +end + -- -- The `slangc` command-line application is just a very thin wrapper -- around the Slang dynamic library, so its build is extermely simple. @@ -781,7 +820,6 @@ standardProject "slangc" kind "ConsoleApp" links { "core", "slang" } - generatorProject("run-generators", "source/slang/") -- We make 'source/slang' the location of the source, to make paths to source @@ -792,9 +830,10 @@ generatorProject("run-generators", "source/slang/") files { - "source/slang/*.meta.slang", -- The stdlib files - "source/slang/slang-ast-reflect.h", -- The C++ reflection - "prelude/*.h", -- The prelude files + "source/slang/*.meta.slang", -- The stdlib files + "source/slang/slang-ast-reflect.h", -- C++ reflection + "source/slang/slang-ref-object-reflect.h", -- More C++ reflection + "prelude/*.h", -- The prelude files -- -- To build we need to have some source! It has to be a source file that @@ -811,46 +850,28 @@ generatorProject("run-generators", "source/slang/") -- dependson { "slang-cpp-extractor", "slang-generate", "slang-embed" } - local executableSuffix = ""; - if(os.target() == "windows") then - executableSuffix = ".exe"; - end - + local executableSuffix = getExecutableSuffix() + -- We need to run the C++ extractor to generate some include files if executeBinary then - filter "files:**/slang-ast-reflect.h" - buildmessage "slang-cpp-extractor AST %{file.relpath}" - - -- Where the input files are located - local sourcePath = "%{file.directory}/" - - -- Specify the files that will be used for the generation - local inputFiles = { "slang-ast-base.h", "slang-ast-decl.h", "slang-ast-expr.h", "slang-ast-modifier.h", "slang-ast-stmt.h", "slang-ast-type.h", "slang-ast-val.h" } - - -- Specify the actual command to run for this action. - -- - -- Note that we use a single-quoted Lua string and wrap the path - -- to the `slang-cpp-extractor` command in double quotes to avoid - -- confusing the Windows shell. It seems that Premake outputs that - -- path with forward slashes, which confused the shell if we don't - -- quote the executable path. - - local buildcmd = '"%{cfg.targetdir}/slang-cpp-extractor" -d ' .. sourcePath .. " " .. table.concat(inputFiles, " ") .. " -strip-prefix slang-ast- -o slang-ast-generated -output-fields" + local sourcePath = "%{file.directory}" + + filter "files:**/slang-ast-reflect.h" - buildcommands { buildcmd } + buildmessage "slang-cpp-extractor value%{file.relpath}" + + runCPPExtractor(sourcePath, "value", { "slang-ast-support-types.h" }, "slang-", "Value", "_VALUE_CLASS") - -- Specify the files output by the extactor - so custom action will run when these files are needed. - -- - buildoutputs { sourcePath .. "slang-ast-generated.h", sourcePath .. "slang-ast-generated-macro.h"} + filter "files:**/slang-ast-reflect.h" + buildmessage "slang-cpp-extractor ref-object %{file.relpath}" + + runCPPExtractor(sourcePath, "ref-object", { "slang-ast-support-types.h" }, "slang-", "RefObject", "_OBJ_CLASS") - -- Make it depend on the extractor tool itself - local buildInputTable = { "%{cfg.targetdir}/slang-cpp-extractor" .. executableSuffix } - for key, inputFile in ipairs(inputFiles) do - table.insert(buildInputTable, sourcePath .. inputFile) + filter "files:**/slang-ast-reflect.h" + do + local inputFiles = { "slang-ast-base.h", "slang-ast-decl.h", "slang-ast-expr.h", "slang-ast-modifier.h", "slang-ast-stmt.h", "slang-ast-type.h", "slang-ast-val.h" } + runCPPExtractor(sourcePath, "ast", inputFiles, "slang-ast", "ASTNode", "_CLASS") end - - -- - buildinputs(buildInputTable) end -- Next, we want to add a custom build rule for each of the diff --git a/source/slang/run-generators.vcxproj b/source/slang/run-generators.vcxproj index 82b993466..56924b0d5 100644 --- a/source/slang/run-generators.vcxproj +++ b/source/slang/run-generators.vcxproj @@ -156,6 +156,7 @@ <ItemGroup> <ClInclude Include="..\..\prelude\slang-cpp-scalar-intrinsics.h" /> <ClInclude Include="..\..\prelude\slang-cpp-types.h" /> + <ClInclude Include="slang-ref-object-reflect.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="..\core\slang-string.cpp" /> @@ -228,16 +229,24 @@ </CustomBuild> <CustomBuild Include="slang-ast-reflect.h"> <FileType>Document</FileType> - <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-cpp-extractor" -d %(RootDir)%(Directory)/ slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast- -o slang-ast-generated -output-fields</Command> - <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-cpp-extractor" -d %(RootDir)%(Directory)/ slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast- -o slang-ast-generated -output-fields</Command> - <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-cpp-extractor" -d %(RootDir)%(Directory)/ slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast- -o slang-ast-generated -output-fields</Command> - <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-cpp-extractor" -d %(RootDir)%(Directory)/ slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast- -o slang-ast-generated -output-fields</Command> - <Outputs>slang-ast-generated.h;slang-ast-generated-macro.h</Outputs> - <Message>slang-cpp-extractor AST %(Identity)</Message> - <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> - <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">../../bin/windows-x64/debug/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> - <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">../../bin/windows-x86/release/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> - <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">../../bin/windows-x64/release/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> + <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type Value -o slang-value-generated -output-fields -mark-suffix _VALUE_CLASS +"../../bin/windows-x86/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type RefObject -o slang-ref-object-generated -output-fields -mark-suffix _OBJ_CLASS +"../../bin/windows-x86/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast -reflect-type ASTNode -o slang-ast-generated -output-fields -mark-suffix _CLASS</Command> + <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">"../../bin/windows-x64/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type Value -o slang-value-generated -output-fields -mark-suffix _VALUE_CLASS +"../../bin/windows-x64/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type RefObject -o slang-ref-object-generated -output-fields -mark-suffix _OBJ_CLASS +"../../bin/windows-x64/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast -reflect-type ASTNode -o slang-ast-generated -output-fields -mark-suffix _CLASS</Command> + <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"../../bin/windows-x86/release/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type Value -o slang-value-generated -output-fields -mark-suffix _VALUE_CLASS +"../../bin/windows-x86/release/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type RefObject -o slang-ref-object-generated -output-fields -mark-suffix _OBJ_CLASS +"../../bin/windows-x86/release/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast -reflect-type ASTNode -o slang-ast-generated -output-fields -mark-suffix _CLASS</Command> + <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">"../../bin/windows-x64/release/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type Value -o slang-value-generated -output-fields -mark-suffix _VALUE_CLASS +"../../bin/windows-x64/release/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h -strip-prefix slang- -reflect-type RefObject -o slang-ref-object-generated -output-fields -mark-suffix _OBJ_CLASS +"../../bin/windows-x64/release/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast -reflect-type ASTNode -o slang-ast-generated -output-fields -mark-suffix _CLASS</Command> + <Outputs>../slangslang-value-generated.h;../slangslang-value-generated-macro.h;../slangslang-ref-object-generated.h;../slangslang-ref-object-generated-macro.h;../slangslang-ast-generated.h;../slangslang-ast-generated-macro.h</Outputs> + <Message>slang-cpp-extractor ref-object %(Identity)</Message> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">slang-ast-support-types.h;../../bin/windows-x86/debug/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">slang-ast-support-types.h;../../bin/windows-x64/debug/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">slang-ast-support-types.h;../../bin/windows-x86/release/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">slang-ast-support-types.h;../../bin/windows-x64/release/slang-cpp-extractor.exe;slang-ast-base.h;slang-ast-decl.h;slang-ast-expr.h;slang-ast-modifier.h;slang-ast-stmt.h;slang-ast-type.h;slang-ast-val.h</AdditionalInputs> </CustomBuild> </ItemGroup> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> diff --git a/source/slang/run-generators.vcxproj.filters b/source/slang/run-generators.vcxproj.filters index e8ec8394a..9ec19c0d7 100644 --- a/source/slang/run-generators.vcxproj.filters +++ b/source/slang/run-generators.vcxproj.filters @@ -15,6 +15,9 @@ <ClInclude Include="..\..\prelude\slang-cpp-types.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-ref-object-reflect.h"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\core\slang-string.cpp"> diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h index 275832342..66b7d7c9e 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -14,12 +14,11 @@ // basic `Decl`, `Stmt`, `Expr`, `type`, etc. definitions come from. namespace Slang -{ +{ class NodeBase { SLANG_ABSTRACT_CLASS(NodeBase) - SLANG_CLASS_ROOT // MUST be called before used. Called automatically via the ASTBuilder. // Note that the astBuilder is not stored in the NodeBase derived types by default. diff --git a/source/slang/slang-ast-reflect.h b/source/slang/slang-ast-reflect.h index 3b055cc87..63bd889b8 100644 --- a/source/slang/slang-ast-reflect.h +++ b/source/slang/slang-ast-reflect.h @@ -3,11 +3,9 @@ #ifndef SLANG_AST_REFLECT_H #define SLANG_AST_REFLECT_H -#include "slang-ast-generated.h" +#include "slang-serialize-reflection.h" -#define SLANG_CLASS_REFLECT_SUPER_BASE(SUPER) -#define SLANG_CLASS_REFLECT_SUPER_INNER(SUPER) typedef SUPER Super; -#define SLANG_CLASS_REFLECT_SUPER_LEAF(SUPER) typedef SUPER Super; +#include "slang-ast-generated.h" // Implementation for SLANG_ABSTRACT_CLASS(x) using reflection from C++ extractor in slang-ast-generated.h #define SLANG_CLASS_REFLECT_IMPL(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ @@ -28,13 +26,6 @@ #define SLANG_ABSTRACT_CLASS(NAME) SLANG_ASTNode_##NAME(SLANG_CLASS_REFLECT_IMPL, _) #define SLANG_CLASS(NAME) SLANG_ASTNode_##NAME(SLANG_CLASS_REFLECT_IMPL, _) -// Does nothing - just a mark to the C++ extractor -#define SLANG_REFLECT_BASE_CLASS(NAME) -#define SLANG_REFLECTED -#define SLANG_UNREFLECTED - -#define SLANG_CLASS_ROOT - // Macros for simulating virtual methods without virtual methods #define SLANG_AST_NODE_INVOKE(method, methodParams) _##method##Override methodParams diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index ae2f6e6be..4cc76804c 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -9,12 +9,13 @@ #include "../core/slang-semantic-version.h" -#include "slang-ast-generated.h" - -#include "slang-ast-reflect.h" +#include "slang-ast-generated.h" #include "slang-serialize-reflection.h" +#include "slang-ast-reflect.h" +#include "slang-ref-object-reflect.h" + #include "slang-name.h" #include <assert.h> @@ -444,6 +445,8 @@ namespace Slang struct QualType { + SLANG_VALUE_CLASS(QualType) + Type* type = nullptr; bool isLeftValue; @@ -1003,9 +1006,98 @@ namespace Slang IgnoreBaseInterfaces = 1 << 0, }; + class SerialRefObject; + // Make sure C++ extractor can see the base class. + SLANG_PRE_DECLARE(_OBJ_CLASS, class SerialRefObject) + + class LookupResultItem_Breadcrumb : public SerialRefObject + { + public: + SLANG_OBJ_CLASS(LookupResultItem_Breadcrumb) + + enum class Kind : uint8_t + { + // The lookup process looked "through" an in-scope + // declaration to the fields inside of it, so that + // even if lookup started with a simple name `f`, + // it needs to result in a member expression `obj.f`. + Member, + + // The lookup process took a pointer(-like) value, and then + // proceeded to derefence it and look at the thing(s) + // it points to instead, so that the final expression + // needs to have `(*obj)` + Deref, + + // The lookup process saw a value `obj` of type `T` and + // took into account an in-scope constraint that says + // `T` is a subtype of some other type `U`, so that + // lookup was able to find a member through type `U` + // instead. + SuperType, + + // The lookup process considered a member of an + // enclosing type as being in scope, so that any + // reference to that member needs to use a `this` + // expression as appropriate. + This, + }; + + // The kind of lookup step that was performed + Kind kind; + + // For the `Kind::This` case, what does the implicit + // `this` or `This` parameter refer to? + // + enum class ThisParameterMode : uint8_t + { + ImmutableValue, // An immutable `this` value + MutableValue, // A mutable `this` value + Type, // A `This` type + + Default = ImmutableValue, + }; + ThisParameterMode thisParameterMode = ThisParameterMode::Default; + + // As needed, a reference to the declaration that faciliated + // the lookup step. + // + // For a `Member` lookup step, this is the declaration whose + // members were implicitly pulled into scope. + // + // For a `Constraint` lookup step, this is the `ConstraintDecl` + // that serves to witness the subtype relationship. + // + DeclRef<Decl> declRef; + + Val* val = nullptr; + + // The next implicit step that the lookup process took to + // arrive at a final value. + RefPtr<LookupResultItem_Breadcrumb> next; + + LookupResultItem_Breadcrumb( + Kind kind, + DeclRef<Decl> declRef, + Val* val, + RefPtr<LookupResultItem_Breadcrumb> next, + ThisParameterMode thisParameterMode = ThisParameterMode::Default) + : kind(kind) + , thisParameterMode(thisParameterMode) + , declRef(declRef) + , val(val) + , next(next) + {} + protected: + // Needed for serialization + LookupResultItem_Breadcrumb() = default; + }; + // Represents one item found during lookup struct LookupResultItem { + typedef LookupResultItem_Breadcrumb Breadcrumb; + // Sometimes lookup finds an item, but there were additional // "hops" taken to reach it. We need to remember these steps // so that if/when we consturct a full expression we generate @@ -1058,83 +1150,7 @@ namespace Slang // the unique result (perhaps by overload resolution), then // we can walk the list of breadcrumbs to create a full // expression. - class Breadcrumb : public RefObject - { - public: - enum class Kind : uint8_t - { - // The lookup process looked "through" an in-scope - // declaration to the fields inside of it, so that - // even if lookup started with a simple name `f`, - // it needs to result in a member expression `obj.f`. - Member, - - // The lookup process took a pointer(-like) value, and then - // proceeded to derefence it and look at the thing(s) - // it points to instead, so that the final expression - // needs to have `(*obj)` - Deref, - - // The lookup process saw a value `obj` of type `T` and - // took into account an in-scope constraint that says - // `T` is a subtype of some other type `U`, so that - // lookup was able to find a member through type `U` - // instead. - SuperType, - - // The lookup process considered a member of an - // enclosing type as being in scope, so that any - // reference to that member needs to use a `this` - // expression as appropriate. - This, - }; - - // The kind of lookup step that was performed - Kind kind; - - // For the `Kind::This` case, what does the implicit - // `this` or `This` parameter refer to? - // - enum class ThisParameterMode : uint8_t - { - ImmutableValue, // An immutable `this` value - MutableValue, // A mutable `this` value - Type, // A `This` type - - Default = ImmutableValue, - }; - ThisParameterMode thisParameterMode = ThisParameterMode::Default; - - // As needed, a reference to the declaration that faciliated - // the lookup step. - // - // For a `Member` lookup step, this is the declaration whose - // members were implicitly pulled into scope. - // - // For a `Constraint` lookup step, this is the `ConstraintDecl` - // that serves to witness the subtype relationship. - // - DeclRef<Decl> declRef; - - Val* val = nullptr; - - // The next implicit step that the lookup process took to - // arrive at a final value. - RefPtr<Breadcrumb> next; - - Breadcrumb( - Kind kind, - DeclRef<Decl> declRef, - Val* val, - RefPtr<Breadcrumb> next, - ThisParameterMode thisParameterMode = ThisParameterMode::Default) - : kind(kind) - , thisParameterMode(thisParameterMode) - , declRef(declRef) - , val(val) - , next(next) - {} - }; + // A properly-specialized reference to the declaration that was found. DeclRef<Decl> declRef; diff --git a/source/slang/slang-ref-object-reflect.cpp b/source/slang/slang-ref-object-reflect.cpp new file mode 100644 index 000000000..caf8eb6a3 --- /dev/null +++ b/source/slang/slang-ref-object-reflect.cpp @@ -0,0 +1,85 @@ +#include "../../slang.h" + +#include "slang-ref-object-reflect.h" + +#include "slang-ref-object-generated.h" +#include "slang-ref-object-generated-macro.h" + +#include "slang-ast-support-types.h" + +//#include "slang-serialize.h" + +#include "slang-serialize-ast-type-info.h" + +namespace Slang +{ + +static const SerialClass* _addClass(SerialClasses* serialClasses, RefObjectType type, RefObjectType super, const List<SerialField>& fields) +{ + const SerialClass* superClass = serialClasses->getSerialClass(SerialTypeKind::RefObject, SerialSubType(super)); + return serialClasses->add(SerialTypeKind::RefObject, SerialSubType(type), fields.getBuffer(), fields.getCount(), superClass); +} + +#define SLANG_REF_OBJECT_ADD_SERIAL_FIELD(FIELD_NAME, TYPE, param) fields.add(SerialField::make(#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_REF_OBJECT_ADD_SERIAL_CLASS(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ +{ \ + NAME* obj = SerialField::getPtr<NAME>(); \ + SLANG_UNUSED(obj); \ + fields.clear(); \ + SLANG_FIELDS_RefObject_##NAME(SLANG_REF_OBJECT_ADD_SERIAL_FIELD, param) \ + _addClass(serialClasses, RefObjectType::NAME, RefObjectType::SUPER, fields); \ +} + +struct RefObjectAccess +{ + template <typename T> + static void* create(void* context) + { + SLANG_UNUSED(context) + return new T; + } + + static void calcClasses(SerialClasses* serialClasses) + { + // Add SerialRefObject first, and specially handle so that we add a null super class + serialClasses->add(SerialTypeKind::RefObject, SerialSubType(RefObjectType::SerialRefObject), nullptr, 0, nullptr); + + // Add the rest in order such that Super class is always added before its children + List<SerialField> fields; + SLANG_CHILDREN_RefObject_SerialRefObject(SLANG_REF_OBJECT_ADD_SERIAL_CLASS, _) + } +}; + +#define SLANG_GET_SUPER_BASE(SUPER) nullptr +#define SLANG_GET_SUPER_INNER(SUPER) &SUPER::kReflectClassInfo +#define SLANG_GET_SUPER_LEAF(SUPER) &SUPER::kReflectClassInfo + +#define SLANG_GET_CREATE_FUNC_NONE(NAME) nullptr +#define SLANG_GET_CREATE_FUNC_OBJ_ABSTRACT(NAME) nullptr +#define SLANG_GET_CREATE_FUNC_OBJ(NAME) &RefObjectAccess::create<NAME> + +#define SLANG_REFLECT_CLASS_INFO(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ + /* static */const ReflectClassInfo NAME::kReflectClassInfo = { uint32_t(RefObjectType::NAME), uint32_t(RefObjectType::LAST), SLANG_GET_SUPER_##TYPE(SUPER), #NAME, SLANG_GET_CREATE_FUNC_##MARKER(NAME), nullptr, uint32_t(sizeof(NAME)), uint8_t(SLANG_ALIGN_OF(NAME)) }; + +SLANG_ALL_RefObject_SerialRefObject(SLANG_REFLECT_CLASS_INFO, _) + +/* static */const SerialRefObjects SerialRefObjects::g_singleton; + +// Macro to set all of the entries in m_infos for SerialRefObjects +#define SLANG_GET_REFLECT_CLASS_INFO(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) m_infos[Index(RefObjectType::NAME)] = &NAME::kReflectClassInfo; + +SerialRefObjects::SerialRefObjects() +{ + SLANG_ALL_RefObject_SerialRefObject(SLANG_GET_REFLECT_CLASS_INFO, _) +} + +/* static */SlangResult SerialRefObjects::addSerialClasses(SerialClasses* serialClasses) +{ + RefObjectAccess::calcClasses(serialClasses); + return SLANG_OK; +} + +} // namespace Slang diff --git a/source/slang/slang-ref-object-reflect.h b/source/slang/slang-ref-object-reflect.h new file mode 100644 index 000000000..cf50c010a --- /dev/null +++ b/source/slang/slang-ref-object-reflect.h @@ -0,0 +1,69 @@ +// slang-ref-object-reflect.h + +#ifndef SLANG_REF_OBJECT_REFLECT_H +#define SLANG_REF_OBJECT_REFLECT_H + +#include "slang-serialize-reflection.h" + +#include "slang-ref-object-generated.h" + +#include "../core/slang-smart-pointer.h" + +class SerialClasses; + +struct RefObjectAccess; + +#define SLANG_OBJ_CLASS_REFLECT_IMPL(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ + public: \ + typedef NAME This; \ + static const ReflectClassInfo kReflectClassInfo; \ + virtual const ReflectClassInfo* getClassInfo() const SLANG_OVERRIDE { return &kReflectClassInfo; } \ + \ + friend struct RefObjectAccess; \ + \ + SLANG_CLASS_REFLECT_SUPER_##TYPE(SUPER) \ + +// Placed in any SerialRefObject derived class +#define SLANG_ABSTRACT_OBJ_CLASS(NAME) SLANG_RefObject_##NAME(SLANG_OBJ_CLASS_REFLECT_IMPL, _) +#define SLANG_OBJ_CLASS(NAME) SLANG_RefObject_##NAME(SLANG_OBJ_CLASS_REFLECT_IMPL, _) + +namespace Slang +{ + +class SerialClasses; + +// Is friended such that internally we have access to construct or get members +struct RefObjectAccess; + +// Base class for Serialized RefObject derived classes. The main feature is that gives away to get ReflectClassInfo +// via getClassInfo() method +class SerialRefObject : public RefObject +{ +public: + typedef RefObject Super; + typedef SerialRefObject This; + + static const ReflectClassInfo kReflectClassInfo; + + virtual const ReflectClassInfo* getClassInfo() const { return &kReflectClassInfo; } +}; + +// For turning RefObjectType back to ReflectClassInfo +struct SerialRefObjects +{ + /// Add serialization classes + static SlangResult addSerialClasses(SerialClasses* serialClasses); + + static const ReflectClassInfo* getClassInfo(RefObjectType type) { return g_singleton.m_infos[Index(type)]; } + + + static const SerialRefObjects g_singleton; + +protected: + SerialRefObjects(); + const ReflectClassInfo* m_infos[Index(RefObjectType::CountOf)]; +}; + +} // namespace Slang + +#endif // SLANG_REF_OBJECT_REFLECT_H diff --git a/source/slang/slang-serialize-ast-type-info.h b/source/slang/slang-serialize-ast-type-info.h new file mode 100644 index 000000000..03fe61fbb --- /dev/null +++ b/source/slang/slang-serialize-ast-type-info.h @@ -0,0 +1,401 @@ +// slang-serialize-ast-type-info.h +#ifndef SLANG_SERIALIZE_AST_TYPE_INFO_H +#define SLANG_SERIALIZE_AST_TYPE_INFO_H + +#include "slang-ast-support-types.h" +#include "slang-ast-all.h" + +#include "slang-serialize-type-info.h" +#include "slang-serialize-misc-type-info.h" + +namespace Slang { + + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AST types !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +// SyntaxClass<T> +template <typename T> +struct SerialTypeInfo<SyntaxClass<T>> +{ + typedef SyntaxClass<T> NativeType; + typedef uint16_t SerialType; + + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* 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(SerialReader* reader, const void* serial, void* native) + { + SLANG_UNUSED(reader); + auto& src = *(const SerialType*)serial; + auto& dst = *(NativeType*)native; + dst.classInfo = ASTClassInfo::getInfo(ASTNodeType(src)); + } +}; + +struct SerialDeclRefBaseTypeInfo +{ + typedef DeclRefBase NativeType; + struct SerialType + { + SerialIndex substitutions; + SerialIndex decl; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* 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(SerialReader* 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 SerialFieldType* getFieldType() + { + static const SerialFieldType type = { sizeof(SerialType), uint8_t(SerialAlignment), &toSerial, &toNative }; + return &type; + } +}; +// Special case DeclRef, because it always uses the same type +template <typename T> +struct SerialGetFieldType<DeclRef<T>> +{ + static const SerialFieldType* getFieldType() { return SerialDeclRefBaseTypeInfo::getFieldType(); } +}; + + +template <typename T> +struct SerialTypeInfo<DeclRef<T>> : public SerialDeclRefBaseTypeInfo {}; + +// MatrixCoord can just go as is +template <> +struct SerialTypeInfo<MatrixCoord> : SerialIdentityTypeInfo<MatrixCoord> {}; + + +// QualType + +template <> +struct SerialTypeInfo<QualType> +{ + typedef QualType NativeType; + struct SerialType + { + SerialIndex type; + uint8_t isLeftValue; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; + + static void toSerial(SerialWriter* writer, const void* native, void* serial) + { + auto dst = (SerialType*)serial; + auto src = (const NativeType*)native; + dst->isLeftValue = src->isLeftValue ? 1 : 0; + dst->type = writer->addPointer(src->type); + } + static void toNative(SerialReader* reader, const void* serial, void* native) + { + auto src = (const SerialType*)serial; + auto dst = (NativeType*)native; + dst->type = reader->getPointer(src->type).dynamicCast<Type>(); + dst->isLeftValue = src->isLeftValue != 0; + } +}; + + +// LookupResult::Breadcrumb +template <> +struct SerialTypeInfo<LookupResultItem::Breadcrumb> +{ + typedef LookupResultItem::Breadcrumb NativeType; + struct SerialType + { + NativeType::Kind kind; + NativeType::ThisParameterMode thisParameterMode; + SerialTypeInfo<DeclRef<Decl>>::SerialType declRef; + SerialTypeInfo<RefPtr<NativeType>> next; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<LookupResultItem> +{ + typedef LookupResultItem NativeType; + struct SerialType + { + SerialTypeInfo<DeclRef<Decl>>::SerialType declRef; + SerialTypeInfo<RefPtr<NativeType::Breadcrumb>> breadcrumbs; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<LookupResult> +{ + typedef LookupResult NativeType; + typedef SerialIndex SerialType; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* 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 = SerialIndex(0); + } + } + static void toNative(SerialReader* 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 SerialTypeInfo<GlobalGenericParamSubstitution::ConstraintArg> +{ + typedef GlobalGenericParamSubstitution::ConstraintArg NativeType; + struct SerialType + { + SerialIndex decl; + SerialIndex val; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; + + static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<ExpandedSpecializationArg> +{ + typedef ExpandedSpecializationArg NativeType; + struct SerialType + { + SerialIndex val; + SerialIndex witness; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; + + static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<TypeExp> +{ + typedef TypeExp NativeType; + struct SerialType + { + SerialIndex type; + SerialIndex expr; + }; + enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; + + static void toSerial(SerialWriter* 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(SerialReader* 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.expr).dynamicCast<Expr>(); + } +}; + +// DeclCheckStateExt +template <> +struct SerialTypeInfo<DeclCheckStateExt> +{ + typedef DeclCheckStateExt NativeType; + typedef DeclCheckStateExt::RawType SerialType; + + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* writer, const void* native, void* serial) + { + SLANG_UNUSED(writer); + *(SerialType*)serial = (*(const NativeType*)native).getRaw(); + } + static void toNative(SerialReader* reader, const void* serial, void* native) + { + SLANG_UNUSED(reader); + (*(NativeType*)serial).setRaw(*(const SerialType*)native); + } +}; + +// Modifiers +template <> +struct SerialTypeInfo<Modifiers> +{ + typedef Modifiers NativeType; + typedef SerialIndex SerialType; + + enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; + + static void toSerial(SerialWriter* writer, const void* native, void* serial) + { + // We need to make into an array + List<SerialIndex> modifierIndices; + for (Modifier* modifier : *(NativeType*)native) + { + modifierIndices.add(writer->addPointer(modifier)); + } + *(SerialType*)serial = writer->addArray(modifierIndices.getBuffer(), modifierIndices.getCount()); + } + static void toNative(SerialReader* 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; + } +}; + +// ASTNodeType +template <> +struct SerialTypeInfo<ASTNodeType> : public SerialConvertTypeInfo<ASTNodeType, uint16_t> {}; + +// LookupResultItem_Breadcrumb::ThisParameterMode +template <> +struct SerialTypeInfo<LookupResultItem_Breadcrumb::ThisParameterMode> : public SerialConvertTypeInfo<LookupResultItem_Breadcrumb::ThisParameterMode, uint8_t> {}; + +// LookupResultItem_Breadcrumb::Kind +template <> +struct SerialTypeInfo<LookupResultItem_Breadcrumb::Kind> : public SerialConvertTypeInfo<LookupResultItem_Breadcrumb::Kind, uint8_t> {}; + +} // namespace Slang + +#endif diff --git a/source/slang/slang-serialize-ast.cpp b/source/slang/slang-serialize-ast.cpp index 65a5488a3..8310c155b 100644 --- a/source/slang/slang-serialize-ast.cpp +++ b/source/slang/slang-serialize-ast.cpp @@ -8,475 +8,27 @@ #include "slang-ast-support-types.h" -// Needed for ModuleSerialFilter -// Needed for 'findModuleForDecl' -#include "slang-legalize-types.h" -#include "slang-mangle.h" +#include "slang-serialize-ast-type-info.h" -#include "slang-serialize-type-info.h" -#include "slang-serialize-misc-type-info.h" +#include "slang-serialize-factory.h" namespace Slang { -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ModuleSerialFilter !!!!!!!!!!!!!!!!!!!!!!!! - -SerialIndex ModuleSerialFilter::writePointer(SerialWriter* writer, const NodeBase* inPtr) -{ - NodeBase* ptr = const_cast<NodeBase*>(inPtr); - SLANG_ASSERT(ptr); - - if (Decl* decl = as<Decl>(ptr)) - { - ModuleDecl* moduleDecl = findModuleForDecl(decl); - SLANG_ASSERT(moduleDecl); - if (moduleDecl && moduleDecl != m_moduleDecl) - { - ASTBuilder* astBuilder = m_moduleDecl->module->getASTBuilder(); - - // It's a reference to a declaration in another module, so create an ImportExternalDecl. - - String mangledName = getMangledName(astBuilder, decl); - - ImportExternalDecl* importDecl = astBuilder->create<ImportExternalDecl>(); - importDecl->mangledName = mangledName; - const SerialIndex index = writer->addPointer(importDecl); - - // Set as the index of this - writer->setPointerIndex(ptr, index); - - return index; - } - else - { - // Okay... we can just write it out then - return writer->writeObject(ptr); - } - } - - // TODO(JS): What we really want to do here is to ignore bodies functions. - // It's not 100% clear if this is even right though - for example does type inference - // imply the body is needed to say infer a return type? - // Also not clear if statements in other scenarios (if there are others) might need to be kept. - // - // For now we just ignore all stmts - - if (Stmt* stmt = as<Stmt>(ptr)) - { - // - writer->setPointerIndex(stmt, SerialIndex(0)); - return SerialIndex(0); - } - - // For now for everything else just write it - return writer->writeObject(ptr); -} - -/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! AST types !!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -// SyntaxClass<T> -template <typename T> -struct SerialTypeInfo<SyntaxClass<T>> -{ - typedef SyntaxClass<T> NativeType; - typedef uint16_t SerialType; - - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* 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(SerialReader* reader, const void* serial, void* native) - { - SLANG_UNUSED(reader); - auto& src = *(const SerialType*)serial; - auto& dst = *(NativeType*)native; - dst.classInfo = ASTClassInfo::getInfo(ASTNodeType(src)); - } -}; - -struct SerialDeclRefBaseTypeInfo -{ - typedef DeclRefBase NativeType; - struct SerialType - { - SerialIndex substitutions; - SerialIndex decl; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* 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(SerialReader* 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 SerialFieldType* getFieldType() - { - static const SerialFieldType type = { sizeof(SerialType), uint8_t(SerialAlignment), &toSerial, &toNative }; - return &type; - } -}; -// Special case DeclRef, because it always uses the same type -template <typename T> -struct SerialGetFieldType<DeclRef<T>> -{ - static const SerialFieldType* getFieldType() { return SerialDeclRefBaseTypeInfo::getFieldType(); } -}; - - -template <typename T> -struct SerialTypeInfo<DeclRef<T>> : public SerialDeclRefBaseTypeInfo {}; - -// MatrixCoord can just go as is -template <> -struct SerialTypeInfo<MatrixCoord> : SerialIdentityTypeInfo<MatrixCoord> {}; - - -// QualType - -template <> -struct SerialTypeInfo<QualType> -{ - typedef QualType NativeType; - struct SerialType - { - SerialIndex type; - uint8_t isLeftValue; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; - - static void toSerial(SerialWriter* writer, const void* native, void* serial) - { - auto dst = (SerialType*)serial; - auto src = (const NativeType*)native; - dst->isLeftValue = src->isLeftValue ? 1 : 0; - dst->type = writer->addPointer(src->type); - } - static void toNative(SerialReader* reader, const void* serial, void* native) - { - auto src = (const SerialType*)serial; - auto dst = (NativeType*)native; - dst->type = reader->getPointer(src->type).dynamicCast<Type>(); - dst->isLeftValue = src->isLeftValue != 0; - } -}; - - -// LookupResult::Breadcrumb -template <> -struct SerialTypeInfo<LookupResultItem::Breadcrumb> -{ - typedef LookupResultItem::Breadcrumb NativeType; - struct SerialType - { - NativeType::Kind kind; - NativeType::ThisParameterMode thisParameterMode; - SerialTypeInfo<DeclRef<Decl>>::SerialType declRef; - SerialTypeInfo<RefPtr<NativeType>> next; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<LookupResultItem> -{ - typedef LookupResultItem NativeType; - struct SerialType - { - SerialTypeInfo<DeclRef<Decl>>::SerialType declRef; - SerialTypeInfo<RefPtr<NativeType::Breadcrumb>> breadcrumbs; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<LookupResult> -{ - typedef LookupResult NativeType; - typedef SerialIndex SerialType; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* 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 = SerialIndex(0); - } - } - static void toNative(SerialReader* 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 SerialTypeInfo<GlobalGenericParamSubstitution::ConstraintArg> -{ - typedef GlobalGenericParamSubstitution::ConstraintArg NativeType; - struct SerialType - { - SerialIndex decl; - SerialIndex val; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; - - static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<ExpandedSpecializationArg> -{ - typedef ExpandedSpecializationArg NativeType; - struct SerialType - { - SerialIndex val; - SerialIndex witness; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; - - static void toSerial(SerialWriter* 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(SerialReader* 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 SerialTypeInfo<TypeExp> -{ - typedef TypeExp NativeType; - struct SerialType - { - SerialIndex type; - SerialIndex expr; - }; - enum { SerialAlignment = SLANG_ALIGN_OF(SerialIndex) }; - - static void toSerial(SerialWriter* 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(SerialReader* 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.expr).dynamicCast<Expr>(); - } -}; - -// DeclCheckStateExt -template <> -struct SerialTypeInfo<DeclCheckStateExt> -{ - typedef DeclCheckStateExt NativeType; - typedef DeclCheckStateExt::RawType SerialType; - - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* writer, const void* native, void* serial) - { - SLANG_UNUSED(writer); - *(SerialType*)serial = (*(const NativeType*)native).getRaw(); - } - static void toNative(SerialReader* reader, const void* serial, void* native) - { - SLANG_UNUSED(reader); - (*(NativeType*)serial).setRaw(*(const SerialType*)native); - } -}; - -// Modifiers -template <> -struct SerialTypeInfo<Modifiers> -{ - typedef Modifiers NativeType; - typedef SerialIndex SerialType; - - enum { SerialAlignment = SLANG_ALIGN_OF(SerialType) }; - - static void toSerial(SerialWriter* writer, const void* native, void* serial) - { - // We need to make into an array - List<SerialIndex> modifierIndices; - for (Modifier* modifier : *(NativeType*)native) - { - modifierIndices.add(writer->addPointer(modifier)); - } - *(SerialType*)serial = writer->addArray(modifierIndices.getBuffer(), modifierIndices.getCount()); - } - static void toNative(SerialReader* 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; - } -}; - -// ASTNodeType -template <> -struct SerialTypeInfo<ASTNodeType> : public SerialConvertTypeInfo<ASTNodeType, uint16_t> {}; - // !!!!!!!!!!!!!!!!!!!!!! Generate fields for a type !!!!!!!!!!!!!!!!!!!!!!!!!!! -template <typename T> -SerialField _makeField(const char* name, T& in) -{ - uint8_t* ptr = &reinterpret_cast<uint8_t&>(in); - - SerialField field; - field.name = name; - field.type = SerialGetFieldType<T>::getFieldType(); - // 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 const SerialClass* _addClass(SerialClasses* serialClasses, ASTNodeType type, ASTNodeType super, const List<SerialField>& fields) { const SerialClass* superClass = serialClasses->getSerialClass(SerialTypeKind::NodeBase, SerialSubType(super)); return serialClasses->add(SerialTypeKind::NodeBase, SerialSubType(type), fields.getBuffer(), fields.getCount(), superClass); } -#define SLANG_AST_ADD_SERIAL_FIELD(FIELD_NAME, TYPE, param) fields.add(_makeField(#FIELD_NAME, obj->FIELD_NAME)); +#define SLANG_AST_ADD_SERIAL_FIELD(FIELD_NAME, TYPE, param) fields.add(SerialField::make(#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_ADD_SERIAL_CLASS(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ { \ - NAME* obj = (NAME*)1; \ + NAME* obj = SerialField::getPtr<NAME>(); \ SLANG_UNUSED(obj); \ fields.clear(); \ SLANG_FIELDS_ASTNode_##NAME(SLANG_AST_ADD_SERIAL_FIELD, param) \ @@ -496,108 +48,18 @@ struct ASTFieldAccess } }; -void addASTTypes(SerialClasses* serialClasses) -{ - { - ASTFieldAccess::calcClasses(serialClasses); - } - - { - { - // Let's hack Breadcrumbs... +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerialUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!! - typedef LookupResultItem::Breadcrumb Type; - Type* obj = (Type*)1; - SerialField field = _makeField("_", *obj); - serialClasses->add(SerialTypeKind::RefObject, SerialSubType(RefObjectSerialSubType::LookupResultItem_Breadcrumb), &field, 1, nullptr); - } - - // Set these types to not serialize - serialClasses->addUnserialized(SerialTypeKind::RefObject, SerialSubType(RefObjectSerialSubType::Module)); - serialClasses->addUnserialized(SerialTypeKind::RefObject, SerialSubType(RefObjectSerialSubType::Scope)); - } -} - -// A Hack for now to turn an RefObject* into a SubType for serialization -extern RefObjectSerialSubType getRefObjectSubType(const RefObject* obj) +/* static */void ASTSerialUtil::addSerialClasses(SerialClasses* serialClasses) { - if (as<LookupResultItem::Breadcrumb>(obj)) - { - return RefObjectSerialSubType::LookupResultItem_Breadcrumb; - } - else if (as<Module>(obj)) - { - return RefObjectSerialSubType::Module; - } - else if (as<Scope>(obj)) - { - return RefObjectSerialSubType::Scope; - } - return RefObjectSerialSubType::Invalid; -} - -/* !!!!!!!!!!!!!!!!!!!!!! DefaultSerialObjectFactory !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ - -void* DefaultSerialObjectFactory::create(SerialTypeKind typeKind, SerialSubType subType) -{ - switch (typeKind) - { - case SerialTypeKind::NodeBase: - { - return m_astBuilder->createByNodeType(ASTNodeType(subType)); - } - case SerialTypeKind::RefObject: - { - switch (RefObjectSerialSubType(subType)) - { - case RefObjectSerialSubType::LookupResultItem_Breadcrumb: - { - typedef LookupResultItem::Breadcrumb Breadcrumb; - return _add(new LookupResultItem::Breadcrumb(Breadcrumb::Kind::Member, DeclRef<Decl>(), nullptr, nullptr)); - } - default: break; - } - } - default: break; - } - - return nullptr; + ASTFieldAccess::calcClasses(serialClasses); } - -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ASTSerializeUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!! - -/* static */SlangResult ASTSerialTestUtil::selfTest() + +/* static */SlangResult ASTSerialUtil::testSerialize(NodeBase* node, RootNamePool* rootNamePool, SharedASTBuilder* sharedASTBuilder, SourceManager* sourceManager) { RefPtr<SerialClasses> classes; - SerialClasses::create(classes); - { - const SerialFieldType* type = SerialGetFieldType<Type*>::getFieldType(); - SLANG_UNUSED(type); - } - - { - const SerialFieldType* type = SerialGetFieldType<int[10]>::getFieldType(); - SLANG_UNUSED(type); - } - - { - const SerialFieldType* type = SerialGetFieldType<bool[3]>::getFieldType(); - SLANG_UNUSED(type); - } - - { - const SerialFieldType* type = SerialGetFieldType<Type*[3]>::getFieldType(); - SLANG_UNUSED(type); - } - - return SLANG_OK; -} - -/* static */SlangResult ASTSerialTestUtil::testSerialize(NodeBase* node, RootNamePool* rootNamePool, SharedASTBuilder* sharedASTBuilder, SourceManager* sourceManager) -{ - RefPtr<SerialClasses> classes; - SerialClasses::create(classes); + SerialClassesUtil::create(classes); List<uint8_t> contents; diff --git a/source/slang/slang-serialize-ast.h b/source/slang/slang-serialize-ast.h index e2b9a956a..3aa790c86 100644 --- a/source/slang/slang-serialize-ast.h +++ b/source/slang/slang-serialize-ast.h @@ -30,6 +30,7 @@ class ModuleSerialFilter : public SerialFilter public: // SerialFilter impl virtual SerialIndex writePointer(SerialWriter* writer, const NodeBase* ptr) SLANG_OVERRIDE; + virtual SerialIndex writePointer(SerialWriter* writer, const RefObject* ptr) SLANG_OVERRIDE; ModuleSerialFilter(ModuleDecl* moduleDecl): m_moduleDecl(moduleDecl) @@ -39,34 +40,10 @@ public: ModuleDecl* m_moduleDecl; }; -class DefaultSerialObjectFactory : public SerialObjectFactory +struct ASTSerialUtil { -public: - - virtual void* create(SerialTypeKind typeKind, SerialSubType subType) SLANG_OVERRIDE; - - DefaultSerialObjectFactory(ASTBuilder* astBuilder) : - m_astBuilder(astBuilder) - { - } - -protected: - RefObject* _add(RefObject* obj) - { - m_scope.add(obj); - return obj; - } - - // We keep RefObjects in scope - List<RefPtr<RefObject>> m_scope; - ASTBuilder* m_astBuilder; -}; - -/* None of the functions in this util should *not* be called from production code, -they exist to test features of AST Serialization */ -struct ASTSerialTestUtil -{ - static SlangResult selfTest(); + /// Add the AST related classes + static void addSerialClasses(SerialClasses* classes); /// Tries to serialize out, read back in and test the results are the same. /// Will write dumped out node to files diff --git a/source/slang/slang-serialize-container.cpp b/source/slang/slang-serialize-container.cpp index 3d5b234ff..7dd2c15a1 100644 --- a/source/slang/slang-serialize-container.cpp +++ b/source/slang/slang-serialize-container.cpp @@ -10,6 +10,7 @@ #include "slang-serialize-ast.h" #include "slang-serialize-ir.h" #include "slang-serialize-source-loc.h" +#include "slang-serialize-factory.h" namespace Slang { @@ -143,7 +144,7 @@ namespace Slang { { if (!serialClasses) { - SLANG_RETURN_ON_FAIL(SerialClasses::create(serialClasses)); + SLANG_RETURN_ON_FAIL(SerialClassesUtil::create(serialClasses)); } ModuleSerialFilter filter(moduleDecl); @@ -295,7 +296,7 @@ namespace Slang { { if (!serialClasses) { - SLANG_RETURN_ON_FAIL(SerialClasses::create(serialClasses)); + SLANG_RETURN_ON_FAIL(SerialClassesUtil::create(serialClasses)); } // TODO(JS): We probably want to store off better information about each of the translation unit diff --git a/source/slang/slang-serialize-factory.cpp b/source/slang/slang-serialize-factory.cpp new file mode 100644 index 000000000..2bb7b047e --- /dev/null +++ b/source/slang/slang-serialize-factory.cpp @@ -0,0 +1,133 @@ +// slang-serialize-factory.cpp +#include "slang-serialize-factory.h" + +#include "../core/slang-math.h" + +#include "slang-ast-builder.h" + +#include "slang-ref-object-reflect.h" +#include "slang-ast-reflect.h" + +#include "slang-serialize-ast.h" +#include "slang-ref-object-reflect.h" + +// Needed for ModuleSerialFilter +// Needed for 'findModuleForDecl' +#include "slang-legalize-types.h" +#include "slang-mangle.h" + +namespace Slang { + +/* !!!!!!!!!!!!!!!!!!!!!! DefaultSerialObjectFactory !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +void* DefaultSerialObjectFactory::create(SerialTypeKind typeKind, SerialSubType subType) +{ + switch (typeKind) + { + case SerialTypeKind::NodeBase: + { + return m_astBuilder->createByNodeType(ASTNodeType(subType)); + } + case SerialTypeKind::RefObject: + { + const ReflectClassInfo* info = SerialRefObjects::getClassInfo(RefObjectType(subType)); + + if (info && info->m_createFunc) + { + RefObject* obj = reinterpret_cast<RefObject*>(info->m_createFunc(nullptr)); + return _add(obj); + } + return nullptr; + } + default: break; + } + + return nullptr; +} + +// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ModuleSerialFilter !!!!!!!!!!!!!!!!!!!!!!!! + +SerialIndex ModuleSerialFilter::writePointer(SerialWriter* writer, const RefObject* inPtr) +{ + // We don't serialize Module or Scope + if (as<Module>(inPtr) || as<Scope>(inPtr)) + { + writer->setPointerIndex(inPtr, SerialIndex(0)); + return SerialIndex(0); + } + + // For now for everything else just write it + return writer->writeObject(inPtr); +} + +SerialIndex ModuleSerialFilter::writePointer(SerialWriter* writer, const NodeBase* inPtr) +{ + NodeBase* ptr = const_cast<NodeBase*>(inPtr); + SLANG_ASSERT(ptr); + + if (Decl* decl = as<Decl>(ptr)) + { + ModuleDecl* moduleDecl = findModuleForDecl(decl); + SLANG_ASSERT(moduleDecl); + if (moduleDecl && moduleDecl != m_moduleDecl) + { + ASTBuilder* astBuilder = m_moduleDecl->module->getASTBuilder(); + + // It's a reference to a declaration in another module, so create an ImportExternalDecl. + + String mangledName = getMangledName(astBuilder, decl); + + ImportExternalDecl* importDecl = astBuilder->create<ImportExternalDecl>(); + importDecl->mangledName = mangledName; + const SerialIndex index = writer->addPointer(importDecl); + + // Set as the index of this + writer->setPointerIndex(ptr, index); + + return index; + } + else + { + // Okay... we can just write it out then + return writer->writeObject(ptr); + } + } + + // TODO(JS): What we really want to do here is to ignore bodies functions. + // It's not 100% clear if this is even right though - for example does type inference + // imply the body is needed to say infer a return type? + // Also not clear if statements in other scenarios (if there are others) might need to be kept. + // + // For now we just ignore all stmts + + if (Stmt* stmt = as<Stmt>(ptr)) + { + // + writer->setPointerIndex(stmt, SerialIndex(0)); + return SerialIndex(0); + } + + // For now for everything else just write it + return writer->writeObject(ptr); +} + +/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialClassesUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +/* static */SlangResult SerialClassesUtil::addSerialClasses(SerialClasses* serialClasses) +{ + ASTSerialUtil::addSerialClasses(serialClasses); + SerialRefObjects::addSerialClasses(serialClasses); + + return SLANG_OK; +} + +/* static */SlangResult SerialClassesUtil::create(RefPtr<SerialClasses>& out) +{ + RefPtr<SerialClasses> classes(new SerialClasses); + SLANG_RETURN_ON_FAIL(addSerialClasses(classes)); + + out = classes; + return SLANG_OK; +} + +} // namespace Slang diff --git a/source/slang/slang-serialize-factory.h b/source/slang/slang-serialize-factory.h new file mode 100644 index 000000000..7e51a840d --- /dev/null +++ b/source/slang/slang-serialize-factory.h @@ -0,0 +1,48 @@ +// slang-serialize-factory.h +#ifndef SLANG_SERIALIZE_FACTORY_H +#define SLANG_SERIALIZE_FACTORY_H + +#include "slang-serialize.h" + +namespace Slang { + +// !!!!!!!!!!!!!!!!!!!!! DefaultSerialObjectFactory !!!!!!!!!!!!!!!!!!!!!!!!!!! + +class ASTBuilder; + +class DefaultSerialObjectFactory : public SerialObjectFactory +{ +public: + + virtual void* create(SerialTypeKind typeKind, SerialSubType subType) SLANG_OVERRIDE; + + DefaultSerialObjectFactory(ASTBuilder* astBuilder) : + m_astBuilder(astBuilder) + { + } + +protected: + RefObject* _add(RefObject* obj) + { + m_scope.add(obj); + return obj; + } + + // We keep RefObjects in scope + List<RefPtr<RefObject>> m_scope; + ASTBuilder* m_astBuilder; +}; + + +struct SerialClassesUtil +{ + /// Add all types to serialClasses + static SlangResult addSerialClasses(SerialClasses* serialClasses); + /// Create SerialClasses with all the types added + static SlangResult create(RefPtr<SerialClasses>& out); +}; + + +} // namespace Slang + +#endif diff --git a/source/slang/slang-serialize-misc-type-info.h b/source/slang/slang-serialize-misc-type-info.h index bdcbf2c98..08fd1269d 100644 --- a/source/slang/slang-serialize-misc-type-info.h +++ b/source/slang/slang-serialize-misc-type-info.h @@ -12,6 +12,11 @@ namespace Slang { /* Conversion for serialization for some more misc Slang types */ + +// Because is sized, we don't need to convert +template <> +struct SerialTypeInfo<FeedbackType::Kind> : public SerialIdentityTypeInfo<FeedbackType::Kind> {}; + // SamplerStateFlavor template <> diff --git a/source/slang/slang-serialize-reflection.h b/source/slang/slang-serialize-reflection.h index 045b7bf97..a6889f795 100644 --- a/source/slang/slang-serialize-reflection.h +++ b/source/slang/slang-serialize-reflection.h @@ -57,6 +57,22 @@ struct ReflectClassInfo uint8_t m_alignment; ///< The required alignment of the type }; +// Does nothing - just a mark to the C++ extractor +#define SLANG_REFLECTED +#define SLANG_UNREFLECTED + +#define SLANG_PRE_DECLARE(SUFFIX, DEF) + +// Use these macros to help define Super, and making the base definition NOT have a Super definition. +// For example something like... + +#define SLANG_CLASS_REFLECT_SUPER_BASE(SUPER) +#define SLANG_CLASS_REFLECT_SUPER_INNER(SUPER) typedef SUPER Super; +#define SLANG_CLASS_REFLECT_SUPER_LEAF(SUPER) typedef SUPER Super; + +// Mark a value class +#define SLANG_VALUE_CLASS(x) + } // namespace Slang #endif diff --git a/source/slang/slang-serialize-type-info.h b/source/slang/slang-serialize-type-info.h index 5440fc201..89097fc32 100644 --- a/source/slang/slang-serialize-type-info.h +++ b/source/slang/slang-serialize-type-info.h @@ -62,11 +62,6 @@ struct SerialIdentityTypeInfo template <> struct SerialTypeInfo<SerialIndex> : public SerialIdentityTypeInfo<SerialIndex> {}; - -// Because is sized, we don't need to convert -template <> -struct SerialTypeInfo<FeedbackType::Kind> : public SerialIdentityTypeInfo<FeedbackType::Kind> {}; - // Implement for Basic Types template <> diff --git a/source/slang/slang-serialize.cpp b/source/slang/slang-serialize.cpp index 06ddbdde0..46aae18b2 100644 --- a/source/slang/slang-serialize.cpp +++ b/source/slang/slang-serialize.cpp @@ -156,24 +156,6 @@ SerialClasses::SerialClasses(): { } -// For now just use an extern so we don't need to include AST serialize -extern void addASTTypes(SerialClasses* serialClasses); -extern RefObjectSerialSubType getRefObjectSubType(const RefObject* obj); - -/* static */SlangResult SerialClasses::create(RefPtr<SerialClasses>& out) -{ - RefPtr<SerialClasses> classes(new SerialClasses); - addASTTypes(classes); - - out = classes; - return SLANG_OK; -} - -/* static */RefObjectSerialSubType SerialClasses::getSubType(const RefObject* obj) -{ - return getRefObjectSubType(obj); -} - // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialWriter !!!!!!!!!!!!!!!!!!!!!!!!!!!! SerialWriter::SerialWriter(SerialClasses* classes, SerialFilter* filter) : @@ -238,14 +220,17 @@ SerialIndex SerialWriter::writeObject(const NodeBase* node) SerialIndex SerialWriter::writeObject(const RefObject* obj) { - const RefObjectSerialSubType subType = SerialClasses::getSubType(obj); - if (subType == RefObjectSerialSubType::Invalid) + const SerialRefObject* serialObj = as<const SerialRefObject>(obj); + if (!serialObj) { SLANG_ASSERT(!"Unhandled type"); return SerialIndex(0); } - const SerialClass* serialClass = m_classes->getSerialClass(SerialTypeKind::RefObject, SerialSubType(subType)); + const ReflectClassInfo* classInfo = serialObj->getClassInfo(); + SLANG_ASSERT(classInfo); + + const SerialClass* serialClass = m_classes->getSerialClass(SerialTypeKind::RefObject, SerialSubType(classInfo->m_classId)); return writeObject(serialClass, (const void*)obj); } @@ -254,6 +239,11 @@ void SerialWriter::setPointerIndex(const NodeBase* ptr, SerialIndex index) m_ptrMap.Add(ptr, Index(index)); } +void SerialWriter::setPointerIndex(const RefObject* ptr, SerialIndex index) +{ + m_ptrMap.Add(ptr, Index(index)); +} + SerialIndex SerialWriter::addPointer(const NodeBase* node) { // Null is always 0 @@ -307,7 +297,14 @@ SerialIndex SerialWriter::addPointer(const RefObject* obj) return addName(name); } - return writeObject(obj); + if (m_filter) + { + return m_filter->writePointer(this, obj); + } + else + { + return writeObject(obj); + } } SerialIndex SerialWriter::addString(const UnownedStringSlice& slice) diff --git a/source/slang/slang-serialize.h b/source/slang/slang-serialize.h index d43bb7960..4c6a57b34 100644 --- a/source/slang/slang-serialize.h +++ b/source/slang/slang-serialize.h @@ -2,7 +2,7 @@ #ifndef SLANG_SERIALIZE_H #define SLANG_SERIALIZE_H -#include <type_traits> +//#include <type_traits> #include "../core/slang-riff.h" #include "../core/slang-byte-encode-util.h" @@ -283,22 +283,6 @@ enum class SerialTypeKind : uint8_t }; typedef uint16_t SerialSubType; -enum class RefObjectSerialSubType -{ - Invalid, ///< Invalid (ie not a known RefObject type) - LookupResultItem_Breadcrumb, - - // TODO(JS): - // ! We don't want to serialize these types. - // We could set a nullptr SerialClass in classes ? - // Perhaps we need some special SerialClass that indicates we want to always write as 0? - - Scope, - Module, - - CountOf, -}; - struct SerialInfo { enum @@ -416,6 +400,7 @@ class SerialFilter { public: virtual SerialIndex writePointer(SerialWriter* writer, const NodeBase* ptr) = 0; + virtual SerialIndex writePointer(SerialWriter* writer, const RefObject* ptr) = 0; }; class SerialObjectFactory @@ -556,6 +541,7 @@ public: /// Set a the ptr associated with an index. /// NOTE! That there cannot be a pre-existing setting. void setPointerIndex(const NodeBase* ptr, SerialIndex index); + void setPointerIndex(const RefObject* ptr, SerialIndex index); /// Get the entries table holding how each index maps to an entry const List<SerialInfo::Entry*>& getEntries() const { return m_entries; } @@ -641,6 +627,14 @@ struct SerialFieldType /* Describes a field in a SerialClass. */ struct SerialField { + /// Returns a suitable ptr for use in make. + /// NOTE! Sets to 1 so it's constant and not 0 (and so nullptr) + template <typename T> + static T* getPtr() { return (T*)1; } + + template <typename T> + static SerialField make(const char* name, T* in); + const char* name; ///< The name of the field const SerialFieldType* type; ///< The type of the field uint32_t nativeOffset; ///< Offset to field from base of type @@ -704,10 +698,6 @@ public: /// Ctor SerialClasses(); - static SlangResult create(RefPtr<SerialClasses>& out); - - static RefObjectSerialSubType getSubType(const RefObject* obj); - protected: SerialClass* _createSerialClass(const SerialClass* cls); @@ -730,6 +720,22 @@ struct SerialGetFieldType } }; +// !!!!!!!!!!!!!!!!!!!!! SerialGetFieldType<T> !!!!!!!!!!!!!!!!!!!!!!!!!!! + +template <typename T> +/* static */SerialField SerialField::make(const char* name, T* in) +{ + uint8_t* ptr = reinterpret_cast<uint8_t*>(in); + + SerialField field; + field.name = name; + field.type = SerialGetFieldType<T>::getFieldType(); + // This only works because we in is an offset from 1 + field.nativeOffset = uint32_t(size_t(ptr) - 1); + field.serialOffset = 0; + return field; +} + // !!!!!!!!!!!!!!!!!!!!! Convenience functions !!!!!!!!!!!!!!!!!!!!!!!!!!! template <typename NATIVE_TYPE, typename SERIAL_TYPE> diff --git a/source/slang/slang-value-reflect.cpp b/source/slang/slang-value-reflect.cpp new file mode 100644 index 000000000..9a7f1feb3 --- /dev/null +++ b/source/slang/slang-value-reflect.cpp @@ -0,0 +1,8 @@ +#include "../../slang.h" + +#include "slang-value-reflect.h" + +namespace Slang +{ + +} // namespace Slang diff --git a/source/slang/slang-value-reflect.h b/source/slang/slang-value-reflect.h new file mode 100644 index 000000000..4d6ec5582 --- /dev/null +++ b/source/slang/slang-value-reflect.h @@ -0,0 +1,6 @@ +// slang-value-reflect.h + +#ifndef SLANG_VALUE_REFLECT_H +#define SLANG_VALUE_REFLECT_H + +#endif // SLANG_VALUE_REFLECT_H diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index 7dafd3823..ec3066778 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -281,10 +281,15 @@ <ClInclude Include="slang-preprocessor.h" /> <ClInclude Include="slang-profile-defs.h" /> <ClInclude Include="slang-profile.h" /> + <ClInclude Include="slang-ref-object-generated-macro.h" /> + <ClInclude Include="slang-ref-object-generated.h" /> + <ClInclude Include="slang-ref-object-reflect.h" /> <ClInclude Include="slang-reflection.h" /> <ClInclude Include="slang-repro.h" /> + <ClInclude Include="slang-serialize-ast-type-info.h" /> <ClInclude Include="slang-serialize-ast.h" /> <ClInclude Include="slang-serialize-container.h" /> + <ClInclude Include="slang-serialize-factory.h" /> <ClInclude Include="slang-serialize-ir-types.h" /> <ClInclude Include="slang-serialize-ir.h" /> <ClInclude Include="slang-serialize-misc-type-info.h" /> @@ -299,6 +304,9 @@ <ClInclude Include="slang-token.h" /> <ClInclude Include="slang-type-layout.h" /> <ClInclude Include="slang-type-system-shared.h" /> + <ClInclude Include="slang-value-generated-macro.h" /> + <ClInclude Include="slang-value-generated.h" /> + <ClInclude Include="slang-value-reflect.h" /> <ClInclude Include="slang-visitor.h" /> </ItemGroup> <ItemGroup> @@ -398,10 +406,12 @@ <ClCompile Include="slang-parser.cpp" /> <ClCompile Include="slang-preprocessor.cpp" /> <ClCompile Include="slang-profile.cpp" /> + <ClCompile Include="slang-ref-object-reflect.cpp" /> <ClCompile Include="slang-reflection.cpp" /> <ClCompile Include="slang-repro.cpp" /> <ClCompile Include="slang-serialize-ast.cpp" /> <ClCompile Include="slang-serialize-container.cpp" /> + <ClCompile Include="slang-serialize-factory.cpp" /> <ClCompile Include="slang-serialize-ir-types.cpp" /> <ClCompile Include="slang-serialize-ir.cpp" /> <ClCompile Include="slang-serialize-reflection.cpp" /> @@ -414,6 +424,7 @@ <ClCompile Include="slang-token.cpp" /> <ClCompile Include="slang-type-layout.cpp" /> <ClCompile Include="slang-type-system-shared.cpp" /> + <ClCompile Include="slang-value-reflect.cpp" /> <ClCompile Include="slang.cpp" /> </ItemGroup> <ItemGroup> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index be81a48c2..d69ff3059 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -294,18 +294,33 @@ <ClInclude Include="slang-profile.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-ref-object-generated-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-ref-object-generated.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-ref-object-reflect.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-reflection.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="slang-repro.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-serialize-ast-type-info.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-serialize-ast.h"> <Filter>Header Files</Filter> </ClInclude> <ClInclude Include="slang-serialize-container.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-serialize-factory.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-serialize-ir-types.h"> <Filter>Header Files</Filter> </ClInclude> @@ -348,6 +363,15 @@ <ClInclude Include="slang-type-system-shared.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-value-generated-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-value-generated.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-value-reflect.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-visitor.h"> <Filter>Header Files</Filter> </ClInclude> @@ -641,6 +665,9 @@ <ClCompile Include="slang-profile.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-ref-object-reflect.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-reflection.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -653,6 +680,9 @@ <ClCompile Include="slang-serialize-container.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-serialize-factory.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-serialize-ir-types.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -689,6 +719,9 @@ <ClCompile Include="slang-type-system-shared.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-value-reflect.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/tools/slang-cpp-extractor/slang-cpp-extractor-diagnostic-defs.h b/tools/slang-cpp-extractor/slang-cpp-extractor-diagnostic-defs.h index 7ed2f0691..97bc8eea0 100644 --- a/tools/slang-cpp-extractor/slang-cpp-extractor-diagnostic-defs.h +++ b/tools/slang-cpp-extractor/slang-cpp-extractor-diagnostic-defs.h @@ -23,6 +23,9 @@ DIAGNOSTIC(-1, Note, seeOpen, "see open $0") DIAGNOSTIC(1, Error, cannotOpenFile, "cannot open file '$0'.") +DIAGNOSTIC(1, Error, extractorFailed, "C++ Extractor failed for '$0'") +DIAGNOSTIC(1, Error, internalError, "Unknown internal error in C++ Extractor, aborted!") + // Parsing errors DIAGNOSTIC(100000, Error, expectingToken, "Expecting token $0") DIAGNOSTIC(100001, Error, typeAlreadyDeclared, "Type '$0' already declared") @@ -35,6 +38,8 @@ DIAGNOSTIC(100007, Error, superTypeNotFound, "Super type not found for $0") DIAGNOSTIC(100008, Error, superTypeNotAType, "Named super type is not a type $0") DIAGNOSTIC(100009, Error, unexpectedUnbalancedToken, "Unexpected unbalanced token") DIAGNOSTIC(100010, Error, unexpectedEndOfFile, "Unexpected end of file") +DIAGNOSTIC(100011, Error, expectingTypeKeyword, "Expecting type keyword - struct or class, found $0") + // Command line errors 100100 diff --git a/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp b/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp index d2f83f53e..fc5c3d1f9 100644 --- a/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp +++ b/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp @@ -22,6 +22,20 @@ #include "slang-cpp-extractor-diagnostics.h" +/* +Some command lines: + +For AST +-d source/slang slang-ast-base.h slang-ast-decl.h slang-ast-expr.h slang-ast-modifier.h slang-ast-stmt.h slang-ast-type.h slang-ast-val.h -strip-prefix slang-ast- -o slang-ast-generated -output-fields -mark-suffix _CLASS + +For RefObjects +-d source/slang slang-ast-support-types.h -strip-prefix slang- -reflect-type RefObject -o slang-ref-object-generated -output-fields -mark-suffix _OBJ_CLASS + +For Values + +-d source/slang slang-ast-support-types.h -strip-prefix slang- -reflect-type Value -o slang-value-generated -output-fields -mark-suffix _VALUE_CLASS +*/ + namespace SlangExperimental { @@ -32,8 +46,8 @@ enum class IdentifierStyle None, ///< It's not an identifier Identifier, ///< Just an identifier - Root, - BaseClass, ///< Has the name of a base class defined elsewhere + + PreDeclare, ///< Declare a type (not visible in C++ code) TypeModifier, ///< const, volatile etc Keyword, ///< A keyword C/C++ keyword that is not another type @@ -63,9 +77,8 @@ struct IdentifierFlag static const IdentifierFlags kIdentifierFlags[Index(IdentifierStyle::CountOf)] = { 0, /// None - 0, /// Identifier - 0, /// Root - 0, /// BaseClass + 0, /// Identifier + 0, /// Declare type IdentifierFlag::Keyword, /// TypeModifier IdentifierFlag::Keyword, /// Keyword IdentifierFlag::Keyword | IdentifierFlag::StartScope | IdentifierFlag::ClassLike, /// Class @@ -74,7 +87,6 @@ static const IdentifierFlags kIdentifierFlags[Index(IdentifierStyle::CountOf)] = IdentifierFlag::Keyword, /// Access IdentifierFlag::Reflection, /// Reflected IdentifierFlag::Reflection, /// Unreflected - }; SLANG_FORCE_INLINE IdentifierFlags getFlags(IdentifierStyle style) @@ -170,13 +182,6 @@ public: ReflectionType reflectionType; }; - enum class BaseType - { - None, ///< Neither a base or marked base - Marked, ///< It's a marked base - Unmarked, ///< It's a base, but it's not marked - }; - bool isClassLike() const { return m_type == Type::StructType || m_type == Type::ClassType; } /// Add a child node to this nodes scope @@ -197,6 +202,9 @@ public: /// Calculate the absolute name for this namespace/type void calcAbsoluteName(StringBuilder& outName) const; + /// Get the absolute name + String getAbsoluteName() const { StringBuilder buf; calcAbsoluteName(buf); return buf.ProduceString(); } + /// Do depth first traversal of nodes void calcScopeDepthFirst(List<Node*>& outNodes); @@ -226,7 +234,18 @@ public: /// Stores in out any reflected derived types void getReflectedDerivedTypes(List<Node*>& out) const; - static void filterReflectedClassLike(List<Node*>& io); + typedef bool (*Filter)(Node* node); + + static bool isClassLikeAndReflected(Node* node) + { + return node->isClassLike() && node->isReflected(); + } + static bool isClassLike(Node* node) + { + return node->isClassLike(); + } + + static void filter(Filter filter, List<Node*>& io); static void calcScopePath(Node* node, List<Node*>& outPath); @@ -236,7 +255,6 @@ public: m_reflectionType(ReflectionType::NotReflected), m_reflectionOverride(ReflectionType::Reflected), m_superNode(nullptr), - m_baseType(BaseType::None), m_origin(nullptr) { m_anonymousNamespace = nullptr; @@ -269,9 +287,6 @@ public: /// For child types, fields, how reflection is handled. If this type is not reflected ReflectionType m_reflectionOverride; - /// The base type of this - BaseType m_baseType; - Token m_name; ///< The name of this scope/type Token m_super; ///< Super class name Token m_marker; ///< The marker associated with this scope (typically the marker is SLANG_CLASS etc, that is used to identify reflectedType) @@ -340,7 +355,10 @@ public: /// we allow files to be processed in any order, so we have to do the type lookup as a separate operation SlangResult calcDerivedTypes(); - /// Only valid after calcDerivedTypes has been executed + /// Find the name starting in specified scope + Node* findNode(Node* scope, const UnownedStringSlice& name); + + /// Only valid after calcDerivedTypes has been executed const List<Node*>& getBaseTypes() const { return m_baseTypes; } /// Get all of the parsed source origins @@ -356,6 +374,8 @@ protected: bool _isMarker(const UnownedStringSlice& name); + SlangResult _parsePreDeclare(); + SlangResult _maybeParseNode(Node::Type type); SlangResult _maybeParseField(); @@ -555,24 +575,26 @@ void Node::dump(int indentCount, StringBuilder& out) void Node::calcAbsoluteName(StringBuilder& outName) const { - if (m_parentScope == nullptr) + List<Node*> path; + calcScopePath(const_cast<Node*>(this), path); + + // 1 so we skip the global scope + for (Index i = 1; i < path.getCount(); ++i) { - if (!m_name.hasContent()) + Node* node = path[i]; + + if (i > 1) { - return; + outName << "::"; } - outName << m_name.getContent(); - } - else - { - outName << "::"; - if (m_type == Type::AnonymousNamespace) + + if (node->m_type == Type::AnonymousNamespace) { outName << "{Anonymous}"; } else { - outName << m_name.getContent(); + outName << node->m_name.getContent(); } } } @@ -593,11 +615,6 @@ Index Node::calcDerivedDepth() const Node* Node::findLastDerived() { - if (!isReflected()) - { - return nullptr; - } - for (Index i = m_derivedTypes.getCount() - 1; i >= 0; --i) { Node* derivedType = m_derivedTypes[i]; @@ -648,14 +665,15 @@ void Node::getReflectedDerivedTypes(List<Node*>& out) const } } -/* static */void Node::filterReflectedClassLike(List<Node*>& ioNodes) +/* static */void Node::filter(Filter inFilter, List<Node*>& ioNodes) { // Filter out all the unreflected nodes Index count = ioNodes.getCount(); for (Index j = 0; j < count; ) { Node* node = ioNodes[j]; - if (!node->isClassLike() || !node->isReflected()) + + if (!inFilter(node)) { ioNodes.removeAt(j); count--; @@ -678,8 +696,8 @@ struct Options Options() { - m_prefixMark = "SLANG_"; - m_postfixMark = "_CLASS"; + m_markPrefix = "SLANG_"; + m_markSuffix = "_CLASS"; } bool m_defs = false; ///< If set will output a '-defs.h' file for each of the input files, that corresponds to previous defs files (although doesn't have fields/RAW) @@ -692,8 +710,8 @@ struct Options String m_outputPath; ///< The ouput path. Note that the extractor can generate multiple output files, and this will actually be the 'stem' of several files String m_inputDirectory; ///< The input directory that is by default used for reading m_inputPaths from. String m_reflectType; ///< The typename used for output - String m_prefixMark; ///< The prefix of the 'marker' used to identify a reflected type - String m_postfixMark; ///< The postfix of the 'marker' used to identify a reflected type + String m_markPrefix; ///< The prefix of the 'marker' used to identify a reflected type + String m_markSuffix; ///< The postfix of the 'marker' used to identify a reflected type String m_stripFilePrefix; ///< Used for the 'origin' information, this is stripped from the source filename, and the remainder of the filename (without extension) is 'macroized' }; @@ -704,6 +722,7 @@ struct OptionsParser SlangResult _parseArgWithValue(const char* option, String& outValue); SlangResult _parseArgReplaceValue(const char* option, String& outValue); + SlangResult _parseArgFlag(const char* option, bool& outFlag); String m_reflectType; @@ -713,6 +732,16 @@ struct OptionsParser DiagnosticSink* m_sink; }; +SlangResult OptionsParser::_parseArgFlag(const char* option, bool& outFlag) +{ + SLANG_ASSERT(UnownedStringSlice(m_args[m_index]) == option); + SLANG_ASSERT(m_index < m_argCount); + + m_index ++; + outFlag = true; + return SLANG_OK; +} + SlangResult OptionsParser::_parseArgWithValue(const char* option, String& ioValue) { SLANG_ASSERT(UnownedStringSlice(m_args[m_index]) == option); @@ -789,25 +818,25 @@ SlangResult OptionsParser::parse(int argc, const char*const* argv, DiagnosticSin SLANG_RETURN_ON_FAIL(_parseArgWithValue("-reflect-type", outOptions.m_reflectType)); continue; } - else if (arg == "-prefix-mark") + else if (arg == "-mark-prefix") { - SLANG_RETURN_ON_FAIL(_parseArgReplaceValue("-prefix-mark", outOptions.m_prefixMark)); + SLANG_RETURN_ON_FAIL(_parseArgReplaceValue("-mark-prefix", outOptions.m_markPrefix)); continue; } - else if (arg == "-postfix-mark") + else if (arg == "-mark-suffix") { - SLANG_RETURN_ON_FAIL(_parseArgReplaceValue("-postfix-mark", outOptions.m_postfixMark)); + SLANG_RETURN_ON_FAIL(_parseArgReplaceValue("-mark-suffix", outOptions.m_markSuffix)); continue; } else if (arg == "-defs") { - outOptions.m_defs = true; + SLANG_RETURN_ON_FAIL(_parseArgFlag("-defs", outOptions.m_defs)); continue; } else if (arg == "-output-fields") { - outOptions.m_outputFields = true; - break; + SLANG_RETURN_ON_FAIL(_parseArgFlag("-output-fields", outOptions.m_outputFields)); + continue; } else if (arg == "-strip-prefix") { @@ -855,7 +884,7 @@ CPPExtractor::CPPExtractor(StringSlicePool* typePool, NamePool* namePool, Diagno bool CPPExtractor::_isMarker(const UnownedStringSlice& name) { - return name.startsWith(m_options->m_prefixMark.getUnownedSlice()) && name.endsWith(m_options->m_postfixMark.getUnownedSlice()); + return name.startsWith(m_options->m_markPrefix.getUnownedSlice()) && name.endsWith(m_options->m_markSuffix.getUnownedSlice()); } SlangResult CPPExtractor::expect(TokenType type, Token* outToken) @@ -1587,6 +1616,84 @@ SlangResult CPPExtractor::_maybeParseField() } } +static UnownedStringSlice _trimUnderscorePrefix(const UnownedStringSlice& slice) +{ + if (slice.getLength() && slice[0] == '_') + { + return UnownedStringSlice(slice.begin() + 1, slice.end()); + } + else + { + return slice; + } +} + + +SlangResult CPPExtractor::_parsePreDeclare() +{ + // Skip the declare type token + m_reader.advanceToken(); + + SLANG_RETURN_ON_FAIL(expect(TokenType::LParent)); + + bool hasMatchingSuffix = false; + + // Get the suffix + { + Token suffix; + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &suffix)); + + hasMatchingSuffix = _trimUnderscorePrefix(m_options->m_markSuffix.getUnownedSlice()) == _trimUnderscorePrefix(suffix.getContent()); + } + + SLANG_RETURN_ON_FAIL(expect(TokenType::Comma)); + + // Get the type of type + Node::Type nodeType; + { + Token typeToken; + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeToken)); + + const IdentifierStyle style = m_identifierLookup->get(typeToken.getContent()); + + if (style != IdentifierStyle::Struct && style != IdentifierStyle::Class) + { + m_sink->diagnose(typeToken, CPPDiagnostics::expectingTypeKeyword, typeToken.getContent()); + return SLANG_FAIL; + } + nodeType = _toNodeType(style); + } + + Token name; + Token super; + + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &name)); + + if (advanceIfToken(TokenType::Colon)) + { + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &super)); + } + + SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); + + if (hasMatchingSuffix) + { + RefPtr<Node> node(new Node(nodeType)); + + node->m_name = name; + node->m_super = super; + + // Assume it is reflected + node->m_reflectionType = ReflectionType::Reflected; + + SLANG_RETURN_ON_FAIL(pushNode(node)); + // Pop out of it + popBrace(); + } + + return SLANG_OK; +} + SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options) { SLANG_ASSERT(options); @@ -1629,24 +1736,9 @@ SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options) switch (style) { - case IdentifierStyle::BaseClass: + case IdentifierStyle::PreDeclare: { - m_reader.advanceToken(); - - Token nameToken; - SLANG_RETURN_ON_FAIL(expect(TokenType::LParent)); - SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &nameToken)); - SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); - - RefPtr<Node> node(new Node(Node::Type::ClassType)); - node->m_name = nameToken; - node->m_baseType = Node::BaseType::Marked; - - // Classes defined this way are not reflected, as the mark means the type exists, but isn't visible - node->m_reflectionType = ReflectionType::NotReflected; - - SLANG_RETURN_ON_FAIL(pushNode(node)); - popBrace(); + SLANG_RETURN_ON_FAIL(_parsePreDeclare()); break; } case IdentifierStyle::Reflected: @@ -1667,15 +1759,6 @@ SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options) } break; } - case IdentifierStyle::Root: - { - if (m_currentNode && m_currentNode->isClassLike()) - { - m_currentNode->m_baseType = Node::BaseType::Marked; - } - m_reader.advanceToken(); - break; - } default: { IdentifierFlags flags = getFlags(style); @@ -1752,9 +1835,32 @@ SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options) } } +Node* CPPExtractor::findNode(Node* scope, const UnownedStringSlice& name) +{ + // TODO(JS): We may want to lookup based on the path. + // If the name is qualified, we give up for not + if (String(name).indexOf("::") >= 0) + { + return nullptr; + } + + // Okay try in all scopes up to the root + while (scope) + { + if (Node* node = scope->findChild(name)) + { + return node; + } + + scope = scope->m_parentScope; + } + + return nullptr; +} + SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node) { - if (node->isClassLike() && node->m_baseType == Node::BaseType::None) + if (node->isClassLike()) { if (node->m_super.hasContent()) { @@ -1765,12 +1871,13 @@ SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node) return SLANG_FAIL; } - Node* superType = parentScope->findChild(node->m_super.getContent()); + Node* superType = findNode(parentScope, node->m_super.getContent()); + if (!superType) { if (node->isReflected()) { - m_sink->diagnose(node->m_name, CPPDiagnostics::superTypeNotFound, node->m_name.getContent()); + m_sink->diagnose(node->m_name, CPPDiagnostics::superTypeNotFound, node->getAbsoluteName()); return SLANG_FAIL; } } @@ -1778,7 +1885,7 @@ SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node) { if (!superType->isClassLike()) { - m_sink->diagnose(node->m_name, CPPDiagnostics::superTypeNotAType, node->m_name.getContent()); + m_sink->diagnose(node->m_name, CPPDiagnostics::superTypeNotAType, node->getAbsoluteName()); return SLANG_FAIL; } @@ -1789,16 +1896,14 @@ SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node) } else { - // If it has no super class defined, then we can just make it a root without being set - node->m_baseType = Node::BaseType::Unmarked; + // Add the root nodes + if (node->isReflected()) + { + m_baseTypes.add(node); + } } } - if (node->m_baseType != Node::BaseType::None) - { - m_baseTypes.add(node); - } - for (Node* child : node->m_children) { SLANG_RETURN_ON_FAIL(_calcDerivedTypesRec(child)); @@ -1877,6 +1982,8 @@ public: SlangResult calcDef(CPPExtractor& extractor, SourceOrigin* origin, StringBuilder& out); + const Options& getOptions() const { return m_options; } + CPPExtractorApp(DiagnosticSink* sink, SourceManager* sourceManager, RootNamePool* rootNamePool): m_sink(sink), m_sourceManager(sourceManager), @@ -1977,14 +2084,10 @@ SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringB for (Index i = 0; i < baseTypes.getCount(); ++i) { Node* baseType = baseTypes[i]; - if (baseType->m_baseType != Node::BaseType::Marked) - { - continue; - } - + List<Node*> nodes; baseType->calcDerivedDepthFirst(nodes); - Node::filterReflectedClassLike(nodes); + Node::filter(Node::isClassLike, nodes); List<Node*> derivedTypes; @@ -1996,7 +2099,7 @@ SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringB node->getReflectedDerivedTypes(derivedTypes); // Define the derived types - out << "#define " << m_options.m_prefixMark << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; + out << "#define " << m_options.m_markPrefix << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; if (derivedTypes.getCount()) { @@ -2005,7 +2108,7 @@ SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringB { Node* derivedType = derivedTypes[j]; _indent(1, out); - out << m_options.m_prefixMark << "ALL_" << reflectTypeName << "_" << derivedType->m_name.getContent() << "(x, param)"; + out << m_options.m_markPrefix << "ALL_" << reflectTypeName << "_" << derivedType->m_name.getContent() << "(x, param)"; if (j < derivedTypes.getCount() - 1) { out << "\\\n"; @@ -2020,16 +2123,16 @@ SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringB for (Node* node : nodes) { // Define the derived types - out << "#define " << m_options.m_prefixMark << "ALL_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) \\\n"; + out << "#define " << m_options.m_markPrefix << "ALL_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) \\\n"; _indent(1, out); - out << m_options.m_prefixMark << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; + out << m_options.m_markPrefix << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; // If has derived types output them if (node->hasReflectedDerivedType()) { out << " \\\n"; _indent(1, out); - out << m_options.m_prefixMark << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; + out << m_options.m_markPrefix << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; } out << "\n\n"; } @@ -2041,7 +2144,7 @@ SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringB for (Node* node : nodes) { // Define the derived types - out << "#define " << m_options.m_prefixMark << "FIELDS_" << reflectTypeName << "_" << node->m_name.getContent() << "(_x_, _param_)"; + out << "#define " << m_options.m_markPrefix << "FIELDS_" << reflectTypeName << "_" << node->m_name.getContent() << "(_x_, _param_)"; if (node->m_fields.getCount() > 0) { @@ -2090,11 +2193,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& for (Index i = 0; i < baseTypes.getCount(); ++i) { Node* baseType = baseTypes[i]; - if (baseType->m_baseType != Node::BaseType::Marked) - { - continue; - } - + List<Node*> baseScopePath; baseType->calcScopePath(baseScopePath); @@ -2111,7 +2210,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& List<Node*> nodes; baseType->calcDerivedDepthFirst(nodes); - Node::filterReflectedClassLike(nodes); + Node::filter(Node::isClassLikeAndReflected, nodes); // Write out the types { @@ -2158,6 +2257,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& out << "// Order is (NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \n"; out << "// NAME - is the class name\n"; out << "// SUPER - is the super class name (or NO_SUPER)\n"; + out << "// ORIGIN - where the definition was found\n"; out << "// LAST - is the class name for the last in the range (or NO_LAST)\n"; out << "// MARKER - is the text inbetween in the prefix/postix (like ABSTRACT). If no inbetween text is is 'NONE'\n"; out << "// TYPE - Can be BASE, INNER or LEAF for the overall base class, an INNER class, or a LEAF class\n"; @@ -2166,7 +2266,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& // Output all of the definitions for each type for (Node* node : nodes) { - out << "#define " << m_options.m_prefixMark << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) "; + out << "#define " << m_options.m_markPrefix << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) "; // Output the X macro part _indent(1, out); @@ -2199,9 +2299,9 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& // Output any specifics of the markup UnownedStringSlice marker = node->m_marker.getContent(); // Need to extract the name - if (marker.getLength() > m_options.m_prefixMark.getLength() + m_options.m_postfixMark.getLength()) + if (marker.getLength() > m_options.m_markPrefix.getLength() + m_options.m_markSuffix.getLength()) { - marker = UnownedStringSlice(marker.begin() + m_options.m_prefixMark.getLength(), marker.end() - m_options.m_postfixMark.getLength()); + marker = UnownedStringSlice(marker.begin() + m_options.m_markPrefix.getLength(), marker.end() - m_options.m_markSuffix.getLength()); } else { @@ -2209,7 +2309,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& } out << marker << ", "; - if (node->m_baseType != Node::BaseType::None || node->m_superNode && node->m_superNode->isReflected() == false) + if (node->m_superNode == nullptr) { out << "BASE, "; } @@ -2240,7 +2340,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& for (SourceOrigin* origin : extractor.getSourceOrigins()) { - out << "#define " << m_options.m_prefixMark << "ORIGIN_" << origin->m_macroOrigin << "_" << reflectTypeName << "(x, param) \\\n"; + out << "#define " << m_options.m_markPrefix << "ORIGIN_" << origin->m_macroOrigin << "_" << reflectTypeName << "(x, param) \\\n"; for (Node* node : origin->m_nodes) { @@ -2355,29 +2455,24 @@ SlangResult CPPExtractorApp::writeOutput(CPPExtractor& extractor) // Special markers { { + const char* names[] = { "const", "volatile" }; StringBuilder buf; - buf << options.m_prefixMark; - buf << "CLASS_ROOT"; - - outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Root); + buf << options.m_markPrefix; + buf << "PRE_DECLARE"; + + outLookup.set(buf.getUnownedSlice(), IdentifierStyle::PreDeclare); } - { - StringBuilder buf; - buf << options.m_prefixMark; - buf << "REFLECT_BASE_CLASS"; - outLookup.set(buf.getUnownedSlice(), IdentifierStyle::BaseClass); - } { StringBuilder buf; - buf << options.m_prefixMark; + buf << options.m_markPrefix; buf << "REFLECTED"; outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Reflected); } { StringBuilder buf; - buf << options.m_prefixMark; + buf << options.m_markPrefix; buf << "UNREFLECTED"; outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Unreflected); @@ -2489,30 +2584,33 @@ int main(int argc, const char*const* argv) { ComPtr<ISlangWriter> writer(new FileWriter(stderr, WriterFlag::AutoFlush)); - try - { - RootNamePool rootNamePool; + RootNamePool rootNamePool; + + SourceManager sourceManager; + sourceManager.initialize(nullptr, nullptr); - SourceManager sourceManager; - sourceManager.initialize(nullptr, nullptr); + DiagnosticSink sink(&sourceManager); + sink.writer = writer; - DiagnosticSink sink(&sourceManager); - sink.writer = writer; + CPPExtractorApp app(&sink, &sourceManager, &rootNamePool); - CPPExtractorApp app(&sink, &sourceManager, &rootNamePool); + try + { if (SLANG_FAILED(app.executeWithArgs(argc - 1, argv + 1))) { + sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed, app.getOptions().m_reflectType); return 1; } if (sink.getErrorCount()) { + sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed, app.getOptions().m_reflectType); return 1; } } catch (...) { - WriterHelper helper(writer); - helper.print("Unknown internal error in C++ extractor, aborted!\n"); + sink.diagnose(SourceLoc(), CPPDiagnostics::internalError); + sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed, app.getOptions().m_reflectType); return 1; } } |
