whitespace.hpp
Go to the documentation of this file.
1 // Copyright (C) 2020-2024 Jonathan Müller and lexy contributors
2 // SPDX-License-Identifier: BSL-1.0
3 
4 #ifndef LEXY_DSL_WHITESPACE_HPP_INCLUDED
5 #define LEXY_DSL_WHITESPACE_HPP_INCLUDED
6 
7 #include <lexy/_detail/swar.hpp>
8 #include <lexy/action/base.hpp>
9 #include <lexy/dsl/base.hpp>
10 #include <lexy/dsl/choice.hpp>
11 #include <lexy/dsl/loop.hpp>
12 #include <lexy/dsl/token.hpp>
13 
14 namespace lexyd
15 {
16 template <typename Rule>
17 struct _wsr;
18 }
19 
20 //=== implementation ===//
21 namespace lexy::_detail
22 {
23 // Parse this production to skip whitespace.
24 template <typename WhitespaceRule>
26 {
27  static constexpr auto name = "<whitespace>";
28  static constexpr auto max_recursion_depth = 0;
29  static constexpr auto rule = lexy::dsl::loop(WhitespaceRule{} | lexy::dsl::break_);
30 };
31 // If the whitespace rule itself uses `dsl::whitespace`, strip it to avoid infinite recursion.
32 template <typename Rule>
33 struct ws_production<lexyd::_wsr<Rule>> : ws_production<Rule>
34 {};
35 
36 // A special handler for parsing whitespace.
37 // It only forwards error events and ignores all others.
38 template <typename Handler>
40 {
41 public:
42  constexpr explicit ws_handler(Handler& handler, typename Handler::event_handler& evh)
43  : _handler(&handler), _event_handler(&evh)
44  {}
45  template <typename Context>
46  constexpr explicit ws_handler(Context& context)
47  : ws_handler(context.control_block->parse_handler, context.handler)
48  {}
49 
51  {
52  public:
53  template <typename Rule>
55  {}
56  template <typename Production>
57  constexpr event_handler(Production)
58  {
59  static_assert(_detail::error<Production>,
60  "whitespace rule must not contain `dsl::p` or `dsl::recurse`;"
61  "use `dsl::inline_` instead");
62  }
63 
64  template <typename Error>
65  constexpr void on(ws_handler& handler, parse_events::error ev, const Error& error)
66  {
67  handler._event_handler->on(*handler._handler, ev, error);
68  }
69 
70  template <typename Event, typename... Args>
71  constexpr int on(ws_handler&, Event, const Args&...)
72  {
73  return 0; // an operation_start event returns something
74  }
75  };
76 
77  template <typename Production, typename State>
79 
80  template <typename>
81  constexpr bool get_result(bool rule_parse_result) &&
82  {
83  return rule_parse_result;
84  }
85 
86  template <typename Event, typename... Args>
87  constexpr auto real_on(Event ev, Args&&... args)
88  {
89  return _event_handler->on(*_handler, ev, LEXY_FWD(args)...);
90  }
91 
92 private:
93  Handler* _handler;
94  typename Handler::event_handler* _event_handler;
95 };
96 template <typename Context>
98 
99 template <typename>
100 using ws_result = bool;
101 
102 template <typename WhitespaceRule>
104 {
105  if constexpr (lexy::is_char_class_rule<WhitespaceRule>)
106  return WhitespaceRule::char_class_ascii().contains[int(' ')];
107  else
108  return false;
109 }
110 
111 template <typename WhitespaceRule, typename Handler, typename Reader>
112 constexpr auto skip_whitespace(ws_handler<Handler>&& handler, Reader& reader)
113 {
114  auto begin = reader.position();
115 
116  if constexpr (lexy::is_token_rule<WhitespaceRule>)
117  {
118  // Parsing a token repeatedly cannot fail, so we can optimize it.
119 
120  if constexpr (_detail::is_swar_reader<Reader> //
121  && space_is_definitely_whitespace<WhitespaceRule>())
122  {
123  while (true)
124  {
125  // Skip as many spaces as possible.
126  using char_type = typename Reader::encoding::char_type;
127  while (reader.peek_swar() == _detail::swar_fill(char_type(' ')))
128  reader.bump_swar();
129 
130  // We no longer have a space, skip the entire whitespace rule once.
131  if (!lexy::try_match_token(WhitespaceRule{}, reader))
132  // If that fails, we definitely have no more whitespace.
133  break;
134  }
135  }
136  else
137  {
138  // Without SWAR, we just repeatedly skip the whitespace rule.
139  while (lexy::try_match_token(WhitespaceRule{}, reader))
140  {
141  }
142  }
143 
145  reader.position());
146  return std::true_type{};
147  }
148  else if constexpr (!std::is_void_v<WhitespaceRule>)
149  {
150  using production = ws_production<WhitespaceRule>;
151 
152  // Parse the production using a special handler that only forwards errors.
153  auto result = lexy::do_action<production, ws_result>(LEXY_MOV(handler),
154  lexy::no_parse_state, reader);
155 
156  handler.real_on(lexy::parse_events::token{},
158  reader.position());
159  return result;
160  }
161  else
162  {
163  (void)handler;
164  (void)reader;
165  (void)begin;
166  return std::true_type{};
167  }
168 }
169 
170 // Inherit from it in a continuation to disable automatic whitespace skipping.
172 {};
173 
174 template <typename NextParser>
175 struct automatic_ws_parser
176 {
177  template <typename Context, typename Reader, typename... Args>
178  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args)
179  {
180  if (!std::is_base_of_v<disable_whitespace_skipping, NextParser> //
181  && context.control_block->enable_whitespace_skipping)
182  {
183  using whitespace = lexy::production_whitespace<typename Context::production,
184  typename Context::whitespace_production>;
185  if (!skip_whitespace<whitespace>(ws_handler(context), reader))
186  return false;
187  }
188 
189  return NextParser::parse(context, reader, LEXY_FWD(args)...);
190  }
191 };
192 } // namespace lexy::_detail
193 
194 //=== whitespace ===//
195 namespace lexyd
196 {
197 template <typename Rule>
198 struct _wsr : rule_base
199 {
200  template <typename NextParser>
201  struct p
202  {
203  template <typename Context, typename Reader, typename... Args>
204  constexpr static bool parse(Context& context, Reader& reader, Args&&... args)
205  {
206  auto result
207  = lexy::_detail::skip_whitespace<Rule>(lexy::_detail::ws_handler(context), reader);
208  if (!result)
209  return false;
210 
211  return NextParser::parse(context, reader, LEXY_FWD(args)...);
212  }
213  };
214 
215  template <typename R>
216  friend constexpr auto operator|(_wsr<Rule>, R r)
217  {
218  return _wsr<decltype(Rule{} | r)>{};
219  }
220  template <typename R>
221  friend constexpr auto operator|(R r, _wsr<Rule>)
222  {
223  return _wsr<decltype(r | Rule{})>{};
224  }
225 };
226 
227 template <typename Rule>
228 constexpr auto whitespace(Rule)
229 {
230  return _wsr<Rule>{};
231 }
232 } // namespace lexyd
233 
234 //=== no_whitespace ===//
235 namespace lexyd
236 {
237 template <typename Rule>
238 struct _wsn : _copy_base<Rule>
239 {
240  template <typename NextParser>
241  struct _pc
242  {
243  template <typename Context, typename Reader, typename... Args>
244  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args)
245  {
246  // Enable automatic whitespace skipping again.
247  context.control_block->enable_whitespace_skipping = true;
248  // And skip whitespace once.
250  LEXY_FWD(args)...);
251  }
252  };
253 
254  template <typename Reader>
255  struct bp
256  {
258 
259  template <typename ControlBlock>
260  constexpr auto try_parse(const ControlBlock* cb, const Reader& reader)
261  {
262  // Note that this can't skip whitespace as there is no way to access the whitespace
263  // rule. We thus don't need to disable anything.
264  return rule.try_parse(cb, reader);
265  }
266 
267  template <typename Context>
268  constexpr void cancel(Context& context)
269  {
270  rule.cancel(context);
271  }
272 
273  template <typename NextParser, typename Context, typename... Args>
274  LEXY_PARSER_FUNC auto finish(Context& context, Reader& reader, Args&&... args)
275  {
276  // Finish the rule with whitespace skipping disabled.
277  context.control_block->enable_whitespace_skipping = false;
278  return rule.template finish<_pc<NextParser>>(context, reader, LEXY_FWD(args)...);
279  }
280  };
281 
282  template <typename NextParser>
283  struct p
284  {
285  template <typename Context, typename Reader, typename... Args>
286  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args)
287  {
288  using whitespace = lexy::production_whitespace<typename Context::production,
289  typename Context::whitespace_production>;
290  if constexpr (std::is_void_v<whitespace>)
291  {
292  // No whitespace, just parse the rule normally.
293  return lexy::parser_for<Rule, NextParser>::parse(context, reader,
294  LEXY_FWD(args)...);
295  }
296  else
297  {
298  // Parse the rule with whitespace skipping disabled.
299  context.control_block->enable_whitespace_skipping = false;
301  return parser::parse(context, reader, LEXY_FWD(args)...);
302  }
303  }
304  };
305 };
306 
308 template <typename Rule>
309 constexpr auto no_whitespace(Rule)
310 {
311  if constexpr (lexy::is_token_rule<Rule>)
312  return Rule{}; // Token already behaves that way.
313  else
314  return _wsn<Rule>{};
315 }
316 } // namespace lexyd
317 
318 #endif // LEXY_DSL_WHITESPACE_HPP_INCLUDED
319 
choice.hpp
LEXY_MOV
#define LEXY_MOV(...)
Definition: config.hpp:29
lexyd::_wsr::p::parse
constexpr static bool parse(Context &context, Reader &reader, Args &&... args)
Definition: whitespace.hpp:204
token.hpp
lexy::_detail::ws_handler::event_handler::on
constexpr int on(ws_handler &, Event, const Args &...)
Definition: whitespace.hpp:71
lexyd::_wsn::bp::rule
lexy::branch_parser_for< Rule, Reader > rule
Definition: whitespace.hpp:257
magic_enum::char_type
string_view::value_type char_type
Definition: magic_enum.hpp:145
lexy::_detail::ws_handler
ws_handler(Context &context) -> ws_handler< typename Context::handler_type >
lexy::_detail::ws_production
Definition: whitespace.hpp:25
lexy::_detail::ws_handler::ws_handler
constexpr ws_handler(Context &context)
Definition: whitespace.hpp:46
lexy::branch_parser_for
typename BranchRule::template bp< Reader > branch_parser_for
Definition: dsl/base.hpp:116
loop.hpp
lexy::_detail::ws_handler::event_handler
Definition: whitespace.hpp:50
lexy::no_parse_state
constexpr void * no_parse_state
Definition: action/base.hpp:198
LEXY_FWD
#define LEXY_FWD(...)
Definition: config.hpp:30
lexyd::no_whitespace
constexpr auto no_whitespace(Rule)
Disables automatic skipping of whitespace for all tokens of the given rule.
Definition: whitespace.hpp:309
lexy::_detail::ws_production::rule
static constexpr auto rule
Definition: whitespace.hpp:29
lexyd::_wsn::p
Definition: whitespace.hpp:283
lexyd::_wsr::operator|
constexpr friend auto operator|(R r, _wsr< Rule >)
Definition: whitespace.hpp:221
lexyd::_wsr
Definition: whitespace.hpp:17
lexy::_detail::ws_handler::ws_handler
constexpr ws_handler(Handler &handler, typename Handler::event_handler &evh)
Definition: whitespace.hpp:42
lexy::_detail::ws_production::max_recursion_depth
static constexpr auto max_recursion_depth
Definition: whitespace.hpp:28
detail::void
j template void())
Definition: json.hpp:4893
lexy::error
Generic failure.
Definition: error.hpp:14
lexy::_detail::ws_handler::_handler
Handler * _handler
Definition: whitespace.hpp:93
lexyd::loop
constexpr auto loop(Rule)
Repeatedly matches the rule until a break rule matches.
Definition: loop.hpp:63
lexy::parse
constexpr auto parse(const Input &input, const ErrorCallback &callback)
Parses the production into a value, invoking the callback on error.
Definition: parse.hpp:171
lexyd::_wsn::bp
Definition: whitespace.hpp:255
lexy::whitespace_token_kind
@ whitespace_token_kind
Definition: grammar.hpp:87
lexyd::_wsn::bp::try_parse
constexpr auto try_parse(const ControlBlock *cb, const Reader &reader)
Definition: whitespace.hpp:260
swar.hpp
lexy::_detail::ws_handler::event_handler::event_handler
constexpr event_handler(ws_production< Rule >)
Definition: whitespace.hpp:54
lexy::parse_events::error
Definition: dsl/base.hpp:68
lexy::try_match_token
constexpr LEXY_FORCE_INLINE auto try_match_token(TokenRule, Reader &reader)
Definition: dsl/base.hpp:245
lexy::_detail::automatic_ws_parser::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader, Args &&... args)
Definition: whitespace.hpp:178
lexy::_detail::space_is_definitely_whitespace
constexpr bool space_is_definitely_whitespace()
Definition: whitespace.hpp:103
lexy::_detail::automatic_ws_parser
Definition: dsl/base.hpp:221
lexyd::_wsn
Definition: whitespace.hpp:238
lexyd::_wsn::bp::cancel
constexpr void cancel(Context &context)
Definition: whitespace.hpp:268
lexyd::_wsr::operator|
constexpr friend auto operator|(_wsr< Rule >, R r)
Definition: whitespace.hpp:216
lexy::_detail::ws_handler::get_result
constexpr bool get_result(bool rule_parse_result) &&
Definition: whitespace.hpp:81
lexyd::_wsn::_pc::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader, Args &&... args)
Definition: whitespace.hpp:244
lexy::error_token_kind
@ error_token_kind
Definition: grammar.hpp:86
lexy::_detail::ws_handler::real_on
constexpr auto real_on(Event ev, Args &&... args)
Definition: whitespace.hpp:87
lexy::production_whitespace
decltype(_production_whitespace< Production, WhitespaceProduction >()) production_whitespace
Definition: grammar.hpp:243
LEXY_PARSER_FUNC
#define LEXY_PARSER_FUNC
Definition: dsl/base.hpp:108
cx::begin
constexpr auto begin(const C &c) -> decltype(c.begin())
Definition: wildcards.hpp:661
lexyd::_wsn::p::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader, Args &&... args)
Definition: whitespace.hpp:286
lexy::_detail::ws_result
bool ws_result
Definition: whitespace.hpp:100
base.hpp
lexy::_detail
Definition: any_ref.hpp:12
lexy::_detail::void_value_callback
Definition: action/base.hpp:253
lexyd::break_
constexpr auto break_
Exits a loop().
Definition: loop.hpp:30
lexy::parse_events::token
Definition: dsl/base.hpp:57
lexy::_detail::ws_handler::event_handler::event_handler
constexpr event_handler(Production)
Definition: whitespace.hpp:57
lexy::_detail::ws_handler::_event_handler
Handler::event_handler * _event_handler
Definition: whitespace.hpp:94
lexyd::_wsn::_pc
Definition: whitespace.hpp:241
lexy::parser_for
typename Rule::template p< NextParser > parser_for
Definition: dsl/base.hpp:113
base.hpp
lexy::_detail::ws_handler
Definition: whitespace.hpp:39
lexyd::whitespace
constexpr auto whitespace(Rule)
Definition: whitespace.hpp:228
lexyd::_wsr::p
Definition: whitespace.hpp:201
lexy::_detail::skip_whitespace
constexpr auto skip_whitespace(ws_handler< Handler > &&handler, Reader &reader)
Definition: whitespace.hpp:112
lexyd
Definition: trace.hpp:22
lexyd::_wsn::bp::finish
LEXY_PARSER_FUNC auto finish(Context &context, Reader &reader, Args &&... args)
Definition: whitespace.hpp:274
lexy::_detail::ws_handler::event_handler::on
constexpr void on(ws_handler &handler, parse_events::error ev, const Error &error)
Definition: whitespace.hpp:65
lexy::_detail::disable_whitespace_skipping
Definition: whitespace.hpp:171
lexyd::_copy_base
decltype(_copy_base_impl< Rule >()) _copy_base
Definition: dsl/base.hpp:104
lexy::_detail::swar_fill
constexpr swar_int swar_fill(CharT _c)
Definition: swar.hpp:46
lexy::_detail::ws_production::name
static constexpr auto name
Definition: whitespace.hpp:27


behaviortree_cpp_v4
Author(s): Davide Faconti
autogenerated on Fri Dec 13 2024 03:19:17