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