parse_tree_doctest.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2023 Jonathan Müller and lexy contributors
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #ifndef LEXY_EXT_PARSE_TREE_DOCTEST_HPP_INCLUDED
5 #define LEXY_EXT_PARSE_TREE_DOCTEST_HPP_INCLUDED
6 
7 #include <cctype>
8 #include <cstdio>
9 #include <doctest/doctest.h>
10 #include <lexy/parse_tree.hpp>
11 
12 namespace lexy_ext
13 {
14 template <typename TokenKind = void>
16 {
17 public:
19  {
20  _tree += "\n";
21  }
22 
23  parse_tree_desc(const char* root_name) : parse_tree_desc()
24  {
25  production(root_name);
26  }
27  template <typename RootProduction, typename = lexy::production_rule<RootProduction>>
28  parse_tree_desc(RootProduction) : parse_tree_desc(lexy::production_name<RootProduction>())
29  {}
30 
31  template <typename Iterator>
33  {
34  prefix();
35 
36  _tree += doctest::String(kind.name());
37 
38  _tree += ": \"";
39  for (auto iter = begin; iter != end; ++iter)
40  {
41  auto c = *iter;
42  if (c == '"')
43  {
44  _tree += "\\\"";
45  }
46  else if (std::isprint(c))
47  {
48  char str[] = {char(c), 0};
49  _tree += str;
50  }
51  else
52  {
53  char buffer[16];
54  auto size = std::snprintf(buffer, 16, "\\{%x}", unsigned(c) % 0xFF);
55  LEXY_ASSERT(0 <= size && size < 16, "formatting error");
56  _tree += buffer;
57  }
58  }
59  _tree += "\"\n";
60  return *this;
61  }
62  template <typename CharT>
63  parse_tree_desc& token(lexy::token_kind<TokenKind> kind, const CharT* spelling)
64  {
65  auto end = spelling;
66  while (*end)
67  ++end;
68 
69  return token(kind, spelling, end);
70  }
71  template <typename CharT>
72  parse_tree_desc& token(const CharT* spelling)
73  {
74  return token(lexy::unknown_token_kind, spelling);
75  }
76  template <typename CharT>
77  parse_tree_desc& literal(const CharT* spelling)
78  {
79  return token(lexy::literal_token_kind, spelling);
80  }
81  template <typename CharT>
82  parse_tree_desc& digits(const CharT* spelling)
83  {
84  return token(lexy::digits_token_kind, spelling);
85  }
86  template <typename CharT>
87  parse_tree_desc& whitespace(const CharT* spelling)
88  {
89  return token(lexy::whitespace_token_kind, spelling);
90  }
91 
93  {
94  return token(lexy::eof_token_kind, "");
95  }
96 
97  parse_tree_desc& production(const char* name)
98  {
99  prefix();
100  _tree += doctest::String(name);
101  _tree += ":\n";
102 
103  ++_level;
104 
105  return *this;
106  }
107  template <typename Production, typename = lexy::production_rule<Production>>
109  {
110  return production(lexy::production_name<Production>());
111  }
112 
114  {
115  --_level;
116  return *this;
117  }
118 
119  friend doctest::String toString(const parse_tree_desc& expected)
120  {
121  return expected._tree + doctest::String(" ");
122  }
123 
124  template <typename Reader, typename MemoryResource>
125  friend bool operator==(const parse_tree_desc& desc,
127  {
128  using string_maker
129  = doctest::StringMaker<lexy::parse_tree<Reader, TokenKind, MemoryResource>>;
130  return toString(desc) == string_maker::convert(tree);
131  }
132  template <typename Reader, typename MemoryResource>
134  const parse_tree_desc& desc)
135  {
136  using string_maker
137  = doctest::StringMaker<lexy::parse_tree<Reader, TokenKind, MemoryResource>>;
138  return toString(desc) == string_maker::convert(tree);
139  }
140 
141 private:
142  void prefix()
143  {
144  // First indent to align output regardless of level.
145  _tree += " ";
146 
147  // Then indent child nodes.
148  if (_level > 0)
149  {
150  for (auto i = 0; i != _level - 1; ++i)
151  _tree += " ";
152  _tree += "- ";
153  }
154  }
155 
156  doctest::String _tree;
157  int _level;
158 };
159 } // namespace lexy_ext
160 
161 namespace doctest
162 {
163 template <typename Reader, typename TokenKind, typename MemoryResource>
164 struct StringMaker<lexy::parse_tree<Reader, TokenKind, MemoryResource>>
165 {
167 
168  static String convert(const parse_tree& tree)
169  {
171 
172  for (auto [event, node] : tree.traverse())
173  switch (event)
174  {
176  builder.production(node.kind().name());
177  break;
179  builder.finish();
180  break;
181 
183  auto token = node.token();
184  builder.token(token.kind(), token.lexeme().begin(), token.lexeme().end());
185  break;
186  }
187  }
188 
189  return toString(builder);
190  }
191 };
192 } // namespace doctest
193 
194 #endif // LEXY_EXT_PARSE_TREE_DOCTEST_HPP_INCLUDED
195 
cx::size
constexpr auto size(const C &c) -> decltype(c.size())
Definition: wildcards.hpp:636
lexy::parse_tree::traverse
traverse_range traverse(const node &n) const noexcept
Definition: parse_tree.hpp:378
lexy::eof_token_kind
@ eof_token_kind
Definition: grammar.hpp:83
lexyd::token
constexpr auto token(Rule)
Turns the arbitrary rule into a token by matching it without producing any values.
Definition: dsl/token.hpp:214
lexy::unknown_token_kind
@ unknown_token_kind
Definition: grammar.hpp:75
lexy_ext::parse_tree_desc::parse_tree_desc
parse_tree_desc(RootProduction)
Definition: parse_tree_doctest.hpp:28
lexy_ext::parse_tree_desc::literal
parse_tree_desc & literal(const CharT *spelling)
Definition: parse_tree_doctest.hpp:77
doctest
Definition: parse_tree_doctest.hpp:161
lexy_ext::parse_tree_desc::toString
friend doctest::String toString(const parse_tree_desc &expected)
Definition: parse_tree_doctest.hpp:119
lexy_ext
Definition: compiler_explorer.hpp:12
lexy::traverse_event::exit
@ exit
We're visiting a production node after all its children.
lexy_ext::parse_tree_desc
Definition: parse_tree_doctest.hpp:15
lexy_ext::parse_tree_desc::parse_tree_desc
parse_tree_desc()
Definition: parse_tree_doctest.hpp:18
lexy_ext::parse_tree_desc::operator==
friend bool operator==(const lexy::parse_tree< Reader, TokenKind, MemoryResource > &tree, const parse_tree_desc &desc)
Definition: parse_tree_doctest.hpp:133
lexy_ext::parse_tree_desc::operator==
friend bool operator==(const parse_tree_desc &desc, const lexy::parse_tree< Reader, TokenKind, MemoryResource > &tree)
Definition: parse_tree_doctest.hpp:125
lexy
Definition: any_ref.hpp:12
lexy::literal_token_kind
@ literal_token_kind
Definition: grammar.hpp:81
lexy_ext::parse_tree_desc::token
parse_tree_desc & token(lexy::token_kind< TokenKind > kind, Iterator begin, Iterator end)
Definition: parse_tree_doctest.hpp:32
cx::end
constexpr auto end(const C &c) -> decltype(c.end())
Definition: wildcards.hpp:686
doctest::StringMaker< lexy::parse_tree< Reader, TokenKind, MemoryResource > >::convert
static String convert(const parse_tree &tree)
Definition: parse_tree_doctest.hpp:168
lexy_ext::parse_tree_desc::production
parse_tree_desc & production(const char *name)
Definition: parse_tree_doctest.hpp:97
lexy_ext::parse_tree_desc::parse_tree_desc
parse_tree_desc(const char *root_name)
Definition: parse_tree_doctest.hpp:23
lexy_ext::parse_tree_desc::_level
int _level
Definition: parse_tree_doctest.hpp:157
lexy::whitespace_token_kind
@ whitespace_token_kind
Definition: grammar.hpp:78
lexy_ext::parse_tree_desc::digits
parse_tree_desc & digits(const CharT *spelling)
Definition: parse_tree_doctest.hpp:82
lexy::token_kind
What sort of token it is.
Definition: token.hpp:102
lexy::buffer
buffer(const CharT *, const CharT *) -> buffer< deduce_encoding< CharT >>
lexy_ext::parse_tree_desc::_tree
doctest::String _tree
Definition: parse_tree_doctest.hpp:156
lexy_ext::parse_tree_desc::production
parse_tree_desc & production(Production)
Definition: parse_tree_doctest.hpp:108
lexy::traverse_event::leaf
@ leaf
We're visiting a token.
lexy::parse_tree
Definition: parse_tree.hpp:331
lexy_ext::parse_tree_desc::token
parse_tree_desc & token(lexy::token_kind< TokenKind > kind, const CharT *spelling)
Definition: parse_tree_doctest.hpp:63
lexy_ext::parse_tree_desc::prefix
void prefix()
Definition: parse_tree_doctest.hpp:142
lexy::digits_token_kind
@ digits_token_kind
Definition: grammar.hpp:86
cx::begin
constexpr auto begin(const C &c) -> decltype(c.begin())
Definition: wildcards.hpp:661
lexy::token_kind::name
constexpr const char * name() const noexcept
Definition: token.hpp:174
lexy_ext::parse_tree_desc::whitespace
parse_tree_desc & whitespace(const CharT *spelling)
Definition: parse_tree_doctest.hpp:87
lexy::production_name
const LEXY_CONSTEVAL char * production_name()
Definition: grammar.hpp:158
lexy_ext::parse_tree_desc::finish
parse_tree_desc & finish()
Definition: parse_tree_doctest.hpp:113
parse_tree.hpp
lexy::traverse_event::enter
@ enter
We're visiting a production node before all its children.
LEXY_ASSERT
#define LEXY_ASSERT(Expr, Msg)
Definition: assert.hpp:37
lexy_ext::parse_tree_desc::token
parse_tree_desc & token(const CharT *spelling)
Definition: parse_tree_doctest.hpp:72
lexy_ext::parse_tree_desc::eof
parse_tree_desc & eof()
Definition: parse_tree_doctest.hpp:92


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Jun 28 2024 02:20:08