From a90c78ac52615d256142ecd64fbedabb612dc73f Mon Sep 17 00:00:00 2001 From: Eduardo Caldas Date: Tue, 4 Aug 2020 17:33:36 +0000 Subject: [SyntaxTree] Implement the List construct. We defined a List construct to help with the implementation of list-like grammar rules. This is a first implementation of this API. Differential Revision: https://reviews.llvm.org/D85295 --- clang/lib/Tooling/Syntax/Tree.cpp | 107 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) (limited to 'clang/lib/Tooling/Syntax/Tree.cpp') diff --git a/clang/lib/Tooling/Syntax/Tree.cpp b/clang/lib/Tooling/Syntax/Tree.cpp index 6f9ee40..6070d16 100644 --- a/clang/lib/Tooling/Syntax/Tree.cpp +++ b/clang/lib/Tooling/Syntax/Tree.cpp @@ -268,3 +268,110 @@ syntax::Node *syntax::Tree::findChild(NodeRole R) { } return nullptr; } + +std::vector> +syntax::List::getElementsAsNodesAndDelimiters() { + if (!firstChild()) + return {}; + + auto children = std::vector>(); + 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(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::List::getElementsAsNodes() { + if (!firstChild()) + return {}; + + auto children = std::vector(); + 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("There are no subclasses of List, thus " + "getDelimiterTokenKind() cannot be called"); +} + +syntax::List::TerminationKind syntax::List::getTerminationKind() { + llvm_unreachable("There are no subclasses of List, thus getTerminationKind() " + "cannot be called"); +} + +bool syntax::List::canBeEmpty() { + llvm_unreachable( + "There are no subclasses of List, thus canBeEmpty() cannot be called"); +} -- cgit v1.1