diff options
| author | Eduardo Caldas <ecaldas@google.com> | 2020-08-04 17:33:36 +0000 |
|---|---|---|
| committer | Eduardo Caldas <ecaldas@google.com> | 2020-08-10 10:32:28 +0000 |
| commit | a90c78ac52615d256142ecd64fbedabb612dc73f (patch) | |
| tree | c1044fffd5dfea8e86add3eb3f9c0db051b1108b /clang/lib | |
| parent | dbcfbffc7ae46cc7b84257787681676144a1bd5f (diff) | |
| download | llvm-a90c78ac52615d256142ecd64fbedabb612dc73f.zip llvm-a90c78ac52615d256142ecd64fbedabb612dc73f.tar.gz llvm-a90c78ac52615d256142ecd64fbedabb612dc73f.tar.bz2 | |
[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
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Tooling/Syntax/Nodes.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Tooling/Syntax/Tree.cpp | 107 |
2 files changed, 111 insertions, 0 deletions
diff --git a/clang/lib/Tooling/Syntax/Nodes.cpp b/clang/lib/Tooling/Syntax/Nodes.cpp index b5a4c50b..5e8deb6 100644 --- a/clang/lib/Tooling/Syntax/Nodes.cpp +++ b/clang/lib/Tooling/Syntax/Nodes.cpp @@ -152,6 +152,10 @@ raw_ostream &syntax::operator<<(raw_ostream &OS, NodeRole R) { return OS << "TemplateKeyword"; 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: 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::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("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"); +} |
