parse_test_helpers.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #ifndef TOOLCHAIN_PARSER_PARSE_TEST_HELPERS_H_
  5. #define TOOLCHAIN_PARSER_PARSE_TEST_HELPERS_H_
  6. #include <gmock/gmock.h>
  7. #include <ostream>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11. #include "common/check.h"
  12. #include "llvm/ADT/STLExtras.h"
  13. #include "llvm/ADT/SmallVector.h"
  14. #include "llvm/ADT/StringRef.h"
  15. #include "toolchain/lexer/tokenized_buffer.h"
  16. #include "toolchain/parser/parse_node_kind.h"
  17. #include "toolchain/parser/parse_tree.h"
  18. namespace Carbon {
  19. // Enable printing a parse tree from Google Mock.
  20. inline void PrintTo(const ParseTree& tree, std::ostream* output) {
  21. std::string text;
  22. llvm::raw_string_ostream text_stream(text);
  23. tree.Print(text_stream);
  24. *output << "\n" << text_stream.str() << "\n";
  25. }
  26. namespace Testing {
  27. // An aggregate used to describe an expected parse tree.
  28. //
  29. // This type is designed to be used via aggregate initialization with designated
  30. // initializers. The latter make it easy to default everything and then override
  31. // the desired aspects when writing an expectation in a test.
  32. struct ExpectedNode {
  33. ParseNodeKind kind = ParseNodeKind::EmptyDeclaration();
  34. std::string text;
  35. bool has_error = false;
  36. bool skip_subtree = false;
  37. std::vector<ExpectedNode> children;
  38. };
  39. // Implementation of a matcher for a parse tree based on a tree of expected
  40. // nodes.
  41. //
  42. // Don't create this directly, instead use `MatchParseTreeNodes` to construct a
  43. // matcher based on this.
  44. class ExpectedNodesMatcher
  45. : public ::testing::MatcherInterface<const ParseTree&> {
  46. public:
  47. explicit ExpectedNodesMatcher(
  48. llvm::SmallVector<ExpectedNode, 0> expected_nodess)
  49. : expected_nodes_(std::move(expected_nodess)) {}
  50. auto MatchAndExplain(const ParseTree& tree,
  51. ::testing::MatchResultListener* output_ptr) const
  52. -> bool override;
  53. auto DescribeTo(std::ostream* output_ptr) const -> void override;
  54. private:
  55. auto MatchExpectedNode(const ParseTree& tree, ParseTree::Node n,
  56. int postorder_index, const ExpectedNode& expected_node,
  57. ::testing::MatchResultListener& output) const -> bool;
  58. llvm::SmallVector<ExpectedNode, 0> expected_nodes_;
  59. };
  60. // Implementation of the Google Mock interface for matching (and explaining any
  61. // failure).
  62. inline auto ExpectedNodesMatcher::MatchAndExplain(
  63. const ParseTree& tree, ::testing::MatchResultListener* output_ptr) const
  64. -> bool {
  65. auto& output = *output_ptr;
  66. bool matches = true;
  67. const auto rpo = llvm::reverse(tree.Postorder());
  68. const auto nodes_begin = rpo.begin();
  69. const auto nodes_end = rpo.end();
  70. auto nodes_it = nodes_begin;
  71. llvm::SmallVector<const ExpectedNode*, 16> expected_node_stack;
  72. for (const ExpectedNode& en : expected_nodes_) {
  73. expected_node_stack.push_back(&en);
  74. }
  75. while (!expected_node_stack.empty()) {
  76. if (nodes_it == nodes_end) {
  77. // We'll check the size outside the loop.
  78. break;
  79. }
  80. ParseTree::Node n = *nodes_it++;
  81. int postorder_index = n.GetIndex();
  82. const ExpectedNode& expected_node = *expected_node_stack.pop_back_val();
  83. if (!MatchExpectedNode(tree, n, postorder_index, expected_node, output)) {
  84. matches = false;
  85. }
  86. if (expected_node.skip_subtree) {
  87. CHECK(expected_node.children.empty())
  88. << "Must not skip an expected subtree while specifying expected "
  89. "children!";
  90. nodes_it = llvm::reverse(tree.Postorder(n)).end();
  91. continue;
  92. }
  93. // We want to make sure we don't end up with unsynchronized walks, so skip
  94. // ahead in the tree to ensure that the number of children of this node and
  95. // the expected number of children match.
  96. int num_children =
  97. std::distance(tree.Children(n).begin(), tree.Children(n).end());
  98. if (num_children != static_cast<int>(expected_node.children.size())) {
  99. output
  100. << "\nParse node (postorder index #" << postorder_index << ") has "
  101. << num_children << " children, expected "
  102. << expected_node.children.size()
  103. << ". Skipping this subtree to avoid any unsynchronized tree walk.";
  104. matches = false;
  105. nodes_it = llvm::reverse(tree.Postorder(n)).end();
  106. continue;
  107. }
  108. // Push the children onto the stack to continue matching. The expectation
  109. // is in preorder, but we visit the parse tree in reverse postorder. This
  110. // causes the siblings to be visited in reverse order from the expected
  111. // list. However, we use a stack which inherently does this reverse for us
  112. // so we simply append to the stack here.
  113. for (const ExpectedNode& child_expected_node : expected_node.children) {
  114. expected_node_stack.push_back(&child_expected_node);
  115. }
  116. }
  117. // We don't directly check the size because we allow expectations to skip
  118. // subtrees. Instead, we need to check that we successfully processed all of
  119. // the actual tree and consumed all of the expected tree.
  120. if (nodes_it != nodes_end) {
  121. CHECK(expected_node_stack.empty())
  122. << "If we have unmatched nodes in the input tree, should only finish "
  123. "having fully processed expected tree.";
  124. output << "\nFinished processing expected nodes and there are still "
  125. << (nodes_end - nodes_it) << " unexpected nodes.";
  126. matches = false;
  127. } else if (!expected_node_stack.empty()) {
  128. output << "\nProcessed all " << (nodes_end - nodes_begin)
  129. << " nodes and still have " << expected_node_stack.size()
  130. << " expected nodes that were unmatched.";
  131. matches = false;
  132. }
  133. return matches;
  134. }
  135. // Implementation of the Google Mock interface for describing the expected node
  136. // tree.
  137. //
  138. // This is designed to describe the expected tree node structure in as similar
  139. // of a format to the parse tree's print format as is reasonable. There is both
  140. // more and less information, so it won't be exact, but should be close enough
  141. // to make it easy to visually compare the two.
  142. inline auto ExpectedNodesMatcher::DescribeTo(std::ostream* output_ptr) const
  143. -> void {
  144. auto& output = *output_ptr;
  145. output << "Matches expected node pattern:\n[\n";
  146. // We want to walk these in RPO instead of in preorder to match the printing
  147. // of the actual parse tree.
  148. llvm::SmallVector<std::pair<const ExpectedNode*, int>, 16>
  149. expected_node_stack;
  150. for (const ExpectedNode& expected_node : llvm::reverse(expected_nodes_)) {
  151. expected_node_stack.push_back({&expected_node, 0});
  152. }
  153. while (!expected_node_stack.empty()) {
  154. const ExpectedNode& expected_node = *expected_node_stack.back().first;
  155. int depth = expected_node_stack.back().second;
  156. expected_node_stack.pop_back();
  157. for (int indent_count = 0; indent_count < depth; ++indent_count) {
  158. output << " ";
  159. }
  160. output << "{kind: '" << expected_node.kind.GetName().str() << "'";
  161. if (!expected_node.text.empty()) {
  162. output << ", text: '" << expected_node.text << "'";
  163. }
  164. if (expected_node.has_error) {
  165. output << ", has_error: yes";
  166. }
  167. if (expected_node.skip_subtree) {
  168. output << ", skip_subtree: yes";
  169. }
  170. if (!expected_node.children.empty()) {
  171. CHECK(!expected_node.skip_subtree)
  172. << "Must not have children and skip a subtree!";
  173. output << ", children: [\n";
  174. for (const ExpectedNode& child_expected_node :
  175. llvm::reverse(expected_node.children)) {
  176. expected_node_stack.push_back({&child_expected_node, depth + 1});
  177. }
  178. // If we have children, we know we're not popping off.
  179. continue;
  180. }
  181. // If this is some form of leaf we'll at least need to close it. It may also
  182. // be the last sibling of its parent, and we'll need to close any parents as
  183. // we pop up.
  184. output << "}";
  185. if (!expected_node_stack.empty()) {
  186. CHECK(depth >= expected_node_stack.back().second)
  187. << "Cannot have an increase in depth on a leaf node!";
  188. // The distance we need to pop is the difference in depth.
  189. int pop_depth = depth - expected_node_stack.back().second;
  190. for (int pop_count = 0; pop_count < pop_depth; ++pop_count) {
  191. // Close both the children array and the node mapping.
  192. output << "]}";
  193. }
  194. }
  195. output << "\n";
  196. }
  197. output << "]\n";
  198. }
  199. inline auto ExpectedNodesMatcher::MatchExpectedNode(
  200. const ParseTree& tree, ParseTree::Node n, int postorder_index,
  201. const ExpectedNode& expected_node,
  202. ::testing::MatchResultListener& output) const -> bool {
  203. bool matches = true;
  204. ParseNodeKind kind = tree.GetNodeKind(n);
  205. if (kind != expected_node.kind) {
  206. output << "\nParse node (postorder index #" << postorder_index << ") is a "
  207. << kind.GetName().str() << ", expected a "
  208. << expected_node.kind.GetName().str() << ".";
  209. matches = false;
  210. }
  211. if (tree.HasErrorInNode(n) != expected_node.has_error) {
  212. output << "\nParse node (postorder index #" << postorder_index << ") "
  213. << (tree.HasErrorInNode(n) ? "has an error"
  214. : "does not have an error")
  215. << ", expected that it "
  216. << (expected_node.has_error ? "has an error"
  217. : "does not have an error")
  218. << ".";
  219. matches = false;
  220. }
  221. llvm::StringRef node_text = tree.GetNodeText(n);
  222. if (!expected_node.text.empty() && node_text != expected_node.text) {
  223. output << "\nParse node (postorder index #" << postorder_index
  224. << ") is spelled '" << node_text.str() << "', expected '"
  225. << expected_node.text << "'.";
  226. matches = false;
  227. }
  228. return matches;
  229. }
  230. // Creates a matcher for a parse tree using a tree of expected nodes.
  231. //
  232. // This is intended to be used with an braced initializer list style aggregate
  233. // initializer for an argument, allowing it to describe a tree structure via
  234. // nested `ExpectedNode` objects.
  235. inline auto MatchParseTreeNodes(
  236. llvm::SmallVector<ExpectedNode, 0> expected_nodes)
  237. -> ::testing::Matcher<const ParseTree&> {
  238. return ::testing::MakeMatcher(
  239. new ExpectedNodesMatcher(std::move(expected_nodes)));
  240. }
  241. // Matcher argument for a node with errors.
  242. struct HasErrorTag {};
  243. inline constexpr HasErrorTag HasError;
  244. // Matcher argument to skip checking the children of a node.
  245. struct AnyChildrenTag {};
  246. inline constexpr AnyChildrenTag AnyChildren;
  247. // A function to generate ExpectedNodes a little more tersely and readably. The
  248. // meaning of each argument is inferred from its type.
  249. template <typename... Args>
  250. auto MatchNode(Args... args) -> ExpectedNode {
  251. struct ArgHandler {
  252. ExpectedNode expected;
  253. void UpdateExpectationsForArg(ParseNodeKind kind) { expected.kind = kind; }
  254. void UpdateExpectationsForArg(std::string text) {
  255. expected.text = std::move(text);
  256. }
  257. void UpdateExpectationsForArg(HasErrorTag) { expected.has_error = true; }
  258. void UpdateExpectationsForArg(AnyChildrenTag) {
  259. expected.skip_subtree = true;
  260. }
  261. void UpdateExpectationsForArg(ExpectedNode node) {
  262. expected.children.push_back(std::move(node));
  263. }
  264. };
  265. ArgHandler handler;
  266. (handler.UpdateExpectationsForArg(args), ...);
  267. return handler.expected;
  268. }
  269. // A MatchFoo function for each parse node Foo. Used to construct ExpectedNodes
  270. // for use in MatchParseTreeNodes. Example:
  271. //
  272. // MatchParseTreeNodes(
  273. // {MatchFunctionDeclaration("fn", MatchIdentifier("F"),
  274. // MatchParameterList(MatchParameterListEnd()),
  275. // MatchDeclarationEnd(";")),
  276. // MatchFileEnd()});
  277. #define CARBON_PARSE_NODE_KIND(kind) \
  278. template <typename... Args> \
  279. auto Match##kind(Args... args)->ExpectedNode { \
  280. return MatchNode(ParseNodeKind::kind(), std::move(args)...); \
  281. }
  282. #include "toolchain/parser/parse_node_kind.def"
  283. // Helper for matching a designator `lhs.rhs`.
  284. inline auto MatchDesignator(ExpectedNode lhs, std::string rhs) -> ExpectedNode {
  285. return MatchDesignatorExpression(std::move(lhs),
  286. MatchDesignatedName(std::move(rhs)));
  287. }
  288. // Helper for matching a function parameter list.
  289. template <typename... Args>
  290. auto MatchParameters(Args... args) -> ExpectedNode {
  291. return MatchParameterList("(", std::move(args)..., MatchParameterListEnd());
  292. }
  293. // Helper for matching the statements in the body of a simple function
  294. // definition with no parameters.
  295. template <typename... Args>
  296. auto MatchFunctionWithBody(Args... args) -> ExpectedNode {
  297. return MatchFunctionDeclaration(
  298. MatchDeclaredName(), MatchParameters(),
  299. MatchCodeBlock(std::move(args)..., MatchCodeBlockEnd()));
  300. }
  301. } // namespace Testing
  302. } // namespace Carbon
  303. #endif // TOOLCHAIN_PARSER_PARSE_TEST_HELPERS_H_