From 778428fecc0548af565e92745cf1344bcf19367f Mon Sep 17 00:00:00 2001 From: jsmall-nvidia Date: Mon, 19 Apr 2021 15:39:42 -0400 Subject: Splitting up C++ extractor (#1800) * #include an absolute path didn't work - because paths were taken to always be relative. * Refactor out ClassLikeNode * WIP around ScopeNode. * Use push and popScope. * Small improvements around C++ extractor. * Adding dynamic casting support. * Made Field another Node type. * Disable command line dumping by default. * Removed comment. * Fix shadowed variable bug found on linux. * Split out node. * Renamed C++ extractor diagnostics to just diagnostics.cpp/.h * Remove C++ extractor Options into separate options.cpp/options.h files. * Split out parser and identifier lookup from C++ extractor. * Put in CppExtract namespace. Simplify some of the class names. * Some simple renaming. * Split out NodeTree from Parser. --- tools/slang-cpp-extractor/node.h | 221 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 tools/slang-cpp-extractor/node.h (limited to 'tools/slang-cpp-extractor/node.h') diff --git a/tools/slang-cpp-extractor/node.h b/tools/slang-cpp-extractor/node.h new file mode 100644 index 000000000..c98a9204d --- /dev/null +++ b/tools/slang-cpp-extractor/node.h @@ -0,0 +1,221 @@ +#ifndef CPP_EXTRACT_NODE_H +#define CPP_EXTRACT_NODE_H + +#include "diagnostics.h" + +namespace CppExtract { +using namespace Slang; + +enum class ReflectionType : uint8_t +{ + NotReflected, + Reflected, +}; + +// Pre-declare +class TypeSet; +class SourceOrigin; + +struct ScopeNode; + +class Node : public RefObject +{ +public: + enum class Type : uint8_t + { + Invalid, + + StructType, + ClassType, + + Namespace, + AnonymousNamespace, + + Field, + }; + + enum class TypeRange + { + ScopeStart = int(Type::StructType), + ScopeEnd = int(Type::AnonymousNamespace), + + ClassLikeStart = int(Type::StructType), + ClassLikeEnd = int(Type::ClassType), + }; + + static bool isScopeType(Type type) { return int(type) >= int(TypeRange::ScopeStart) && int(type) <= int(TypeRange::ScopeEnd); } + static bool isClassLikeType(Type type) { return int(type) >= int(TypeRange::ClassLikeStart) && int(type) <= int(TypeRange::ClassLikeEnd); } + + static bool isType(Type type) { return true; } + + bool isClassLike() const { return isClassLikeType(m_type); } + + virtual void dump(int indent, StringBuilder& out) = 0; + + /// Do depth first traversal of nodes in scopes + virtual void calcScopeDepthFirst(List& outNodes); + + /// Calculate the absolute name for this namespace/type + void calcAbsoluteName(StringBuilder& outName) const; + + /// Get the absolute name + String getAbsoluteName() const { StringBuilder buf; calcAbsoluteName(buf); return buf.ProduceString(); } + + /// Calculate the scope path to this node, from the root + void calcScopePath(List& outPath) { calcScopePath(this, outPath); } + + /// True if reflected + bool isReflected() const { return m_reflectionType == ReflectionType::Reflected; } + + typedef bool(*Filter)(Node* node); + + static bool isClassLikeAndReflected(Node* node) { return node->isClassLike() && node->isReflected(); } + static bool isClassLike(Node* node) { return isClassLikeType(node->m_type); } + + template + static void filter(Filter filter, List& io) { const Node* _isNodeDerived = (T*)nullptr; SLANG_UNUSED(_isNodeDerived); filterImpl(filter, reinterpret_cast&>(io)); } + + static void filterImpl(Filter filter, List& io); + + static void calcScopePath(Node* node, List& outPath); + + /// Find the name starting in specified scope + static Node* findNode(ScopeNode* scope, const UnownedStringSlice& name); + + Node(Type type) : + m_type(type), + m_parentScope(nullptr), + m_reflectionType(ReflectionType::NotReflected) + { + } + + Type m_type; ///< The type of node this is + ReflectionType m_reflectionType; /// Classes can be traversed, but not reflected. To be reflected they have to contain the marker + + Token m_name; ///< The name of this scope/type + + ScopeNode* m_parentScope; ///< The scope this type/scope is defined in +}; + +struct ScopeNode : public Node +{ + typedef Node Super; + + static bool isType(Type type) { return isScopeType(type); } + + virtual void dump(int indent, StringBuilder& out) SLANG_OVERRIDE; + virtual void calcScopeDepthFirst(List& outNodes) SLANG_OVERRIDE; + + /// True if can accept fields (class like types can) + bool acceptsFields() const { return isClassLike(); } + + /// Gets the reflection for any contained types + ReflectionType getContainedReflectionType() const { return m_reflectionType == ReflectionType::NotReflected ? ReflectionType::NotReflected : m_reflectionOverride; } + + /// Add a child node to this nodes scope + void addChild(Node* child); + + /// Find a child node in this scope with the specified name. Return nullptr if not found + Node* findChild(const UnownedStringSlice& name) const; + + /// Gets the anonymous namespace associated with this scope + ScopeNode* getAnonymousNamespace(); + + ScopeNode(Type type) : + Super(type), + m_reflectionOverride(ReflectionType::Reflected), + m_anonymousNamespace(nullptr) + { + } + + /// For child types, fields, how reflection is handled. If this type is not reflected + ReflectionType m_reflectionOverride; + + /// All of the types and namespaces in this *scope* + List> m_children; + + /// Map from a name (in this scope) to the Node + Dictionary m_childMap; + + /// There can only be one anonymousNamespace for a scope. If there is one it's held here + ScopeNode* m_anonymousNamespace; +}; + +struct FieldNode : public Node +{ + typedef Node Super; + + static bool isType(Type type) { return type == Type::Field; } + + virtual void dump(int indent, StringBuilder& out) SLANG_OVERRIDE; + + FieldNode() : + Super(Type::Field) + { + } + + UnownedStringSlice m_fieldType; + + // We may want to add initializer tokens +}; + +struct ClassLikeNode : public ScopeNode +{ + typedef ScopeNode Super; + + static bool isType(Type type) { return isClassLikeType(type); } + + /// Add a node that is derived from this + void addDerived(ClassLikeNode* derived); + + /// Dump all of the derived types + void dumpDerived(int indentCount, StringBuilder& out); + + /// Calculates the derived depth + Index calcDerivedDepth() const; + + /// Find the last (reflected) derived type + ClassLikeNode* findLastDerived(); + + /// Traverse the hierarchy of derived nodes, in depth first order + void calcDerivedDepthFirst(List& outNodes); + + /// True if has a derived type that is reflected + bool hasReflectedDerivedType() const; + + /// Stores in out any reflected derived types + void getReflectedDerivedTypes(List& out) const; + + // Node Impl + virtual void dump(int indent, StringBuilder& out) SLANG_OVERRIDE; + + ClassLikeNode(Type type) : + Super(type), + m_origin(nullptr), + m_typeSet(nullptr), + m_superNode(nullptr) + { + SLANG_ASSERT(type == Type::ClassType || type == Type::StructType); + } + + SourceOrigin* m_origin; ///< Defines where this was uniquely defined. + + Token m_marker; ///< The marker associated with this scope (typically the marker is SLANG_CLASS etc, that is used to identify reflectedType) + + List> m_derivedTypes; ///< All of the types derived from this type + + TypeSet* m_typeSet; ///< The typeset this type belongs to. + + Token m_super; ///< Super class name + ClassLikeNode* m_superNode; ///< If this is a class/struct, the type it is derived from (or nullptr if base) +}; + +template +T* as(Node* node) { return (node && T::isType(node->m_type)) ? static_cast(node) : nullptr; } + +// A macro to define a single indent as a string +#define CPP_EXTRACT_INDENT_STRING " " + +} // CppExtract + +#endif -- cgit v1.2.3