eduucaldas updated this revision to Diff 283536. eduucaldas marked 9 inline comments as done. eduucaldas added a comment.
Answer comments non-delimited-lists need further discussion Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D85295/new/ https://reviews.llvm.org/D85295 Files: clang/include/clang/Tooling/Syntax/Nodes.h clang/include/clang/Tooling/Syntax/Tree.h clang/lib/Tooling/Syntax/Nodes.cpp clang/lib/Tooling/Syntax/Tree.cpp
Index: clang/lib/Tooling/Syntax/Tree.cpp =================================================================== --- clang/lib/Tooling/Syntax/Tree.cpp +++ clang/lib/Tooling/Syntax/Tree.cpp @@ -270,3 +270,107 @@ } return nullptr; } + +std::vector<syntax::List::ElementAndDelimiter<syntax::Node>> +syntax::List::getElementsAsNodesAndDelimiters() { + if (!firstChild()) + return {}; + + auto children = std::vector<syntax::List::ElementAndDelimiter<Node>>(); + syntax::Node *elementWithoutDelimiter = nullptr; + for (auto *C = firstChild(); C; C = C->nextSibling()) { + switch (C->role()) { + case syntax::NodeRole::List_element: { + if (elementWithoutDelimiter) { + children.push_back({elementWithoutDelimiter, nullptr}); + } + elementWithoutDelimiter = C; + break; + } + case syntax::NodeRole::List_delimiter: { + children.push_back({elementWithoutDelimiter, cast<syntax::Leaf>(C)}); + elementWithoutDelimiter = nullptr; + break; + } + default: + llvm_unreachable( + "A list can have only elements and delimiters as children."); + } + } + + switch (getTerminationKind()) { + case syntax::List::TerminationKind::Separated: { + children.push_back({elementWithoutDelimiter, nullptr}); + break; + } + case syntax::List::TerminationKind::Terminated: + case syntax::List::TerminationKind::MaybeTerminated: { + if (elementWithoutDelimiter) { + children.push_back({elementWithoutDelimiter, nullptr}); + } + break; + } + } + + return children; +} + +// Almost the same implementation of `getElementsAsNodesAndDelimiters` but +// ignoring delimiters +std::vector<syntax::Node *> syntax::List::getElementsAsNodes() { + if (!firstChild()) + return {}; + + auto children = std::vector<syntax::Node *>(); + syntax::Node *elementWithoutDelimiter = nullptr; + for (auto *C = firstChild(); C; C = C->nextSibling()) { + switch (C->role()) { + case syntax::NodeRole::List_element: { + if (elementWithoutDelimiter) { + children.push_back(elementWithoutDelimiter); + } + elementWithoutDelimiter = C; + break; + } + case syntax::NodeRole::List_delimiter: { + children.push_back(elementWithoutDelimiter); + elementWithoutDelimiter = nullptr; + break; + } + default: + llvm_unreachable("A list has only elements or delimiters."); + } + } + + switch (getTerminationKind()) { + case syntax::List::TerminationKind::Separated: { + children.push_back(elementWithoutDelimiter); + break; + } + case syntax::List::TerminationKind::Terminated: + case syntax::List::TerminationKind::MaybeTerminated: { + if (elementWithoutDelimiter) { + children.push_back(elementWithoutDelimiter); + } + break; + } + } + + return children; +} + +// The methods below can't be implemented without information about the derived +// list. These methods will be implemented by switching on the derived list's +// `NodeKind` + +clang::tok::TokenKind syntax::List::getDelimiterTokenKind() { + llvm_unreachable("A list can have only elements and delimiters as children."); +} + +syntax::List::TerminationKind syntax::List::getTerminationKind() { + llvm_unreachable("A list can have only elements and delimiters as children."); +} + +bool syntax::List::canBeEmpty() { + llvm_unreachable("A list can have only elements and delimiters as children."); +} Index: clang/lib/Tooling/Syntax/Nodes.cpp =================================================================== --- clang/lib/Tooling/Syntax/Nodes.cpp +++ clang/lib/Tooling/Syntax/Nodes.cpp @@ -144,6 +144,10 @@ return OS << "ExternKeyword"; case syntax::NodeRole::BodyStatement: return OS << "BodyStatement"; + case syntax::NodeRole::List_element: + return OS << "List_element"; + case syntax::NodeRole::List_delimiter: + return OS << "List_delimiter"; case syntax::NodeRole::CaseStatement_value: return OS << "CaseStatement_value"; case syntax::NodeRole::IfStatement_thenStatement: Index: clang/include/clang/Tooling/Syntax/Tree.h =================================================================== --- clang/include/clang/Tooling/Syntax/Tree.h +++ clang/include/clang/Tooling/Syntax/Tree.h @@ -191,6 +191,68 @@ Node *FirstChild = nullptr; }; +/// A Tree that represents a syntactic list of elements. +/// +/// We try to model with this type the artificial grammar-construct: +/// delimited-list(element, delimiter, termination, canBeEmpty) +/// +/// For example, from C++ [dcl.decl]: +/// init-declarator-list: +/// init-declarator +/// init-declarator-list , init-declarator +/// May be mapped to: +/// delimited-list(init-declarator, ',', separated, !canBeEmpty) +/// +/// Thus the `InitDeclaratorList` syntax node would inherit from `List`, with: +/// getTerminationKind() returning `Separated` +/// canBeEmpty() returning `true` +/// getDelimiterTokenKind() returning `,` +class List : public Tree { + template <typename Element> struct ElementAndDelimiter { + Element *element; + Leaf *delimiter; + }; + + enum class TerminationKind { + Terminated, + MaybeTerminated, + Separated, + }; + + /// Returns the elements and corresponding delimiters. Missing elements + /// and delimiters are represented as null pointers. + /// + /// For example, in a separated list: + /// "a, b, c" <=> [("a", ","), ("b", ","), ("c", null)] + /// "a, , c" <=> [("a", ","), (null, ","), ("c", ",)] + /// "a, b," <=> [("a", ","), ("b", ","), (null, null)] + /// + /// In a terminated or maybe-terminated list: + /// "a, b," <=> [("a", ","), ("b", ",")] + std::vector<ElementAndDelimiter<Node>> getElementsAsNodesAndDelimiters(); + + /// Returns the elements of the list. Missing elements are represented + /// as null pointers in the same way as in the return value of + /// `getElementsAsNodesAndDelimiters()`. + std::vector<Node *> getElementsAsNodes(); + + // These can't be implemented with the information we have! + + /// Returns the appropriate delimiter for this list. + /// + /// Useful for discovering the correct delimiter to use when adding + /// elements to empty or one-element lists. + clang::tok::TokenKind getDelimiterTokenKind(); + + TerminationKind getTerminationKind(); + + /// Return whether *under valid code* the list can be empty. + /// + /// If the underlying source code is not expected to be valid, then the list + /// may be empty even if canBeEmpty() returns false. + bool canBeEmpty(); +}; + } // namespace syntax } // namespace clang Index: clang/include/clang/Tooling/Syntax/Nodes.h =================================================================== --- clang/include/clang/Tooling/Syntax/Nodes.h +++ clang/include/clang/Tooling/Syntax/Nodes.h @@ -142,6 +142,8 @@ /// statement, e.g. loop body for while, for, etc; inner statement for case, /// default, etc. BodyStatement, + List_element, + List_delimiter, // Roles specific to particular node kinds. OperatorExpression_operatorToken,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits