identifier.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_IDENTIFIER_HPP_INCLUDED
5 #define LEXY_DSL_IDENTIFIER_HPP_INCLUDED
6 
7 #include <lexy/dsl/base.hpp>
9 #include <lexy/dsl/literal.hpp>
10 #include <lexy/dsl/token.hpp>
11 #include <lexy/lexeme.hpp>
12 
13 //=== identifier ===//
14 namespace lexy
15 {
18 {
19  static LEXY_CONSTEVAL auto name()
20  {
21  return "reserved identifier";
22  }
23 };
24 } // namespace lexy
25 
26 namespace lexyd
27 {
28 template <typename Id, typename CharT, CharT... C>
29 struct _kw;
30 template <typename Literal, template <typename> typename CaseFolding>
31 struct _cfl;
32 
33 template <typename Leading, typename Trailing>
34 struct _idp : token_base<_idp<Leading, Trailing>>
35 {
36  template <typename Reader>
37  struct tp
38  {
39  typename Reader::marker end;
40 
41  constexpr explicit tp(const Reader& reader) : end(reader.current()) {}
42 
43  constexpr bool try_parse(Reader reader)
44  {
45  static_assert(lexy::is_char_encoding<typename Reader::encoding>);
46 
47  // Need to match Leading character.
48  if (!lexy::try_match_token(Leading{}, reader))
49  return false;
50 
51  // Match zero or more trailing characters.
52  while (true)
53  {
54  if constexpr (lexy::_detail::is_swar_reader<Reader>)
55  {
56  // If we have a swar reader, consume as much as possible at once.
57  while (Trailing{}.template char_class_match_swar<typename Reader::encoding>(
58  reader.peek_swar()))
59  reader.bump_swar();
60  }
61 
62  if (!lexy::try_match_token(Trailing{}, reader))
63  break;
64  }
65 
66  end = reader.current();
67  return true;
68  }
69 
70  template <typename Context>
71  constexpr void report_error(Context& context, const Reader& reader)
72  {
73  Leading::template char_class_report_error<Reader>(context, reader.position());
74  }
75  };
76 };
77 
78 template <typename Set>
79 struct _idrp // reserve predicate
80 {
81  template <typename Input>
82  static constexpr bool is_reserved(const Input& input)
83  {
84  auto reader = input.reader();
85  return lexy::try_match_token(Set{}, reader)
86  && reader.peek() == decltype(reader)::encoding::eof();
87  }
88 };
89 template <typename Set>
90 struct _idpp // reserve prefix predicate
91 {
92  template <typename Input>
93  static constexpr bool is_reserved(const Input& input)
94  {
95  auto reader = input.reader();
96  return lexy::try_match_token(Set{}, reader);
97  }
98 };
99 template <typename Set>
100 struct _idcp // reserve contains predicate
101 {
102  template <typename Input>
103  static constexpr bool is_reserved(const Input& input)
104  {
105  auto reader = input.reader();
106  while (true)
107  {
108  if (lexy::try_match_token(Set{}, reader))
109  return true;
110  else if (reader.peek() == decltype(reader)::encoding::eof())
111  return false;
112  else
113  reader.bump();
114  }
115 
116  // unreachable
117  }
118 };
119 template <typename Set>
120 struct _idsp // reserve suffix predicate
121 {
122  template <typename Input>
123  static constexpr bool is_reserved(const Input& input)
124  {
125  auto reader = input.reader();
126  while (true)
127  {
128  if (lexy::try_match_token(Set{}, reader)
129  && reader.peek() == decltype(reader)::encoding::eof())
130  return true;
131  else if (reader.peek() == decltype(reader)::encoding::eof())
132  return false;
133  else
134  reader.bump();
135  }
136 
137  // unreachable
138  }
139 };
140 
141 template <typename Leading, typename Trailing, typename... ReservedPredicate>
142 struct _id : branch_base
143 {
144  template <typename NextParser>
145  struct p
146  {
147  template <typename Context, typename Reader, typename... Args>
148  LEXY_PARSER_FUNC static bool parse(Context& context, Reader& reader, Args&&... args)
149  {
150  // Parse the pattern; this does not consume whitespace, so the range is accurate.
151  auto begin = reader.position();
152  if (!pattern().token_parse(context, reader))
153  return false;
154  auto end = reader.position();
155 
156  // Check for a reserved identifier.
157  [[maybe_unused]] auto input = lexy::partial_input(reader, begin, end);
158  if ((ReservedPredicate::is_reserved(input) || ...))
159  {
160  // It is reserved, report an error but trivially recover.
162  context.on(_ev::error{}, err);
163  }
164 
165  // Skip whitespace and continue with the value.
167  return continuation::parse(context, reader, LEXY_FWD(args)...,
169  }
170  };
171 
172  template <typename Reader>
173  struct bp
174  {
175  typename Reader::marker end;
176 
177  constexpr bool try_parse(const void*, const Reader& reader)
178  {
179  // Parse the pattern.
180  lexy::token_parser_for<decltype(pattern()), Reader> parser(reader);
181  if (!parser.try_parse(reader))
182  return false;
183  end = parser.end;
184 
185  // We only succeed if it's not a reserved identifier.
186  [[maybe_unused]] auto input
187  = lexy::partial_input(reader, reader.position(), end.position());
188  return !(ReservedPredicate::is_reserved(input) || ...);
189  }
190 
191  template <typename Context>
192  constexpr void cancel(Context&)
193  {}
194 
195  template <typename NextParser, typename Context, typename... Args>
196  LEXY_PARSER_FUNC auto finish(Context& context, Reader& reader, Args&&... args)
197  {
198  auto begin = reader.position();
199 
200  context.on(_ev::token{}, lexy::identifier_token_kind, begin, end.position());
201  reader.reset(end);
202 
204  return continuation::parse(context, reader, LEXY_FWD(args)...,
205  lexy::lexeme<Reader>(begin, end.position()));
206  }
207  };
208 
209  template <typename R>
210  constexpr auto _make_reserve(R r) const
211  {
212  static_assert(lexy::is_literal_rule<R> || lexy::is_literal_set_rule<R>);
213  return r;
214  }
215  template <typename Id, typename CharT, CharT... C>
216  constexpr auto _make_reserve(_kw<Id, CharT, C...>) const
217  {
218  static_assert(std::is_same_v<decltype(Id{}.pattern()), decltype(pattern())>,
219  "must not reserve keywords from another identifier");
220  // No need to remember that it was a keyword originally.
221  return _lit<CharT, C...>{};
222  }
223  template <typename Id, typename CharT, CharT... C, template <typename> typename CaseFolding>
224  constexpr auto _make_reserve(_cfl<_kw<Id, CharT, C...>, CaseFolding>) const
225  {
226  static_assert(std::is_same_v<decltype(Id{}.pattern()), decltype(pattern())>,
227  "must not reserve keywords from another identifier");
228  // No need to remember that it was a keyword originally.
229  return _cfl<_lit<CharT, C...>, CaseFolding>{};
230  }
231 
232  //=== dsl ===//
234  template <typename... R>
235  constexpr auto reserve(R... r) const
236  {
237  static_assert(sizeof...(R) > 0);
238  auto set = (lexyd::literal_set() / ... / _make_reserve(r));
239  return _id<Leading, Trailing, ReservedPredicate..., _idrp<decltype(set)>>{};
240  }
241 
243  template <typename... R>
244  constexpr auto reserve_prefix(R... r) const
245  {
246  static_assert(sizeof...(R) > 0);
247  auto set = (lexyd::literal_set() / ... / _make_reserve(r));
248  return _id<Leading, Trailing, ReservedPredicate..., _idpp<decltype(set)>>{};
249  }
250 
252  template <typename... R>
253  constexpr auto reserve_containing(R... r) const
254  {
255  static_assert(sizeof...(R) > 0);
256  auto set = (lexyd::literal_set() / ... / _make_reserve(r));
257  return _id<Leading, Trailing, ReservedPredicate..., _idcp<decltype(set)>>{};
258  }
259 
261  template <typename... R>
262  constexpr auto reserve_suffix(R... r) const
263  {
264  static_assert(sizeof...(R) > 0);
265  auto set = (lexyd::literal_set() / ... / _make_reserve(r));
266  return _id<Leading, Trailing, ReservedPredicate..., _idsp<decltype(set)>>{};
267  }
268 
270  static constexpr auto pattern()
271  {
272  return _idp<Leading, Trailing>{};
273  }
274 
276  constexpr auto leading_pattern() const
277  {
278  return Leading{};
279  }
280 
282  constexpr auto trailing_pattern() const
283  {
284  return Trailing{};
285  }
286 };
287 
289 template <typename CharClass>
290 constexpr auto identifier(CharClass)
291 {
292  static_assert(lexy::is_char_class_rule<CharClass>);
293  return _id<CharClass, CharClass>{};
294 }
295 
298 template <typename LeadingClass, typename TrailingClass>
299 constexpr auto identifier(LeadingClass, TrailingClass)
300 {
301  static_assert(lexy::is_char_class_rule<LeadingClass> //
302  && lexy::is_char_class_rule<TrailingClass>);
304 }
305 } // namespace lexyd
306 
307 namespace lexy
308 {
309 template <typename Leading, typename Trailing>
310 constexpr auto token_kind_of<lexy::dsl::_idp<Leading, Trailing>> = lexy::identifier_token_kind;
311 } // namespace lexy
312 
313 //=== keyword ===//
314 namespace lexyd
315 {
316 template <typename Id, typename CharT, CharT... C>
317 struct _kw : token_base<_kw<Id, CharT, C...>>, _lit_base
318 {
319  static constexpr auto lit_max_char_count = sizeof...(C);
320 
321  // We must not end on a trailing character.
322  static constexpr auto lit_char_classes
323  = lexy::_detail::char_class_list<decltype(Id{}.trailing_pattern())>{};
324 
326 
327  template <typename Encoding>
328  static constexpr auto lit_first_char() -> typename Encoding::char_type
329  {
330  typename Encoding::char_type result = 0;
331  (void)((result = lexy::_detail::transcode_char<decltype(result)>(C), true) || ...);
332  return result;
333  }
334 
335  template <typename Trie>
336  static LEXY_CONSTEVAL std::size_t lit_insert(Trie& trie, std::size_t pos,
337  std::size_t char_class)
338  {
339  auto end = ((pos = trie.insert(pos, C)), ...);
340  trie.node_char_class[end] = char_class;
341  return end;
342  }
343 
344  template <typename Reader>
345  struct tp
346  {
347  typename Reader::marker end;
348 
349  constexpr explicit tp(const Reader& reader) : end(reader.current()) {}
350 
351  constexpr bool try_parse(Reader reader)
352  {
353  // Need to match the literal.
354  if (!lexy::_detail::match_literal<0, CharT, C...>(reader))
355  return false;
356  end = reader.current();
357 
358  // To qualify as a keyword, and not just the prefix of an identifier,
359  // we must not have a trailing identifier character.
360  return !lexy::try_match_token(Id{}.trailing_pattern(), reader);
361  }
362 
363  template <typename Context>
364  constexpr void report_error(Context& context, Reader reader)
365  {
366  using char_type = typename Reader::encoding::char_type;
367  constexpr auto str = lexy::_detail::type_string<CharT, C...>::template c_str<char_type>;
368 
369  // Match the entire identifier.
370  auto begin = reader.position();
371  lexy::try_match_token(Id{}.pattern(), reader);
372  auto end = reader.position();
373 
374  auto err = lexy::error<Reader, lexy::expected_keyword>(begin, end, str, sizeof...(C));
375  context.on(_ev::error{}, err);
376  }
377  };
378 };
379 
380 template <typename Id>
381 struct _keyword;
382 template <typename L, typename T, typename... R>
383 struct _keyword<_id<L, T, R...>>
384 {
385  template <typename CharT, CharT... C>
386  using get = _kw<_id<L, T>, CharT, C...>;
387 };
388 
389 #if LEXY_HAS_NTTP
390 template <lexy::_detail::string_literal Str, typename L, typename T, typename... R>
391 constexpr auto keyword(_id<L, T, R...>)
392 {
393  return lexy::_detail::to_type_string<_keyword<_id<L, T>>::template get, Str>{};
394 }
395 #else
396 template <auto C, typename L, typename T, typename... R>
397 constexpr auto keyword(_id<L, T, R...>)
398 {
399  return _kw<_id<L, T>, LEXY_DECAY_DECLTYPE(C), C>{};
400 }
401 #endif
402 
403 #define LEXY_KEYWORD(Str, Id) \
404  LEXY_NTTP_STRING(::lexyd::_keyword<LEXY_DECAY_DECLTYPE(Id)>::template get, Str) {}
405 } // namespace lexyd
406 
407 namespace lexy
408 {
409 template <typename Id, typename CharT, CharT... C>
410 constexpr auto token_kind_of<lexy::dsl::_kw<Id, CharT, C...>> = lexy::literal_token_kind;
411 } // namespace lexy
412 
413 #endif // LEXY_DSL_IDENTIFIER_HPP_INCLUDED
414 
LEXY_CONSTEVAL
#define LEXY_CONSTEVAL
Definition: config.hpp:98
lexyd::branch_base
Definition: grammar.hpp:20
lexyd::_id::bp::end
Reader::marker end
Definition: identifier.hpp:175
lexyd::_idcp::is_reserved
static constexpr bool is_reserved(const Input &input)
Definition: identifier.hpp:103
lexy::_detail::transcode_char
LEXY_CONSTEVAL TargetCharT transcode_char(CharT c)
Definition: encoding.hpp:300
token.hpp
lexyd::_id::reserve_containing
constexpr auto reserve_containing(R... r) const
Reservers everything containing the given rule.
Definition: identifier.hpp:253
lexyd::_id::bp::cancel
constexpr void cancel(Context &)
Definition: identifier.hpp:192
literal.hpp
magic_enum::char_type
string_view::value_type char_type
Definition: magic_enum.hpp:145
lexyd::_kw::tp::end
Reader::marker end
Definition: identifier.hpp:347
lexyd::_id::leading_pattern
constexpr auto leading_pattern() const
Matches the initial char set of an identifier.
Definition: identifier.hpp:276
lexy::_detail::char_class_list
Definition: literal.hpp:154
lexyd::_idp::tp::try_parse
constexpr bool try_parse(Reader reader)
Definition: identifier.hpp:43
lexyd::_idp
Definition: identifier.hpp:34
lexyd::_kw::tp
Definition: identifier.hpp:345
lexyd::_id
Definition: identifier.hpp:142
lexyd::_id::trailing_pattern
constexpr auto trailing_pattern() const
Matches the trailing char set of an identifier.
Definition: identifier.hpp:282
LEXY_FWD
#define LEXY_FWD(...)
Definition: config.hpp:30
lexyd::_kw::lit_char_classes
static constexpr auto lit_char_classes
Definition: identifier.hpp:323
lexyd::_idpp
Definition: identifier.hpp:90
lexy::_detail::type_string
Definition: nttp_string.hpp:15
lexyd::_keyword
Definition: identifier.hpp:381
lexyd::_id::bp::finish
LEXY_PARSER_FUNC auto finish(Context &context, Reader &reader, Args &&... args)
Definition: identifier.hpp:196
lexyd::_kw::lit_case_folding
void lit_case_folding
Definition: identifier.hpp:325
lexy
Definition: any_ref.hpp:12
lexyd::_cfl
Definition: case_folding.hpp:23
lexy::reserved_identifier::name
static LEXY_CONSTEVAL auto name()
Definition: identifier.hpp:19
lexy::literal_token_kind
@ literal_token_kind
Definition: grammar.hpp:90
lexyd::_idp::tp::report_error
constexpr void report_error(Context &context, const Reader &reader)
Definition: identifier.hpp:71
cx::end
constexpr auto end(const C &c) -> decltype(c.end())
Definition: wildcards.hpp:686
char_class.hpp
detail::void
j template void())
Definition: json.hpp:4893
lexyd::_idcp
Definition: identifier.hpp:100
lexy::error
Generic failure.
Definition: error.hpp:14
lexyd::_idsp
Definition: identifier.hpp:120
lexyd::_kw::lit_first_char
static constexpr auto lit_first_char() -> typename Encoding::char_type
Definition: identifier.hpp:328
lexyd::_id::bp
Definition: identifier.hpp:173
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::_id::pattern
static constexpr auto pattern()
Matches every identifier, ignoring reserved ones.
Definition: identifier.hpp:270
lexyd::keyword
constexpr auto keyword(_id< L, T, R... >)
Definition: identifier.hpp:397
lexyd::_id::reserve
constexpr auto reserve(R... r) const
Adds a set of reserved identifiers.
Definition: identifier.hpp:235
lexyd::_id::_make_reserve
constexpr auto _make_reserve(R r) const
Definition: identifier.hpp:210
lexyd::_id::reserve_prefix
constexpr auto reserve_prefix(R... r) const
Reserves everything starting with the given rule.
Definition: identifier.hpp:244
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
lexeme.hpp
lexyd::token_base
Definition: dsl/token.hpp:42
lexyd::_idp::tp::end
Reader::marker end
Definition: identifier.hpp:39
lexyd::_kw::tp::report_error
constexpr void report_error(Context &context, Reader reader)
Definition: identifier.hpp:364
LEXY_DECAY_DECLTYPE
#define LEXY_DECAY_DECLTYPE(...)
Definition: config.hpp:34
lexyd::_idpp::is_reserved
static constexpr bool is_reserved(const Input &input)
Definition: identifier.hpp:93
lexyd::_id::_make_reserve
constexpr auto _make_reserve(_kw< Id, CharT, C... >) const
Definition: identifier.hpp:216
lexy::reserved_identifier
Error when we matched a reserved.
Definition: identifier.hpp:17
lexyd::_idp::tp
Definition: identifier.hpp:37
lexy::partial_input
constexpr auto partial_input(const Reader &, typename Reader::iterator begin, typename Reader::iterator end)
Definition: input/base.hpp:133
lexyd::_id::_make_reserve
constexpr auto _make_reserve(_cfl< _kw< Id, CharT, C... >, CaseFolding >) const
Definition: identifier.hpp:224
LEXY_PARSER_FUNC
#define LEXY_PARSER_FUNC
Definition: dsl/base.hpp:108
detail::get
auto get(const nlohmann::detail::iteration_proxy_value< IteratorType > &i) -> decltype(i.key())
Definition: json.hpp:5342
lexyd::_kw::tp::try_parse
constexpr bool try_parse(Reader reader)
Definition: identifier.hpp:351
cx::begin
constexpr auto begin(const C &c) -> decltype(c.begin())
Definition: wildcards.hpp:661
lexy::whitespace_parser
Definition: dsl/base.hpp:229
lexyd::_id::bp::try_parse
constexpr bool try_parse(const void *, const Reader &reader)
Definition: identifier.hpp:177
lexyd::_idp::tp::tp
constexpr tp(const Reader &reader)
Definition: identifier.hpp:41
base.hpp
lexyd::_id::p::parse
static LEXY_PARSER_FUNC bool parse(Context &context, Reader &reader, Args &&... args)
Definition: identifier.hpp:148
lexyd::identifier
constexpr auto identifier(CharClass)
Creates an identifier that consists of one or more of the given characters.
Definition: identifier.hpp:290
lexyd::_lit
Definition: char_class.hpp:300
lexy::parse_events::token
Definition: dsl/base.hpp:57
lexyd::_idrp
Definition: identifier.hpp:79
lexy::lexeme
Definition: lexeme.hpp:16
lexy::identifier_token_kind
@ identifier_token_kind
Definition: grammar.hpp:94
lexyd::_kw::lit_insert
static LEXY_CONSTEVAL std::size_t lit_insert(Trie &trie, std::size_t pos, std::size_t char_class)
Definition: identifier.hpp:336
lexyd::_kw
Definition: identifier.hpp:29
lexyd::literal_set
constexpr auto literal_set(Literals...)
Matches one of the specified literals.
Definition: literal.hpp:594
lexyd::_idsp::is_reserved
static constexpr bool is_reserved(const Input &input)
Definition: identifier.hpp:123
lexyd::_kw::lit_max_char_count
static constexpr auto lit_max_char_count
Definition: identifier.hpp:319
lexyd::_id::p
Definition: identifier.hpp:145
lexyd::_kw::tp::tp
constexpr tp(const Reader &reader)
Definition: identifier.hpp:349
lexy::token_parser_for
typename TokenRule::template tp< Reader > token_parser_for
Definition: dsl/base.hpp:242
lexyd
Definition: trace.hpp:22
lexyd::_id::reserve_suffix
constexpr auto reserve_suffix(R... r) const
Reserves everything that ends with the given rule.
Definition: identifier.hpp:262
lexyd::eof
constexpr auto eof
Matches EOF.
Definition: eof.hpp:72
lexyd::_idrp::is_reserved
static constexpr bool is_reserved(const Input &input)
Definition: identifier.hpp:82
lexy::token_kind_of
constexpr auto token_kind_of
Specialize to define the token kind of a rule.
Definition: grammar.hpp:137


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