summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjsmall-nvidia <jsmall@nvidia.com>2020-05-20 10:56:49 -0400
committerGitHub <noreply@github.com>2020-05-20 10:56:49 -0400
commit96a00c8e8d14964c8e1f45c7c3c85d321b2a1b61 (patch)
tree5cda70f1c650db831afa4b3efb1b0d2bda497856
parentc54c957d2e647d2f9bfdc0bf31561fca5a02c5df (diff)
AST dumping via C++ Extractor reflection (#1348)
* Add support for parsing array types to C++ extractor. * C++ extractor looks for 'balanced tokens'. Use for extracting array suffixes. * First pass at field dumping. * Update project for field dumping. * WIP AST Dumper. * More AST dump compiling. * Fix bug in StringSlicePool where it doesn't use the copy of the UnownedStringSlice in the map. * Add support for SLANG_RELFECTED and SLANG_UNREFLECTED More AST dump support. * Support for hierarchical dumping/flat dumping. Use SourceWriter to dump. * Add -dump-ast command line option. * Add fixes to VS project to incude AST dump. * Fix compilation on gcc. * Add fix for type ambiguity issue on x86 VS. * Fixes from merge of reducing Token size. * Fix comment about using SourceWriter.
-rw-r--r--premake5.lua2
-rw-r--r--source/core/slang-string-slice-pool.cpp13
-rw-r--r--source/slang/slang-ast-base.h2
-rw-r--r--source/slang/slang-ast-decl.h2
-rw-r--r--source/slang/slang-ast-dump.cpp613
-rw-r--r--source/slang/slang-ast-dump.h28
-rw-r--r--source/slang/slang-ast-reflect.h2
-rw-r--r--source/slang/slang-compiler.h2
-rw-r--r--source/slang/slang-options.cpp4
-rw-r--r--source/slang/slang.cpp21
-rw-r--r--source/slang/slang.vcxproj10
-rw-r--r--source/slang/slang.vcxproj.filters6
-rw-r--r--tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp317
13 files changed, 899 insertions, 123 deletions
diff --git a/premake5.lua b/premake5.lua
index d148ce6dd..93d310ee0 100644
--- a/premake5.lua
+++ b/premake5.lua
@@ -784,7 +784,7 @@ standardProject "slang"
-- 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"
+ local buildcmd = '"%{cfg.targetdir}/slang-cpp-extractor" -d ' .. sourcePath .. " " .. table.concat(inputFiles, " ") .. " -strip-prefix slang-ast- -o slang-ast-generated -output-fields"
buildcommands { buildcmd }
diff --git a/source/core/slang-string-slice-pool.cpp b/source/core/slang-string-slice-pool.cpp
index 24187ba5c..a0af3ba68 100644
--- a/source/core/slang-string-slice-pool.cpp
+++ b/source/core/slang-string-slice-pool.cpp
@@ -61,16 +61,23 @@ StringSlicePool::Handle StringSlicePool::add(const Slice& slice)
bool StringSlicePool::findOrAdd(const Slice& slice, Handle& outHandle)
{
- Handle newHandle = Handle(m_slices.getCount());
- const Handle* handlePtr = m_map.TryGetValueOrAdd(slice, newHandle);
+ const Handle* handlePtr = m_map.TryGetValue(slice);
if (handlePtr)
{
outHandle = *handlePtr;
return true;
}
- // Need to add
+ // Need to add.
+
+ // Make a copy stored in the arena
UnownedStringSlice scopeSlice(m_arena.allocateString(slice.begin(), slice.getLength()), slice.getLength());
+
+ // Add using the arenas copy
+ Handle newHandle = Handle(m_slices.getCount());
+ m_map.Add(scopeSlice, newHandle);
+
+ // Add to slices list
m_slices.add(scopeSlice);
outHandle = newHandle;
return false;
diff --git a/source/slang/slang-ast-base.h b/source/slang/slang-ast-base.h
index 1175f0288..522bdd817 100644
--- a/source/slang/slang-ast-base.h
+++ b/source/slang/slang-ast-base.h
@@ -118,6 +118,8 @@ class Type: public Val
{
SLANG_ABSTRACT_CLASS(Type)
+ friend struct ASTDumpAccess;
+
typedef ITypeVisitor Visitor;
virtual void accept(IValVisitor* visitor, void* extra) override;
diff --git a/source/slang/slang-ast-decl.h b/source/slang/slang-ast-decl.h
index 5020debfa..069f1ac11 100644
--- a/source/slang/slang-ast-decl.h
+++ b/source/slang/slang-ast-decl.h
@@ -441,6 +441,8 @@ class SyntaxDecl : public Decl
// What type of syntax node will be produced when parsing with this keyword?
SyntaxClass<RefObject> syntaxClass;
+ SLANG_UNREFLECTED
+
// Callback to invoke in order to parse syntax with this keyword.
SyntaxParseCallback parseCallback;
void* parseUserData;
diff --git a/source/slang/slang-ast-dump.cpp b/source/slang/slang-ast-dump.cpp
new file mode 100644
index 000000000..a6d947619
--- /dev/null
+++ b/source/slang/slang-ast-dump.cpp
@@ -0,0 +1,613 @@
+// slang-ast-dump.cpp
+#include "slang-ast-dump.h"
+#include <assert.h>
+
+#include "slang-compiler.h"
+
+#include "../core/slang-string.h"
+
+#include "slang-ast-generated-macro.h"
+
+namespace Slang {
+
+namespace { // anonymous
+
+struct Context
+{
+ struct ObjectInfo
+ {
+ const ReflectClassInfo* m_typeInfo;
+ RefObject* m_object;
+ bool m_isDumped;
+ };
+
+ struct ScopeWrite
+ {
+ ScopeWrite(Context* context):
+ m_context(context)
+ {
+ if (m_context->m_scopeWriteCount == 0)
+ {
+ m_context->m_buf.Clear();
+ }
+ m_context->m_scopeWriteCount++;
+ }
+
+ ~ScopeWrite()
+ {
+ if (--m_context->m_scopeWriteCount == 0)
+ {
+ m_context->m_writer->emit(m_context->m_buf);
+ }
+ }
+
+ StringBuilder& getBuf() { return m_context->m_buf; }
+
+ operator StringBuilder&() { return m_context->m_buf; }
+
+ Context* m_context;
+ };
+
+ void dumpObject(const ReflectClassInfo& type, RefObject* obj);
+
+ void dumpObjectFull(const ReflectClassInfo& type, RefObject* obj, Index objIndex);
+ void dumpObjectReference(const ReflectClassInfo& type, RefObject* obj, Index objIndex);
+
+ void dump(NodeBase* node)
+ {
+ if (node == nullptr)
+ {
+ dumpPtr(nullptr);
+ }
+ else
+ {
+ dumpObject(node->getClassInfo(), node);
+ }
+ }
+
+ void dump(Substitutions* subs)
+ {
+ if (subs == nullptr)
+ {
+ dumpPtr(nullptr);
+ }
+ else
+ {
+ dumpObject(subs->getClassInfo(), subs);
+ }
+ }
+
+ void dump(const Name* name)
+ {
+ if (name == nullptr)
+ {
+ dumpPtr(nullptr);
+ }
+ else
+ {
+ dump(name->text);
+ }
+ }
+
+ void dump(const RefObject* obj)
+ {
+ if (obj == nullptr)
+ {
+ dumpPtr(nullptr);
+ }
+ else
+ {
+ // We don't know what this is!
+ ScopeWrite(this).getBuf() << "Unknown@" << size_t(obj);
+ }
+ }
+
+ template <typename T>
+ void dump(const List<T>& list)
+ {
+ m_writer->emit(" { \n");
+ m_writer->indent();
+ for (Index i = 0; i < list.getCount(); ++i)
+ {
+ dump(list[i]);
+ if (i < list.getCount() - 1)
+ {
+ m_writer->emit(",\n");
+ }
+ else
+ {
+ m_writer->emit("\n");
+ }
+ }
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+
+ void dump(SourceLoc sourceLoc)
+ {
+ SourceManager* manager = m_writer->getSourceManager();
+
+ {
+ ScopeWrite(this).getBuf() << "SourceLoc(" << sourceLoc.getRaw() << ")";
+ }
+
+ if (manager && sourceLoc.isValid())
+ {
+ HumaneSourceLoc humaneLoc = manager->getHumaneLoc(sourceLoc);
+ ScopeWrite(this).getBuf() << " " << humaneLoc.pathInfo.foundPath << ":" << humaneLoc.line;
+ }
+ }
+
+ static char _getHexDigit(UInt v)
+ {
+ return (v < 10) ? char(v + '0') : char('a' + v - 10);
+ }
+
+ void dump(const UnownedStringSlice& slice)
+ {
+ m_writer->emitChar('\"');
+
+ {
+ ScopeWrite scope(this);
+ auto& buf = scope.getBuf();
+ for (const char c : slice)
+ {
+ if (c < 0x20 || c >= 0x80)
+ {
+ buf << "\\0x" << _getHexDigit(UInt32(c) >> 4) << _getHexDigit(c & 0xf);
+ }
+ else
+ {
+ buf << c;
+ }
+ }
+ }
+ m_writer->emitChar('\"');
+ }
+
+ void dump(const Token& token)
+ {
+ ScopeWrite(this).getBuf() << " { " << TokenTypeToString(token.type) << ", ";
+ dump(token.loc);
+ dump(token.getContent());
+ m_writer->emit(" }");
+ }
+
+ Index getObjectIndex(const ReflectClassInfo& typeInfo, RefObject* obj)
+ {
+ Index* indexPtr = m_objectMap.TryGetValueOrAdd(obj, m_objects.getCount());
+ if (indexPtr)
+ {
+ return *indexPtr;
+ }
+
+ ObjectInfo info;
+ info.m_isDumped = false;
+ info.m_object = obj;
+ info.m_typeInfo = &typeInfo;
+
+ m_objects.add(info);
+ return m_objects.getCount() - 1;
+ }
+
+ void dump(uint32_t v)
+ {
+ m_writer->emit(UInt(v));
+ }
+ void dump(int32_t v)
+ {
+ m_writer->emit(v);
+ }
+ void dump(FloatingPointLiteralValue v)
+ {
+ m_writer->emit(v);
+ }
+
+ void dump(IntegerLiteralValue v)
+ {
+ m_writer->emit(v);
+ }
+
+
+ void dump(const SemanticVersion& version)
+ {
+ ScopeWrite(this).getBuf() << UInt(version.m_major) << "." << UInt(version.m_minor) << "." << UInt(version.m_patch);
+ }
+ void dump(const NameLoc& nameLoc)
+ {
+ m_writer->emit("NameLoc{");
+ if (nameLoc.name)
+ {
+ dump(nameLoc.name->text.getUnownedSlice());
+ }
+ else
+ {
+ dumpPtr(nullptr);
+ }
+ m_writer->emit(", ");
+ dump(nameLoc.loc);
+ m_writer->emit(" }");
+ }
+ void dump(BaseType baseType)
+ {
+ m_writer->emit(BaseTypeInfo::asText(baseType));
+ }
+ void dump(Stage stage)
+ {
+ m_writer->emit(getStageName(stage));
+ }
+ void dump(ImageFormat imageFormat)
+ {
+ m_writer->emit(getGLSLNameForImageFormat(imageFormat));
+ }
+
+ void dump(const String& string)
+ {
+ dump(string.getUnownedSlice());
+ }
+
+ void dump(const DiagnosticInfo* info)
+ {
+ ScopeWrite(this).getBuf() << "DiagnosticInfo {" << info->id << "}";
+ }
+ void dump(const Layout* layout)
+ {
+ ScopeWrite(this).getBuf() << "Layout@" << size_t(layout);
+ }
+
+ void dump(const Modifiers& modifiers)
+ {
+ auto& nonConstModifiers = const_cast<Modifiers&>(modifiers);
+
+ m_writer->emit(" { \n");
+ m_writer->indent();
+
+ for (const auto& mod : nonConstModifiers)
+ {
+ dump(mod);
+ m_writer->emit("\n");
+ }
+
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+
+ template <typename T>
+ void dump(const SyntaxClass<T>& cls)
+ {
+ m_writer->emit(cls.classInfo->m_name);
+ }
+
+ template <typename KEY, typename VALUE>
+ void dump(const Dictionary<KEY, VALUE>& dict)
+ {
+ m_writer->emit(" { \n");
+ m_writer->indent();
+
+ for (auto iter : dict)
+ {
+ const auto& key = iter.Key;
+ const auto& value = iter.Value;
+
+ dump(key);
+ m_writer->emit(" : ");
+ dump(value);
+
+ m_writer->emit("\n");
+ }
+
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+
+ void dump(const DeclCheckStateExt& extState)
+ {
+ auto state = extState.getState();
+
+ ScopeWrite(this).getBuf() << "DeclCheckStateExt{" << extState.isBeingChecked() << ", " << Index(state) << "}";
+ }
+
+ void dump(TextureFlavor texFlavor)
+ {
+ m_buf.Clear();
+ m_buf << "TextureFlavor{" << Index(texFlavor.flavor) << "}";
+ m_writer->emit(m_buf);
+ }
+
+ void dump(SamplerStateFlavor flavor)
+ {
+ switch (flavor)
+ {
+ case SamplerStateFlavor::SamplerState: m_writer->emit("sampler"); break;
+ case SamplerStateFlavor::SamplerComparisonState: m_writer->emit("samplerComparison"); break;
+ default: m_writer->emit("unknown"); break;
+ }
+ }
+
+ void dump(const QualType& qualType)
+ {
+ if (qualType.IsLeftValue)
+ {
+ m_writer->emit("left ");
+ }
+ else
+ {
+ m_writer->emit("right ");
+ }
+ dump(qualType.type);
+ }
+
+ void dumpPtr(const void* ptr)
+ {
+ if (ptr)
+ {
+ ScopeWrite(this).getBuf() << "Unknown@" << size_t(ptr);
+ }
+ else
+ {
+ m_writer->emit("null");
+ }
+ }
+
+ void dump(SyntaxParseCallback callback) { dumpPtr((const void*)callback); }
+
+ template <typename T, int SIZE>
+ void dump(const T (&in)[SIZE])
+ {
+ m_writer->emit(" { \n");
+ m_writer->indent();
+
+ for (Index i = 0; i < Index(SIZE); ++i)
+ {
+ dump(in[i]);
+ if (i < Index(SIZE) - 1)
+ {
+ m_writer->emit(", ");
+ }
+ m_writer->emit("\n");
+ }
+
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+
+ //void dump(const void* ptr) { dumpPtr(ptr); }
+
+ void dump(const LookupResult& result)
+ {
+ auto& nonConstResult = const_cast<LookupResult&>(result);
+
+ m_writer->emit(" { \n");
+ m_writer->indent();
+
+ for (auto item : nonConstResult)
+ {
+ // TODO(JS):
+ m_writer->emit("...\n");
+ }
+
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+ void dump(const GlobalGenericParamSubstitution::ConstraintArg& arg)
+ {
+ m_writer->emit(" { \n");
+ m_writer->indent();
+
+ dump(arg.decl);
+ m_writer->emit(",\n");
+ dump(arg.val);
+ m_writer->emit("\n");
+
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+ void dump(const TypeExp& exp)
+ {
+ m_writer->emit(" { \n");
+ m_writer->indent();
+
+ dump(exp.exp);
+ m_writer->emit(",\n");
+ dump(exp.type);
+ m_writer->emit("\n");
+
+ m_writer->dedent();
+ m_writer->emit("}");
+ }
+ void dump(const ExpandedSpecializationArg& arg)
+ {
+ dump(arg.witness);
+ }
+
+ void dump(const TransparentMemberInfo& memInfo)
+ {
+ dump(memInfo.decl);
+ }
+
+ void dumpRemaining()
+ {
+ // Have to keep checking count, as dumping objects can add objects
+ for (Index i = 0; i < m_objects.getCount(); ++i)
+ {
+ ObjectInfo& info = m_objects[i];
+ if (!info.m_isDumped)
+ {
+ dumpObjectFull(*info.m_typeInfo, info.m_object, i);
+ }
+ }
+ }
+
+ template <typename T>
+ void dumpField(const char* name, const T& value)
+ {
+ m_writer->emit(name);
+ m_writer->emit(" : ");
+ dump(value);
+ m_writer->emit("\n");
+ }
+
+ void dumpObjectFull(NodeBase* node);
+ void dumpObjectFull(Substitutions* subs);
+
+ Context(SourceWriter* writer, ASTDumpUtil::Style dumpStyle):
+ m_writer(writer),
+ m_scopeWriteCount(0),
+ m_dumpStyle(dumpStyle)
+ {
+ }
+
+ ASTDumpUtil::Style m_dumpStyle;
+
+ Index m_scopeWriteCount;
+
+ // Using the SourceWriter, for automatic indentation.
+ SourceWriter* m_writer;
+
+ Dictionary<RefObject*, Index> m_objectMap; ///< Object index
+ List<ObjectInfo> m_objects;
+
+ StringBuilder m_buf;
+};
+
+} // anonymous
+
+// Lets generate functions one for each that attempts to write out *it's* fields.
+// We can write out the Super types fields by looking that up
+
+struct ASTDumpAccess
+{
+#define SLANG_AST_DUMP_FIELD(FIELD_NAME, TYPE, param) context.dumpField(#FIELD_NAME, node->FIELD_NAME);
+
+#define SLANG_AST_DUMP_FIELDS_IMPL(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) \
+static void dumpFields_##NAME(NAME* node, Context& context) \
+{ \
+ SLANG_UNUSED(node); \
+ SLANG_UNUSED(context); \
+ SLANG_FIELDS_ASTNode_##NAME(SLANG_AST_DUMP_FIELD, _) \
+}
+
+SLANG_ALL_ASTNode_Substitutions(SLANG_AST_DUMP_FIELDS_IMPL, _)
+SLANG_ALL_ASTNode_NodeBase(SLANG_AST_DUMP_FIELDS_IMPL, _)
+
+};
+
+#define SLANG_AST_GET_DUMP_FUNC(NAME, SUPER, ORIGIN, LAST, MARKER, TYPE, param) m_funcs[Index(ASTNodeType::NAME)] = (DumpFieldsFunc)&ASTDumpAccess::dumpFields_##NAME;
+
+typedef void (*DumpFieldsFunc)(RefObject* obj, Context& context);
+
+struct DumpFieldFuncs
+{
+ DumpFieldFuncs()
+ {
+ memset(m_funcs, 0, sizeof(m_funcs));
+ SLANG_ALL_ASTNode_Substitutions(SLANG_AST_GET_DUMP_FUNC, _)
+ SLANG_ALL_ASTNode_NodeBase(SLANG_AST_GET_DUMP_FUNC, _)
+ }
+
+ DumpFieldsFunc m_funcs[Index(ASTNodeType::CountOf)];
+};
+
+static const DumpFieldFuncs s_funcs;
+
+void Context::dumpObjectReference(const ReflectClassInfo& type, RefObject* obj, Index objIndex)
+{
+ SLANG_UNUSED(obj);
+ ScopeWrite(this).getBuf() << type.m_name << "@" << objIndex;
+}
+
+void Context::dumpObjectFull(const ReflectClassInfo& type, RefObject* obj, Index objIndex)
+{
+ ObjectInfo& info = m_objects[objIndex];
+ SLANG_ASSERT(info.m_isDumped == false);
+ info.m_isDumped = true;
+
+ // We need to dump the fields.
+
+ ScopeWrite(this).getBuf() << type.m_name << "(" << objIndex << ") {\n";
+ m_writer->indent();
+
+ List<const ReflectClassInfo*> allTypes;
+ {
+ const ReflectClassInfo* curType = &type;
+ do
+ {
+ allTypes.add(curType);
+ curType = curType->m_superClass;
+ } while (curType);
+ }
+
+ // Okay we go backwards so we output in the 'normal' order
+ for (Index i = allTypes.getCount() - 1; i >= 0; --i)
+ {
+ const ReflectClassInfo* curType = allTypes[i];
+ DumpFieldsFunc func = s_funcs.m_funcs[Index(curType->m_classId)];
+ if (func)
+ {
+ func(obj, *this);
+ }
+ }
+
+ m_writer->dedent();
+ m_writer->emit("}\n");
+}
+
+void Context::dumpObject(const ReflectClassInfo& typeInfo, RefObject* obj)
+{
+ Index index = getObjectIndex(typeInfo, obj);
+
+ ObjectInfo& info = m_objects[index];
+ if (info.m_isDumped || m_dumpStyle == ASTDumpUtil::Style::Flat)
+ {
+ dumpObjectReference(typeInfo, obj, index);
+ }
+ else
+ {
+ dumpObjectFull(typeInfo, obj, index);
+ }
+}
+
+void Context::dumpObjectFull(NodeBase* node)
+{
+ if (!node)
+ {
+ dumpPtr(nullptr);
+ }
+ else
+ {
+ const ReflectClassInfo& typeInfo = node->getClassInfo();
+ Index index = getObjectIndex(typeInfo, node);
+ dumpObjectFull(typeInfo, node, index);
+ }
+}
+
+void Context::dumpObjectFull(Substitutions* subs)
+{
+ if (!subs)
+ {
+ dumpPtr(nullptr);
+ }
+ else
+ {
+ const ReflectClassInfo& typeInfo = subs->getClassInfo();
+ Index index = getObjectIndex(typeInfo, subs);
+ dumpObjectFull(typeInfo, subs, index);
+ }
+}
+
+/* static */void ASTDumpUtil::dump(NodeBase* node, Style style, SourceWriter* writer)
+{
+ Context context(writer, style);
+ context.dumpObjectFull(node);
+ context.dumpRemaining();
+}
+
+/* static */void ASTDumpUtil::dump(Substitutions* subs, Style style, SourceWriter* writer)
+{
+ Context context(writer, style);
+ context.dumpObjectFull(subs);
+ context.dumpRemaining();
+
+}
+
+} // namespace Slang
diff --git a/source/slang/slang-ast-dump.h b/source/slang/slang-ast-dump.h
new file mode 100644
index 000000000..71df8aafc
--- /dev/null
+++ b/source/slang/slang-ast-dump.h
@@ -0,0 +1,28 @@
+// slang-ast-dump.h
+#ifndef SLANG_AST_DUMP_H
+#define SLANG_AST_DUMP_H
+
+#include "slang-syntax.h"
+
+#include "slang-emit-source-writer.h"
+
+namespace Slang
+{
+
+struct ASTDumpAccess;
+
+struct ASTDumpUtil
+{
+ enum class Style
+ {
+ Hierachical,
+ Flat,
+ };
+
+ static void dump(NodeBase* node, Style style, SourceWriter* writer);
+ static void dump(Substitutions* subs, Style style, SourceWriter* writer);
+};
+
+} // namespace Slang
+
+#endif
diff --git a/source/slang/slang-ast-reflect.h b/source/slang/slang-ast-reflect.h
index 9c93d0621..0c57dc757 100644
--- a/source/slang/slang-ast-reflect.h
+++ b/source/slang/slang-ast-reflect.h
@@ -53,5 +53,7 @@
// Does nothing - just a mark to the C++ extractor
#define SLANG_REFLECT_BASE_CLASS(NAME)
+#define SLANG_REFLECTED
+#define SLANG_UNREFLECTED
#endif // SLANG_AST_REFLECT_H
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h
index fb13ab146..852898de6 100644
--- a/source/slang/slang-compiler.h
+++ b/source/slang/slang-compiler.h
@@ -1449,6 +1449,8 @@ namespace Slang
bool shouldDumpIR = false;
bool shouldValidateIR = false;
+ bool shouldDumpAST = false;
+
protected:
CompileRequestBase(
Linkage* linkage,
diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp
index c642c196a..8100fab4f 100644
--- a/source/slang/slang-options.cpp
+++ b/source/slang/slang-options.cpp
@@ -465,6 +465,10 @@ struct OptionsParser
requestImpl->getFrontEndReq()->shouldDumpIR = true;
requestImpl->getBackEndReq()->shouldDumpIR = true;
}
+ else if (argStr == "-dump-ast")
+ {
+ requestImpl->getFrontEndReq()->shouldDumpAST = true;
+ }
else if (argStr == "-dump-repro")
{
SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, requestImpl->dumpRepro));
diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp
index 34f1402b5..82bc5e478 100644
--- a/source/slang/slang.cpp
+++ b/source/slang/slang.cpp
@@ -14,6 +14,8 @@
#include "slang-reflection.h"
#include "slang-type-layout.h"
+#include "slang-ast-dump.h"
+
#include "slang-state-serialize.h"
#include "slang-file-system.h"
@@ -996,6 +998,25 @@ void FrontEndCompileRequest::parseTranslationUnit(
tokens,
getSink(),
languageScope);
+
+ // Let's try dumping
+
+ if (shouldDumpAST)
+ {
+ StringBuilder buf;
+ SourceWriter writer(linkage->getSourceManager(), LineDirectiveMode::None);
+
+ ASTDumpUtil::dump(translationUnit->getModuleDecl(), ASTDumpUtil::Style::Flat, &writer);
+
+ const String& path = sourceFile->getPathInfo().foundPath;
+ if (path.getLength())
+ {
+ String fileName = Path::getFileNameWithoutExt(path);
+ fileName.append(".slang-ast");
+
+ File::writeAllText(fileName, writer.getContent());
+ }
+ }
}
}
diff --git a/source/slang/slang.vcxproj b/source/slang/slang.vcxproj
index cf5a81499..1b391cac0 100644
--- a/source/slang/slang.vcxproj
+++ b/source/slang/slang.vcxproj
@@ -192,6 +192,7 @@
<ClInclude Include="slang-ast-all.h" />
<ClInclude Include="slang-ast-base.h" />
<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" />
@@ -271,6 +272,7 @@
<ClInclude Include="slang-visitor.h" />
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="slang-ast-dump.cpp" />
<ClCompile Include="slang-ast-reflect.cpp" />
<ClCompile Include="slang-check-conformance.cpp" />
<ClCompile Include="slang-check-constraint.cpp" />
@@ -382,10 +384,10 @@
<Natvis Include="slang.natvis" />
<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</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</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</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</Command>
+ <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>%(RootDir)%(Directory)/slang-ast-generated.h;%(RootDir)%(Directory)/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;%(RootDir)%(Directory)/slang-ast-base.h;%(RootDir)%(Directory)/slang-ast-decl.h;%(RootDir)%(Directory)/slang-ast-expr.h;%(RootDir)%(Directory)/slang-ast-modifier.h;%(RootDir)%(Directory)/slang-ast-stmt.h;%(RootDir)%(Directory)/slang-ast-type.h;%(RootDir)%(Directory)/slang-ast-val.h</AdditionalInputs>
diff --git a/source/slang/slang.vcxproj.filters b/source/slang/slang.vcxproj.filters
index 4060a6019..c2c9268dc 100644
--- a/source/slang/slang.vcxproj.filters
+++ b/source/slang/slang.vcxproj.filters
@@ -27,6 +27,9 @@
<ClInclude Include="slang-ast-decl.h">
<Filter>Header Files</Filter>
</ClInclude>
+ <ClInclude Include="slang-ast-dump.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
<ClInclude Include="slang-ast-expr.h">
<Filter>Header Files</Filter>
</ClInclude>
@@ -260,6 +263,9 @@
</ClInclude>
</ItemGroup>
<ItemGroup>
+ <ClCompile Include="slang-ast-dump.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
<ClCompile Include="slang-ast-reflect.cpp">
<Filter>Source Files</Filter>
</ClCompile>
diff --git a/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp b/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp
index 5118a3a9b..792cf3458 100644
--- a/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp
+++ b/tools/slang-cpp-extractor/slang-cpp-extractor-main.cpp
@@ -42,6 +42,9 @@ enum class IdentifierStyle
Namespace, ///< namespace
Access, ///< public, protected, private
+ Reflected,
+ Unreflected,
+
CountOf,
};
@@ -53,6 +56,7 @@ struct IdentifierFlag
StartScope = 0x1, ///< namespace, struct or class
ClassLike = 0x2, ///< Struct or class
Keyword = 0x4,
+ Reflection = 0x8,
};
};
@@ -67,7 +71,10 @@ static const IdentifierFlags kIdentifierFlags[Index(IdentifierStyle::CountOf)] =
IdentifierFlag::Keyword | IdentifierFlag::StartScope | IdentifierFlag::ClassLike, /// Class
IdentifierFlag::Keyword | IdentifierFlag::StartScope | IdentifierFlag::ClassLike, /// Struct
IdentifierFlag::Keyword | IdentifierFlag::StartScope, /// Namespace
- IdentifierFlag::Keyword,
+ IdentifierFlag::Keyword, /// Access
+ IdentifierFlag::Reflection, /// Reflected
+ IdentifierFlag::Reflection, /// Unreflected
+
};
SLANG_FORCE_INLINE IdentifierFlags getFlags(IdentifierStyle style)
@@ -118,6 +125,12 @@ public:
set(UnownedStringSlice(names[i]), style);
}
}
+ void reset()
+ {
+ m_styles.clear();
+ m_pool.clear();
+ }
+
IdentifierLookup():
m_pool(StringSlicePool::Style::Empty)
{
@@ -128,6 +141,12 @@ protected:
StringSlicePool m_pool;
};
+enum class ReflectionType
+{
+ NotReflected,
+ Reflected,
+};
+
class SourceOrigin;
class Node : public RefObject
@@ -144,8 +163,11 @@ public:
struct Field
{
+ bool isReflected() const { return reflectionType == ReflectionType::Reflected; }
+
UnownedStringSlice type;
Token name;
+ ReflectionType reflectionType;
};
enum class BaseType
@@ -193,6 +215,12 @@ public:
/// Find the last (reflected) derived type
Node* findLastDerived();
+ /// True if reflected
+ bool isReflected() const { return m_reflectionType == ReflectionType::Reflected; }
+
+ /// Gets the reflection for any contained types
+ ReflectionType getContainedReflectionType() const { return m_reflectionType == ReflectionType::NotReflected ? ReflectionType::NotReflected : m_reflectionOverride; }
+
/// True if has a derived type that is reflected
bool hasReflectedDerivedType() const;
/// Stores in out any reflected derived types
@@ -205,7 +233,8 @@ public:
Node(Type type):
m_type(type),
m_parentScope(nullptr),
- m_isReflected(false),
+ m_reflectionType(ReflectionType::NotReflected),
+ m_reflectionOverride(ReflectionType::Reflected),
m_superNode(nullptr),
m_baseType(BaseType::None),
m_origin(nullptr)
@@ -235,7 +264,11 @@ public:
SourceOrigin* m_origin;
/// Classes can be traversed, but not reflected. To be reflected they have to contain the marker
- bool m_isReflected;
+ ReflectionType m_reflectionType;
+
+ /// 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;
@@ -393,11 +426,9 @@ void Node::addChild(Node* child)
child->m_parentScope = this;
m_children.add(child);
- UnownedStringSlice content = child->m_name.getContent();
-
- if (content.getLength())
+ if (child->m_name.hasContent())
{
- m_childMap.Add(content, child);
+ m_childMap.Add(child->m_name.getContent(), child);
}
}
@@ -443,7 +474,7 @@ static void _indent(Index indentCount, StringBuilder& out)
void Node::dumpDerived(int indentCount, StringBuilder& out)
{
- if (isClassLike() && m_isReflected && m_name.hasContent())
+ if (isClassLike() && isReflected() && m_name.hasContent())
{
_indent(indentCount, out);
out << m_name.getContent() << "\n";
@@ -484,12 +515,12 @@ void Node::dump(int indentCount, StringBuilder& out)
out << typeName << " ";
- if (!m_isReflected)
+ if (!isReflected())
{
out << " (";
}
out << m_name.getContent();
- if (!m_isReflected)
+ if (!isReflected())
{
out << ") ";
}
@@ -511,8 +542,11 @@ void Node::dump(int indentCount, StringBuilder& out)
for (const Field& field : m_fields)
{
- _indent(indentCount + 1, out);
- out << field.type << " " << field.name.getContent() << "\n";
+ if (field.isReflected())
+ {
+ _indent(indentCount + 1, out);
+ out << field.type << " " << field.name.getContent() << "\n";
+ }
}
_indent(indentCount, out);
@@ -559,7 +593,7 @@ Index Node::calcDerivedDepth() const
Node* Node::findLastDerived()
{
- if (!m_isReflected)
+ if (!isReflected())
{
return nullptr;
}
@@ -594,7 +628,7 @@ bool Node::hasReflectedDerivedType() const
{
for (Node* type : m_derivedTypes)
{
- if (type->m_isReflected)
+ if (type->isReflected())
{
return true;
}
@@ -607,7 +641,7 @@ void Node::getReflectedDerivedTypes(List<Node*>& out) const
out.clear();
for (Node* type : m_derivedTypes)
{
- if (type->m_isReflected)
+ if (type->isReflected())
{
out.add(type);
}
@@ -621,7 +655,7 @@ void Node::getReflectedDerivedTypes(List<Node*>& out) const
for (Index j = 0; j < count; )
{
Node* node = ioNodes[j];
- if (!node->isClassLike() || !node->m_isReflected)
+ if (!node->isClassLike() || !node->isReflected())
{
ioNodes.removeAt(j);
count--;
@@ -651,6 +685,8 @@ struct Options
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)
bool m_dump = false; ///< If true will dump to stderr the types/fields and hierarchy it extracted
+ bool m_outputFields = false; ///< When dumping macros also dump field definitions
+
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
@@ -766,7 +802,12 @@ SlangResult OptionsParser::parse(int argc, const char*const* argv, DiagnosticSin
else if (arg == "-defs")
{
outOptions.m_defs = true;
- continue;
+ continue;
+ }
+ else if (arg == "-output-fields")
+ {
+ outOptions.m_outputFields = true;
+ break;
}
else if (arg == "-strip-prefix")
{
@@ -809,6 +850,7 @@ CPPExtractor::CPPExtractor(StringSlicePool* typePool, NamePool* namePool, Diagno
m_identifierLookup(identifierLookup)
{
m_rootNode = new Node(Node::Type::Namespace);
+ m_rootNode->m_reflectionType = ReflectionType::Reflected;
}
bool CPPExtractor::_isMarker(const UnownedStringSlice& name)
@@ -1038,6 +1080,9 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type)
RefPtr<Node> node(new Node(type));
node->m_name = name;
+ // Defaults to not reflected
+ SLANG_ASSERT(!node->isReflected());
+
if (advanceIfToken(TokenType::Colon))
{
// Could have public
@@ -1068,8 +1113,6 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type)
m_reader.advanceToken();
}
- // Node does define a class, but it's not reflected
- node->m_isReflected = false;
return pushNode(node);
}
@@ -1094,7 +1137,6 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type)
case TokenType::Identifier: break;
case TokenType::RBrace:
{
- node->m_isReflected = false;
SLANG_RETURN_ON_FAIL(pushNode(node));
SLANG_RETURN_ON_FAIL(popBrace());
m_reader.advanceToken();
@@ -1102,7 +1144,6 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type)
}
default:
{
- node->m_isReflected = false;
SLANG_RETURN_ON_FAIL(pushNode(node));
return SLANG_OK;
}
@@ -1114,8 +1155,6 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type)
break;
}
- // Looks like a class, but looks like non-reflected
- node->m_isReflected = false;
// We still need to add the node,
SLANG_RETURN_ON_FAIL(pushNode(node));
return SLANG_OK;
@@ -1134,7 +1173,7 @@ SlangResult CPPExtractor::_maybeParseNode(Node::Type type)
return SLANG_FAIL;
}
- node->m_isReflected = true;
+ node->m_reflectionType = ReflectionType::Reflected;
return pushNode(node);
}
@@ -1478,6 +1517,7 @@ SlangResult CPPExtractor::_maybeParseField()
Node::Field field;
field.type = typeName;
field.name = fieldName;
+ field.reflectionType = m_currentNode->getContainedReflectionType();
m_currentNode->m_fields.add(field);
break;
@@ -1538,8 +1578,8 @@ SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options)
{
case TokenType::Identifier:
{
- IdentifierStyle style = m_identifierLookup->get(m_reader.peekToken().getContent());
-
+ const IdentifierStyle style = m_identifierLookup->get(m_reader.peekToken().getContent());
+
switch (style)
{
case IdentifierStyle::BaseClass:
@@ -1555,10 +1595,31 @@ SlangResult CPPExtractor::parse(SourceFile* sourceFile, const Options* options)
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();
break;
}
+ case IdentifierStyle::Reflected:
+ {
+ m_reader.advanceToken();
+ if (m_currentNode)
+ {
+ m_currentNode->m_reflectionOverride = ReflectionType::Reflected;
+ }
+ break;
+ }
+ case IdentifierStyle::Unreflected:
+ {
+ m_reader.advanceToken();
+ if (m_currentNode)
+ {
+ m_currentNode->m_reflectionOverride = ReflectionType::NotReflected;
+ }
+ break;
+ }
case IdentifierStyle::Root:
{
if (m_currentNode && m_currentNode->isClassLike())
@@ -1660,7 +1721,7 @@ SlangResult CPPExtractor::_calcDerivedTypesRec(Node* node)
Node* superType = parentScope->findChild(node->m_super.getContent());
if (!superType)
{
- if (node->m_isReflected)
+ if (node->isReflected())
{
m_sink->diagnose(node->m_name, CPPDiagnostics::superTypeNotFound, node->m_name.getContent());
return SLANG_FAIL;
@@ -1775,48 +1836,18 @@ public:
m_slicePool(StringSlicePool::Style::Default)
{
m_namePool.setRootNamePool(rootNamePool);
-
- // Some keywords
- {
- const char* names[] = { "virtual", "typedef", "continue", "if", "case", "break", "catch", "default", "delete", "do", "else", "for", "new", "goto", "return", "switch", "throw", "using", "while" };
- m_identifierLookup.set(names, SLANG_COUNT_OF(names), IdentifierStyle::Keyword);
- }
-
- // Type modifier keywords
- {
- const char* names[] = { "const", "volatile" };
- m_identifierLookup.set(names, SLANG_COUNT_OF(names), IdentifierStyle::TypeModifier);
- }
-
- // Special markers
- {
- m_identifierLookup.set("SLANG_CLASS_ROOT", IdentifierStyle::Root);
- m_identifierLookup.set("SLANG_REFLECT_BASE_CLASS", IdentifierStyle::BaseClass);
- }
-
- // Keywords which introduce types/scopes
- {
- m_identifierLookup.set("struct", IdentifierStyle::Struct);
- m_identifierLookup.set("class", IdentifierStyle::Class);
- m_identifierLookup.set("namespace", IdentifierStyle::Namespace);
- }
-
- // Keywords that control access
- {
- const char* names[] = { "private", "protected", "public" };
- m_identifierLookup.set(names, SLANG_COUNT_OF(names), IdentifierStyle::Access);
- }
}
protected:
-
+
+ /// Called to set up identifier lookup. Must be performed after options are initials
+ static void _initIdentifierLookup(const Options& options, IdentifierLookup& outLookup);
+
NamePool m_namePool;
Options m_options;
DiagnosticSink* m_sink;
SourceManager* m_sourceManager;
- IdentifierLookup m_identifierLookup;
-
StringSlicePool m_slicePool;
};
@@ -1864,7 +1895,7 @@ SlangResult CPPExtractorApp::calcDef(CPPExtractor& extractor, SourceOrigin* orig
for (Node* node : origin->m_nodes)
{
- if (node->isClassLike() && node->m_isReflected)
+ if (node->isClassLike() && node->isReflected())
{
if (node->m_marker.getContent().indexOf(UnownedStringSlice::fromLiteral("ABSTRACT")) >= 0)
{
@@ -1878,8 +1909,6 @@ SlangResult CPPExtractorApp::calcDef(CPPExtractor& extractor, SourceOrigin* orig
return SLANG_OK;
}
-
-
SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringBuilder& out)
{
const List<Node*>& baseTypes = extractor.getBaseTypes();
@@ -1948,6 +1977,46 @@ SlangResult CPPExtractorApp::calcChildrenHeader(CPPExtractor& extractor, StringB
}
out << "\n\n";
}
+
+ if (m_options.m_outputFields)
+ {
+ out << "\n\n /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! FIELDS !!!!!!!!!!!!!!!!!!!!!!!!!!!! */\n\n";
+
+ for (Node* node : nodes)
+ {
+ // Define the derived types
+ out << "#define " << m_options.m_prefixMark << "FIELDS_" << reflectTypeName << "_" << node->m_name.getContent() << "(_x_, _param_)";
+
+ if (node->m_fields.getCount() > 0)
+ {
+ 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];
+
+ if (field.isReflected())
+ {
+ if (previousField)
+ {
+ out << "\\\n";
+ }
+
+ _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;
+ }
+ }
+ }
+
+ out << "\n\n";
+ }
+ }
}
return SLANG_OK;
@@ -2010,33 +2079,6 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder&
out << "};\n\n";
}
-#if 0
- out << "\n";
- out << "enum class " << reflectTypeName << "Last\n";
- out << "{\n";
-
- for (Node* node : nodes)
- {
- SLANG_ASSERT(node->isClassLike());
- // If it's not reflected we don't output, in the enum list
- if (!node->m_isReflected)
- {
- continue;
- }
-
- Node* lastDerived = node->findLastDerived();
- if (lastDerived)
- {
- // Okay first we are going to output the enum values
- const Index depth = node->calcDerivedDepth() - 1;
- _indent(depth, out);
- out << node->m_name.Content << " = int(" << reflectTypeName << "Type::" << lastDerived->m_name.Content << "),\n";
- }
- }
-
- out << "};\n\n";
-#endif
-
// Predeclare the classes
{
out << "// Predeclare\n\n";
@@ -2044,7 +2086,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder&
{
SLANG_ASSERT(node->isClassLike());
// If it's not reflected we don't output, in the enum list
- if (node->m_isReflected)
+ if (node->isReflected())
{
const char* type = (node->m_type == Node::Type::ClassType) ? "class" : "struct";
out << type << " " << node->m_name.getContent() << ";\n";
@@ -2052,24 +2094,6 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder&
}
}
-#if 0
- out << "struct " << reflectTypeName << "Super\n";
- out << "{\n";
-
- for (Node* node : nodes)
- {
- // If it's not reflected we don't output, in the enum list
- if (node->m_isReflected && node->m_superNode)
- {
- _indent(1, out);
- // We concat _Super so the typedef are distinct from the ones being referenced
- out << "typedef " << node->m_superNode->m_name.Content << " " << node->m_name.Content << "_Super;\n";
- }
- }
-
- out << "};\n";
-#endif
-
// Do the macros for each of the types
{
@@ -2129,7 +2153,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder&
}
out << marker << ", ";
- if (node->m_baseType != Node::BaseType::None || node->m_superNode && node->m_superNode->m_isReflected == false)
+ if (node->m_baseType != Node::BaseType::None || node->m_superNode && node->m_superNode->isReflected() == false)
{
out << "BASE, ";
}
@@ -2164,7 +2188,7 @@ SlangResult CPPExtractorApp::calcHeader(CPPExtractor& extractor, StringBuilder&
for (Node* node : origin->m_nodes)
{
- if (!(node->m_isReflected && node->isClassLike()))
+ if (!(node->isReflected() && node->isClassLike()))
{
continue;
}
@@ -2208,7 +2232,6 @@ SlangResult CPPExtractorApp::writeDefs(CPPExtractor& extractor)
SlangResult CPPExtractorApp::writeOutput(CPPExtractor& extractor)
{
-
String path;
if (m_options.m_inputDirectory.getLength())
{
@@ -2257,13 +2280,77 @@ SlangResult CPPExtractorApp::writeOutput(CPPExtractor& extractor)
return SLANG_OK;
}
+/* static */void CPPExtractorApp::_initIdentifierLookup(const Options& options, IdentifierLookup& outLookup)
+{
+ outLookup.reset();
+
+ // Some keywords
+ {
+ const char* names[] = { "virtual", "typedef", "continue", "if", "case", "break", "catch", "default", "delete", "do", "else", "for", "new", "goto", "return", "switch", "throw", "using", "while" };
+ outLookup.set(names, SLANG_COUNT_OF(names), IdentifierStyle::Keyword);
+ }
+
+ // Type modifier keywords
+ {
+ const char* names[] = { "const", "volatile" };
+ outLookup.set(names, SLANG_COUNT_OF(names), IdentifierStyle::TypeModifier);
+ }
+
+ // Special markers
+ {
+ {
+ StringBuilder buf;
+ buf << options.m_prefixMark;
+ buf << "CLASS_ROOT";
+
+ outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Root);
+ }
+ {
+ StringBuilder buf;
+ buf << options.m_prefixMark;
+ buf << "REFLECT_BASE_CLASS";
+
+ outLookup.set(buf.getUnownedSlice(), IdentifierStyle::BaseClass);
+ }
+ {
+ StringBuilder buf;
+ buf << options.m_prefixMark;
+ buf << "REFLECTED";
+
+ outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Reflected);
+ }
+ {
+ StringBuilder buf;
+ buf << options.m_prefixMark;
+ buf << "UNREFLECTED";
+
+ outLookup.set(buf.getUnownedSlice(), IdentifierStyle::Unreflected);
+ }
+ }
+
+
+ // Keywords which introduce types/scopes
+ {
+ outLookup.set("struct", IdentifierStyle::Struct);
+ outLookup.set("class", IdentifierStyle::Class);
+ outLookup.set("namespace", IdentifierStyle::Namespace);
+ }
+
+ // Keywords that control access
+ {
+ const char* names[] = { "private", "protected", "public" };
+ outLookup.set(names, SLANG_COUNT_OF(names), IdentifierStyle::Access);
+ }
+}
SlangResult CPPExtractorApp::execute(const Options& options)
{
m_options = options;
-
- CPPExtractor extractor(&m_slicePool, &m_namePool, m_sink, &m_identifierLookup);
+ IdentifierLookup identifierLookup;
+ _initIdentifierLookup(options, identifierLookup);
+
+ CPPExtractor extractor(&m_slicePool, &m_namePool, m_sink, &identifierLookup);
// Read in each of the input files
for (Index i = 0; i < m_options.m_inputPaths.getCount(); ++i)