diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2020-10-22 08:46:12 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-10-22 08:46:12 -0400 |
| commit | 10e1bae34733f1cdb5abc001666b1aafa1c1f406 (patch) | |
| tree | ad9571c071b7b7c2384cdd42426851d257fc5f7b | |
| parent | c0943661e5441bfb996430c4f67fb4dddea9dfcf (diff) | |
Single pass C++ extraction (#1583)
* #include an absolute path didn't work - because paths were taken to always be relative.
* Added CharUtil.
Added TypeSet to extractor.
First pass at being able to specify all headers for multiple output headers.
* Fix includes for new C++ extractor convension.
Update premake5 to use new extractor mechanisms.
* Small improvements around StringUtil.
* Split out NameConventionUtil.
* Use a 'convert' to convert between convention types.
* Fix output of build message for C++ extractor.
Improve NameConventionUtil interface.
* Improve comments.
* Fix warning on gcc.
* Fix clang warning.
* Fix some typos in NameConventionUtil.
* Small fix to premake5.lua
* Fix generated includes.
* Remove m_reflectType as no longer applicable with TypeSet.
* Fix .gitignore for slang-generated-* files.
Added getConvention to determine convention from slice.
Add versions of split and convert that infer the from convention
* Fix typo in spliting camel.
* LineWhitespace -> HorizontalWhitespace
* Improve CharUtil comments.
32 files changed, 971 insertions, 492 deletions
diff --git a/.gitignore b/.gitignore index f03caafb7..5e6985759 100644 --- a/.gitignore +++ b/.gitignore @@ -37,8 +37,7 @@ tests/**/*.slang-module *.spv # Intermediate source files generated during build process -/source/slang/slang-ast-generated.h -/source/slang/slang-ast-generated-macro.h +/source/slang/slang-generated-*.h /source/slang/hlsl.meta.slang.h /source/slang/core.meta.slang.h prelude/*.h.cpp diff --git a/premake5.lua b/premake5.lua index 23d7d3e60..1bbfa26a7 100644 --- a/premake5.lua +++ b/premake5.lua @@ -773,40 +773,6 @@ 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. @@ -832,7 +798,6 @@ generatorProject("run-generators", "source/slang/") { "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 -- @@ -854,24 +819,55 @@ generatorProject("run-generators", "source/slang/") -- We need to run the C++ extractor to generate some include files if executeBinary then - local sourcePath = "%{file.directory}" - - filter "files:**/slang-ast-reflect.h" + filter "files:**/slang-ast-reflect.h" + do + buildmessage "C++ Extractor %{file.relpath}" - buildmessage "slang-cpp-extractor value%{file.relpath}" - - runCPPExtractor(sourcePath, "value", { "slang-ast-support-types.h" }, "slang-", "Value", "_VALUE_CLASS") + local sourcePath = "%{file.directory}" - 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") + -- Work out the output files - 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", "_AST_CLASS") + local outputTypes = { "obj", "ast", "value" }; + + local outputTable = {} + + for key, outputType in ipairs(outputTypes) do + table.insert(outputTable, sourcePath .. "/slang-generated-" .. outputType .. ".h") + table.insert(outputTable, sourcePath .. "/slang-generated-" .. outputType .. "-macro.h") + end + + -- List all of the input files to be scanned + + local inputFiles = { "slang-ast-support-types.h", "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" } + + local options = { "-strip-prefix", "slang-", "-o", "slang-generated", "-output-fields", "-mark-suffix", "_CLASS"} + + -- 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(outputTable) + + -- 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 + end -- Next, we want to add a custom build rule for each of the diff --git a/source/core/core.vcxproj b/source/core/core.vcxproj index 38f06b407..063d1aa0b 100644 --- a/source/core/core.vcxproj +++ b/source/core/core.vcxproj @@ -176,6 +176,7 @@ <ClInclude Include="slang-basic.h" /> <ClInclude Include="slang-blob.h" /> <ClInclude Include="slang-byte-encode-util.h" /> + <ClInclude Include="slang-char-util.h" /> <ClInclude Include="slang-common.h" /> <ClInclude Include="slang-dictionary.h" /> <ClInclude Include="slang-downstream-compiler.h" /> @@ -189,6 +190,7 @@ <ClInclude Include="slang-list.h" /> <ClInclude Include="slang-math.h" /> <ClInclude Include="slang-memory-arena.h" /> + <ClInclude Include="slang-name-convention-util.h" /> <ClInclude Include="slang-nvrtc-compiler.h" /> <ClInclude Include="slang-offset-container.h" /> <ClInclude Include="slang-platform.h" /> @@ -219,12 +221,14 @@ <ItemGroup> <ClCompile Include="slang-blob.cpp" /> <ClCompile Include="slang-byte-encode-util.cpp" /> + <ClCompile Include="slang-char-util.cpp" /> <ClCompile Include="slang-downstream-compiler.cpp" /> <ClCompile Include="slang-free-list.cpp" /> <ClCompile Include="slang-gcc-compiler-util.cpp" /> <ClCompile Include="slang-hex-dump-util.cpp" /> <ClCompile Include="slang-io.cpp" /> <ClCompile Include="slang-memory-arena.cpp" /> + <ClCompile Include="slang-name-convention-util.cpp" /> <ClCompile Include="slang-nvrtc-compiler.cpp" /> <ClCompile Include="slang-offset-container.cpp" /> <ClCompile Include="slang-platform.cpp" /> diff --git a/source/core/core.vcxproj.filters b/source/core/core.vcxproj.filters index 7514fa1c9..afae1d124 100644 --- a/source/core/core.vcxproj.filters +++ b/source/core/core.vcxproj.filters @@ -27,6 +27,9 @@ <ClInclude Include="slang-byte-encode-util.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-char-util.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-common.h"> <Filter>Header Files</Filter> </ClInclude> @@ -66,6 +69,9 @@ <ClInclude Include="slang-memory-arena.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-name-convention-util.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-nvrtc-compiler.h"> <Filter>Header Files</Filter> </ClInclude> @@ -152,6 +158,9 @@ <ClCompile Include="slang-byte-encode-util.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-char-util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-downstream-compiler.cpp"> <Filter>Source Files</Filter> </ClCompile> @@ -170,6 +179,9 @@ <ClCompile Include="slang-memory-arena.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="slang-name-convention-util.cpp"> + <Filter>Source Files</Filter> + </ClCompile> <ClCompile Include="slang-nvrtc-compiler.cpp"> <Filter>Source Files</Filter> </ClCompile> diff --git a/source/core/slang-char-util.cpp b/source/core/slang-char-util.cpp new file mode 100644 index 000000000..53dd98541 --- /dev/null +++ b/source/core/slang-char-util.cpp @@ -0,0 +1,48 @@ +#include "slang-char-util.h" + +namespace Slang { + +static const CharUtil::CharFlagMap _calcCharFlagsMap() +{ + typedef CharUtil::Flag Flag; + + CharUtil::CharFlagMap map; + memset(&map, 0, sizeof(map)); + + { + for (Index i = 'a'; i <= 'z'; ++i) + { + map.flags[i] |= Flag::Lower; + } + } + { + for (Index i = 'A'; i <= 'Z'; ++i) + { + map.flags[i] |= Flag::Upper; + } + } + { + for (Index i = '0'; i <= '9'; ++i) + { + map.flags[i] |= Flag::Digit | Flag::HexDigit; + } + } + { + for (Index i = 'a'; i <= 'f'; ++i) + { + map.flags[i] |= Flag::HexDigit; + map.flags[size_t(CharUtil::toUpper(char(i)))] |= Flag::HexDigit; + } + } + + { + map.flags[size_t(' ')] |= Flag::HorizontalWhitespace; + map.flags[size_t('\t')] |= Flag::HorizontalWhitespace; + } + + return map; +} + +/* static */const CharUtil::CharFlagMap CharUtil::g_charFlagMap = _calcCharFlagsMap(); + +} // namespace Slang diff --git a/source/core/slang-char-util.h b/source/core/slang-char-util.h new file mode 100644 index 000000000..810cde0b1 --- /dev/null +++ b/source/core/slang-char-util.h @@ -0,0 +1,51 @@ +#ifndef SLANG_CORE_CHAR_UTIL_H +#define SLANG_CORE_CHAR_UTIL_H + +#include "slang-string.h" + +namespace Slang { + +struct CharUtil +{ + typedef uint8_t Flags; + struct Flag + { + enum Enum : Flags + { + Upper = 0x01, ///< A-Z + Lower = 0x02, ///< a-z + Digit = 0x04, ///< 0-9 + HorizontalWhitespace = 0x08, ///< Whitespace that can appear horizontally (ie excluding CR/LF) + HexDigit = 0x10, ///< 0-9, a-f, A-F + }; + }; + + SLANG_FORCE_INLINE static bool isDigit(char c) { return c >= '0' && c <= '9'; } + SLANG_FORCE_INLINE static bool isLower(char c) { return c >= 'a' && c <= 'z'; } + SLANG_FORCE_INLINE static bool isUpper(char c) { return c >= 'A' && c <= 'Z'; } + SLANG_FORCE_INLINE static bool isHorizontalWhitespace(char c) { return c == ' ' || c == '\t'; } + + /// True if it's alpha + SLANG_FORCE_INLINE static bool isAlpha(char c) { return (getFlags(c) & (Flag::Upper | Flag::Lower)) != 0; } + + SLANG_FORCE_INLINE static bool isHexDigit(char c) { return (getFlags(c) & Flag::HexDigit) != 0; } + + /// For a given character get the associated flags + SLANG_FORCE_INLINE static Flags getFlags(char c) { return g_charFlagMap.flags[size_t(c)]; } + + /// Given a character return the lower case equivalent + SLANG_FORCE_INLINE static char toLower(char c) { return (c >= 'A' && c <= 'Z') ? (c -'A' + 'a') : c; } + /// Given a character return the upper case equivalent + SLANG_FORCE_INLINE static char toUpper(char c) { return (c >= 'a' && c <= 'z') ? (c -'a' + 'A') : c; } + + struct CharFlagMap + { + Flags flags[0x100]; + }; + + static const CharFlagMap g_charFlagMap; +}; + +} // namespace Slang + +#endif // SLANG_CHAR_UTIL_H diff --git a/source/core/slang-name-convention-util.cpp b/source/core/slang-name-convention-util.cpp new file mode 100644 index 000000000..a5acc6370 --- /dev/null +++ b/source/core/slang-name-convention-util.cpp @@ -0,0 +1,213 @@ + +#include "slang-name-convention-util.h" + +#include "slang-char-util.h" +#include "slang-string-util.h" + +namespace Slang +{ + +/* static */NameConvention NameConventionUtil::getConvention(const UnownedStringSlice& slice) +{ + for (const char c : slice) + { + switch (c) + { + case '-': return NameConvention::Kabab; + case '_': return NameConvention::Snake; + default: break; + } + } + return NameConvention::Camel; +} + +/* static */void NameConventionUtil::split(NameConvention convention, const UnownedStringSlice& slice, List<UnownedStringSlice>& out) +{ + switch (convention) + { + case NameConvention::Kabab: + { + StringUtil::split(slice, '-', out); + break; + } + case NameConvention::Snake: + { + StringUtil::split(slice, '_', out); + break; + } + case NameConvention::Camel: + { + typedef CharUtil::Flags CharFlags; + typedef CharUtil::Flag CharFlag; + + CharFlags prevFlags = 0; + const char*const end = slice.end(); + + const char* start = slice.begin(); + for (const char* cur = start; cur < end; ++cur) + { + const char c = *cur; + const CharUtil::Flags flags = CharUtil::getFlags(c); + + if (flags & CharFlag::Upper) + { + if (prevFlags & CharFlag::Lower) + { + // If we go from lower to upper, we have a transition + out.add(UnownedStringSlice(start, cur)); + start = cur; + } + else if ((prevFlags & CharFlag::Upper) && cur + 1 < end) + { + // This works with capital or uncapitalized acronyms, but if we have two capitalized acronyms following each other - it can't split. + // + // For example + // "IAABBSystem" -> "IAABB", "System" + // + // If it only accepted lower case acronyms the logic could be changed such that the following could be produced + // "IAabbSystem" -> "I", "Aabb", "System" + // + // Since Slang source largely goes with upper case acronyms, we work with the heuristic here.. + + if (CharUtil::isLower(cur[1])) + { + out.add(UnownedStringSlice(start, cur)); + start = cur; + } + } + } + + prevFlags = flags; + } + + // Add any end section + if (start < end) + { + out.add(UnownedStringSlice(start, end)); + } + break; + } + } +} + +void NameConventionUtil::split(const UnownedStringSlice& slice, List<UnownedStringSlice>& out) +{ + split(getConvention(slice), slice, out); +} + +/* static */void NameConventionUtil::join(const UnownedStringSlice* slices, Index slicesCount, CharCase charCase, char joinChar, StringBuilder& out) +{ + if (slicesCount <= 0) + { + return; + } + + Index totalSize = slicesCount - 1; + for (Index i = 0; i < slicesCount; ++i) + { + totalSize += slices[i].getLength(); + } + + char*const dstStart = out.prepareForAppend(totalSize); + char* dst = dstStart; + + for (Index i = 0; i < slicesCount; ++i) + { + const UnownedStringSlice& slice = slices[i]; + const Index count = slice.getLength(); + const char*const src = slice.begin(); + + if (i > 0) + { + *dst++ = joinChar; + } + + switch (charCase) + { + case CharCase::Upper: + { + for (Index j = 0; j < count; ++j) + { + dst[j] = CharUtil::toUpper(src[j]); + } + break; + } + case CharCase::Lower: + { + for (Index j = 0; j < count; ++j) + { + dst[j] = CharUtil::toLower(src[j]); + } + break; + } + } + + dst += count; + } + + SLANG_ASSERT(dstStart + totalSize == dst); + out.appendInPlace(dstStart, totalSize); +} + +/* static */void NameConventionUtil::join(const UnownedStringSlice* slices, Index slicesCount, CharCase charCase, NameConvention convention, StringBuilder& out) +{ + switch (convention) + { + case NameConvention::Kabab: return join(slices, slicesCount, charCase, '-', out); + case NameConvention::Snake: return join(slices, slicesCount, charCase, '_', out); + case NameConvention::Camel: + { + Index totalSize = 0; + + for (Index i = 0; i < slicesCount; ++i) + { + totalSize += slices[i].getLength(); + } + + char*const dstStart = out.prepareForAppend(totalSize); + char* dst = dstStart; + + for (Index i = 0; i < slicesCount; ++i) + { + const UnownedStringSlice& slice = slices[i]; + Index count = slice.getLength(); + const char* src = slice.begin(); + + Int j = 0; + + if (count > 0 && !(i == 0 && charCase == CharCase::Lower)) + { + // Capitalize first letter of each word, unless on first word and 'lower' + dst[j] = CharUtil::toUpper(src[j]); + j++; + } + + for (; j < count; ++j) + { + dst[j] = CharUtil::toLower(src[j]); + } + + dst += count; + } + break; + } + } +} + +/* static */void NameConventionUtil::convert(NameConvention fromConvention, const UnownedStringSlice& slice, CharCase charCase, NameConvention toConvention, StringBuilder& out) +{ + // Split into slices + List<UnownedStringSlice> slices; + split(fromConvention, slice, slices); + + // Join the slices in the toConvention + join(slices.getBuffer(), slices.getCount(), charCase, toConvention, out); +} + +/* static */void NameConventionUtil::convert(const UnownedStringSlice& slice, CharCase charCase, NameConvention toConvention, StringBuilder& out) +{ + convert(getConvention(slice), slice, charCase, toConvention, out); +} + +} + diff --git a/source/core/slang-name-convention-util.h b/source/core/slang-name-convention-util.h new file mode 100644 index 000000000..d4a984ca0 --- /dev/null +++ b/source/core/slang-name-convention-util.h @@ -0,0 +1,54 @@ +#ifndef SLANG_CORE_NAME_CONVENTION_UTIL_H +#define SLANG_CORE_NAME_CONVENTION_UTIL_H + +#include "slang-string.h" +#include "slang-list.h" + +namespace Slang +{ + +enum class NameConvention +{ + Kabab, /// Words are separated with -. WORDS-ARE-SEPARATED + Snake, /// Words are separated with _. WORDS_ARE_SEPARATED + Camel, /// Words start with a capital. (Upper will make first words character capitalized, aka PascalCase) +}; + +enum class CharCase +{ + Upper, + Lower, +}; + +/* This utility is to enable easy conversion and interpretation of names that use standard conventions, typically in programming +languages. The conventions are largely how to represent multiple words together. + +Split is used to split up a name into it's constituent 'words' based on a convention. +Join is used to combine words based on a convention/character case + +Convert uses split and join to allow easy conversion between conventions. +*/ +struct NameConventionUtil +{ + /// Given a slice tries to determine the convention used. + /// If no separators are found, will assume Camel + static NameConvention getConvention(const UnownedStringSlice& slice); + + /// Given a slice and a naming convention, split into it's constituent parts. If convention isn't specified, will infer from slice using getConvention. + static void split(NameConvention convention, const UnownedStringSlice& slice, List<UnownedStringSlice>& out); + static void split(const UnownedStringSlice& slice, List<UnownedStringSlice>& out); + + /// Given slices, join together with the specified convention into out + static void join(const UnownedStringSlice* slices, Index slicesCount, CharCase charCase, NameConvention convention, StringBuilder& out); + + /// Join with a join char, and potentially changing case of input slices + static void join(const UnownedStringSlice* slices, Index slicesCount, CharCase charCase, char joinChar, StringBuilder& out); + + /// Convert from one convention to another. If fromConvention isn't specified, will infer from slice using getConvention. + static void convert(NameConvention fromConvention, const UnownedStringSlice& slice, CharCase charCase, NameConvention toConvention, StringBuilder& out); + static void convert(const UnownedStringSlice& slice, CharCase charCase, NameConvention toConvention, StringBuilder& out); +}; + +} + +#endif // SLANG_CORE_NAME_CONVENTION_UTIL_H diff --git a/source/core/slang-string-util.h b/source/core/slang-string-util.h index 9f1508cb1..dee4c7d66 100644 --- a/source/core/slang-string-util.h +++ b/source/core/slang-string-util.h @@ -93,6 +93,7 @@ struct StringUtil /// Convert in to int. Returns SLANG_FAIL on error static SlangResult parseInt(const UnownedStringSlice& in, Int& outValue); + }; /* A helper class that allows parsing of lines from text with iteration. Uses StringUtil::extractLine for the actual underlying implementation. */ diff --git a/source/core/slang-string.cpp b/source/core/slang-string.cpp index bcf5853d5..3ce4c7ec9 100644 --- a/source/core/slang-string.cpp +++ b/source/core/slang-string.cpp @@ -1,6 +1,8 @@ #include "slang-string.h" #include "slang-text-io.h" +#include "slang-char-util.h" + namespace Slang { // TODO: this belongs in a different file: @@ -12,11 +14,6 @@ namespace Slang throw InternalError(message); } - SLANG_FORCE_INLINE static bool _isWhiteSpace(char c) - { - return c == ' ' || c == '\t'; - } - // OSString OSString::OSString() @@ -112,11 +109,20 @@ namespace Slang const char* start = m_begin; const char* end = m_end; - while (start < end && _isWhiteSpace(*start)) start++; - while (end > start && _isWhiteSpace(end[-1])) end--; + while (start < end && CharUtil::isHorizontalWhitespace(*start)) start++; + while (end > start && CharUtil::isHorizontalWhitespace(end[-1])) end--; return UnownedStringSlice(start, end); } + UnownedStringSlice UnownedStringSlice::trim(char c) const + { + const char* start = m_begin; + const char* end = m_end; + + while (start < end && *start == c) start++; + while (end > start && end[-1] == c) end--; + return UnownedStringSlice(start, end); + } // StringSlice diff --git a/source/core/slang-string.h b/source/core/slang-string.h index 25bf99023..75c282a58 100644 --- a/source/core/slang-string.h +++ b/source/core/slang-string.h @@ -174,6 +174,7 @@ namespace Slang UnownedStringSlice trim() const; + UnownedStringSlice trim(char c) const; HashCode getHashCode() const { diff --git a/source/slang/run-generators.vcxproj b/source/slang/run-generators.vcxproj index 599f221b1..e38f9dc2d 100644 --- a/source/slang/run-generators.vcxproj +++ b/source/slang/run-generators.vcxproj @@ -156,7 +156,6 @@ <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" /> @@ -229,24 +228,16 @@ </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-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 _AST_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 _AST_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 _AST_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 _AST_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> + <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"../../bin/windows-x86/debug/slang-cpp-extractor" -d %(RootDir)%(Directory) slang-ast-support-types.h 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- -o slang-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 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- -o slang-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 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- -o slang-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 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- -o slang-generated -output-fields -mark-suffix _CLASS</Command> + <Outputs>slang-generated-obj.h;slang-generated-obj-macro.h;slang-generated-ast.h;slang-generated-ast-macro.h;slang-generated-value.h;slang-generated-value-macro.h</Outputs> + <Message>C++ Extractor %(Identity)</Message> + <AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">../../bin/windows-x86/debug/slang-cpp-extractor.exe;slang-ast-support-types.h;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-support-types.h;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-support-types.h;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-support-types.h;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 9ec19c0d7..e8ec8394a 100644 --- a/source/slang/run-generators.vcxproj.filters +++ b/source/slang/run-generators.vcxproj.filters @@ -15,9 +15,6 @@ <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 5cbfd1e45..931f0d5bd 100644 --- a/source/slang/slang-ast-base.h +++ b/source/slang/slang-ast-base.h @@ -4,7 +4,7 @@ #include "slang-ast-support-types.h" -#include "slang-ast-generated.h" +#include "slang-generated-ast.h" #include "slang-ast-reflect.h" #include "slang-serialize-reflection.h" diff --git a/source/slang/slang-ast-decl.cpp b/source/slang/slang-ast-decl.cpp index a10411ebb..edc79c030 100644 --- a/source/slang/slang-ast-decl.cpp +++ b/source/slang/slang-ast-decl.cpp @@ -2,7 +2,7 @@ #include "slang-ast-builder.h" #include <assert.h> -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" namespace Slang { diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp index 688e99031..552c97d7f 100644 --- a/source/slang/slang-ast-dump.cpp +++ b/source/slang/slang-ast-dump.cpp @@ -6,7 +6,7 @@ #include "../core/slang-string.h" -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" namespace Slang { diff --git a/source/slang/slang-ast-reflect.cpp b/source/slang/slang-ast-reflect.cpp index 520592e73..b16568d2e 100644 --- a/source/slang/slang-ast-reflect.cpp +++ b/source/slang/slang-ast-reflect.cpp @@ -11,7 +11,7 @@ #include "slang-visitor.h" -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" namespace Slang { @@ -54,11 +54,11 @@ struct ASTConstructAccess #define SLANG_GET_SUPER_INNER(SUPER) &SUPER::kReflectClassInfo #define SLANG_GET_SUPER_LEAF(SUPER) &SUPER::kReflectClassInfo -#define SLANG_GET_CREATE_FUNC_ABSTRACT(NAME) nullptr -#define SLANG_GET_CREATE_FUNC_NONE(NAME) &ASTConstructAccess::Impl<NAME>::create +#define SLANG_GET_CREATE_FUNC_ABSTRACT_AST(NAME) nullptr +#define SLANG_GET_CREATE_FUNC_AST(NAME) &ASTConstructAccess::Impl<NAME>::create -#define SLANG_GET_DESTROY_FUNC_ABSTRACT(NAME) nullptr -#define SLANG_GET_DESTROY_FUNC_NONE(NAME) &ASTConstructAccess::Impl<NAME>::destroy +#define SLANG_GET_DESTROY_FUNC_ABSTRACT_AST(NAME) nullptr +#define SLANG_GET_DESTROY_FUNC_AST(NAME) &ASTConstructAccess::Impl<NAME>::destroy #define SLANG_REFLECT_CLASS_INFO(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ /* static */const ReflectClassInfo NAME::kReflectClassInfo = { uint32_t(ASTNodeType::NAME), uint32_t(ASTNodeType::LAST), SLANG_GET_SUPER_##TYPE(SUPER), #NAME, SLANG_GET_CREATE_FUNC_##MARKER(NAME), SLANG_GET_DESTROY_FUNC_##MARKER(NAME), uint32_t(sizeof(NAME)), uint8_t(SLANG_ALIGN_OF(NAME)) }; @@ -66,8 +66,8 @@ struct ASTConstructAccess SLANG_ALL_ASTNode_NodeBase(SLANG_REFLECT_CLASS_INFO, _) // We dispatch to non 'abstract' types -#define SLANG_CASE_NONE(NAME) case ASTNodeType::NAME: return visitor->dispatch_##NAME(static_cast<NAME*>(this), extra); -#define SLANG_CASE_ABSTRACT(NAME) +#define SLANG_CASE_AST(NAME) case ASTNodeType::NAME: return visitor->dispatch_##NAME(static_cast<NAME*>(this), extra); +#define SLANG_CASE_ABSTRACT_AST(NAME) #define SLANG_CASE_DISPATCH(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) SLANG_CASE_##MARKER(NAME) diff --git a/source/slang/slang-ast-reflect.h b/source/slang/slang-ast-reflect.h index 6ba895f71..457e88d0d 100644 --- a/source/slang/slang-ast-reflect.h +++ b/source/slang/slang-ast-reflect.h @@ -5,7 +5,7 @@ #include "slang-serialize-reflection.h" -#include "slang-ast-generated.h" +#include "slang-generated-ast.h" // Implementation for SLANG_ABSTRACT_CLASS(x) using reflection from C++ extractor in slang-ast-generated.h #define SLANG_AST_CLASS_REFLECT_IMPL(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \ diff --git a/source/slang/slang-ast-substitutions.cpp b/source/slang/slang-ast-substitutions.cpp index 8a54a1d74..acff8201e 100644 --- a/source/slang/slang-ast-substitutions.cpp +++ b/source/slang/slang-ast-substitutions.cpp @@ -2,7 +2,7 @@ #include "slang-ast-builder.h" #include <assert.h> -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" namespace Slang { diff --git a/source/slang/slang-ast-support-types.h b/source/slang/slang-ast-support-types.h index 4cc76804c..a2fa16b53 100644 --- a/source/slang/slang-ast-support-types.h +++ b/source/slang/slang-ast-support-types.h @@ -9,7 +9,7 @@ #include "../core/slang-semantic-version.h" -#include "slang-ast-generated.h" +#include "slang-generated-ast.h" #include "slang-serialize-reflection.h" @@ -1007,8 +1007,13 @@ namespace Slang }; class SerialRefObject; + // Make sure C++ extractor can see the base class. - SLANG_PRE_DECLARE(_OBJ_CLASS, class SerialRefObject) + SLANG_PRE_DECLARE(OBJ, class SerialRefObject) + + SLANG_TYPE_SET(OBJ, RefObject) + SLANG_TYPE_SET(VALUE, Value) + SLANG_TYPE_SET(AST, ASTNode) class LookupResultItem_Breadcrumb : public SerialRefObject { diff --git a/source/slang/slang-ast-type.cpp b/source/slang/slang-ast-type.cpp index 55bb9a1e5..2c2557233 100644 --- a/source/slang/slang-ast-type.cpp +++ b/source/slang/slang-ast-type.cpp @@ -5,7 +5,7 @@ #include "slang-syntax.h" -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" namespace Slang { diff --git a/source/slang/slang-ast-val.cpp b/source/slang/slang-ast-val.cpp index 76ddb644c..7dbda6e86 100644 --- a/source/slang/slang-ast-val.cpp +++ b/source/slang/slang-ast-val.cpp @@ -3,7 +3,7 @@ #include <assert.h> #include <typeinfo> -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" #include "slang-syntax.h" diff --git a/source/slang/slang-diagnostics.cpp b/source/slang/slang-diagnostics.cpp index d16e8e84e..c3b7e27a2 100644 --- a/source/slang/slang-diagnostics.cpp +++ b/source/slang/slang-diagnostics.cpp @@ -5,6 +5,8 @@ #include "../core/slang-memory-arena.h" #include "../core/slang-dictionary.h" +#include "../core/slang-string-util.h" +#include "../core/slang-name-convention-util.h" #include <assert.h> @@ -302,60 +304,17 @@ public: return singleton; } - typedef uint8_t CharFlags; - struct CharFlag - { - enum Enum : CharFlags - { - Upper = 0x1, - Lower = 0x2, - }; - }; - - static CharFlags _classifyChar(char c) - { - CharFlags flags = 0; - flags |= (c >= 'a' && c <= 'z') ? CharFlag::Lower : 0; - flags |= (c >= 'A' && c <= 'Z') ? CharFlag::Upper : 0; - return flags; - } protected: void _add(const char* name, Index index) { - m_map.Add(UnownedStringSlice(name), index); + UnownedStringSlice nameSlice(name); + m_map.Add(nameSlice, index); - // Add a dashed version + // Add a dashed version (KababCase) { m_work.Clear(); - CharFlags prevFlags = 0; - for (const char* cur = name; *cur; cur++) - { - char c = *cur; - const CharFlags flags = _classifyChar(c); - - if (flags & CharFlag::Upper) - { - if (prevFlags & CharFlag::Lower) - { - // If we go from lower to upper, insert a dash. aA -> a-a - m_work << '-'; - } - else if (prevFlags & CharFlag::Upper) - { - // Could be an acronym, if the next character is lower, we need to insert a - here - if (_classifyChar(cur[1]) & CharFlag::Lower) - { - m_work << '-'; - } - } - // Make it lower - c = c - 'A' + 'a'; - } - m_work << c; - - prevFlags = flags; - } + NameConventionUtil::convert(NameConvention::Camel, nameSlice, CharCase::Lower, NameConvention::Kabab, m_work); UnownedStringSlice dashSlice(m_arena.allocateString(m_work.getBuffer(), m_work.getLength()), m_work.getLength()); m_map.AddIfNotExists(dashSlice, index); diff --git a/source/slang/slang-ref-object-reflect.cpp b/source/slang/slang-ref-object-reflect.cpp index caf8eb6a3..f07dcbba7 100644 --- a/source/slang/slang-ref-object-reflect.cpp +++ b/source/slang/slang-ref-object-reflect.cpp @@ -2,8 +2,8 @@ #include "slang-ref-object-reflect.h" -#include "slang-ref-object-generated.h" -#include "slang-ref-object-generated-macro.h" +#include "slang-generated-obj.h" +#include "slang-generated-obj-macro.h" #include "slang-ast-support-types.h" diff --git a/source/slang/slang-ref-object-reflect.h b/source/slang/slang-ref-object-reflect.h index cf50c010a..1fda8ee69 100644 --- a/source/slang/slang-ref-object-reflect.h +++ b/source/slang/slang-ref-object-reflect.h @@ -5,7 +5,7 @@ #include "slang-serialize-reflection.h" -#include "slang-ref-object-generated.h" +#include "slang-generated-obj.h" #include "../core/slang-smart-pointer.h" diff --git a/source/slang/slang-serialize-ast.cpp b/source/slang/slang-serialize-ast.cpp index 8310c155b..0e8acc3b3 100644 --- a/source/slang/slang-serialize-ast.cpp +++ b/source/slang/slang-serialize-ast.cpp @@ -1,8 +1,8 @@ // slang-serialize-ast.cpp #include "slang-serialize-ast.h" -#include "slang-ast-generated.h" -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast.h" +#include "slang-generated-ast-macro.h" #include "slang-ast-dump.h" diff --git a/source/slang/slang-serialize-reflection.h b/source/slang/slang-serialize-reflection.h index a6889f795..7eaf8543c 100644 --- a/source/slang/slang-serialize-reflection.h +++ b/source/slang/slang-serialize-reflection.h @@ -63,6 +63,8 @@ struct ReflectClassInfo #define SLANG_PRE_DECLARE(SUFFIX, DEF) +#define SLANG_TYPE_SET(SUFFIX, ...) + // Use these macros to help define Super, and making the base definition NOT have a Super definition. // For example something like... diff --git a/source/slang/slang-visitor.h b/source/slang/slang-visitor.h index 449fda917..25e0aafe4 100644 --- a/source/slang/slang-visitor.h +++ b/source/slang/slang-visitor.h @@ -7,15 +7,15 @@ #include "slang-syntax.h" -#include "slang-ast-generated-macro.h" +#include "slang-generated-ast-macro.h" namespace Slang { // Macros to generate from ast-generated-macro file the vistors // Only runs 'param' macro if the marker is NONE (ie not ABSTRACT here) -#define SLANG_CLASS_ONLY_ABSTRACT(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) -#define SLANG_CLASS_ONLY_NONE(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) param(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) +#define SLANG_CLASS_ONLY_ABSTRACT_AST(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) +#define SLANG_CLASS_ONLY_AST(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) param(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) #define SLANG_CLASS_ONLY(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) SLANG_CLASS_ONLY_##MARKER(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj index ec3066778..bb4293b8f 100644 --- a/source/slang/slang.vcxproj +++ b/source/slang/slang.vcxproj @@ -195,8 +195,6 @@ <ClInclude Include="slang-ast-decl.h" /> <ClInclude Include="slang-ast-dump.h" /> <ClInclude Include="slang-ast-expr.h" /> - <ClInclude Include="slang-ast-generated-macro.h" /> - <ClInclude Include="slang-ast-generated.h" /> <ClInclude Include="slang-ast-modifier.h" /> <ClInclude Include="slang-ast-reflect.h" /> <ClInclude Include="slang-ast-stmt.h" /> @@ -217,6 +215,12 @@ <ClInclude Include="slang-emit-source-writer.h" /> <ClInclude Include="slang-emit.h" /> <ClInclude Include="slang-file-system.h" /> + <ClInclude Include="slang-generated-ast-macro.h" /> + <ClInclude Include="slang-generated-ast.h" /> + <ClInclude Include="slang-generated-obj-macro.h" /> + <ClInclude Include="slang-generated-obj.h" /> + <ClInclude Include="slang-generated-value-macro.h" /> + <ClInclude Include="slang-generated-value.h" /> <ClInclude Include="slang-glsl-extension-tracker.h" /> <ClInclude Include="slang-hlsl-intrinsic-set.h" /> <ClInclude Include="slang-image-format-defs.h" /> @@ -281,7 +285,13 @@ <ClInclude Include="slang-preprocessor.h" /> <ClInclude Include="slang-profile-defs.h" /> <ClInclude Include="slang-profile.h" /> + <ClInclude Include="slang-ref-object-generated-ast-macro.h" /> + <ClInclude Include="slang-ref-object-generated-ast.h" /> <ClInclude Include="slang-ref-object-generated-macro.h" /> + <ClInclude Include="slang-ref-object-generated-obj-macro.h" /> + <ClInclude Include="slang-ref-object-generated-obj.h" /> + <ClInclude Include="slang-ref-object-generated-value-macro.h" /> + <ClInclude Include="slang-ref-object-generated-value.h" /> <ClInclude Include="slang-ref-object-generated.h" /> <ClInclude Include="slang-ref-object-reflect.h" /> <ClInclude Include="slang-reflection.h" /> diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters index d69ff3059..aad88a15f 100644 --- a/source/slang/slang.vcxproj.filters +++ b/source/slang/slang.vcxproj.filters @@ -36,12 +36,6 @@ <ClInclude Include="slang-ast-expr.h"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="slang-ast-generated-macro.h"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="slang-ast-generated.h"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="slang-ast-modifier.h"> <Filter>Header Files</Filter> </ClInclude> @@ -102,6 +96,24 @@ <ClInclude Include="slang-file-system.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-generated-ast-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-generated-ast.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-generated-obj-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-generated-obj.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-generated-value-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-generated-value.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-glsl-extension-tracker.h"> <Filter>Header Files</Filter> </ClInclude> @@ -294,9 +306,27 @@ <ClInclude Include="slang-profile.h"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="slang-ref-object-generated-ast-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-ref-object-generated-ast.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-obj-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-ref-object-generated-obj.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-ref-object-generated-value-macro.h"> + <Filter>Header Files</Filter> + </ClInclude> + <ClInclude Include="slang-ref-object-generated-value.h"> + <Filter>Header Files</Filter> + </ClInclude> <ClInclude Include="slang-ref-object-generated.h"> <Filter>Header Files</Filter> </ClInclude> 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 97bc8eea0..3ab133414 100644 --- a/tools/slang-cpp-extractor/slang-cpp-extractor-diagnostic-defs.h +++ b/tools/slang-cpp-extractor/slang-cpp-extractor-diagnostic-defs.h @@ -23,7 +23,7 @@ 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, extractorFailed, "C++ Extractor failed") DIAGNOSTIC(1, Error, internalError, "Unknown internal error in C++ Extractor, aborted!") // Parsing errors @@ -40,6 +40,7 @@ DIAGNOSTIC(100009, Error, unexpectedUnbalancedToken, "Unexpected unbalanced toke DIAGNOSTIC(100010, Error, unexpectedEndOfFile, "Unexpected end of file") DIAGNOSTIC(100011, Error, expectingTypeKeyword, "Expecting type keyword - struct or class, found $0") +DIAGNOSTIC(100011, Error, typeInDifferentTypeSet, "Type $0 in different type set $1 from super class $2") // 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 fc5c3d1f9..210369e97 100644 --- a/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp +++ b/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp @@ -13,6 +13,7 @@ #include "../../source/core/slang-io.h" #include "../../source/core/slang-string-slice-pool.h" #include "../../source/core/slang-writer.h" +#include "../../source/core/slang-name-convention-util.h" #include "../../source/slang/slang-source-loc.h" #include "../../source/slang/slang-lexer.h" @@ -25,15 +26,7 @@ /* 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 +-d source/slang slang-ast-support-types.h 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- -o slang-generated -output-fields -mark-suffix _CLASS */ namespace SlangExperimental @@ -48,6 +41,7 @@ enum class IdentifierStyle Identifier, ///< Just an identifier PreDeclare, ///< Declare a type (not visible in C++ code) + TypeSet, ///< TypeSet TypeModifier, ///< const, volatile etc Keyword, ///< A keyword C/C++ keyword that is not another type @@ -79,6 +73,7 @@ static const IdentifierFlags kIdentifierFlags[Index(IdentifierStyle::CountOf)] = 0, /// None 0, /// Identifier 0, /// Declare type + 0, /// Type set IdentifierFlag::Keyword, /// TypeModifier IdentifierFlag::Keyword, /// Keyword IdentifierFlag::Keyword | IdentifierFlag::StartScope | IdentifierFlag::ClassLike, /// Class @@ -159,6 +154,8 @@ enum class ReflectionType Reflected, }; +// Pre-declare +class TypeSet; class SourceOrigin; class Node : public RefObject @@ -255,7 +252,8 @@ public: m_reflectionType(ReflectionType::NotReflected), m_reflectionOverride(ReflectionType::Reflected), m_superNode(nullptr), - m_origin(nullptr) + m_origin(nullptr), + m_typeSet(nullptr) { m_anonymousNamespace = nullptr; } @@ -291,8 +289,10 @@ public: 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) + TypeSet* m_typeSet; ///< The typeset this type belongs to. + Node* m_parentScope; ///< The scope this type/scope is defined in - Node* m_superNode; ///< If this is a class/struct, the type it is derived from (or nullptr if base) + Node* m_superNode; ///< If this is a class/struct, the type it is derived from (or nullptr if base) }; class SourceOrigin : public RefObject @@ -331,6 +331,19 @@ public: List<RefPtr<Node> > m_nodes; }; +class TypeSet : public RefObject +{ +public: + + /// This is the looked up name. + UnownedStringSlice m_macroName; ///< The name extracted from the macro SLANG_ABSTRACT_AST_CLASS -> AST + + String m_typeName; ///< The enum type name associated with this type for AST it is ASTNode + String m_fileMark; ///< This 'mark' becomes of the output filename + + List<Node*> m_baseTypes; ///< The base types for this type set +}; + struct Options; class CPPExtractor @@ -351,20 +364,23 @@ public: /// Parse the contents of the source file SlangResult parse(SourceFile* sourceFile, const Options* options); - /// When parsing we don't lookup all up super types/add derived types. This is because - /// we allow files to be processed in any order, so we have to do the type lookup as a separate operation + /// When parsing we don't lookup all up super types/add derived types. This is because + /// we allow files to be processed in any order, so we have to do the type lookup as a separate operation SlangResult calcDerivedTypes(); /// 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 const List<RefPtr<SourceOrigin> >& getSourceOrigins() const { return m_origins; } - /// Get the root node + TypeSet* getTypeSet(const UnownedStringSlice& slice); + TypeSet* getOrAddTypeSet(const UnownedStringSlice& slice); + + /// Get all of the type sets + const List<RefPtr<TypeSet>>& getTypeSets() const { return m_typeSets; } + + /// Get the root node Node* getRootNode() const { return m_rootNode; } CPPExtractor(StringSlicePool* typePool, NamePool* namePool, DiagnosticSink* sink, IdentifierLookup* identifierLookup); @@ -375,6 +391,7 @@ protected: bool _isMarker(const UnownedStringSlice& name); SlangResult _parsePreDeclare(); + SlangResult _parseTypeSet(); SlangResult _maybeParseNode(Node::Type type); SlangResult _maybeParseField(); @@ -405,8 +422,6 @@ protected: RefPtr<Node> m_rootNode; ///< The root scope - List<Node*> m_baseTypes; ///< All of the types which are base. Only set after calcDerivedTypes - SourceOrigin* m_origin; DiagnosticSink* m_sink; @@ -417,8 +432,11 @@ protected: const Options* m_options; + StringSlicePool m_typeSetPool; ///< Pool for type set names + List<RefPtr<TypeSet> > m_typeSets; ///< The type sets + IdentifierLookup* m_identifierLookup; - StringSlicePool* m_typePool; + StringSlicePool* m_typePool; ///< Pool for just types }; @@ -707,9 +725,9 @@ struct Options List<String> m_inputPaths; ///< The input paths to the files to be processed - 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_outputPath; ///< The output 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_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' @@ -813,11 +831,6 @@ SlangResult OptionsParser::parse(int argc, const char*const* argv, DiagnosticSin m_index++; continue; } - else if (arg == "-reflect-type") - { - SLANG_RETURN_ON_FAIL(_parseArgWithValue("-reflect-type", outOptions.m_reflectType)); - continue; - } else if (arg == "-mark-prefix") { SLANG_RETURN_ON_FAIL(_parseArgReplaceValue("-mark-prefix", outOptions.m_markPrefix)); @@ -861,12 +874,6 @@ SlangResult OptionsParser::parse(int argc, const char*const* argv, DiagnosticSin return SLANG_FAIL; } - // Set default name - if (outOptions.m_reflectType.getLength() == 0) - { - outOptions.m_reflectType = "ASTNode"; - } - return SLANG_OK; } @@ -876,12 +883,41 @@ CPPExtractor::CPPExtractor(StringSlicePool* typePool, NamePool* namePool, Diagno m_typePool(typePool), m_sink(sink), m_namePool(namePool), - m_identifierLookup(identifierLookup) + m_identifierLookup(identifierLookup), + m_typeSetPool(StringSlicePool::Style::Empty) { m_rootNode = new Node(Node::Type::Namespace); m_rootNode->m_reflectionType = ReflectionType::Reflected; } +TypeSet* CPPExtractor::getTypeSet(const UnownedStringSlice& slice) +{ + Index index = m_typeSetPool.findIndex(slice); + if (index < 0) + { + return nullptr; + } + return m_typeSets[index]; +} + +TypeSet* CPPExtractor::getOrAddTypeSet(const UnownedStringSlice& slice) +{ + const Index index = Index(m_typeSetPool.add(slice)); + if (index >= m_typeSets.getCount()) + { + SLANG_ASSERT(m_typeSets.getCount() == index); + TypeSet* typeSet = new TypeSet; + + m_typeSets.add(typeSet); + typeSet->m_macroName = m_typeSetPool.getSlice(StringSlicePool::Handle(index)); + return typeSet; + } + else + { + return m_typeSets[index]; + } +} + bool CPPExtractor::_isMarker(const UnownedStringSlice& name) { return name.startsWith(m_options->m_markPrefix.getUnownedSlice()) && name.endsWith(m_options->m_markSuffix.getUnownedSlice()); @@ -1099,7 +1135,7 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type) SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier)); // Next is the class name SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &name)); - + if (m_reader.peekTokenType() == TokenType::Semicolon) { // pre declaration; @@ -1189,6 +1225,29 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type) return SLANG_OK; } + // Let's extract the type set + { + UnownedStringSlice slice(node->m_marker.getContent()); + + SLANG_ASSERT(_isMarker(slice)); + + // Strip the prefix and suffix + slice = UnownedStringSlice(slice.begin() + m_options->m_markPrefix.getLength(), slice.end() - m_options->m_markSuffix.getLength()); + + // Strip ABSTRACT_ if it's there + UnownedStringSlice abstractSlice("ABSTRACT_"); + if (slice.startsWith(abstractSlice)) + { + slice = UnownedStringSlice(slice.begin() + abstractSlice.getLength(), slice.end()); + } + + // TODO: We could strip other stuff or have other heuristics there, but this is + // probably okay for now + + // Set the typeSet + node->m_typeSet = getOrAddTypeSet(slice); + } + // Okay now looking for ( identifier) Token typeNameToken; @@ -1636,15 +1695,10 @@ SlangResult CPPExtractor::_parsePreDeclare() 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()); - } + // Get the typeSet + Token typeSetToken; + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeSetToken)); + TypeSet* typeSet = getOrAddTypeSet(typeSetToken.getContent()); SLANG_RETURN_ON_FAIL(expect(TokenType::Comma)); @@ -1676,24 +1730,48 @@ SlangResult CPPExtractor::_parsePreDeclare() SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); - if (hasMatchingSuffix) - { - RefPtr<Node> node(new Node(nodeType)); + RefPtr<Node> node(new Node(nodeType)); - node->m_name = name; - node->m_super = super; + node->m_name = name; + node->m_super = super; + node->m_typeSet = typeSet; - // Assume it is reflected - node->m_reflectionType = ReflectionType::Reflected; + // Assume it is reflected + node->m_reflectionType = ReflectionType::Reflected; - SLANG_RETURN_ON_FAIL(pushNode(node)); - // Pop out of it - popBrace(); - } + SLANG_RETURN_ON_FAIL(pushNode(node)); + // Pop out of the node + popBrace(); return SLANG_OK; } +SlangResult CPPExtractor::_parseTypeSet() +{ + // Skip the declare type token + m_reader.advanceToken(); + + SLANG_RETURN_ON_FAIL(expect(TokenType::LParent)); + + Token typeSetToken; + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeSetToken)); + + TypeSet* typeSet = getOrAddTypeSet(typeSetToken.getContent()); + + SLANG_RETURN_ON_FAIL(expect(TokenType::Comma)); + + // Get the type of type + Token typeToken; + SLANG_RETURN_ON_FAIL(expect(TokenType::Identifier, &typeToken)); + + SLANG_RETURN_ON_FAIL(expect(TokenType::RParent)); + + // Set the typename + typeSet->m_typeName = typeToken.getContent(); + + return SLANG_OK; +} + SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options) { SLANG_ASSERT(options); @@ -1741,6 +1819,11 @@ SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options) SLANG_RETURN_ON_FAIL(_parsePreDeclare()); break; } + case IdentifierStyle::TypeSet: + { + SLANG_RETURN_ON_FAIL(_parseTypeSet()); + break; + } case IdentifierStyle::Reflected: { m_reader.advanceToken(); @@ -1889,8 +1972,13 @@ SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node) return SLANG_FAIL; } - // The base class must be defined in same scope (as we didn't allow different scopes for base classes) + if (superType->m_typeSet != node->m_typeSet) + { + m_sink->diagnose(node->m_name, CPPDiagnostics::typeInDifferentTypeSet, node->m_name.getContent(), node->m_typeSet->m_macroName, superType->m_typeSet->m_macroName); + return SLANG_FAIL; + } + // The base class must be defined in same scope (as we didn't allow different scopes for base classes) superType->addDerived(node); } } @@ -1899,7 +1987,7 @@ SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node) // Add the root nodes if (node->isReflected()) { - m_baseTypes.add(node); + node->m_typeSet->m_baseTypes.add(node); } } } @@ -1917,42 +2005,26 @@ SlangResult CPPExtractor::calcDerivedTypes() return _calcDerivedTypesRec(m_rootNode); } - /* static */String CPPExtractor::_calcMacroOrigin(const String& filePath, const Options& options) { + // Get the filename without extension String fileName = Path::getFileNameWithoutExt(filePath); - if (options.m_stripFilePrefix.getLength() && fileName.startsWith(options.m_stripFilePrefix)) + // We can work on just the slice + UnownedStringSlice slice = fileName.getUnownedSlice(); + + // Filename prefix + if (options.m_stripFilePrefix.getLength() && slice.startsWith(options.m_stripFilePrefix.getUnownedSlice())) { const Index len = options.m_stripFilePrefix.getLength(); - fileName = UnownedStringSlice(fileName.begin() + len, fileName.end()); + slice = UnownedStringSlice(slice.begin() + len, slice.end()); } - const char* start = fileName.begin(); - const char* end = fileName.end(); - - // Trim any - - while (start < end && *start == '-') ++start; - while (end - 1 > start && end[-1] == '-') --end; + // Trim - + slice = slice.trim('-'); StringBuilder out; - - // Make into macro like name - for (; start < end; ++start) - { - char c = *start; - - if (c == '-') - { - c = '_'; - } - else if (c >= 'a' && c <= 'z') - { - c = c - 'a' + 'A'; - } - out.append(c); - } - + NameConventionUtil::convert(slice, CharCase::Upper, NameConvention::Snake, out); return out; } @@ -1977,8 +2049,9 @@ public: SlangResult writeDefs(CPPExtractor& extractor); /// Calculate the header - SlangResult calcHeader(CPPExtractor& extractor, StringBuilder& out); - SlangResult calcChildrenHeader(CPPExtractor& exctractor, StringBuilder& out); + SlangResult calcTypeHeader(CPPExtractor& extractor, TypeSet* typeSet, StringBuilder& out); + SlangResult calcChildrenHeader(CPPExtractor& exctractor, TypeSet* typeSet, StringBuilder& out); + SlangResult calcOriginHeader(CPPExtractor& extractor, StringBuilder& out); SlangResult calcDef(CPPExtractor& extractor, SourceOrigin* origin, StringBuilder& out); @@ -2072,287 +2145,300 @@ SlangResult CPPExtractorApp::calcDef(CPPExtractor& extractor, SourceOrigin* orig return SLANG_OK; } -SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringBuilder& out) +SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, TypeSet* typeSet, StringBuilder& out) { - const List<Node*>& baseTypes = extractor.getBaseTypes(); - - const String& reflectTypeName = m_options.m_reflectType; + const List<Node*>& baseTypes = typeSet->m_baseTypes; + const String& reflectTypeName = typeSet->m_typeName; out << "#pragma once\n\n"; out << "// Do not edit this file is generated from slang-cpp-extractor tool\n\n"; + List<Node*> nodes; for (Index i = 0; i < baseTypes.getCount(); ++i) { - Node* baseType = baseTypes[i]; - - List<Node*> nodes; + Node* baseType = baseTypes[i]; baseType->calcDerivedDepthFirst(nodes); - Node::filter(Node::isClassLike, nodes); + } - List<Node*> derivedTypes; + Node::filter(Node::isClassLike, nodes); - out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! CHILDREN !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ \n\n"; + List<Node*> derivedTypes; - // Now the children - for (Node* node : nodes) - { - node->getReflectedDerivedTypes(derivedTypes); + out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! CHILDREN !!!!!!!!!!!!!!!!!!!!!!!!!!!! */ \n\n"; - // Define the derived types - out << "#define " << m_options.m_markPrefix << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; + // Now the children + for (Node* node : nodes) + { + node->getReflectedDerivedTypes(derivedTypes); + + // Define the derived types + out << "#define " << m_options.m_markPrefix << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; - if (derivedTypes.getCount()) + if (derivedTypes.getCount()) + { + out << " \\\n"; + for (Index j = 0; j < derivedTypes.getCount(); ++j) { - out << " \\\n"; - for (Index j = 0; j < derivedTypes.getCount(); ++j) + Node* derivedType = derivedTypes[j]; + _indent(1, out); + out << m_options.m_markPrefix << "ALL_" << reflectTypeName << "_" << derivedType->m_name.getContent() << "(x, param)"; + if (j < derivedTypes.getCount() - 1) { - Node* derivedType = derivedTypes[j]; - _indent(1, out); - out << m_options.m_markPrefix << "ALL_" << reflectTypeName << "_" << derivedType->m_name.getContent() << "(x, param)"; - if (j < derivedTypes.getCount() - 1) - { - out << "\\\n"; - } - } - } - out << "\n\n"; + out << "\\\n"; + } + } } + out << "\n\n"; + } - out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ALL !!!!!!!!!!!!!!!!!!!!!!!!!!!! */\n\n"; + out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ALL !!!!!!!!!!!!!!!!!!!!!!!!!!!! */\n\n"; - for (Node* node : nodes) + for (Node* node : nodes) + { + // Define the derived types + out << "#define " << m_options.m_markPrefix << "ALL_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) \\\n"; + _indent(1, out); + out << m_options.m_markPrefix << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; + + // If has derived types output them + if (node->hasReflectedDerivedType()) { - // Define the derived types - out << "#define " << m_options.m_markPrefix << "ALL_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) \\\n"; + out << " \\\n"; _indent(1, out); - 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_markPrefix << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; - } - out << "\n\n"; + out << m_options.m_markPrefix << "CHILDREN_" << reflectTypeName << "_" << node->m_name.getContent() << "(x, param)"; } + out << "\n\n"; + } + + if (m_options.m_outputFields) + { + out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! FIELDS !!!!!!!!!!!!!!!!!!!!!!!!!!!! */\n\n"; - if (m_options.m_outputFields) + for (Node* node : nodes) { - out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! FIELDS !!!!!!!!!!!!!!!!!!!!!!!!!!!! */\n\n"; + // Define the derived types + out << "#define " << m_options.m_markPrefix << "FIELDS_" << reflectTypeName << "_" << node->m_name.getContent() << "(_x_, _param_)"; - for (Node* node : nodes) + if (node->m_fields.getCount() > 0) { - // Define the derived types - out << "#define " << m_options.m_markPrefix << "FIELDS_" << reflectTypeName << "_" << node->m_name.getContent() << "(_x_, _param_)"; + out << "\\\n"; - if (node->m_fields.getCount() > 0) + const Index fieldsCount = node->m_fields.getCount(); + bool previousField = false; + for (Index j = 0; j < fieldsCount; ++j) { - out << "\\\n"; - - const Index fieldsCount = node->m_fields.getCount(); - bool previousField = false; - for (Index j = 0; j < fieldsCount; ++j) - { - const auto& field = node->m_fields[j]; + const auto& field = node->m_fields[j]; - if (field.isReflected()) + if (field.isReflected()) + { + if (previousField) { - if (previousField) - { - out << "\\\n"; - } + out << "\\\n"; + } - _indent(1, out); + _indent(1, out); - // NOTE! We put the type field in brackets, such that there is no issue with templates containing a comma. - // If stringified - out << "_x_(" << field.name.getContent() << ", (" << field.type << "), _param_)"; - previousField = true; - } + // NOTE! We put the type field in brackets, such that there is no issue with templates containing a comma. + // If stringified + out << "_x_(" << field.name.getContent() << ", (" << field.type << "), _param_)"; + previousField = true; } } - - out << "\n\n"; } + + out << "\n\n"; } } return SLANG_OK; } -SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder& out) +SlangResult CPPExtractorApp::calcOriginHeader(CPPExtractor& extractor, StringBuilder& out) { - const List<Node*>& baseTypes = extractor.getBaseTypes(); + // Do macros by origin - const String& reflectTypeName = m_options.m_reflectType; + out << "// Origin macros\n\n"; + + for (SourceOrigin* origin : extractor.getSourceOrigins()) + { + out << "#define " << m_options.m_markPrefix << "ORIGIN_" << origin->m_macroOrigin << "(x, param) \\\n"; + + for (Node* node : origin->m_nodes) + { + if (!(node->isReflected() && node->isClassLike())) + { + continue; + } + + _indent(1, out); + out << "x(" << node->m_name.getContent() << ", param) \\\n"; + } + out << "/* */\n\n"; + } + + return SLANG_OK; +} + +SlangResult CPPExtractorApp::calcTypeHeader(CPPExtractor& extractor, TypeSet* typeSet, StringBuilder& out) +{ + const List<Node*>& baseTypes = typeSet->m_baseTypes; + const String& reflectTypeName = typeSet->m_typeName; out << "#pragma once\n\n"; out << "// Do not edit this file is generated from slang-cpp-extractor tool\n\n"; - for (Index i = 0; i < baseTypes.getCount(); ++i) + if (baseTypes.getCount() == 0) { - Node* baseType = baseTypes[i]; - - List<Node*> baseScopePath; - baseType->calcScopePath(baseScopePath); + return SLANG_OK; + } - // Remove the global scope - baseScopePath.removeAt(0); - // Remove the type itself - baseScopePath.removeLast(); + // Set up the scope + List<Node*> baseScopePath; + baseTypes[0]->calcScopePath(baseScopePath); - for (Node* scopeNode : baseScopePath) - { - SLANG_ASSERT(scopeNode->m_type == Node::Type::Namespace); - out << "namespace " << scopeNode->m_name.getContent() << " {\n"; - } + // Remove the global scope + baseScopePath.removeAt(0); + // Remove the type itself + baseScopePath.removeLast(); - List<Node*> nodes; + for (Node* scopeNode : baseScopePath) + { + SLANG_ASSERT(scopeNode->m_type == Node::Type::Namespace); + out << "namespace " << scopeNode->m_name.getContent() << " {\n"; + } + + // Add all the base types, with in order traversals + List<Node*> nodes; + for (Index i = 0; i < baseTypes.getCount(); ++i) + { + Node* baseType = baseTypes[i]; baseType->calcDerivedDepthFirst(nodes); - Node::filter(Node::isClassLikeAndReflected, nodes); + } + + Node::filter(Node::isClassLikeAndReflected, nodes); + + // Write out the types + { + out << "\n"; + out << "enum class " << reflectTypeName << "Type\n"; + out << "{\n"; - // Write out the types + Index typeIndex = 0; + for (Node* node : nodes) { - out << "\n"; - out << "enum class " << reflectTypeName << "Type\n"; - out << "{\n"; + // Okay first we are going to output the enum values + const Index depth = node->calcDerivedDepth() - 1; + _indent(depth, out); + out << node->m_name.getContent() << " = " << typeIndex << ",\n"; + typeIndex++; + } - Index typeIndex = 0; - for (Node* node : nodes) - { - // Okay first we are going to output the enum values - const Index depth = node->calcDerivedDepth() - 1; - _indent(depth, out); - out << node->m_name.getContent() << " = " << typeIndex << ",\n"; - typeIndex++; - } + _indent(1, out); + out << "CountOf\n"; - _indent(1, out); - out << "CountOf\n"; + out << "};\n\n"; + } - out << "};\n\n"; - } + // TODO(JS): + // Strictly speaking if we wanted the types to be in different scopes, we would have to + // change the namespaces here - // Predeclare the classes + // Predeclare the classes + { + out << "// Predeclare\n\n"; + for (Node* node : nodes) { - out << "// Predeclare\n\n"; - for (Node* node : nodes) + SLANG_ASSERT(node->isClassLike()); + // If it's not reflected we don't output, in the enum list + if (node->isReflected()) { - SLANG_ASSERT(node->isClassLike()); - // If it's not reflected we don't output, in the enum list - if (node->isReflected()) - { - const char* type = (node->m_type == Node::Type::ClassType) ? "class" : "struct"; - out << type << " " << node->m_name.getContent() << ";\n"; - } + const char* type = (node->m_type == Node::Type::ClassType) ? "class" : "struct"; + out << type << " " << node->m_name.getContent() << ";\n"; } } + } - // Do the macros for each of the types - - { - out << "// Type macros\n\n"; + // Do the macros for each of the types - 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"; - out << "// param is a user defined parameter that can be parsed to the invoked x macro\n\n"; + { + out << "// Type macros\n\n"; - // Output all of the definitions for each type - for (Node* node : nodes) - { - out << "#define " << m_options.m_markPrefix << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) "; + 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"; + out << "// param is a user defined parameter that can be parsed to the invoked x macro\n\n"; - // Output the X macro part - _indent(1, out); - out << "x(" << node->m_name.getContent() << ", "; + // Output all of the definitions for each type + for (Node* node : nodes) + { + out << "#define " << m_options.m_markPrefix << reflectTypeName << "_" << node->m_name.getContent() << "(x, param) "; - if (node->m_superNode) - { - out << node->m_superNode->m_name.getContent() << ", "; - } - else - { - out << "NO_SUPER, "; - } + // Output the X macro part + _indent(1, out); + out << "x(" << node->m_name.getContent() << ", "; - // Output the (file origin) - out << node->m_origin->m_macroOrigin; - out << ", "; + if (node->m_superNode) + { + out << node->m_superNode->m_name.getContent() << ", "; + } + else + { + out << "NO_SUPER, "; + } - // The last type - Node* lastDerived = node->findLastDerived(); - if (lastDerived) - { - out << lastDerived->m_name.getContent() << ", "; - } - else - { - out << "NO_LAST, "; - } + // Output the (file origin) + out << node->m_origin->m_macroOrigin; + out << ", "; - // Output any specifics of the markup - UnownedStringSlice marker = node->m_marker.getContent(); - // Need to extract the name - if (marker.getLength() > m_options.m_markPrefix.getLength() + m_options.m_markSuffix.getLength()) - { - marker = UnownedStringSlice(marker.begin() + m_options.m_markPrefix.getLength(), marker.end() - m_options.m_markSuffix.getLength()); - } - else - { - marker = UnownedStringSlice::fromLiteral("NONE"); - } - out << marker << ", "; + // The last type + Node* lastDerived = node->findLastDerived(); + if (lastDerived) + { + out << lastDerived->m_name.getContent() << ", "; + } + else + { + out << "NO_LAST, "; + } - if (node->m_superNode == nullptr) - { - out << "BASE, "; - } - else if (node->hasReflectedDerivedType()) - { - out << "INNER, "; - } - else - { - out << "LEAF, "; - } - out << "param)\n"; + // Output any specifics of the markup + UnownedStringSlice marker = node->m_marker.getContent(); + // Need to extract the name + if (marker.getLength() > m_options.m_markPrefix.getLength() + m_options.m_markSuffix.getLength()) + { + marker = UnownedStringSlice(marker.begin() + m_options.m_markPrefix.getLength(), marker.end() - m_options.m_markSuffix.getLength()); } - } + else + { + marker = UnownedStringSlice::fromLiteral("NONE"); + } + out << marker << ", "; - - // Now pop the scope in revers - for (Index j = baseScopePath.getCount() - 1; j >= 0; j--) - { - Node* scopeNode = baseScopePath[j]; - out << "} // namespace " << scopeNode->m_name.getContent() << "\n"; + if (node->m_superNode == nullptr) + { + out << "BASE, "; + } + else if (node->hasReflectedDerivedType()) + { + out << "INNER, "; + } + else + { + out << "LEAF, "; + } + out << "param)\n"; } } - // Do macros by origin - - out << "// Origin macros\n\n"; - - for (SourceOrigin* origin : extractor.getSourceOrigins()) + // Now pop the scope in revers + for (Index j = baseScopePath.getCount() - 1; j >= 0; j--) { - out << "#define " << m_options.m_markPrefix << "ORIGIN_" << origin->m_macroOrigin << "_" << reflectTypeName << "(x, param) \\\n"; - - for (Node* node : origin->m_nodes) - { - if (!(node->isReflected() && node->isClassLike())) - { - continue; - } - - _indent(1, out); - out << "x(" << node->m_name.getContent() << ", param) \\\n"; - } - out << "/* */\n\n"; + Node* scopeNode = baseScopePath[j]; + out << "} // namespace " << scopeNode->m_name.getContent() << "\n"; } return SLANG_OK; @@ -2409,30 +2495,30 @@ SlangResult CPPExtractorApp::writeOutput(CPPExtractor& extractor) // Strip the extension if set path = Path::getPathWithoutExt(path); + for (TypeSet* typeSet : extractor.getTypeSets()) { - /// Calculate the header - StringBuilder header; - SLANG_RETURN_ON_FAIL(calcHeader(extractor, header)); + { + /// Calculate the header + StringBuilder header; + SLANG_RETURN_ON_FAIL(calcTypeHeader(extractor, typeSet, header)); - // Write it out + // Write it out - StringBuilder headerPath; - headerPath << path << "." << ext; - SLANG_RETURN_ON_FAIL(writeAllText(headerPath, header.getUnownedSlice())); - } + StringBuilder headerPath; + headerPath << path << "-" << typeSet->m_fileMark << "." << ext; + SLANG_RETURN_ON_FAIL(writeAllText(headerPath, header.getUnownedSlice())); + } - { - StringBuilder childrenHeader; - SLANG_RETURN_ON_FAIL(calcChildrenHeader(extractor, childrenHeader)); + { + StringBuilder childrenHeader; + SLANG_RETURN_ON_FAIL(calcChildrenHeader(extractor, typeSet, childrenHeader)); - StringBuilder headerPath; - headerPath << path << "-macro." + ext; - SLANG_RETURN_ON_FAIL(writeAllText(headerPath, childrenHeader.getUnownedSlice())); + StringBuilder headerPath; + headerPath << path << "-" << typeSet->m_fileMark << "-macro." + ext; + SLANG_RETURN_ON_FAIL(writeAllText(headerPath, childrenHeader.getUnownedSlice())); + } } - // Write to output - // m_sink->writer->write(header.getBuffer(), header.getLength()); - return SLANG_OK; } @@ -2454,32 +2540,19 @@ SlangResult CPPExtractorApp::writeOutput(CPPExtractor& extractor) // Special markers { - { - const char* names[] = { "const", "volatile" }; - StringBuilder buf; - buf << options.m_markPrefix; - buf << "PRE_DECLARE"; - - outLookup.set(buf.getUnownedSlice(), IdentifierStyle::PreDeclare); - } - - { - StringBuilder buf; - buf << options.m_markPrefix; - buf << "REFLECTED"; + const char* names[] = {"PRE_DECLARE", "TYPE_SET", "REFLECTED", "UNREFLECTED"}; + const IdentifierStyle styles[] = { IdentifierStyle::PreDeclare, IdentifierStyle::TypeSet, IdentifierStyle::Reflected, IdentifierStyle::Unreflected }; + SLANG_COMPILE_TIME_ASSERT(SLANG_COUNT_OF(names) == SLANG_COUNT_OF(styles)); - outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Reflected); - } + StringBuilder buf; + for (Index i = 0; i < SLANG_COUNT_OF(names); ++i) { - StringBuilder buf; - buf << options.m_markPrefix; - buf << "UNREFLECTED"; - - outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Unreflected); + buf.Clear(); + buf << options.m_markPrefix << names[i]; + outLookup.set(buf.getUnownedSlice(), styles[i]); } } - // Keywords which introduce types/scopes { outLookup.set("struct", IdentifierStyle::Struct); @@ -2530,6 +2603,32 @@ SlangResult CPPExtractorApp::execute(const Options& options) SLANG_RETURN_ON_FAIL(extractor.calcDerivedTypes()); + // Okay let's check out the typeSets + { + for (TypeSet* typeSet : extractor.getTypeSets()) + { + // The macro name is in upper snake, so split it + List<UnownedStringSlice> slices; + NameConventionUtil::split(typeSet->m_macroName, slices); + + if (typeSet->m_fileMark.getLength() == 0) + { + StringBuilder buf; + // Let's guess a 'fileMark' (it becomes part of the filename) based on the macro name. Use lower kabab. + NameConventionUtil::join(slices.getBuffer(), slices.getCount(), CharCase::Lower, NameConvention::Kabab, buf); + typeSet->m_fileMark = buf.ProduceString(); + } + + if (typeSet->m_typeName.getLength() == 0) + { + // Let's guess a typename if not set -> go with upper camel + StringBuilder buf; + NameConventionUtil::join(slices.getBuffer(), slices.getCount(), CharCase::Upper, NameConvention::Camel, buf); + typeSet->m_typeName = buf.ProduceString(); + } + } + } + // Dump out the tree if (options.m_dump) { @@ -2539,8 +2638,9 @@ SlangResult CPPExtractorApp::execute(const Options& options) m_sink->writer->write(buf.getBuffer(), buf.getLength()); } + for (TypeSet* typeSet : extractor.getTypeSets()) { - const List<Node*>& baseTypes = extractor.getBaseTypes(); + const List<Node*>& baseTypes = typeSet->m_baseTypes; for (Node* baseType : baseTypes) { @@ -2598,19 +2698,18 @@ int main(int argc, const char*const* argv) { if (SLANG_FAILED(app.executeWithArgs(argc - 1, argv + 1))) { - sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed, app.getOptions().m_reflectType); + sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed); return 1; } if (sink.getErrorCount()) { - sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed, app.getOptions().m_reflectType); + sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed); return 1; } } catch (...) { sink.diagnose(SourceLoc(), CPPDiagnostics::internalError); - sink.diagnose(SourceLoc(), CPPDiagnostics::extractorFailed, app.getOptions().m_reflectType); return 1; } } |
