Cockatrice 2026-09-01-Development-3.1.0-beta.10
A virtual tabletop for multiplayer card games
Loading...
Searching...
No Matches
peglib.h
Go to the documentation of this file.
1//
2// peglib.h
3//
4// Copyright (c) 2022 Yuji Hirose. All rights reserved.
5// MIT License
6//
7
8#pragma once
9
10#define CPPPEGLIB_VERSION "1.16.0"
11#define CPPPEGLIB_VERSION_NUM "0x011000"
12
13/*
14 * Configuration
15 */
16
17#ifndef CPPPEGLIB_HEURISTIC_ERROR_TOKEN_MAX_CHAR_COUNT
18#define CPPPEGLIB_HEURISTIC_ERROR_TOKEN_MAX_CHAR_COUNT 32
19#endif
20
21#include <algorithm>
22#include <any>
23#include <bitset>
24#include <cassert>
25#include <cctype>
26#if __has_include(<charconv>)
27#include <charconv>
28#endif
29#include <cstring>
30#include <functional>
31#include <initializer_list>
32#include <iostream>
33#include <limits>
34#include <map>
35#include <memory>
36#include <mutex>
37#include <optional>
38#include <set>
39#include <sstream>
40#include <string>
41#include <unordered_map>
42#include <unordered_set>
43#include <utility>
44#include <vector>
45
46#if !defined(__cplusplus) || __cplusplus < 201703L
47#error "Requires complete C++17 support"
48#endif
49
50namespace peg {
51
52struct GrammarBlob;
53
54/*-----------------------------------------------------------------------------
55 * scope_exit
56 *---------------------------------------------------------------------------*/
57
58// This is based on
59// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".
60
61template <typename EF> struct scope_exit {
62 explicit scope_exit(EF &&f)
63 : exit_function(std::move(f)), execute_on_destruction{true} {}
64
66 : exit_function(std::move(rhs.exit_function)),
68 rhs.release();
69 }
70
73 }
74
75 void release() { this->execute_on_destruction = false; }
76
77private:
78 scope_exit(const scope_exit &) = delete;
79 void operator=(const scope_exit &) = delete;
81
84};
85
86/*-----------------------------------------------------------------------------
87 * UTF8 functions
88 *---------------------------------------------------------------------------*/
89
90inline size_t codepoint_length(const char *s8, size_t l) {
91 if (l) {
92 auto b = static_cast<uint8_t>(s8[0]);
93 if ((b & 0x80) == 0) {
94 return 1;
95 } else if ((b & 0xE0) == 0xC0 && l >= 2) {
96 return 2;
97 } else if ((b & 0xF0) == 0xE0 && l >= 3) {
98 return 3;
99 } else if ((b & 0xF8) == 0xF0 && l >= 4) {
100 return 4;
101 }
102 }
103 return 0;
104}
105
106inline size_t codepoint_count(const char *s8, size_t l) {
107 size_t count = 0;
108 for (size_t i = 0; i < l;) {
109 auto len = codepoint_length(s8 + i, l - i);
110 if (len == 0) {
111 // Invalid UTF-8 byte, treat as single byte to avoid infinite loop
112 len = 1;
113 }
114 i += len;
115 count++;
116 }
117 return count;
118}
119
120inline size_t encode_codepoint(char32_t cp, char *buff) {
121 if (cp < 0x0080) {
122 buff[0] = static_cast<char>(cp & 0x7F);
123 return 1;
124 } else if (cp < 0x0800) {
125 buff[0] = static_cast<char>(0xC0 | ((cp >> 6) & 0x1F));
126 buff[1] = static_cast<char>(0x80 | (cp & 0x3F));
127 return 2;
128 } else if (cp < 0xD800) {
129 buff[0] = static_cast<char>(0xE0 | ((cp >> 12) & 0xF));
130 buff[1] = static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
131 buff[2] = static_cast<char>(0x80 | (cp & 0x3F));
132 return 3;
133 } else if (cp < 0xE000) {
134 // D800 - DFFF is invalid...
135 return 0;
136 } else if (cp < 0x10000) {
137 buff[0] = static_cast<char>(0xE0 | ((cp >> 12) & 0xF));
138 buff[1] = static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
139 buff[2] = static_cast<char>(0x80 | (cp & 0x3F));
140 return 3;
141 } else if (cp < 0x110000) {
142 buff[0] = static_cast<char>(0xF0 | ((cp >> 18) & 0x7));
143 buff[1] = static_cast<char>(0x80 | ((cp >> 12) & 0x3F));
144 buff[2] = static_cast<char>(0x80 | ((cp >> 6) & 0x3F));
145 buff[3] = static_cast<char>(0x80 | (cp & 0x3F));
146 return 4;
147 }
148 return 0;
149}
150
151inline std::string encode_codepoint(char32_t cp) {
152 char buff[4];
153 auto l = encode_codepoint(cp, buff);
154 return std::string(buff, l);
155}
156
157inline bool decode_codepoint(const char *s8, size_t l, size_t &bytes,
158 char32_t &cp) {
159 if (l) {
160 auto b = static_cast<uint8_t>(s8[0]);
161 if ((b & 0x80) == 0) {
162 bytes = 1;
163 cp = b;
164 return true;
165 } else if ((b & 0xE0) == 0xC0) {
166 if (l >= 2) {
167 bytes = 2;
168 cp = ((static_cast<char32_t>(s8[0] & 0x1F)) << 6) |
169 (static_cast<char32_t>(s8[1] & 0x3F));
170 return true;
171 }
172 } else if ((b & 0xF0) == 0xE0) {
173 if (l >= 3) {
174 bytes = 3;
175 cp = ((static_cast<char32_t>(s8[0] & 0x0F)) << 12) |
176 ((static_cast<char32_t>(s8[1] & 0x3F)) << 6) |
177 (static_cast<char32_t>(s8[2] & 0x3F));
178 return true;
179 }
180 } else if ((b & 0xF8) == 0xF0) {
181 if (l >= 4) {
182 bytes = 4;
183 cp = ((static_cast<char32_t>(s8[0] & 0x07)) << 18) |
184 ((static_cast<char32_t>(s8[1] & 0x3F)) << 12) |
185 ((static_cast<char32_t>(s8[2] & 0x3F)) << 6) |
186 (static_cast<char32_t>(s8[3] & 0x3F));
187 return true;
188 }
189 }
190 }
191 return false;
192}
193
194inline size_t decode_codepoint(const char *s8, size_t l, char32_t &cp) {
195 size_t bytes;
196 if (decode_codepoint(s8, l, bytes, cp)) { return bytes; }
197 return 0;
198}
199
200inline char32_t decode_codepoint(const char *s8, size_t l) {
201 char32_t cp = 0;
202 decode_codepoint(s8, l, cp);
203 return cp;
204}
205
206inline std::u32string decode(const char *s8, size_t l) {
207 std::u32string out;
208 size_t i = 0;
209 while (i < l) {
210 auto beg = i++;
211 while (i < l && (s8[i] & 0xc0) == 0x80) {
212 i++;
213 }
214 out += decode_codepoint(&s8[beg], (i - beg));
215 }
216 return out;
217}
218
219template <typename T> const char *u8(const T *s) {
220 return reinterpret_cast<const char *>(s);
221}
222
223/*-----------------------------------------------------------------------------
224 * escape_characters
225 *---------------------------------------------------------------------------*/
226
227inline std::string escape_characters(const char *s, size_t n) {
228 std::string str;
229 for (size_t i = 0; i < n; i++) {
230 auto c = s[i];
231 switch (c) {
232 case '\f': str += "\\f"; break;
233 case '\n': str += "\\n"; break;
234 case '\r': str += "\\r"; break;
235 case '\t': str += "\\t"; break;
236 case '\v': str += "\\v"; break;
237 default: str += c; break;
238 }
239 }
240 return str;
241}
242
243inline std::string escape_characters(std::string_view sv) {
244 return escape_characters(sv.data(), sv.size());
245}
246
247/*-----------------------------------------------------------------------------
248 * resolve_escape_sequence
249 *---------------------------------------------------------------------------*/
250
251inline bool is_hex(char c, int &v) {
252 if ('0' <= c && c <= '9') {
253 v = c - '0';
254 return true;
255 } else if ('a' <= c && c <= 'f') {
256 v = c - 'a' + 10;
257 return true;
258 } else if ('A' <= c && c <= 'F') {
259 v = c - 'A' + 10;
260 return true;
261 }
262 return false;
263}
264
265inline bool is_digit(char c, int &v) {
266 if ('0' <= c && c <= '9') {
267 v = c - '0';
268 return true;
269 }
270 return false;
271}
272
273inline std::pair<int, size_t> parse_hex_number(const char *s, size_t n,
274 size_t i) {
275 int ret = 0;
276 int val;
277 while (i < n && is_hex(s[i], val)) {
278 ret = static_cast<int>(ret * 16 + val);
279 i++;
280 }
281 return std::pair(ret, i);
282}
283
284inline std::pair<int, size_t> parse_octal_number(const char *s, size_t n,
285 size_t i) {
286 int ret = 0;
287 int val;
288 while (i < n && is_digit(s[i], val)) {
289 ret = static_cast<int>(ret * 8 + val);
290 i++;
291 }
292 return std::pair(ret, i);
293}
294
295inline std::string resolve_escape_sequence(const char *s, size_t n) {
296 std::string r;
297 r.reserve(n);
298
299 size_t i = 0;
300 while (i < n) {
301 auto ch = s[i];
302 if (ch == '\\') {
303 i++;
304 assert(i < n);
305
306 switch (s[i]) {
307 case 'f':
308 r += '\f';
309 i++;
310 break;
311 case 'n':
312 r += '\n';
313 i++;
314 break;
315 case 'r':
316 r += '\r';
317 i++;
318 break;
319 case 't':
320 r += '\t';
321 i++;
322 break;
323 case 'v':
324 r += '\v';
325 i++;
326 break;
327 case '\'':
328 r += '\'';
329 i++;
330 break;
331 case '"':
332 r += '"';
333 i++;
334 break;
335 case '[':
336 r += '[';
337 i++;
338 break;
339 case ']':
340 r += ']';
341 i++;
342 break;
343 case '^':
344 r += '^';
345 i++;
346 break;
347 case '-':
348 r += '-';
349 i++;
350 break;
351 case '\\':
352 r += '\\';
353 i++;
354 break;
355 case 'x':
356 case 'u': {
357 char32_t cp;
358 std::tie(cp, i) = parse_hex_number(s, n, i + 1);
359 r += encode_codepoint(cp);
360 break;
361 }
362 default: {
363 char32_t cp;
364 std::tie(cp, i) = parse_octal_number(s, n, i);
365 r += encode_codepoint(cp);
366 break;
367 }
368 }
369 } else {
370 r += ch;
371 i++;
372 }
373 }
374 return r;
375}
376
377/*
378 * Predefined character classes (ASCII semantics)
379 */
380inline const std::vector<std::pair<char32_t, char32_t>> *
381predefined_character_class(std::string_view name) {
382 static const std::map<std::string_view,
383 std::vector<std::pair<char32_t, char32_t>>>
384 table = {
385 {"alnum", {{'0', '9'}, {'A', 'Z'}, {'a', 'z'}}},
386 {"alpha", {{'A', 'Z'}, {'a', 'z'}}},
387 {"ascii", {{0x00, 0x7F}}},
388 {"blank", {{'\t', '\t'}, {' ', ' '}}},
389 {"cntrl", {{0x00, 0x1F}, {0x7F, 0x7F}}},
390 {"digit", {{'0', '9'}}},
391 {"graph", {{0x21, 0x7E}}},
392 {"lower", {{'a', 'z'}}},
393 {"print", {{0x20, 0x7E}}},
394 {"punct", {{0x21, 0x2F}, {0x3A, 0x40}, {0x5B, 0x60}, {0x7B, 0x7E}}},
395 {"space", {{'\t', '\r'}, {' ', ' '}}},
396 {"upper", {{'A', 'Z'}}},
397 {"word", {{'0', '9'}, {'A', 'Z'}, {'_', '_'}, {'a', 'z'}}},
398 {"xdigit", {{'0', '9'}, {'A', 'F'}, {'a', 'f'}}},
399 };
400 auto it = table.find(name);
401 return it != table.end() ? &it->second : nullptr;
402}
403
404// Ranges must be sorted and non-overlapping.
405inline std::vector<std::pair<char32_t, char32_t>> complement_character_ranges(
406 const std::vector<std::pair<char32_t, char32_t>> &ranges) {
407 std::vector<std::pair<char32_t, char32_t>> r;
408 char32_t next = 0;
409 for (const auto &[lo, hi] : ranges) {
410 if (lo > next) { r.emplace_back(next, lo - 1); }
411 next = hi + 1;
412 }
413 if (next <= 0x10FFFF) { r.emplace_back(next, 0x10FFFF); }
414 return r;
415}
416
417/*-----------------------------------------------------------------------------
418 * token_to_number_ - This function should be removed eventually
419 *---------------------------------------------------------------------------*/
420
421template <typename T> T token_to_number_(std::string_view sv) {
422 T n = 0;
423#if __has_include(<charconv>)
424 if constexpr (!std::is_floating_point<T>::value) {
425 std::from_chars(sv.data(), sv.data() + sv.size(), n);
426#else
427 if constexpr (false) {
428#endif
429 } else {
430 auto s = std::string(sv);
431 std::istringstream ss(s);
432 ss >> n;
433 }
434 return n;
435}
436
437inline std::string to_lower(std::string s) {
438 for (auto &c : s) {
439 c = static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
440 }
441 return s;
442}
443
444/*-----------------------------------------------------------------------------
445 * Trie
446 *---------------------------------------------------------------------------*/
447
448class Trie {
449public:
450 Trie(const std::vector<std::string> &items, bool ignore_case)
451 : ignore_case_(ignore_case), items_count_(items.size()) {
452 size_t id = 0;
453 for (const auto &item : items) {
454 const auto &s = ignore_case ? to_lower(item) : item;
455 if (item.size() > max_len_) { max_len_ = item.size(); }
456 for (size_t len = 1; len <= item.size(); len++) {
457 auto last = len == item.size();
458 std::string_view sv(s.data(), len);
459 auto it = dic_.find(sv);
460 if (it == dic_.end()) {
461 dic_.emplace(sv, Info{last, last, id});
462 } else if (last) {
463 it->second.match = true;
464 } else {
465 it->second.done = false;
466 }
467 }
468 id++;
469 }
470 }
471
472 size_t match(const char *text, size_t text_len, size_t &id) const {
473 auto limit = std::min(text_len, max_len_);
474 std::string lower_text;
475 if (ignore_case_) {
476 lower_text = to_lower(std::string(text, limit));
477 text = lower_text.data();
478 }
479
480 size_t match_len = 0;
481 auto done = false;
482 size_t len = 1;
483 while (!done && len <= limit) {
484 std::string_view sv(text, len);
485 auto it = dic_.find(sv);
486 if (it == dic_.end()) {
487 done = true;
488 } else {
489 if (it->second.match) {
490 match_len = len;
491 id = it->second.id;
492 }
493 if (it->second.done) { done = true; }
494 }
495 len += 1;
496 }
497 return match_len;
498 }
499
500 size_t size() const { return dic_.size(); }
501 size_t items_count() const { return items_count_; }
502
503 friend struct ComputeFirstSet;
504 friend struct GrammarBlob;
505
506private:
507 struct Info {
508 bool done;
509 bool match;
510 size_t id;
511 };
512
513 // TODO: Use unordered_map when heterogeneous lookup is supported in C++20
514 // std::unordered_map<std::string, Info> dic_;
515 std::map<std::string, Info, std::less<>> dic_;
516
519 size_t max_len_ = 0;
520};
521
522/*-----------------------------------------------------------------------------
523 * PEG
524 *---------------------------------------------------------------------------*/
525
526/*
527 * Line information utility function
528 */
529inline std::pair<size_t, size_t> line_info(const char *start, const char *cur) {
530 auto p = start;
531 auto col_ptr = p;
532 auto no = 1;
533
534 while (p < cur) {
535 if (*p == '\n') {
536 no++;
537 col_ptr = p + 1;
538 }
539 p++;
540 }
541
542 auto col = codepoint_count(col_ptr, p - col_ptr) + 1;
543
544 return std::pair(no, col);
545}
546
547/*
548 * String tag
549 */
550inline constexpr unsigned int str2tag_core(const char *s, size_t l,
551 unsigned int h) {
552 return (l == 0) ? h
553 : str2tag_core(s + 1, l - 1,
554 (h * 33) ^ static_cast<unsigned char>(*s));
555}
556
557inline constexpr unsigned int str2tag(std::string_view sv) {
558 return str2tag_core(sv.data(), sv.size(), 0);
559}
560
561namespace udl {
562
563inline constexpr unsigned int operator""_(const char *s, size_t l) {
564 return str2tag_core(s, l, 0);
565}
566
567} // namespace udl
568
569/*
570 * Semantic values
571 */
572class Context;
573
574struct SemanticValues : protected std::vector<std::any> {
575 SemanticValues() = default;
577
578 // Input text
579 const char *path = nullptr;
580 const char *ss = nullptr;
581
582 // Matched string
583 std::string_view sv() const { return sv_; }
584
585 // Definition name
586 const std::string &name() const { return name_; }
587
588 std::vector<unsigned int> tags;
589
590 // Line number and column at which the matched string is
591 std::pair<size_t, size_t> line_info() const;
592
593 // Choice count
594 size_t choice_count() const { return choice_count_; }
595
596 // Choice number (0 based index)
597 size_t choice() const { return choice_; }
598
599 // Tokens
600 std::vector<std::string_view> tokens;
601
602 std::string_view token(size_t id = 0) const {
603 if (tokens.empty()) { return sv_; }
604 assert(id < tokens.size());
605 return tokens[id];
606 }
607
608 // Token conversion
609 std::string token_to_string(size_t id = 0) const {
610 return std::string(token(id));
611 }
612
613 template <typename T> T token_to_number() const {
614 return token_to_number_<T>(token());
615 }
616
617 // Transform the semantic value vector to another vector
618 template <typename T>
619 std::vector<T> transform(size_t beg = 0,
620 size_t end = static_cast<size_t>(-1)) const {
621 std::vector<T> r;
622 end = (std::min)(end, size());
623 for (size_t i = beg; i < end; i++) {
624 r.emplace_back(std::any_cast<T>((*this)[i]));
625 }
626 return r;
627 }
628
629 using std::vector<std::any>::iterator;
630 using std::vector<std::any>::const_iterator;
631 using std::vector<std::any>::size;
632 using std::vector<std::any>::empty;
633 using std::vector<std::any>::assign;
634 using std::vector<std::any>::begin;
635 using std::vector<std::any>::end;
636 using std::vector<std::any>::rbegin;
637 using std::vector<std::any>::rend;
638 using std::vector<std::any>::operator[];
639 using std::vector<std::any>::at;
640 using std::vector<std::any>::resize;
641 using std::vector<std::any>::front;
642 using std::vector<std::any>::back;
643 using std::vector<std::any>::push_back;
644 using std::vector<std::any>::pop_back;
645 using std::vector<std::any>::insert;
646 using std::vector<std::any>::erase;
647 using std::vector<std::any>::clear;
648 using std::vector<std::any>::swap;
649 using std::vector<std::any>::emplace;
650 using std::vector<std::any>::emplace_back;
651
652private:
653 friend class Context;
654 friend class Dictionary;
655 friend class Sequence;
656 friend class PrioritizedChoice;
657 friend class Repetition;
658 friend class Holder;
659 friend class PrecedenceClimbing;
660
661 Context *c_ = nullptr;
662 std::string_view sv_;
663 size_t choice_count_ = 0;
664 size_t choice_ = 0;
665 std::string name_;
666};
667
668/*
669 * Semantic action
670 */
671template <typename F, typename... Args> std::any call(F fn, Args &&...args) {
672 using R = decltype(fn(std::forward<Args>(args)...));
673 if constexpr (std::is_void<R>::value) {
674 fn(std::forward<Args>(args)...);
675 return std::any();
676 } else if constexpr (std::is_same<typename std::remove_cv<R>::type,
677 std::any>::value) {
678 return fn(std::forward<Args>(args)...);
679 } else {
680 return std::any(fn(std::forward<Args>(args)...));
681 }
682}
683
684template <typename T>
685struct argument_count : argument_count<decltype(&T::operator())> {};
686template <typename R, typename... Args>
687struct argument_count<R (*)(Args...)>
688 : std::integral_constant<unsigned, sizeof...(Args)> {};
689template <typename R, typename C, typename... Args>
690struct argument_count<R (C::*)(Args...)>
691 : std::integral_constant<unsigned, sizeof...(Args)> {};
692template <typename R, typename C, typename... Args>
693struct argument_count<R (C::*)(Args...) const>
694 : std::integral_constant<unsigned, sizeof...(Args)> {};
695
696class Action {
697public:
698 Action() = default;
699 Action(Action &&rhs) = default;
700 template <typename F> Action(F fn) : fn_(make_adaptor(fn)) {}
701 template <typename F> void operator=(F fn) { fn_ = make_adaptor(fn); }
702 Action &operator=(const Action &rhs) = default;
703
704 operator bool() const { return bool(fn_); }
705
706 std::any operator()(SemanticValues &vs, std::any &dt,
707 const std::any &predicate_data) const {
708 return fn_(vs, dt, predicate_data);
709 }
710
711private:
712 using Fty = std::function<std::any(SemanticValues &vs, std::any &dt,
713 const std::any &predicate_data)>;
714
715 template <typename F> Fty make_adaptor(F fn) {
716 if constexpr (argument_count<F>::value == 1) {
717 return [fn](auto &vs, auto & /*dt*/, const auto & /*predicate_data*/) {
718 return call(fn, vs);
719 };
720 } else if constexpr (argument_count<F>::value == 2) {
721 return [fn](auto &vs, auto &dt, const auto & /*predicate_data*/) {
722 return call(fn, vs, dt);
723 };
724 } else {
725 return [fn](auto &vs, auto &dt, const auto &predicate_data) {
726 return call(fn, vs, dt, predicate_data);
727 };
728 }
729 }
730
732};
733
735public:
736 Predicate() = default;
737 Predicate(Predicate &&rhs) = default;
738 template <typename F> Predicate(F fn) : fn_(make_adaptor(fn)) {}
739 template <typename F> void operator=(F fn) { fn_ = make_adaptor(fn); }
740 Predicate &operator=(const Predicate &rhs) = default;
741
742 operator bool() const { return bool(fn_); }
743
744 bool operator()(const SemanticValues &vs, const std::any &dt,
745 std::string &msg, std::any &predicate_data) const {
746 return fn_(vs, dt, msg, predicate_data);
747 }
748
749private:
750 using Fty = std::function<bool(const SemanticValues &vs, const std::any &dt,
751 std::string &msg, std::any &predicate_data)>;
752
753 template <typename F> Fty make_adaptor(F fn) {
754 if constexpr (argument_count<F>::value == 3) {
755 return [fn](const auto &vs, const auto &dt, auto &msg,
756 auto & /*predicate_data*/) { return fn(vs, dt, msg); };
757 } else {
758 return [fn](const auto &vs, const auto &dt, auto &msg,
759 auto &predicate_data) {
760 return fn(vs, dt, msg, predicate_data);
761 };
762 }
763 }
764
766};
767
768/*
769 * Parse result helper
770 */
771inline bool success(size_t len) { return len != static_cast<size_t>(-1); }
772
773inline bool fail(size_t len) { return len == static_cast<size_t>(-1); }
774
775/*
776 * Log
777 */
778using Log = std::function<void(size_t line, size_t col, const std::string &msg,
779 const std::string &rule)>;
780
781/*
782 * ErrorReport - structured error information passed to an ErrorReporter.
783 * Unlike Log, nothing is flattened into a display string, so applications
784 * can map errors to their own error types, localize messages, or feed
785 * diagnostics to IDEs.
786 */
788 size_t line = 0; // 1-based
789 size_t col = 1; // 1-based
790 size_t position = 0; // byte offset in the input
791 std::string unexpected_token; // heuristic token at the error position
792 std::vector<std::string> expected_literals;
793 std::vector<std::string> expected_rules; // rules starting with '_' excluded
794 std::string message; // custom error_message if any (placeholders resolved)
795 std::string label; // rule name or recovery label the error belongs to
796};
797
798using ErrorReporter = std::function<void(const ErrorReport &report)>;
799
800/*
801 * ErrorInfo
802 */
803class Definition;
804
805struct ErrorInfo {
806 const char *error_pos = nullptr;
807 std::vector<std::pair<const char *, const Definition *>> expected_tokens;
808 const char *message_pos = nullptr;
809 std::string message;
810 std::string label;
811 const char *last_output_pos = nullptr;
813
814 void clear() {
815 error_pos = nullptr;
816 expected_tokens.clear();
817 message_pos = nullptr;
818 message.clear();
819 }
820
821 void add(const char *error_literal, const Definition *error_rule) {
822 for (const auto &[t, r] : expected_tokens) {
823 if (t == error_literal && r == error_rule) { return; }
824 }
825 expected_tokens.emplace_back(error_literal, error_rule);
826 }
827
828 void output_log(const Log &log, const char *s, size_t n) {
829 output_log(log, nullptr, s, n);
830 }
831 void output_log(const Log &log, const ErrorReporter &reporter, const char *s,
832 size_t n);
833
834private:
835 int cast_char(char c) const { return static_cast<unsigned char>(c); }
836
837 std::string heuristic_error_token(const char *s, size_t n,
838 const char *pos) const {
839 auto len = n - std::distance(s, pos);
840 if (len) {
841 size_t i = 0;
842 auto c = cast_char(pos[i++]);
843 if (!std::ispunct(c) && !std::isspace(c)) {
844 while (i < len && !std::ispunct(cast_char(pos[i])) &&
845 !std::isspace(cast_char(pos[i]))) {
846 i++;
847 }
848 }
849
851 size_t j = 0;
852 while (count > 0 && j < i) {
853 j += codepoint_length(&pos[j], i - j);
854 count--;
855 }
856
857 return escape_characters(pos, j);
858 }
859 return std::string();
860 }
861
862 std::string replace_all(std::string str, const std::string &from,
863 const std::string &to) const {
864 size_t pos = 0;
865 while ((pos = str.find(from, pos)) != std::string::npos) {
866 str.replace(pos, from.length(), to);
867 pos += to.length();
868 }
869 return str;
870 }
871};
872
873/*
874 * Context
875 */
876class Ope;
877
878using TracerEnter = std::function<void(
879 const Ope &name, const char *s, size_t n, const SemanticValues &vs,
880 const Context &c, const std::any &dt, std::any &trace_data)>;
881
882using TracerLeave = std::function<void(
883 const Ope &ope, const char *s, size_t n, const SemanticValues &vs,
884 const Context &c, const std::any &dt, size_t, std::any &trace_data)>;
885
886using TracerStartOrEnd = std::function<void(std::any &trace_data)>;
887
888// Packrat memoization table: open-addressing hash map keyed by the fused
889// (position * rule count + rule id) index. The insert-heavy access pattern
890// makes node-based containers a bottleneck, so keys and lengths live in one
891// flat array of 16-byte POD slots probed linearly; semantic values go into a
892// parallel array that is never allocated when no cached result carries a
893// value. Erased slots become tombstones (erase only happens during
894// left-recursion cache invalidation).
896public:
897 explicit PackratCache(size_t expected_entries) {
898 while (initial_capacity_ < expected_entries) {
900 }
901 }
902
903 bool find(size_t key, size_t &len, std::any &val) const {
904 if (slots_.empty()) { return false; }
905 auto mask = slots_.size() - 1;
906 auto i = mix(key) & mask;
907 while (true) {
908 auto &slot = slots_[i];
909 if (slot.key == key) {
910 len = slot.len;
911 if (!vals_.empty()) {
912 val = vals_[i];
913 } else {
914 val.reset();
915 }
916 return true;
917 }
918 if (slot.key == kEmpty) { return false; }
919 i = (i + 1) & mask;
920 }
921 }
922
923 void insert_or_assign(size_t key, size_t len, const std::any &val) {
924 if (slots_.empty() || (used_ + 1) * 4 > slots_.size() * 3) { grow(); }
925 auto mask = slots_.size() - 1;
926 auto i = mix(key) & mask;
927 auto insert_pos = kEmpty;
928 while (true) {
929 auto &slot = slots_[i];
930 if (slot.key == key) {
931 insert_pos = i;
932 break;
933 }
934 if (slot.key == kTombstone) {
935 if (insert_pos == kEmpty) { insert_pos = i; }
936 } else if (slot.key == kEmpty) {
937 if (insert_pos == kEmpty) { insert_pos = i; }
938 if (slots_[insert_pos].key == kEmpty) { used_++; }
939 break;
940 }
941 i = (i + 1) & mask;
942 }
943 auto &dest = slots_[insert_pos];
944 dest.key = key;
945 dest.len = len;
946 if (val.has_value()) {
947 if (vals_.empty()) { vals_.resize(slots_.size()); }
948 vals_[insert_pos] = val;
949 } else if (!vals_.empty()) {
950 vals_[insert_pos].reset();
951 }
952 }
953
954 void erase(size_t key) {
955 if (slots_.empty()) { return; }
956 auto mask = slots_.size() - 1;
957 auto i = mix(key) & mask;
958 while (true) {
959 auto &slot = slots_[i];
960 if (slot.key == key) {
961 slot.key = kTombstone;
962 if (!vals_.empty()) { vals_[i].reset(); }
963 return;
964 }
965 if (slot.key == kEmpty) { return; }
966 i = (i + 1) & mask;
967 }
968 }
969
970private:
971 static constexpr size_t kEmpty = static_cast<size_t>(-1);
972 static constexpr size_t kTombstone = static_cast<size_t>(-2);
973
974 struct Slot {
975 size_t key = kEmpty;
976 size_t len = 0;
977 };
978
979 static size_t mix(size_t key) {
980 // Mix in 64 bits so `h >> 32` stays well-defined where size_t is 32-bit
981 // (wasm32); on 64-bit targets this is bit-identical to the size_t mix.
982 auto h = static_cast<uint64_t>(key) * 0x9E3779B97F4A7C15ull;
983 return static_cast<size_t>(h ^ (h >> 32));
984 }
985
986 void grow() {
987 auto new_cap = slots_.empty() ? initial_capacity_ : slots_.size() * 2;
988 std::vector<Slot> old_slots = std::move(slots_);
989 std::vector<std::any> old_vals = std::move(vals_);
990 slots_.assign(new_cap, Slot{});
991 if (!old_vals.empty()) { vals_.assign(new_cap, std::any()); }
992 used_ = 0;
993 auto mask = new_cap - 1;
994 for (size_t j = 0; j < old_slots.size(); j++) {
995 auto &slot = old_slots[j];
996 if (slot.key == kEmpty || slot.key == kTombstone) { continue; }
997 auto i = mix(slot.key) & mask;
998 while (slots_[i].key != kEmpty) {
999 i = (i + 1) & mask;
1000 }
1001 slots_[i] = slot;
1002 if (!old_vals.empty()) { vals_[i] = std::move(old_vals[j]); }
1003 used_++;
1004 }
1005 }
1006
1007 size_t initial_capacity_ = 1024;
1008 std::vector<Slot> slots_;
1009 std::vector<std::any> vals_;
1010 size_t used_ = 0; // occupied + tombstone slots
1011};
1012
1013class Context {
1014public:
1015 const char *path;
1016 const char *s;
1017 const size_t l;
1018
1020 bool recovered = false;
1021
1022 std::vector<std::unique_ptr<SemanticValues>> value_stack;
1024
1025 std::vector<Definition *> rule_stack;
1026
1027 // One frame per rule reference: the macro arguments in scope, and the
1028 // instantiation they identify (0 for anything but a left-recursive macro).
1029 struct ArgsFrame {
1030 std::vector<std::shared_ptr<Ope>> args;
1031 size_t macro_inst = 0;
1032 };
1033 std::vector<ArgsFrame> args_stack;
1034
1036
1037 std::shared_ptr<Ope> whitespaceOpe;
1038 bool in_whitespace = false;
1039
1040 std::shared_ptr<Ope> wordOpe;
1041
1042 std::vector<std::pair<std::string_view, std::string>> capture_entries;
1043
1044 std::vector<bool> cut_stack;
1045
1046 const size_t def_count;
1048 const std::vector<int32_t> *packrat_index; // def_id -> cache slot or -1
1049 size_t packrat_cached_count; // number of memoized rules
1050 std::vector<bool> cache_registered;
1051 std::vector<bool> cache_success;
1052 // Innermost active start position per rule; re-entry guard for rules that
1053 // are not memoized (replaces the per-position bitvector for them).
1054 std::vector<const char *> active_pos;
1055
1057
1058 // Left recursion support
1059 struct LRMemo {
1060 size_t len = static_cast<size_t>(-1);
1061 std::any val;
1062 };
1063
1064 // A left-recursive rule instance: the definition plus, for a macro, the
1065 // instantiation it was invoked with (0 for a plain rule). Two
1066 // instantiations of the same macro grow independent seeds.
1067 using LRRule = std::pair<const Definition *, size_t>;
1068 using LRKey = std::pair<LRRule, const char *>;
1069
1070 std::map<LRKey, LRMemo> lr_memo;
1071
1072 // Rules whose lr_memo was hit during the current parse scope.
1073 // Used to track LR cycle membership.
1074 std::set<LRRule> lr_refs_hit;
1075
1076 // Rules currently in their seeding/growing phase at a given position.
1077 // Protected from having their lr_memo erased by inner growers.
1078 std::set<LRKey> lr_active_seeds;
1079
1080 // Interned macro instantiations: (definition, resolved arguments) -> id.
1081 std::map<std::vector<const void *>, size_t> macro_inst_ids;
1083
1084 // Map a def_id to its slot in the cache tables, or -1 for guard-only
1085 // rules (not memoized).
1086 int32_t cache_slot(size_t def_id) const {
1087 if (!packrat_index) { return static_cast<int32_t>(def_id); }
1088 return def_id < packrat_index->size() ? (*packrat_index)[def_id] : -1;
1089 }
1090
1091 void clear_packrat_cache(const char *pos, size_t def_id) {
1092 if (!enablePackratParsing) { return; }
1093 auto slot = cache_slot(def_id);
1094 if (slot < 0) { return; }
1095 auto col = static_cast<size_t>(pos - s);
1096 auto idx = packrat_cached_count * col + static_cast<size_t>(slot);
1097 if (idx < cache_registered.size()) {
1098 cache_registered[idx] = false;
1099 cache_success[idx] = false;
1100 }
1101 cache_values.erase(idx);
1102 }
1103
1104 void write_packrat_cache(const char *pos, size_t def_id, size_t len,
1105 const std::any &val) {
1106 if (!enablePackratParsing) { return; }
1107 auto slot = cache_slot(def_id);
1108 if (slot < 0) { return; }
1109 auto col = pos - s;
1110 auto idx = packrat_cached_count * static_cast<size_t>(col) +
1111 static_cast<size_t>(slot);
1112 if (idx >= cache_registered.size()) { return; }
1113 cache_registered[idx] = true;
1114 cache_success[idx] = true;
1115 cache_values.insert_or_assign(idx, len, val);
1116 }
1117
1120 const bool has_tracer;
1121 std::any trace_data;
1122 const bool verbose_trace;
1123
1124 // Byte-wise tolower frozen at parse start, so case-insensitive matching
1125 // avoids a locale-sensitive libc call per input byte.
1126 unsigned char tolower_table[256];
1127
1130
1131 Context(const char *path, const char *s, size_t l, size_t def_count,
1132 std::shared_ptr<Ope> whitespaceOpe, std::shared_ptr<Ope> wordOpe,
1136 const std::vector<int32_t> *packrat_index = nullptr,
1137 size_t packrat_cached_count = 0)
1143 enablePackratParsing ? this->packrat_cached_count * (l + 1) : 0),
1145 enablePackratParsing ? this->packrat_cached_count * (l + 1) : 0),
1148 : 0),
1152
1153 for (size_t i = 0; i < 256; i++) {
1154 tolower_table[i] =
1155 static_cast<unsigned char>(std::tolower(static_cast<int>(i)));
1156 }
1157
1158 push_args({});
1159 }
1160
1162 assert(!value_stack_size);
1163 assert(cut_stack.empty());
1164 }
1165
1166 Context(const Context &) = delete;
1167 Context(Context &&) = delete;
1168 Context operator=(const Context &) = delete;
1169
1170 // Per-rule packrat stats (populated when packrat_stats is non-null)
1172 size_t hits = 0;
1173 size_t misses = 0;
1174 };
1175 std::vector<PackratStats> *packrat_stats = nullptr;
1176
1177 template <typename T>
1178 void packrat(const char *a_s, size_t def_id, size_t &len, std::any &val,
1179 T fn) {
1180 if (!enablePackratParsing) {
1181 fn(val);
1182 return;
1183 }
1184
1185 auto slot = cache_slot(def_id);
1186 if (slot < 0) {
1187 // Guard-only rule: no memoization. Recursion at the same position is
1188 // caught by the per-rule active-position guard.
1189 if (active_pos[def_id] == a_s) {
1190 if (packrat_stats && def_id < packrat_stats->size()) {
1191 (*packrat_stats)[def_id].hits++;
1192 }
1193 len = static_cast<size_t>(-1);
1194 return;
1195 }
1196 if (packrat_stats && def_id < packrat_stats->size()) {
1197 (*packrat_stats)[def_id].misses++;
1198 }
1199 auto save = active_pos[def_id];
1200 active_pos[def_id] = a_s;
1201 fn(val);
1202 active_pos[def_id] = save;
1203 return;
1204 }
1205
1206 auto col = a_s - s;
1207 auto idx = packrat_cached_count * static_cast<size_t>(col) +
1208 static_cast<size_t>(slot);
1209
1210 if (cache_registered[idx]) {
1211 if (packrat_stats && def_id < packrat_stats->size()) {
1212 (*packrat_stats)[def_id].hits++;
1213 }
1214 if (cache_success[idx]) {
1215 if (!cache_values.find(idx, len, val)) {
1216 len = 0;
1217 val.reset();
1218 }
1219 return;
1220 } else {
1221 len = static_cast<size_t>(-1);
1222 return;
1223 }
1224 } else {
1225 // Pre-register as failure (re-entry guard + failure memoization)
1226 cache_registered[idx] = true;
1227 cache_success[idx] = false;
1228
1229 if (packrat_stats && def_id < packrat_stats->size()) {
1230 (*packrat_stats)[def_id].misses++;
1231 }
1232
1233 fn(val);
1234
1235 if (success(len)) { write_packrat_cache(a_s, def_id, len, val); }
1236 return;
1237 }
1238 }
1239
1240 // Semantic values
1242 assert(value_stack_size <= value_stack.size());
1243 if (value_stack_size == value_stack.size()) {
1244 value_stack.emplace_back(std::make_unique<SemanticValues>(this));
1245 } else {
1246 auto &vs = *value_stack[value_stack_size];
1247 if (!vs.empty()) {
1248 vs.clear();
1249 if (!vs.tags.empty()) { vs.tags.clear(); }
1250 }
1251 vs.sv_ = std::string_view();
1252 vs.choice_count_ = 0;
1253 vs.choice_ = 0;
1254 if (!vs.tokens.empty()) { vs.tokens.clear(); }
1255 }
1256
1257 auto &vs = *value_stack[value_stack_size++];
1258 vs.path = path;
1259 vs.ss = s;
1260 return vs;
1261 }
1262
1264
1265 // Arguments
1266 void push_args(std::vector<std::shared_ptr<Ope>> &&args,
1267 size_t macro_inst = 0) {
1268 args_stack.push_back({std::move(args), macro_inst});
1269 }
1270
1271 void pop_args() { args_stack.pop_back(); }
1272
1273 const std::vector<std::shared_ptr<Ope>> &top_args() const {
1274 return args_stack[args_stack.size() - 1].args;
1275 }
1276
1277 size_t top_macro_inst() const {
1278 return args_stack[args_stack.size() - 1].macro_inst;
1279 }
1280
1281 // Identify a macro invocation by what its resolved arguments denote (see
1282 // macro_inst_key). `Sum(A)` inside `Sum(N)`'s own body resolves A back to
1283 // the argument the outer call was given, so both invocations intern to the
1284 // same id and the inner one finds the outer's seed — which is what makes
1285 // growing terminate.
1286 size_t intern_macro_inst(std::vector<const void *> &&key) {
1287 auto [it, inserted] =
1288 macro_inst_ids.emplace(std::move(key), next_macro_inst_);
1289 if (inserted) { next_macro_inst_++; }
1290 return it->second;
1291 }
1292
1293 // Snapshot/Rollback
1294 struct Snapshot {
1295 size_t sv_size;
1298 std::string_view sv_sv;
1300 size_t choice;
1302 };
1303
1305 return {vs.size(), vs.tags.size(), vs.tokens.size(), vs.sv_,
1306 vs.choice_count_, vs.choice_, capture_entries.size()};
1307 }
1308
1309 void rollback(SemanticValues &vs, const Snapshot &snap) {
1310 vs.resize(snap.sv_size);
1311 vs.tags.resize(snap.sv_tags_size);
1312 vs.tokens.resize(snap.sv_tokens_size);
1313 vs.sv_ = snap.sv_sv;
1314 vs.choice_count_ = snap.choice_count;
1315 vs.choice_ = snap.choice;
1316 capture_entries.resize(snap.capture_size);
1317 }
1318
1319 // Skip trailing whitespace with trace suppression.
1320 // Returns whitespace length, or -1 on failure.
1321 // No-op (returns 0) if inside a token boundary or no whitespaceOpe.
1322 size_t skip_whitespace(const char *a_s, size_t n, SemanticValues &vs,
1323 std::any &dt);
1324
1325 // Error
1326 void set_error_pos(const char *a_s, const char *literal = nullptr);
1327
1328 // Trace
1329 void trace_enter(const Ope &ope, const char *a_s, size_t n,
1330 const SemanticValues &vs, std::any &dt);
1331 void trace_leave(const Ope &ope, const char *a_s, size_t n,
1332 const SemanticValues &vs, std::any &dt, size_t len);
1333 bool is_traceable(const Ope &ope) const;
1334
1335 // Line info
1336 std::pair<size_t, size_t> line_info(const char *cur) const {
1337 std::call_once(source_line_index_init_, [this]() {
1338 for (size_t pos = 0; pos < l; pos++) {
1339 if (s[pos] == '\n') { source_line_index.push_back(pos); }
1340 }
1341 source_line_index.push_back(l);
1342 });
1343
1344 auto pos = static_cast<size_t>(std::distance(s, cur));
1345
1346 auto it = std::lower_bound(
1347 source_line_index.begin(), source_line_index.end(), pos,
1348 [](size_t element, size_t value) { return element < value; });
1349
1350 auto id = static_cast<size_t>(std::distance(source_line_index.begin(), it));
1351 auto off = pos - (id == 0 ? 0 : source_line_index[id - 1] + 1);
1352 return std::pair(id + 1, off + 1);
1353 }
1354
1355 size_t next_trace_id = 0;
1356 std::vector<size_t> trace_ids;
1358 mutable std::once_flag source_line_index_init_;
1359 mutable std::vector<size_t> source_line_index;
1360};
1361
1362/*
1363 * Parser operators
1364 */
1365class Ope {
1366public:
1367 struct Visitor;
1368
1369 virtual ~Ope() = default;
1370 size_t parse(const char *s, size_t n, SemanticValues &vs, Context &c,
1371 std::any &dt) const;
1372 virtual size_t parse_core(const char *s, size_t n, SemanticValues &vs,
1373 Context &c, std::any &dt) const = 0;
1374 virtual void accept(Visitor &v) = 0;
1375
1376 bool is_token_boundary = false;
1377 bool is_choice_like = false;
1378};
1379
1380// Keyword-guarded identifier data, heap-allocated only for matching Sequences.
1381// Avoids bloating all Sequence objects with bitsets and keyword sets.
1383 std::bitset<256> identifier_first; // first char of identifier
1384 std::bitset<256> identifier_rest; // subsequent chars of identifier
1385 std::vector<std::string> exact_keywords; // single-word keywords (lowercase)
1386 std::vector<std::string> prefix_keywords; // first word of compound keywords
1389
1390 static bool matches_any(const std::vector<std::string> &keywords,
1391 std::string_view input) {
1392 return std::any_of(keywords.begin(), keywords.end(),
1393 [&](const auto &kw) { return kw == input; });
1394 }
1395};
1396
1397class Sequence : public Ope {
1398public:
1399 template <typename... Args>
1400 Sequence(const Args &...args)
1401 : opes_{static_cast<std::shared_ptr<Ope>>(args)...} {}
1402 Sequence(const std::vector<std::shared_ptr<Ope>> &opes) : opes_(opes) {}
1403 Sequence(std::vector<std::shared_ptr<Ope>> &&opes) : opes_(std::move(opes)) {}
1404
1405 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1406 std::any &dt) const override {
1407 // Keyword-guarded identifier fast path:
1408 // Fuses !ReservedKeyword <identifier> into scan-then-lookup
1409 if (kw_guard_) {
1410 if (auto result = parse_keyword_guarded(s, n, vs, c, dt)) {
1411 return *result;
1412 }
1413 // nullopt means prefix keyword match — fall through to normal path
1414 }
1415 size_t i = 0;
1416 for (const auto &ope : opes_) {
1417 auto len = ope->parse(s + i, n - i, vs, c, dt);
1418 if (fail(len)) { return len; }
1419 i += len;
1420 }
1421 return i;
1422 }
1423
1424 void accept(Visitor &v) override;
1425
1426 std::vector<std::shared_ptr<Ope>> opes_;
1427
1428private:
1429 friend struct SetupFirstSets;
1430 std::unique_ptr<KeywordGuardData> kw_guard_;
1431
1432 // Returns parse result, or nullopt to fall through to normal path
1433 std::optional<size_t> parse_keyword_guarded(const char *s, size_t n,
1434 SemanticValues &vs, Context &c,
1435 std::any &dt) const {
1436 const auto &kw = *kw_guard_;
1437 if (n < 1 || !kw.identifier_first.test(static_cast<unsigned char>(*s))) {
1438 c.set_error_pos(s);
1439 return static_cast<size_t>(-1);
1440 }
1441 // Scan identifier using bitset
1442 size_t id_len = 1;
1443 while (id_len < n &&
1444 kw.identifier_rest.test(static_cast<unsigned char>(s[id_len]))) {
1445 id_len++;
1446 }
1447 // Skip keyword matching if identifier length is out of range
1448 if (id_len >= kw.min_keyword_len && id_len <= kw.max_keyword_len) {
1449 char lower_buf[64];
1450 std::unique_ptr<char[]> lower_heap;
1451 char *lower = lower_buf;
1452 if (id_len > sizeof(lower_buf)) {
1453 lower_heap.reset(new char[id_len]);
1454 lower = lower_heap.get();
1455 }
1456 std::transform(s, s + id_len, lower, [&c](unsigned char ch) {
1457 return static_cast<char>(c.tolower_table[ch]);
1458 });
1459 std::string_view lower_sv(lower, id_len);
1460
1461 if (KeywordGuardData::matches_any(kw.exact_keywords, lower_sv)) {
1462 c.set_error_pos(s);
1463 return static_cast<size_t>(-1);
1464 }
1465 if (KeywordGuardData::matches_any(kw.prefix_keywords, lower_sv)) {
1466 return std::nullopt;
1467 }
1468 }
1469 // Success: emit token and consume trailing whitespace
1470 vs.tokens.emplace_back(std::string_view(s, id_len));
1471 auto wl = c.skip_whitespace(s + id_len, n - id_len, vs, dt);
1472 if (fail(wl)) { return wl; }
1473 return id_len + wl;
1474 }
1475};
1476
1477struct FirstSet {
1478 // First-Set: set of possible first bytes for an expression.
1479 // Used by PrioritizedChoice to skip alternatives that cannot match.
1480 std::bitset<256> chars; // byte values that can appear as the first byte
1481 bool can_be_empty = false; // true if the expression can match empty string
1482 bool any_char = false; // true if any character can appear (cannot filter)
1483 const char *first_literal = nullptr; // first literal for error reporting
1485 nullptr; // first token rule for error reporting
1486
1487 void merge(const FirstSet &other) {
1488 chars |= other.chars;
1489 if (other.can_be_empty) { can_be_empty = true; }
1490 if (other.any_char) { any_char = true; }
1491 // Note: first_literal/first_rule are NOT merged — per-alternative
1492 }
1493};
1494
1495class PrioritizedChoice : public Ope {
1496public:
1497 template <typename... Args>
1498 PrioritizedChoice(bool for_label, const Args &...args)
1499 : opes_{static_cast<std::shared_ptr<Ope>>(args)...},
1500 for_label_(for_label) {
1501 is_choice_like = true;
1502 }
1503 PrioritizedChoice(const std::vector<std::shared_ptr<Ope>> &opes)
1504 : opes_(opes) {
1505 is_choice_like = true;
1506 }
1507 PrioritizedChoice(std::vector<std::shared_ptr<Ope>> &&opes)
1508 : opes_(std::move(opes)) {
1509 is_choice_like = true;
1510 }
1511
1512 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1513 std::any &dt) const override {
1514 size_t len = static_cast<size_t>(-1);
1515
1516 if (!for_label_) { c.cut_stack.push_back(false); }
1517 auto se = scope_exit([&]() {
1518 if (!for_label_) { c.cut_stack.pop_back(); }
1519 });
1520
1521 size_t id = 0;
1522 for (const auto &ope : opes_) {
1523 // First-Set filtering: skip if next byte cannot start this alternative
1524 if (n > 0 && id < first_sets_.size()) {
1525 const auto &fs = first_sets_[id];
1526 if (!fs.any_char && !fs.can_be_empty &&
1527 !fs.chars.test(static_cast<unsigned char>(*s))) {
1528 if ((c.log || c.error_reporter) &&
1529 (fs.first_literal || fs.first_rule)) {
1530 if (c.error_info.error_pos <= s) {
1531 if (c.error_info.error_pos < s || !(id > 0)) {
1532 c.error_info.error_pos = s;
1533 c.error_info.expected_tokens.clear();
1534 }
1535 if (fs.first_literal) {
1536 c.error_info.add(fs.first_literal, nullptr);
1537 } else {
1538 c.error_info.add(nullptr, fs.first_rule);
1539 }
1540 }
1541 }
1542 id++;
1543 continue;
1544 }
1545 }
1546
1547 if (!c.cut_stack.empty()) { c.cut_stack.back() = false; }
1548
1549 auto snap = c.snapshot(vs);
1551
1552 len = ope->parse(s, n, vs, c, dt);
1553
1554 if (success(len)) {
1555 vs.choice_count_ = opes_.size();
1556 vs.choice_ = id;
1557 break;
1558 }
1559
1560 c.rollback(vs, snap);
1561
1562 if (!c.cut_stack.empty() && c.cut_stack.back()) { break; }
1563
1564 id++;
1565 }
1566
1568 return len;
1569 }
1570
1571 void accept(Visitor &v) override;
1572
1573 size_t size() const { return opes_.size(); }
1574
1575 std::vector<std::shared_ptr<Ope>> opes_;
1576 bool for_label_ = false;
1577 std::vector<FirstSet> first_sets_;
1578};
1579
1580class Repetition : public Ope {
1581public:
1582 Repetition(const std::shared_ptr<Ope> &ope, size_t min, size_t max)
1583 : ope_(ope), min_(min), max_(max) {}
1584
1585 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1586 std::any &dt) const override {
1587 // ISpan fast path: tight loop for ASCII CharacterClass repetition.
1588 // Safe because each ASCII match is exactly 1 byte, so byte count == match
1589 // count.
1590 if (span_bitset_) {
1591 const auto &bitset = *span_bitset_;
1592 size_t i = 0;
1593 if (max_ == std::numeric_limits<size_t>::max()) {
1594 // Unbounded repetition (*, +): no per-iteration max check
1595 while (i < n && bitset.test(static_cast<unsigned char>(s[i]))) {
1596 i++;
1597 }
1598 } else {
1599 auto limit = std::min(n, max_);
1600 while (i < limit && bitset.test(static_cast<unsigned char>(s[i]))) {
1601 i++;
1602 }
1603 }
1604 if (i < min_) {
1605 c.set_error_pos(s + i);
1606 return static_cast<size_t>(-1);
1607 }
1608 return i;
1609 }
1610
1611 size_t count = 0;
1612 size_t i = 0;
1613 while (count < min_) {
1614 auto len = ope_->parse(s + i, n - i, vs, c, dt);
1615 if (fail(len)) { return len; }
1616 i += len;
1617 count++;
1618 }
1619
1620 while (count < max_) {
1621 auto snap = c.snapshot(vs);
1622 auto len = ope_->parse(s + i, n - i, vs, c, dt);
1623 if (fail(len)) {
1624 c.rollback(vs, snap);
1625 break;
1626 }
1627 i += len;
1628 count++;
1629 }
1630 return i;
1631 }
1632
1633 void accept(Visitor &v) override;
1634
1635 bool is_zom() const {
1636 return min_ == 0 && max_ == std::numeric_limits<size_t>::max();
1637 }
1638
1639 static std::shared_ptr<Repetition> zom(const std::shared_ptr<Ope> &ope) {
1640 return std::make_shared<Repetition>(ope, 0,
1641 std::numeric_limits<size_t>::max());
1642 }
1643
1644 static std::shared_ptr<Repetition> oom(const std::shared_ptr<Ope> &ope) {
1645 return std::make_shared<Repetition>(ope, 1,
1646 std::numeric_limits<size_t>::max());
1647 }
1648
1649 static std::shared_ptr<Repetition> opt(const std::shared_ptr<Ope> &ope) {
1650 return std::make_shared<Repetition>(ope, 0, 1);
1651 }
1652
1653 std::shared_ptr<Ope> ope_;
1654 size_t min_;
1655 size_t max_;
1656 const std::bitset<256> *span_bitset_ =
1657 nullptr; // non-owning, set by SetupFirstSets
1658};
1659
1660class AndPredicate : public Ope {
1661public:
1662 AndPredicate(const std::shared_ptr<Ope> &ope) : ope_(ope) {}
1663
1664 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1665 std::any &dt) const override {
1666 auto snap = c.snapshot(vs);
1667 auto len = ope_->parse(s, n, vs, c, dt);
1668 c.rollback(vs, snap); // Always rollback — predicates consume nothing
1669 if (success(len)) {
1670 return 0;
1671 } else {
1672 return len;
1673 }
1674 }
1675
1676 void accept(Visitor &v) override;
1677
1678 std::shared_ptr<Ope> ope_;
1679};
1680
1681class NotPredicate : public Ope {
1682public:
1683 NotPredicate(const std::shared_ptr<Ope> &ope) : ope_(ope) {}
1684
1685 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1686 std::any &dt) const override {
1687 auto snap = c.snapshot(vs);
1688 auto len = ope_->parse(s, n, vs, c, dt);
1689 c.rollback(vs, snap); // Always rollback — predicates consume nothing
1690 if (success(len)) {
1691 c.set_error_pos(s);
1692 return static_cast<size_t>(-1);
1693 } else {
1694 return 0;
1695 }
1696 }
1697
1698 void accept(Visitor &v) override;
1699
1700 std::shared_ptr<Ope> ope_;
1701};
1702
1703class Dictionary : public Ope, public std::enable_shared_from_this<Dictionary> {
1704public:
1705 Dictionary(const std::vector<std::string> &v, bool ignore_case)
1706 : trie_(v, ignore_case) {
1707 is_choice_like = true;
1708 }
1709
1710 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1711 std::any &dt) const override;
1712
1713 void accept(Visitor &v) override;
1714
1716};
1717
1718class LiteralString : public Ope,
1719 public std::enable_shared_from_this<LiteralString> {
1720public:
1721 LiteralString(std::string &&s, bool ignore_case)
1722 : lit_(std::move(s)), ignore_case_(ignore_case),
1723 lower_lit_(ignore_case ? to_lower(lit_) : std::string()),
1724 is_word_(false) {}
1725
1726 LiteralString(const std::string &s, bool ignore_case)
1727 : lit_(s), ignore_case_(ignore_case),
1728 lower_lit_(ignore_case ? to_lower(lit_) : std::string()),
1729 is_word_(false) {}
1730
1731 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1732 std::any &dt) const override;
1733
1734 void accept(Visitor &v) override;
1735
1736 std::string lit_;
1738 std::string lower_lit_; // pre-computed for ignore_case
1739 mutable std::once_flag init_is_word_;
1740 mutable bool is_word_;
1741};
1742
1743class CharacterClass : public Ope,
1744 public std::enable_shared_from_this<CharacterClass> {
1745public:
1746 CharacterClass(const std::string &s, bool negated, bool ignore_case)
1747 : negated_(negated), ignore_case_(ignore_case) {
1748 auto chars = decode(s.data(), s.length());
1749 auto i = 0u;
1750 while (i < chars.size()) {
1751 if (i + 2 < chars.size() && chars[i + 1] == '-') {
1752 auto cp1 = chars[i];
1753 auto cp2 = chars[i + 2];
1754 ranges_.emplace_back(std::pair(cp1, cp2));
1755 i += 3;
1756 } else {
1757 auto cp = chars[i];
1758 ranges_.emplace_back(std::pair(cp, cp));
1759 i += 1;
1760 }
1761 }
1762 assert(!ranges_.empty());
1764 }
1765
1766 CharacterClass(const std::vector<std::pair<char32_t, char32_t>> &ranges,
1767 bool negated, bool ignore_case)
1768 : ranges_(ranges), negated_(negated), ignore_case_(ignore_case) {
1769 assert(!ranges_.empty());
1771 }
1772
1773 size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/,
1774 Context &c, std::any & /*dt*/) const override {
1775 if (n < 1) {
1776 c.set_error_pos(s);
1777 return static_cast<size_t>(-1);
1778 }
1779
1780 char32_t cp = 0;
1781 auto len = decode_codepoint(s, n, cp);
1782
1783 for (const auto &range : ranges_) {
1784 if (in_range(range, cp)) {
1785 if (negated_) {
1786 c.set_error_pos(s);
1787 return static_cast<size_t>(-1);
1788 } else {
1789 return len;
1790 }
1791 }
1792 }
1793
1794 if (negated_) {
1795 return len;
1796 } else {
1797 c.set_error_pos(s);
1798 return static_cast<size_t>(-1);
1799 }
1800 }
1801
1802 void accept(Visitor &v) override;
1803
1804 friend struct ComputeFirstSet;
1805 friend struct GrammarBlob;
1806 friend struct OpeSignature;
1807
1808 bool is_ascii_only() const { return is_ascii_only_; }
1809 const std::bitset<256> &ascii_bitset() const { return ascii_bitset_; }
1810
1811private:
1812 bool in_range(const std::pair<char32_t, char32_t> &range, char32_t cp) const {
1813 if (ignore_case_) {
1814 auto cpl = std::tolower(cp);
1815 return std::tolower(range.first) <= cpl &&
1816 cpl <= std::tolower(range.second);
1817 } else {
1818 return range.first <= cp && cp <= range.second;
1819 }
1820 }
1821
1823 if (negated_) { return; } // negated classes can match non-ASCII
1824 for (const auto &[lo, hi] : ranges_) {
1825 if (lo > 0x7F || hi > 0x7F) { return; }
1826 }
1827 is_ascii_only_ = true;
1828 for (const auto &[lo, hi] : ranges_) {
1829 for (auto cp = lo; cp <= hi; cp++) {
1830 auto ch = static_cast<unsigned char>(cp);
1831 ascii_bitset_.set(ch);
1832 if (ignore_case_) {
1833 ascii_bitset_.set(static_cast<unsigned char>(std::toupper(ch)));
1834 ascii_bitset_.set(static_cast<unsigned char>(std::tolower(ch)));
1835 }
1836 }
1837 }
1838 }
1839
1840 std::vector<std::pair<char32_t, char32_t>> ranges_;
1843 std::bitset<256> ascii_bitset_;
1844 bool is_ascii_only_ = false;
1845};
1846
1847class Character : public Ope, public std::enable_shared_from_this<Character> {
1848public:
1849 Character(char32_t ch) : ch_(ch) {}
1850
1851 size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/,
1852 Context &c, std::any & /*dt*/) const override {
1853 if (n < 1) {
1854 c.set_error_pos(s);
1855 return static_cast<size_t>(-1);
1856 }
1857
1858 char32_t cp = 0;
1859 auto len = decode_codepoint(s, n, cp);
1860
1861 if (cp != ch_) {
1862 c.set_error_pos(s);
1863 return static_cast<size_t>(-1);
1864 }
1865 return len;
1866 }
1867
1868 void accept(Visitor &v) override;
1869
1870 char32_t ch_;
1871};
1872
1873class AnyCharacter : public Ope,
1874 public std::enable_shared_from_this<AnyCharacter> {
1875public:
1876 size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/,
1877 Context &c, std::any & /*dt*/) const override {
1878 auto len = codepoint_length(s, n);
1879 if (len < 1) {
1880 c.set_error_pos(s);
1881 return static_cast<size_t>(-1);
1882 }
1883 return len;
1884 }
1885
1886 void accept(Visitor &v) override;
1887};
1888
1889class CaptureScope : public Ope {
1890public:
1891 CaptureScope(const std::shared_ptr<Ope> &ope) : ope_(ope) {}
1892
1893 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1894 std::any &dt) const override {
1895 auto cap_snap = c.capture_entries.size();
1896 auto len = ope_->parse(s, n, vs, c, dt);
1897 c.capture_entries.resize(cap_snap); // Always rollback (isolation)
1898 return len;
1899 }
1900
1901 void accept(Visitor &v) override;
1902
1903 std::shared_ptr<Ope> ope_;
1904};
1905
1906class Capture : public Ope {
1907public:
1908 using MatchAction = std::function<void(const char *s, size_t n, Context &c)>;
1909
1910 Capture(const std::shared_ptr<Ope> &ope, MatchAction ma)
1911 : ope_(ope), match_action_(ma) {}
1912
1913 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1914 std::any &dt) const override {
1915 auto len = ope_->parse(s, n, vs, c, dt);
1916 if (success(len) && match_action_) { match_action_(s, len, c); }
1917 return len;
1918 }
1919
1920 void accept(Visitor &v) override;
1921
1922 std::shared_ptr<Ope> ope_;
1924};
1925
1926class TokenBoundary : public Ope {
1927public:
1928 TokenBoundary(const std::shared_ptr<Ope> &ope) : ope_(ope) {
1929 is_token_boundary = true;
1930 }
1931
1932 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1933 std::any &dt) const override;
1934
1935 void accept(Visitor &v) override;
1936
1937 std::shared_ptr<Ope> ope_;
1938};
1939
1940class Ignore : public Ope {
1941public:
1942 Ignore(const std::shared_ptr<Ope> &ope) : ope_(ope) {}
1943
1944 size_t parse_core(const char *s, size_t n, SemanticValues & /*vs*/,
1945 Context &c, std::any &dt) const override {
1946 auto &chvs = c.push_semantic_values_scope();
1947 auto se = scope_exit([&]() { c.pop_semantic_values_scope(); });
1948 return ope_->parse(s, n, chvs, c, dt);
1949 }
1950
1951 void accept(Visitor &v) override;
1952
1953 std::shared_ptr<Ope> ope_;
1954};
1955
1956using Parser = std::function<size_t(const char *s, size_t n, SemanticValues &vs,
1957 std::any &dt)>;
1958
1959class User : public Ope {
1960public:
1961 User(Parser fn) : fn_(fn) {}
1962 size_t parse_core(const char *s, size_t n, SemanticValues &vs,
1963 Context & /*c*/, std::any &dt) const override {
1964 assert(fn_);
1965 return fn_(s, n, vs, dt);
1966 }
1967 void accept(Visitor &v) override;
1968 std::function<size_t(const char *s, size_t n, SemanticValues &vs,
1969 std::any &dt)>
1971};
1972
1973class WeakHolder : public Ope {
1974public:
1975 WeakHolder(const std::shared_ptr<Ope> &ope) : weak_(ope) {}
1976
1977 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1978 std::any &dt) const override {
1979 auto ope = weak_.lock();
1980 assert(ope);
1981 return ope->parse(s, n, vs, c, dt);
1982 }
1983
1984 void accept(Visitor &v) override;
1985
1986 std::weak_ptr<Ope> weak_;
1987};
1988
1989class Holder : public Ope {
1990public:
1991 Holder(Definition *outer) : outer_(outer) {}
1992
1993 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
1994 std::any &dt) const override;
1995
1996 void accept(Visitor &v) override;
1997
1998 std::any reduce(SemanticValues &vs, std::any &dt,
1999 const std::any &predicate_data) const;
2000
2001 const std::string &name() const;
2002 const std::string &trace_name() const;
2003
2004 std::shared_ptr<Ope> ope_;
2006 mutable std::once_flag trace_name_init_;
2007 mutable std::string trace_name_;
2008
2009 friend class Definition;
2010};
2011
2012using Grammar = std::unordered_map<std::string, Definition>;
2013
2014class Reference : public Ope, public std::enable_shared_from_this<Reference> {
2015public:
2016 Reference(const Grammar &grammar, const std::string &name, const char *s,
2017 bool is_macro, const std::vector<std::shared_ptr<Ope>> &args)
2018 : grammar_(grammar), name_(name), s_(s), is_macro_(is_macro), args_(args),
2019 rule_(nullptr), iarg_(0) {}
2020
2021 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
2022 std::any &dt) const override;
2023
2024 void accept(Visitor &v) override;
2025
2026 std::shared_ptr<Ope> get_core_operator() const;
2027
2029 const std::string name_;
2030 const char *s_;
2031
2032 const bool is_macro_;
2033 const std::vector<std::shared_ptr<Ope>> args_;
2034
2036 size_t iarg_;
2037};
2038
2039class Whitespace : public Ope {
2040public:
2041 Whitespace(const std::shared_ptr<Ope> &ope) : ope_(ope) {}
2042
2043 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
2044 std::any &dt) const override {
2045 if (c.in_whitespace) { return 0; }
2046 c.in_whitespace = true;
2047 auto se = scope_exit([&]() { c.in_whitespace = false; });
2048 return ope_->parse(s, n, vs, c, dt);
2049 }
2050
2051 void accept(Visitor &v) override;
2052
2053 std::shared_ptr<Ope> ope_;
2054};
2055
2056class BackReference : public Ope {
2057public:
2058 BackReference(std::string &&name) : name_(std::move(name)) {}
2059
2060 BackReference(const std::string &name) : name_(name) {}
2061
2062 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
2063 std::any &dt) const override;
2064
2065 void accept(Visitor &v) override;
2066
2067 std::string name_;
2068};
2069
2070class PrecedenceClimbing : public Ope {
2071public:
2072 using BinOpeInfo = std::map<std::string_view, std::pair<size_t, char>>;
2073
2074 PrecedenceClimbing(const std::shared_ptr<Ope> &atom,
2075 const std::shared_ptr<Ope> &binop, const BinOpeInfo &info,
2076 const Definition &rule)
2077 : atom_(atom), binop_(binop), info_(info), rule_(rule) {}
2078
2079 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
2080 std::any &dt) const override {
2081 return parse_expression(s, n, vs, c, dt, 0);
2082 }
2083
2084 void accept(Visitor &v) override;
2085
2086 std::shared_ptr<Ope> atom_;
2087 std::shared_ptr<Ope> binop_;
2089 // Owned backing storage for info_ keys when this node is built by
2090 // GrammarBlob::deserialize. Grammars parsed from source leave this empty and
2091 // point info_ keys into the retained grammar text instead.
2092 std::vector<std::string> info_keys_;
2094
2095private:
2096 size_t parse_expression(const char *s, size_t n, SemanticValues &vs,
2097 Context &c, std::any &dt, size_t min_prec) const;
2098
2100};
2101
2102class Recovery : public Ope {
2103public:
2104 Recovery(const std::shared_ptr<Ope> &ope) : ope_(ope) {}
2105
2106 size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c,
2107 std::any &dt) const override;
2108
2109 void accept(Visitor &v) override;
2110
2111 std::shared_ptr<Ope> ope_;
2112};
2113
2114class Cut : public Ope, public std::enable_shared_from_this<Cut> {
2115public:
2116 size_t parse_core(const char * /*s*/, size_t /*n*/, SemanticValues & /*vs*/,
2117 Context &c, std::any & /*dt*/) const override {
2118 if (!c.cut_stack.empty()) { c.cut_stack.back() = true; }
2119 return 0;
2120 }
2121
2122 void accept(Visitor &v) override;
2123};
2124
2125/*
2126 * Factories
2127 */
2128template <typename... Args> std::shared_ptr<Ope> seq(Args &&...args) {
2129 return std::make_shared<Sequence>(static_cast<std::shared_ptr<Ope>>(args)...);
2130}
2131
2132template <typename... Args> std::shared_ptr<Ope> cho(Args &&...args) {
2133 return std::make_shared<PrioritizedChoice>(
2134 false, static_cast<std::shared_ptr<Ope>>(args)...);
2135}
2136
2137template <typename... Args> std::shared_ptr<Ope> cho4label_(Args &&...args) {
2138 return std::make_shared<PrioritizedChoice>(
2139 true, static_cast<std::shared_ptr<Ope>>(args)...);
2140}
2141
2142inline std::shared_ptr<Ope> zom(const std::shared_ptr<Ope> &ope) {
2143 return Repetition::zom(ope);
2144}
2145
2146inline std::shared_ptr<Ope> oom(const std::shared_ptr<Ope> &ope) {
2147 return Repetition::oom(ope);
2148}
2149
2150inline std::shared_ptr<Ope> opt(const std::shared_ptr<Ope> &ope) {
2151 return Repetition::opt(ope);
2152}
2153
2154inline std::shared_ptr<Ope> rep(const std::shared_ptr<Ope> &ope, size_t min,
2155 size_t max) {
2156 return std::make_shared<Repetition>(ope, min, max);
2157}
2158
2159inline std::shared_ptr<Ope> apd(const std::shared_ptr<Ope> &ope) {
2160 return std::make_shared<AndPredicate>(ope);
2161}
2162
2163inline std::shared_ptr<Ope> npd(const std::shared_ptr<Ope> &ope) {
2164 return std::make_shared<NotPredicate>(ope);
2165}
2166
2167inline std::shared_ptr<Ope> dic(const std::vector<std::string> &v,
2168 bool ignore_case) {
2169 return std::make_shared<Dictionary>(v, ignore_case);
2170}
2171
2172inline std::shared_ptr<Ope> lit(std::string &&s) {
2173 return std::make_shared<LiteralString>(s, false);
2174}
2175
2176inline std::shared_ptr<Ope> liti(std::string &&s) {
2177 return std::make_shared<LiteralString>(s, true);
2178}
2179
2180inline std::shared_ptr<Ope> cls(const std::string &s) {
2181 return std::make_shared<CharacterClass>(s, false, false);
2182}
2183
2184inline std::shared_ptr<Ope>
2185cls(const std::vector<std::pair<char32_t, char32_t>> &ranges,
2186 bool ignore_case = false) {
2187 return std::make_shared<CharacterClass>(ranges, false, ignore_case);
2188}
2189
2190inline std::shared_ptr<Ope> ncls(const std::string &s) {
2191 return std::make_shared<CharacterClass>(s, true, false);
2192}
2193
2194inline std::shared_ptr<Ope>
2195ncls(const std::vector<std::pair<char32_t, char32_t>> &ranges,
2196 bool ignore_case = false) {
2197 return std::make_shared<CharacterClass>(ranges, true, ignore_case);
2198}
2199
2200inline std::shared_ptr<Ope> chr(char32_t dt) {
2201 return std::make_shared<Character>(dt);
2202}
2203
2204inline std::shared_ptr<Ope> dot() { return std::make_shared<AnyCharacter>(); }
2205
2206inline std::shared_ptr<Ope> csc(const std::shared_ptr<Ope> &ope) {
2207 return std::make_shared<CaptureScope>(ope);
2208}
2209
2210inline std::shared_ptr<Ope> cap(const std::shared_ptr<Ope> &ope,
2212 return std::make_shared<Capture>(ope, ma);
2213}
2214
2215inline std::shared_ptr<Ope> tok(const std::shared_ptr<Ope> &ope) {
2216 return std::make_shared<TokenBoundary>(ope);
2217}
2218
2219inline std::shared_ptr<Ope> ign(const std::shared_ptr<Ope> &ope) {
2220 return std::make_shared<Ignore>(ope);
2221}
2222
2223inline std::shared_ptr<Ope>
2224usr(std::function<size_t(const char *s, size_t n, SemanticValues &vs,
2225 std::any &dt)>
2226 fn) {
2227 return std::make_shared<User>(fn);
2228}
2229
2230inline std::shared_ptr<Ope> ref(const Grammar &grammar, const std::string &name,
2231 const char *s, bool is_macro,
2232 const std::vector<std::shared_ptr<Ope>> &args) {
2233 return std::make_shared<Reference>(grammar, name, s, is_macro, args);
2234}
2235
2236inline std::shared_ptr<Ope> wsp(const std::shared_ptr<Ope> &ope) {
2237 return std::make_shared<Whitespace>(std::make_shared<Ignore>(ope));
2238}
2239
2240inline std::shared_ptr<Ope> bkr(std::string &&name) {
2241 return std::make_shared<BackReference>(name);
2242}
2243
2244inline std::shared_ptr<Ope> pre(const std::shared_ptr<Ope> &atom,
2245 const std::shared_ptr<Ope> &binop,
2247 const Definition &rule) {
2248 return std::make_shared<PrecedenceClimbing>(atom, binop, info, rule);
2249}
2250
2251inline std::shared_ptr<Ope> rec(const std::shared_ptr<Ope> &ope) {
2252 return std::make_shared<Recovery>(ope);
2253}
2254
2255inline std::shared_ptr<Ope> cut() { return std::make_shared<Cut>(); }
2256
2257/*
2258 * Visitor
2259 */
2261 virtual ~Visitor() {}
2262 virtual void visit(Sequence &) {}
2263 virtual void visit(PrioritizedChoice &) {}
2264 virtual void visit(Repetition &) {}
2265 virtual void visit(AndPredicate &) {}
2266 virtual void visit(NotPredicate &) {}
2267 virtual void visit(Dictionary &) {}
2268 virtual void visit(LiteralString &) {}
2269 virtual void visit(CharacterClass &) {}
2270 virtual void visit(Character &) {}
2271 virtual void visit(AnyCharacter &) {}
2272 virtual void visit(CaptureScope &) {}
2273 virtual void visit(Capture &) {}
2274 virtual void visit(TokenBoundary &) {}
2275 virtual void visit(Ignore &) {}
2276 virtual void visit(User &) {}
2277 virtual void visit(WeakHolder &) {}
2278 virtual void visit(Holder &) {}
2279 virtual void visit(Reference &) {}
2280 virtual void visit(Whitespace &) {}
2281 virtual void visit(BackReference &) {}
2282 virtual void visit(PrecedenceClimbing &) {}
2283 virtual void visit(Recovery &) {}
2284 virtual void visit(Cut &) {}
2285};
2286
2289 void visit(Sequence &ope) override {
2290 for (auto &op : ope.opes_) {
2291 op->accept(*this);
2292 }
2293 }
2294 void visit(PrioritizedChoice &ope) override {
2295 for (auto &op : ope.opes_) {
2296 op->accept(*this);
2297 }
2298 }
2299 void visit(Repetition &ope) override { ope.ope_->accept(*this); }
2300 void visit(AndPredicate &ope) override { ope.ope_->accept(*this); }
2301 void visit(NotPredicate &ope) override { ope.ope_->accept(*this); }
2302 void visit(CaptureScope &ope) override { ope.ope_->accept(*this); }
2303 void visit(Capture &ope) override { ope.ope_->accept(*this); }
2304 void visit(TokenBoundary &ope) override { ope.ope_->accept(*this); }
2305 void visit(Ignore &ope) override { ope.ope_->accept(*this); }
2306 void visit(WeakHolder &ope) override { ope.weak_.lock()->accept(*this); }
2307 void visit(Holder &ope) override { ope.ope_->accept(*this); }
2308 void visit(Whitespace &ope) override { ope.ope_->accept(*this); }
2309 void visit(Recovery &ope) override { ope.ope_->accept(*this); }
2310 void visit(PrecedenceClimbing &ope) override { ope.atom_->accept(*this); }
2311};
2312
2314 using Ope::Visitor::visit;
2315
2316 void visit(Sequence &) override { name_ = "Sequence"; }
2317 void visit(PrioritizedChoice &) override { name_ = "PrioritizedChoice"; }
2318 void visit(Repetition &) override { name_ = "Repetition"; }
2319 void visit(AndPredicate &) override { name_ = "AndPredicate"; }
2320 void visit(NotPredicate &) override { name_ = "NotPredicate"; }
2321 void visit(Dictionary &) override { name_ = "Dictionary"; }
2322 void visit(LiteralString &) override { name_ = "LiteralString"; }
2323 void visit(CharacterClass &) override { name_ = "CharacterClass"; }
2324 void visit(Character &) override { name_ = "Character"; }
2325 void visit(AnyCharacter &) override { name_ = "AnyCharacter"; }
2326 void visit(CaptureScope &) override { name_ = "CaptureScope"; }
2327 void visit(Capture &) override { name_ = "Capture"; }
2328 void visit(TokenBoundary &) override { name_ = "TokenBoundary"; }
2329 void visit(Ignore &) override { name_ = "Ignore"; }
2330 void visit(User &) override { name_ = "User"; }
2331 void visit(WeakHolder &) override { name_ = "WeakHolder"; }
2332 void visit(Holder &ope) override { name_ = ope.trace_name().data(); }
2333 void visit(Reference &) override { name_ = "Reference"; }
2334 void visit(Whitespace &) override { name_ = "Whitespace"; }
2335 void visit(BackReference &) override { name_ = "BackReference"; }
2336 void visit(PrecedenceClimbing &) override { name_ = "PrecedenceClimbing"; }
2337 void visit(Recovery &) override { name_ = "Recovery"; }
2338 void visit(Cut &) override { name_ = "Cut"; }
2339
2340 static std::string get(Ope &ope) {
2341 TraceOpeName vis;
2342 ope.accept(vis);
2343 return vis.name_;
2344 }
2345
2346private:
2347 const char *name_ = nullptr;
2348};
2349
2352
2353 void visit(Holder &ope) override;
2354 void visit(Reference &ope) override;
2355 void visit(PrecedenceClimbing &ope) override;
2356
2357 std::unordered_map<void *, size_t> ids;
2358};
2359
2361 using Ope::Visitor::visit;
2362
2363 void visit(PrioritizedChoice &ope) override {
2364 for (const auto &op : ope.opes_) {
2365 if (!IsLiteralToken::check(*op)) { return; }
2366 }
2367 result_ = true;
2368 }
2369
2370 void visit(Dictionary &) override { result_ = true; }
2371 void visit(LiteralString &) override { result_ = true; }
2372
2373 static bool check(Ope &ope) {
2374 IsLiteralToken vis;
2375 ope.accept(vis);
2376 return vis.result_;
2377 }
2378
2379private:
2380 bool result_ = false;
2381};
2382
2385
2386 void visit(TokenBoundary &) override { has_token_boundary_ = true; }
2387 void visit(AndPredicate &) override {}
2388 void visit(NotPredicate &) override {}
2389 void visit(WeakHolder &) override { has_rule_ = true; }
2390 void visit(Reference &ope) override;
2391
2392 static bool is_token(Ope &ope) {
2393 if (IsLiteralToken::check(ope)) { return true; }
2394
2395 TokenChecker vis;
2396 ope.accept(vis);
2397 return vis.has_token_boundary_ || !vis.has_rule_;
2398 }
2399
2400private:
2402 bool has_rule_ = false;
2403};
2404
2406 using Ope::Visitor::visit;
2407
2408 void visit(LiteralString &ope) override { token_ = ope.lit_.data(); }
2409 void visit(TokenBoundary &ope) override { ope.ope_->accept(*this); }
2410 void visit(Ignore &ope) override { ope.ope_->accept(*this); }
2411 void visit(Reference &ope) override;
2412 void visit(Recovery &ope) override { ope.ope_->accept(*this); }
2413
2414 static const char *token(Ope &ope) {
2415 FindLiteralToken vis;
2416 ope.accept(vis);
2417 return vis.token_;
2418 }
2419
2420private:
2421 const char *token_ = nullptr;
2422};
2423
2426
2427 DetectLeftRecursion(const std::string &name) : name_(name) {}
2428
2429 void visit(Sequence &ope) override {
2430 for (const auto &op : ope.opes_) {
2431 op->accept(*this);
2432 if (done_) {
2433 break;
2434 } else if (error_s) {
2435 done_ = true;
2436 break;
2437 }
2438 }
2439 }
2440 void visit(PrioritizedChoice &ope) override {
2441 for (const auto &op : ope.opes_) {
2442 op->accept(*this);
2443 if (error_s) {
2444 done_ = true;
2445 break;
2446 }
2447 }
2448 }
2449 void visit(Repetition &ope) override {
2450 ope.ope_->accept(*this);
2451 done_ = ope.min_ > 0;
2452 }
2453 void visit(AndPredicate &ope) override {
2454 ope.ope_->accept(*this);
2455 done_ = false;
2456 }
2457 void visit(NotPredicate &ope) override {
2458 ope.ope_->accept(*this);
2459 done_ = false;
2460 }
2461 void visit(Dictionary &) override { done_ = true; }
2462 void visit(LiteralString &ope) override { done_ = !ope.lit_.empty(); }
2463 void visit(CharacterClass &) override { done_ = true; }
2464 void visit(Character &) override { done_ = true; }
2465 void visit(AnyCharacter &) override { done_ = true; }
2466 void visit(User &) override { done_ = true; }
2467 void visit(Reference &ope) override;
2468 void visit(BackReference &) override { done_ = true; }
2469 void visit(Cut &) override { done_ = true; }
2470
2471 const char *error_s = nullptr;
2472
2473 // What a bare parameter reference denotes, plus the frame it was found at
2474 // -- see visit_in_defining_scope.
2476 std::shared_ptr<Ope> ope;
2477 size_t depth = 0;
2478 };
2479 ResolvedArg resolve_macro_arg(size_t iarg) const;
2480 void visit_in_defining_scope(const ResolvedArg &arg);
2481
2482 // A macro's body depends on its arguments, so "already visited" has to be
2483 // per instantiation, not per name: in `A <- W('z') / W(A)`, visiting W with
2484 // 'z' says nothing about W with A. Instantiations are identified by their
2485 // resolved arguments, the same way as at parse time.
2486 size_t intern_macro_inst(const Reference &ope);
2487
2488 // A macro that instantiates itself with a growing argument
2489 // (`M(s) <- M(s / 'x')`) has no finite set of instantiations. Stop
2490 // descending instead of looping forever; the rule is then reported as
2491 // non-left-recursive, which is what this analysis did for every macro
2492 // before it became instantiation-aware. The bound is on nesting depth in
2493 // general, not self-recursion specifically, so it also caps any other
2494 // chain of nested macro calls -- generously, for real grammars.
2495 static const size_t max_macro_inst_depth = 32;
2496
2497private:
2498 std::string name_;
2499 std::set<std::pair<const Definition *, size_t>> refs_;
2500 std::map<std::vector<const void *>, size_t> macro_inst_ids_;
2502 bool done_ = false;
2503 std::vector<const std::vector<std::shared_ptr<Ope>> *> macro_args_stack_;
2504};
2505
2508
2509 bool result = false;
2510
2511 void visit(Sequence &ope) override {
2512 result = std::all_of(ope.opes_.begin(), ope.opes_.end(), [](auto &op) {
2513 ComputeCanBeEmpty vis;
2514 op->accept(vis);
2515 return vis.result;
2516 });
2517 }
2518 void visit(PrioritizedChoice &ope) override {
2519 result = std::any_of(ope.opes_.begin(), ope.opes_.end(), [](auto &op) {
2520 ComputeCanBeEmpty vis;
2521 op->accept(vis);
2522 return vis.result;
2523 });
2524 }
2525 void visit(Repetition &ope) override { result = ope.min_ == 0; }
2526 void visit(AndPredicate &) override { result = true; }
2527 void visit(NotPredicate &) override { result = true; }
2528 void visit(Dictionary &) override { result = false; }
2529 void visit(LiteralString &ope) override { result = ope.lit_.empty(); }
2530 void visit(CharacterClass &) override { result = false; }
2531 void visit(Character &) override { result = false; }
2532 void visit(AnyCharacter &) override { result = false; }
2533 void visit(User &) override { result = false; }
2534 void visit(Reference &ope) override;
2535 void visit(BackReference &) override { result = false; }
2536 void visit(Cut &) override { result = false; }
2537};
2538
2539// Structural signature of an Ope. Two alternatives whose first k elements
2540// have equal signatures consume the same text, so their (k+1)-th elements
2541// start at the same position. Opes whose state cannot be serialized get
2542// their address instead: that only ever reads as "these differ", which
2543// costs an optimization rather than adding one.
2545 using Ope::Visitor::visit;
2546 std::string s;
2547
2548 void visit(Sequence &ope) override { group("seq", ope.opes_); }
2549 void visit(PrioritizedChoice &ope) override { group("cho", ope.opes_); }
2550 void visit(Repetition &ope) override {
2551 s += "(rep " + std::to_string(ope.min_) + " " +
2552 (ope.max_ == std::numeric_limits<size_t>::max()
2553 ? std::string("inf")
2554 : std::to_string(ope.max_));
2555 wrap(*ope.ope_);
2556 }
2557 void visit(AndPredicate &ope) override { unary("and", *ope.ope_); }
2558 void visit(NotPredicate &ope) override { unary("not", *ope.ope_); }
2559 void visit(CaptureScope &ope) override { unary("cps", *ope.ope_); }
2560 void visit(Capture &ope) override { unary("cap", *ope.ope_); }
2561 void visit(TokenBoundary &ope) override { unary("tok", *ope.ope_); }
2562 void visit(Ignore &ope) override { unary("ign", *ope.ope_); }
2563 void visit(Whitespace &ope) override { unary("wsp", *ope.ope_); }
2564 void visit(Recovery &ope) override { unary("rec", *ope.ope_); }
2565 // A rule is named, never expanded — that is what keeps a recursive
2566 // grammar's signature finite. WeakHolder only ever wraps a Holder, so
2567 // descending through it lands on a name too.
2568 void visit(Holder &ope) override { s += "(hld " + ope.name() + ")"; }
2569 void visit(WeakHolder &ope) override {
2570 if (auto p = ope.weak_.lock()) {
2571 unary("wek", *p);
2572 } else {
2573 opaque(&ope);
2574 }
2575 }
2576 void visit(Reference &ope) override {
2577 s += "(ref " + ope.name_;
2578 for (auto &arg : ope.args_) {
2579 s += ' ';
2580 arg->accept(*this);
2581 }
2582 s += ')';
2583 }
2584 void visit(LiteralString &ope) override {
2585 s += "(lit " + std::to_string(ope.ignore_case_) + " " + ope.lit_ + ")";
2586 }
2587 void visit(CharacterClass &ope) override {
2588 s += "(cls " + std::to_string(ope.negated_) + " " +
2589 std::to_string(ope.ignore_case_);
2590 for (const auto &[lo, hi] : ope.ranges_) {
2591 s += " " + std::to_string(static_cast<uint32_t>(lo)) + "-" +
2592 std::to_string(static_cast<uint32_t>(hi));
2593 }
2594 s += ')';
2595 }
2596 void visit(Character &ope) override {
2597 s += "(chr " + std::to_string(static_cast<uint32_t>(ope.ch_)) + ")";
2598 }
2599 void visit(AnyCharacter &) override { s += "(any)"; }
2600 void visit(Dictionary &ope) override { opaque(&ope); }
2601 void visit(User &ope) override { opaque(&ope); }
2602 void visit(BackReference &ope) override { opaque(&ope); }
2603 void visit(PrecedenceClimbing &ope) override { opaque(&ope); }
2604 void visit(Cut &ope) override { opaque(&ope); }
2605
2606 static std::string get(Ope &ope) {
2607 OpeSignature vis;
2608 ope.accept(vis);
2609 return std::move(vis.s);
2610 }
2611
2612private:
2613 void group(const char *tag, const std::vector<std::shared_ptr<Ope>> &v) {
2614 s += '(';
2615 s += tag;
2616 for (const auto &op : v) {
2617 s += ' ';
2618 op->accept(*this);
2619 }
2620 s += ')';
2621 }
2622 void unary(const char *tag, Ope &inner) {
2623 s += '(';
2624 s += tag;
2625 wrap(inner);
2626 }
2627 void wrap(Ope &inner) {
2628 s += ' ';
2629 inner.accept(*this);
2630 s += ')';
2631 }
2632 void opaque(const void *p) {
2633 s += "(opq " + std::to_string(reinterpret_cast<std::uintptr_t>(p)) + ")";
2634 }
2635};
2636
2639
2640 HasEmptyElement(std::vector<std::pair<const char *, std::string>> &refs,
2641 std::unordered_map<std::string, bool> &has_error_cache)
2642 : refs_(refs), has_error_cache_(has_error_cache) {}
2643
2644 void visit(Sequence &ope) override;
2645 void visit(PrioritizedChoice &ope) override {
2646 for (const auto &op : ope.opes_) {
2647 op->accept(*this);
2648 if (is_empty) { return; }
2649 }
2650 }
2651 void visit(Repetition &ope) override {
2652 if (ope.min_ == 0) {
2653 set_error();
2654 } else {
2655 ope.ope_->accept(*this);
2656 }
2657 }
2658 void visit(AndPredicate &) override { set_error(); }
2659 void visit(NotPredicate &) override { set_error(); }
2660 void visit(LiteralString &ope) override {
2661 if (ope.lit_.empty()) { set_error(); }
2662 }
2663 void visit(Reference &ope) override;
2664
2665 bool is_empty = false;
2666 const char *error_s = nullptr;
2667 std::string error_name;
2668
2669private:
2670 void set_error() {
2671 is_empty = true;
2672 tie(error_s, error_name) = refs_.back();
2673 }
2674 std::vector<std::pair<const char *, std::string>> &refs_;
2675 std::unordered_map<std::string, bool> &has_error_cache_;
2676};
2677
2680
2681 DetectInfiniteLoop(const char *s, const std::string &name,
2682 std::vector<std::pair<const char *, std::string>> &refs,
2683 std::unordered_map<std::string, bool> &has_error_cache)
2684 : refs_(refs), has_error_cache_(has_error_cache) {
2685 refs_.emplace_back(s, name);
2686 }
2687
2688 DetectInfiniteLoop(std::vector<std::pair<const char *, std::string>> &refs,
2689 std::unordered_map<std::string, bool> &has_error_cache)
2690 : refs_(refs), has_error_cache_(has_error_cache) {}
2691
2692 void visit(Sequence &ope) override {
2693 for (const auto &op : ope.opes_) {
2694 op->accept(*this);
2695 if (has_error) { return; }
2696 }
2697 }
2698 void visit(PrioritizedChoice &ope) override {
2699 for (const auto &op : ope.opes_) {
2700 op->accept(*this);
2701 if (has_error) { return; }
2702 }
2703 }
2704 void visit(Repetition &ope) override {
2705 if (ope.max_ == std::numeric_limits<size_t>::max()) {
2707 ope.ope_->accept(vis);
2708 if (vis.is_empty) {
2709 has_error = true;
2710 error_s = vis.error_s;
2711 error_name = vis.error_name;
2712 }
2713 } else {
2714 ope.ope_->accept(*this);
2715 }
2716 }
2717 void visit(Reference &ope) override;
2718
2719 bool has_error = false;
2720 const char *error_s = nullptr;
2721 std::string error_name;
2722
2723private:
2724 std::vector<std::pair<const char *, std::string>> &refs_;
2725 std::unordered_map<std::string, bool> &has_error_cache_;
2726};
2727
2730
2732 const std::vector<std::string> &params)
2733 : grammar_(grammar), params_(params) {}
2734
2735 void visit(Reference &ope) override;
2736
2737 std::unordered_map<std::string, const char *> error_s;
2738 std::unordered_map<std::string, std::string> error_message;
2739 std::unordered_set<std::string> referenced;
2740
2741private:
2743 const std::vector<std::string> &params_;
2744};
2745
2748
2749 LinkReferences(Grammar &grammar, const std::vector<std::string> &params)
2750 : grammar_(grammar), params_(params) {}
2751
2752 void visit(Reference &ope) override;
2753
2754private:
2756 const std::vector<std::string> &params_;
2757};
2758
2760 using Ope::Visitor::visit;
2761
2762 FindReference(const std::vector<std::shared_ptr<Ope>> &args,
2763 const std::vector<std::string> &params)
2764 : args_(args), params_(params) {}
2765
2766 void visit(Sequence &ope) override {
2767 std::vector<std::shared_ptr<Ope>> opes;
2768 for (const auto &o : ope.opes_) {
2769 o->accept(*this);
2770 opes.emplace_back(std::move(found_ope));
2771 }
2772 found_ope = std::make_shared<Sequence>(opes);
2773 }
2774 void visit(PrioritizedChoice &ope) override {
2775 std::vector<std::shared_ptr<Ope>> opes;
2776 for (const auto &o : ope.opes_) {
2777 o->accept(*this);
2778 opes.emplace_back(std::move(found_ope));
2779 }
2780 found_ope = std::make_shared<PrioritizedChoice>(opes);
2781 }
2782 void visit(Repetition &ope) override {
2783 ope.ope_->accept(*this);
2784 found_ope = rep(found_ope, ope.min_, ope.max_);
2785 }
2786 void visit(AndPredicate &ope) override {
2787 ope.ope_->accept(*this);
2789 }
2790 void visit(NotPredicate &ope) override {
2791 ope.ope_->accept(*this);
2793 }
2794 void visit(Dictionary &ope) override { found_ope = ope.shared_from_this(); }
2795 void visit(LiteralString &ope) override {
2796 found_ope = ope.shared_from_this();
2797 }
2798 void visit(CharacterClass &ope) override {
2799 found_ope = ope.shared_from_this();
2800 }
2801 void visit(Character &ope) override { found_ope = ope.shared_from_this(); }
2802 void visit(AnyCharacter &ope) override { found_ope = ope.shared_from_this(); }
2803 void visit(CaptureScope &ope) override {
2804 ope.ope_->accept(*this);
2806 }
2807 void visit(Capture &ope) override {
2808 ope.ope_->accept(*this);
2810 }
2811 void visit(TokenBoundary &ope) override {
2812 ope.ope_->accept(*this);
2814 }
2815 void visit(Ignore &ope) override {
2816 ope.ope_->accept(*this);
2818 }
2819 void visit(WeakHolder &ope) override { ope.weak_.lock()->accept(*this); }
2820 void visit(Holder &ope) override { ope.ope_->accept(*this); }
2821 void visit(Reference &ope) override;
2822 void visit(Whitespace &ope) override {
2823 ope.ope_->accept(*this);
2825 }
2826 void visit(PrecedenceClimbing &ope) override {
2827 ope.atom_->accept(*this);
2829 }
2830 void visit(Recovery &ope) override {
2831 ope.ope_->accept(*this);
2833 }
2834 void visit(Cut &ope) override { found_ope = ope.shared_from_this(); }
2835
2836 std::shared_ptr<Ope> found_ope;
2837
2838private:
2839 const std::vector<std::shared_ptr<Ope>> &args_;
2840 const std::vector<std::string> &params_;
2841};
2842
2843/*
2844 * First-Set computation
2845 */
2848
2849 void visit(Sequence &ope) override {
2850 for (const auto &op : ope.opes_) {
2851 FirstSet element_fs;
2852 auto save = result_;
2853 result_ = FirstSet{};
2854 op->accept(*this);
2855 element_fs = result_;
2856 result_ = save;
2857 result_.chars |= element_fs.chars;
2858 if (element_fs.any_char) { result_.any_char = true; }
2859 if (!result_.first_literal) {
2860 result_.first_literal = element_fs.first_literal;
2861 }
2862 if (!result_.first_rule) { result_.first_rule = element_fs.first_rule; }
2863 if (!element_fs.can_be_empty) { return; }
2864 // This element can be empty, continue to next
2865 }
2866 result_.can_be_empty = true;
2867 }
2868 void visit(PrioritizedChoice &ope) override {
2869 auto save = result_;
2870 for (const auto &op : ope.opes_) {
2871 result_ = FirstSet{};
2872 op->accept(*this);
2873 save.merge(result_);
2874 }
2875 result_ = save;
2876 }
2877 void visit(Repetition &ope) override {
2878 ope.ope_->accept(*this);
2879 if (ope.min_ == 0) { result_.can_be_empty = true; }
2880 }
2881 void visit(AndPredicate &) override { result_.can_be_empty = true; }
2882 void visit(NotPredicate &) override { result_.can_be_empty = true; }
2883 void visit(Dictionary &ope) override {
2884 for (const auto &[key, info] : ope.trie_.dic_) {
2885 if (!key.empty()) {
2886 auto ch = static_cast<unsigned char>(key[0]);
2887 result_.chars.set(ch);
2888 if (ope.trie_.ignore_case_) {
2889 result_.chars.set(static_cast<unsigned char>(std::toupper(ch)));
2890 result_.chars.set(static_cast<unsigned char>(std::tolower(ch)));
2891 }
2892 }
2893 }
2894 }
2895 void visit(LiteralString &ope) override {
2896 if (ope.lit_.empty()) {
2897 result_.can_be_empty = true;
2898 } else {
2899 auto ch = static_cast<unsigned char>(ope.lit_[0]);
2900 result_.chars.set(ch);
2901 if (ope.ignore_case_) {
2902 result_.chars.set(static_cast<unsigned char>(std::toupper(ch)));
2903 result_.chars.set(static_cast<unsigned char>(std::tolower(ch)));
2904 }
2905 if (!result_.first_literal) { result_.first_literal = ope.lit_.c_str(); }
2906 }
2907 }
2908 void visit(CharacterClass &ope) override {
2909 for (const auto &range : ope.ranges_) {
2910 auto cp1 = range.first;
2911 auto cp2 = range.second;
2912 if (cp1 > 0x7F || cp2 > 0x7F) {
2913 // Non-ASCII range: conservative fallback
2914 result_.any_char = true;
2915 return;
2916 }
2917 for (auto cp = cp1; cp <= cp2; cp++) {
2918 auto ch = static_cast<unsigned char>(cp);
2919 result_.chars.set(ch);
2920 if (ope.ignore_case_) {
2921 result_.chars.set(static_cast<unsigned char>(std::toupper(ch)));
2922 result_.chars.set(static_cast<unsigned char>(std::tolower(ch)));
2923 }
2924 }
2925 }
2926 if (ope.negated_) {
2927 result_.chars.flip();
2928 result_.any_char = true; // negated class can match non-ASCII
2929 }
2930 }
2931 void visit(Character &ope) override {
2932 if (ope.ch_ > 0x7F) {
2933 result_.any_char = true;
2934 } else {
2935 result_.chars.set(static_cast<unsigned char>(ope.ch_));
2936 }
2937 }
2938 void visit(AnyCharacter &) override { result_.any_char = true; }
2939 void visit(User &) override { result_.any_char = true; }
2940 void visit(Reference &ope) override;
2941 void visit(BackReference &) override { result_.any_char = true; }
2942 void visit(Cut &) override { result_.can_be_empty = true; }
2943
2944 // Per-rule cache shared across a SetupFirstSets traversal. Without it,
2945 // every alternative of every PrioritizedChoice re-walks referenced
2946 // rules — O(refs^depth) work for grammars with many cross-references.
2947 // Only cycle-free rule computations are cached; results computed under
2948 // a cycle (left recursion) would be incomplete and unsafe to reuse from
2949 // a different call context.
2950 using FirstSetCache = std::unordered_map<const Definition *, FirstSet>;
2951
2952 explicit ComputeFirstSet(FirstSetCache &cache) : cache_(cache) {}
2953
2955
2956private:
2958 std::unordered_set<const Definition *> refs_;
2959 size_t cycle_count_ = 0;
2960};
2961
2964
2965 void visit(Sequence &ope) override;
2967
2968 void visit(PrioritizedChoice &ope) override {
2969 ope.first_sets_.clear();
2970 ope.first_sets_.reserve(ope.opes_.size());
2971 for (const auto &op : ope.opes_) {
2973 op->accept(cfs);
2974 ope.first_sets_.push_back(cfs.result_);
2975 }
2976 for (const auto &op : ope.opes_) {
2977 op->accept(*this);
2978 }
2979 }
2980 void visit(Repetition &ope) override {
2981 ope.ope_->accept(*this);
2982 // ISpan optimization: detect Repetition + ASCII CharacterClass
2983 auto cc = dynamic_cast<CharacterClass *>(ope.ope_.get());
2984 if (cc && cc->is_ascii_only()) { ope.span_bitset_ = &cc->ascii_bitset(); }
2985 }
2986 void visit(Reference &ope) override;
2987 void visit(Holder &ope) override;
2988
2989private:
2991 std::unordered_set<const Definition *> visited_rules_;
2992};
2993
2994/*
2995 * Keywords
2996 */
2997static const char *WHITESPACE_DEFINITION_NAME = "%whitespace";
2998static const char *WORD_DEFINITION_NAME = "%word";
2999static const char *RECOVER_DEFINITION_NAME = "%recover";
3000
3001/*
3002 * Definition
3003 */
3005public:
3006 struct Result {
3007 bool ret;
3009 size_t len;
3011 };
3012
3013 Definition() : holder_(std::make_shared<Holder>(this)) {}
3014
3015 Definition(const Definition &rhs) : name(rhs.name), holder_(rhs.holder_) {
3016 holder_->outer_ = this;
3017 }
3018
3019 Definition(const std::shared_ptr<Ope> &ope)
3020 : holder_(std::make_shared<Holder>(this)) {
3021 *this <= ope;
3022 }
3023
3024 operator std::shared_ptr<Ope>() {
3025 return std::make_shared<WeakHolder>(holder_);
3026 }
3027
3028 Definition &operator<=(const std::shared_ptr<Ope> &ope) {
3029 holder_->ope_ = ope;
3030 return *this;
3031 }
3032
3033 Result parse(const char *s, size_t n, const char *path = nullptr,
3034 Log log = nullptr,
3035 ErrorReporter error_reporter = nullptr) const {
3036 SemanticValues vs;
3037 std::any dt;
3038 return parse_core(s, n, vs, dt, path, log, error_reporter);
3039 }
3040
3041 Result parse(const char *s, const char *path = nullptr, Log log = nullptr,
3042 ErrorReporter error_reporter = nullptr) const {
3043 auto n = strlen(s);
3044 return parse(s, n, path, log, error_reporter);
3045 }
3046
3047 Result parse(const char *s, size_t n, std::any &dt,
3048 const char *path = nullptr, Log log = nullptr,
3049 ErrorReporter error_reporter = nullptr) const {
3050 SemanticValues vs;
3051 return parse_core(s, n, vs, dt, path, log, error_reporter);
3052 }
3053
3054 Result parse(const char *s, std::any &dt, const char *path = nullptr,
3055 Log log = nullptr,
3056 ErrorReporter error_reporter = nullptr) const {
3057 auto n = strlen(s);
3058 return parse(s, n, dt, path, log, error_reporter);
3059 }
3060
3061 template <typename T>
3062 Result parse_and_get_value(const char *s, size_t n, T &val,
3063 const char *path = nullptr, Log log = nullptr,
3064 ErrorReporter error_reporter = nullptr) const {
3065 SemanticValues vs;
3066 std::any dt;
3067 auto r = parse_core(s, n, vs, dt, path, log, error_reporter);
3068 if (r.ret && !vs.empty() && vs.front().has_value()) {
3069 val = std::any_cast<T>(vs[0]);
3070 }
3071 return r;
3072 }
3073
3074 template <typename T>
3075 Result parse_and_get_value(const char *s, T &val, const char *path = nullptr,
3076 Log log = nullptr,
3077 ErrorReporter error_reporter = nullptr) const {
3078 auto n = strlen(s);
3079 return parse_and_get_value(s, n, val, path, log, error_reporter);
3080 }
3081
3082 template <typename T>
3083 Result parse_and_get_value(const char *s, size_t n, std::any &dt, T &val,
3084 const char *path = nullptr, Log log = nullptr,
3085 ErrorReporter error_reporter = nullptr) const {
3086 SemanticValues vs;
3087 auto r = parse_core(s, n, vs, dt, path, log, error_reporter);
3088 if (r.ret && !vs.empty() && vs.front().has_value()) {
3089 val = std::any_cast<T>(vs[0]);
3090 }
3091 return r;
3092 }
3093
3094 template <typename T>
3095 Result parse_and_get_value(const char *s, std::any &dt, T &val,
3096 const char *path = nullptr, Log log = nullptr,
3097 ErrorReporter error_reporter = nullptr) const {
3098 auto n = strlen(s);
3099 return parse_and_get_value(s, n, dt, val, path, log, error_reporter);
3100 }
3101
3102#if defined(__cpp_lib_char8_t)
3103 Result parse(const char8_t *s, size_t n, const char *path = nullptr,
3104 Log log = nullptr) const {
3105 return parse(reinterpret_cast<const char *>(s), n, path, log);
3106 }
3107
3108 Result parse(const char8_t *s, const char *path = nullptr,
3109 Log log = nullptr) const {
3110 return parse(reinterpret_cast<const char *>(s), path, log);
3111 }
3112
3113 Result parse(const char8_t *s, size_t n, std::any &dt,
3114 const char *path = nullptr, Log log = nullptr) const {
3115 return parse(reinterpret_cast<const char *>(s), n, dt, path, log);
3116 }
3117
3118 Result parse(const char8_t *s, std::any &dt, const char *path = nullptr,
3119 Log log = nullptr) const {
3120 return parse(reinterpret_cast<const char *>(s), dt, path, log);
3121 }
3122
3123 template <typename T>
3124 Result parse_and_get_value(const char8_t *s, size_t n, T &val,
3125 const char *path = nullptr,
3126 Log log = nullptr) const {
3127 return parse_and_get_value(reinterpret_cast<const char *>(s), n, val, path,
3128 log);
3129 }
3130
3131 template <typename T>
3132 Result parse_and_get_value(const char8_t *s, T &val,
3133 const char *path = nullptr,
3134 Log log = nullptr) const {
3135 return parse_and_get_value(reinterpret_cast<const char *>(s), val, path,
3136 log);
3137 }
3138
3139 template <typename T>
3140 Result parse_and_get_value(const char8_t *s, size_t n, std::any &dt, T &val,
3141 const char *path = nullptr,
3142 Log log = nullptr) const {
3143 return parse_and_get_value(reinterpret_cast<const char *>(s), n, dt, val,
3144 path, log);
3145 }
3146
3147 template <typename T>
3148 Result parse_and_get_value(const char8_t *s, std::any &dt, T &val,
3149 const char *path = nullptr,
3150 Log log = nullptr) const {
3151 return parse_and_get_value(reinterpret_cast<const char *>(s), dt, val, path,
3152 log);
3153 }
3154#endif
3155
3156 void operator=(Action a) { action = a; }
3157
3158 template <typename T> Definition &operator,(T fn) {
3159 operator=(fn);
3160 return *this;
3161 }
3162
3164 ignoreSemanticValue = true;
3165 return *this;
3166 }
3167
3168 void accept(Ope::Visitor &v) { holder_->accept(v); }
3169
3170 std::shared_ptr<Ope> get_core_operator() const { return holder_->ope_; }
3171
3172 bool is_token() const {
3173 std::call_once(is_token_init_, [this]() {
3175 });
3176 return is_token_;
3177 }
3178
3179 std::string name;
3180 const char *s_ = nullptr;
3181 std::pair<size_t, size_t> line_ = {1, 1};
3182
3184
3185 size_t id = 0;
3187 std::function<void(const Context &c, const char *s, size_t n, std::any &dt)>
3189 std::function<void(const Context &c, const char *s, size_t n, size_t matchlen,
3190 std::any &value, std::any &dt)>
3193 std::shared_ptr<Ope> whitespaceOpe;
3194 std::shared_ptr<Ope> wordOpe;
3196 bool is_macro = false;
3197 std::vector<std::string> params;
3198 bool disable_action = false;
3199 bool is_left_recursive = false;
3200 bool can_be_empty = false;
3201
3204 bool verbose_trace = false;
3207
3208 std::string error_message;
3209 bool no_ast_opt = false;
3210 bool no_whitespace = false; // Disable %whitespace skipping inside this rule
3211 // (like a token boundary, without capturing)
3212 std::string ast_name; // When non-empty, AST nodes produced by this rule carry
3213 // this name/tag instead of the rule's own name
3214
3215 bool eoi_check = true;
3216
3217 // Per-rule packrat stats (optional, for profiling)
3218 mutable bool collect_packrat_stats = false;
3219 mutable std::vector<Context::PackratStats> packrat_stats_;
3220
3221private:
3222 friend class Reference;
3223 friend class ParserGenerator;
3224
3227
3229 std::call_once(definition_ids_init_, [&]() {
3231 holder_->accept(vis);
3232 if (whitespaceOpe) { whitespaceOpe->accept(vis); }
3233 if (wordOpe) { wordOpe->accept(vis); }
3234 definition_ids_.swap(vis.ids);
3235 });
3236 }
3237
3238 void initialize_packrat_filter() const;
3239
3240 Result parse_core(const char *s, size_t n, SemanticValues &vs, std::any &dt,
3241 const char *path, Log log,
3242 ErrorReporter error_reporter = nullptr) const {
3244
3245 std::shared_ptr<Ope> ope = holder_;
3246
3247 std::any trace_data;
3248 if (tracer_start) { tracer_start(trace_data); }
3249 auto se = scope_exit([&]() {
3250 if (tracer_end) { tracer_end(trace_data); }
3251 });
3252
3253 const std::vector<int32_t> *packrat_index = nullptr;
3254 size_t packrat_cached_count = 0;
3257 if (!packrat_index_.empty()) {
3258 packrat_index = &packrat_index_;
3259 packrat_cached_count = packrat_cached_count_;
3260 } else {
3261 packrat_cached_count = definition_ids_.size();
3262 }
3263 }
3264
3265 Context c(path, s, n, definition_ids_.size(), whitespaceOpe, wordOpe,
3267 verbose_trace, log, error_reporter, packrat_index,
3268 packrat_cached_count);
3269
3271 packrat_stats_.resize(definition_ids_.size());
3273 }
3274
3275 size_t i = 0;
3276
3277 if (whitespaceOpe) {
3278 auto save_ignore_trace_state = c.ignore_trace_state;
3280 auto se =
3281 scope_exit([&]() { c.ignore_trace_state = save_ignore_trace_state; });
3282
3283 auto len = whitespaceOpe->parse(s, n, vs, c, dt);
3284 if (fail(len)) { return Result{false, c.recovered, i, c.error_info}; }
3285
3286 i = len;
3287 }
3288
3289 auto len = ope->parse(s + i, n - i, vs, c, dt);
3290 auto ret = success(len);
3291 if (ret) {
3292 i += len;
3293 if (eoi_check) {
3294 if (i < n) {
3295 if (c.error_info.error_pos - c.s < s + i - c.s) {
3296 c.error_info.message_pos = s + i;
3297 c.error_info.message = "expected end of input";
3298 }
3299 ret = false;
3300 }
3301 }
3302 }
3303 return Result{ret, c.recovered, i, c.error_info};
3304 }
3305
3306 std::shared_ptr<Holder> holder_;
3307 mutable std::once_flag is_token_init_;
3308 mutable bool is_token_ = false;
3309 mutable std::once_flag assign_id_to_definition_init_;
3310 mutable std::once_flag definition_ids_init_;
3311 mutable std::unordered_map<void *, size_t> definition_ids_;
3312 mutable std::once_flag packrat_filter_init_;
3313 mutable std::vector<int32_t> packrat_index_; // def_id -> cache slot or -1
3314 mutable size_t packrat_cached_count_ = 0;
3315};
3316
3317/*
3318 * Implementations
3319 */
3320
3321inline size_t parse_literal(const char *s, size_t n, SemanticValues &vs,
3322 Context &c, std::any &dt, const std::string &lit,
3323 std::once_flag &init_is_word, bool &is_word,
3324 bool ignore_case, const std::string &lower_lit) {
3325 size_t i = 0;
3326 for (; i < lit.size(); i++) {
3327 if (i >= n ||
3328 (ignore_case
3329 ? (static_cast<char>(
3330 c.tolower_table[static_cast<unsigned char>(s[i])]) !=
3331 lower_lit[i])
3332 : (s[i] != lit[i]))) {
3333 c.set_error_pos(s, lit.data());
3334 return static_cast<size_t>(-1);
3335 }
3336 }
3337
3338 // Word check
3339 if (c.wordOpe) {
3340 auto save_ignore_trace_state = c.ignore_trace_state;
3342 auto se =
3343 scope_exit([&]() { c.ignore_trace_state = save_ignore_trace_state; });
3344
3345 std::call_once(init_is_word, [&]() {
3346 SemanticValues dummy_vs;
3347 Context dummy_c(nullptr, c.s, c.l, 0, nullptr, nullptr, false, nullptr,
3348 nullptr, nullptr, false, nullptr);
3349 std::any dummy_dt;
3350
3351 auto len =
3352 c.wordOpe->parse(lit.data(), lit.size(), dummy_vs, dummy_c, dummy_dt);
3353 is_word = success(len);
3354 });
3355
3356 if (is_word) {
3357 SemanticValues dummy_vs;
3358 Context dummy_c(nullptr, c.s, c.l, 0, nullptr, nullptr, false, nullptr,
3359 nullptr, nullptr, false, nullptr);
3360 std::any dummy_dt;
3361
3362 NotPredicate ope(c.wordOpe);
3363 auto len = ope.parse(s + i, n - i, dummy_vs, dummy_c, dummy_dt);
3364 if (fail(len)) {
3365 c.set_error_pos(s, lit.data());
3366 return len;
3367 }
3368 i += len;
3369 }
3370 }
3371
3372 // Skip whitespace
3373 auto wl = c.skip_whitespace(s + i, n - i, vs, dt);
3374 if (fail(wl)) { return wl; }
3375 i += wl;
3376
3377 return i;
3378}
3379
3380inline std::pair<size_t, size_t> SemanticValues::line_info() const {
3381 assert(c_);
3382 return c_->line_info(sv_.data());
3383}
3384
3385inline void ErrorInfo::output_log(const Log &log, const ErrorReporter &reporter,
3386 const char *s, size_t n) {
3387 if (message_pos) {
3390 auto line = line_info(s, message_pos);
3391 std::string msg;
3392 auto unexpected_token = heuristic_error_token(s, n, message_pos);
3393 if (!unexpected_token.empty()) {
3394 msg = replace_all(message, "%t", unexpected_token);
3395
3396 auto unexpected_char = unexpected_token.substr(
3397 0,
3398 codepoint_length(unexpected_token.data(), unexpected_token.size()));
3399
3400 msg = replace_all(msg, "%c", unexpected_char);
3401 } else {
3402 msg = message;
3403 }
3404 if (reporter) {
3405 ErrorReport report;
3406 report.line = line.first;
3407 report.col = line.second;
3408 report.position = static_cast<size_t>(message_pos - s);
3409 report.unexpected_token = unexpected_token;
3410 report.message = msg;
3411 report.label = label;
3412 reporter(report);
3413 }
3414 if (log) { log(line.first, line.second, msg, label); }
3415 }
3416 } else if (error_pos) {
3417 if (error_pos > last_output_pos) {
3419 auto line = line_info(s, error_pos);
3420
3421 ErrorReport report;
3422 report.line = line.first;
3423 report.col = line.second;
3424 report.position = static_cast<size_t>(error_pos - s);
3425
3426 std::string msg;
3427 if (expected_tokens.empty()) {
3428 msg = "syntax error.";
3429 } else {
3430 msg = "syntax error";
3431
3432 // unexpected token
3433 if (auto unexpected_token = heuristic_error_token(s, n, error_pos);
3434 !unexpected_token.empty()) {
3435 msg += ", unexpected '";
3436 msg += unexpected_token;
3437 msg += "'";
3438 report.unexpected_token = unexpected_token;
3439 }
3440
3441 auto first_item = true;
3442 size_t i = 0;
3443 while (i < expected_tokens.size()) {
3444 auto [error_literal, error_rule] = expected_tokens[i];
3445
3446 // Skip rules start with '_'
3447 if (!(error_rule && error_rule->name[0] == '_')) {
3448 msg += (first_item ? ", expecting " : ", ");
3449 if (error_literal) {
3450 msg += "'";
3451 msg += error_literal;
3452 msg += "'";
3453 report.expected_literals.emplace_back(error_literal);
3454 } else {
3455 msg += "<" + error_rule->name + ">";
3456 if (label.empty()) { label = error_rule->name; }
3457 report.expected_rules.emplace_back(error_rule->name);
3458 }
3459 first_item = false;
3460 }
3461
3462 i++;
3463 }
3464 msg += ".";
3465 }
3466 if (reporter) {
3467 report.label = label;
3468 reporter(report);
3469 }
3470 if (log) { log(line.first, line.second, msg, label); }
3471 }
3472 }
3473}
3474
3475inline size_t Context::skip_whitespace(const char *a_s, size_t n,
3476 SemanticValues &vs, std::any &dt) {
3477 if (in_token_boundary_count || !whitespaceOpe) { return 0; }
3478 auto save = ignore_trace_state;
3480 auto se = scope_exit([&]() { ignore_trace_state = save; });
3481 return whitespaceOpe->parse(a_s, n, vs, *this, dt);
3482}
3483
3484inline void Context::set_error_pos(const char *a_s, const char *literal) {
3485 if (log || error_reporter) {
3486 if (error_info.error_pos <= a_s) {
3487 if (error_info.error_pos < a_s || !error_info.keep_previous_token) {
3488 error_info.error_pos = a_s;
3489 error_info.expected_tokens.clear();
3490 }
3491
3492 const char *error_literal = nullptr;
3493 const Definition *error_rule = nullptr;
3494
3495 if (literal) {
3496 error_literal = literal;
3497 } else if (!rule_stack.empty()) {
3498 auto rule = rule_stack.back();
3499 auto ope = rule->get_core_operator();
3500 if (auto token = FindLiteralToken::token(*ope);
3501 token && token[0] != '\0') {
3502 error_literal = token;
3503 }
3504 }
3505
3506 for (auto r : rule_stack) {
3507 error_rule = r;
3508 if (r->is_token()) { break; }
3509 }
3510
3511 if (error_literal || error_rule) {
3512 error_info.add(error_literal, error_rule);
3513 }
3514 }
3515 }
3516}
3517
3518inline void Context::trace_enter(const Ope &ope, const char *a_s, size_t n,
3519 const SemanticValues &vs, std::any &dt) {
3520 trace_ids.push_back(next_trace_id++);
3521 tracer_enter(ope, a_s, n, vs, *this, dt, trace_data);
3522}
3523
3524inline void Context::trace_leave(const Ope &ope, const char *a_s, size_t n,
3525 const SemanticValues &vs, std::any &dt,
3526 size_t len) {
3527 tracer_leave(ope, a_s, n, vs, *this, dt, len, trace_data);
3528 trace_ids.pop_back();
3529}
3530
3531inline bool Context::is_traceable(const Ope &ope) const {
3532 if (has_tracer) {
3533 if (ignore_trace_state) { return false; }
3534 return !dynamic_cast<const peg::Reference *>(&ope);
3535 }
3536 return false;
3537}
3538
3539inline size_t Ope::parse(const char *s, size_t n, SemanticValues &vs,
3540 Context &c, std::any &dt) const {
3541 if (c.is_traceable(*this)) {
3542 c.trace_enter(*this, s, n, vs, dt);
3543 auto len = parse_core(s, n, vs, c, dt);
3544 c.trace_leave(*this, s, n, vs, dt, len);
3545 return len;
3546 }
3547 return parse_core(s, n, vs, c, dt);
3548}
3549
3550inline size_t Dictionary::parse_core(const char *s, size_t n,
3551 SemanticValues &vs, Context &c,
3552 std::any &dt) const {
3553 size_t id;
3554 auto i = trie_.match(s, n, id);
3555
3556 if (i == 0) {
3557 c.set_error_pos(s);
3558 return static_cast<size_t>(-1);
3559 }
3560
3561 vs.choice_count_ = trie_.items_count();
3562 vs.choice_ = id;
3563
3564 // Word check
3565 if (c.wordOpe) {
3566 auto save_ignore_trace_state = c.ignore_trace_state;
3568 auto se =
3569 scope_exit([&]() { c.ignore_trace_state = save_ignore_trace_state; });
3570
3571 {
3572 SemanticValues dummy_vs;
3573 Context dummy_c(nullptr, c.s, c.l, 0, nullptr, nullptr, false, nullptr,
3574 nullptr, nullptr, false, nullptr);
3575 std::any dummy_dt;
3576
3577 NotPredicate ope(c.wordOpe);
3578 auto len = ope.parse(s + i, n - i, dummy_vs, dummy_c, dummy_dt);
3579 if (fail(len)) {
3580 c.set_error_pos(s);
3581 return len;
3582 }
3583 i += len;
3584 }
3585 }
3586
3587 // Skip whitespace
3588 auto wl = c.skip_whitespace(s + i, n - i, vs, dt);
3589 if (fail(wl)) { return wl; }
3590 i += wl;
3591
3592 return i;
3593}
3594
3595inline size_t LiteralString::parse_core(const char *s, size_t n,
3596 SemanticValues &vs, Context &c,
3597 std::any &dt) const {
3598 return parse_literal(s, n, vs, c, dt, lit_, init_is_word_, is_word_,
3600}
3601
3602inline size_t TokenBoundary::parse_core(const char *s, size_t n,
3603 SemanticValues &vs, Context &c,
3604 std::any &dt) const {
3605 auto save_ignore_trace_state = c.ignore_trace_state;
3607 auto se =
3608 scope_exit([&]() { c.ignore_trace_state = save_ignore_trace_state; });
3609
3610 size_t len;
3611 {
3613 auto se = scope_exit([&]() { c.in_token_boundary_count--; });
3614 len = ope_->parse(s, n, vs, c, dt);
3615 }
3616
3617 if (success(len)) {
3618 vs.tokens.emplace_back(std::string_view(s, len));
3619
3620 auto wl = c.skip_whitespace(s + len, n - len, vs, dt);
3621 if (fail(wl)) { return wl; }
3622 len += wl;
3623 }
3624 return len;
3625}
3626
3627// Resolve `%{name}` placeholders in a custom error message against the
3628// named captures recorded so far ($name<...>). Unknown names resolve to an
3629// empty string. `%t` / `%c` are resolved later, at log-output time.
3630inline std::string resolve_capture_placeholders(const std::string &msg,
3631 const Context &c) {
3632 auto pos = msg.find("%{");
3633 if (pos == std::string::npos) { return msg; }
3634
3635 std::string r;
3636 size_t i = 0;
3637 while (pos != std::string::npos) {
3638 auto end = msg.find('}', pos + 2);
3639 if (end == std::string::npos) { break; }
3640 r.append(msg, i, pos - i);
3641 auto name = std::string_view(msg).substr(pos + 2, end - (pos + 2));
3642 for (auto it = c.capture_entries.rbegin(); it != c.capture_entries.rend();
3643 ++it) {
3644 if (it->first == name) {
3645 // The captured span can include whitespace skipped after a token
3646 // boundary; trim it for display.
3647 auto v = std::string_view(it->second);
3648 while (!v.empty() &&
3649 std::isspace(static_cast<unsigned char>(v.back()))) {
3650 v.remove_suffix(1);
3651 }
3652 while (!v.empty() &&
3653 std::isspace(static_cast<unsigned char>(v.front()))) {
3654 v.remove_prefix(1);
3655 }
3656 r += v;
3657 break;
3658 }
3659 }
3660 i = end + 1;
3661 pos = msg.find("%{", i);
3662 }
3663 r.append(msg, i, msg.size() - i);
3664 return r;
3665}
3666
3667inline size_t Holder::parse_core(const char *s, size_t n, SemanticValues &vs,
3668 Context &c, std::any &dt) const {
3669 if (!ope_) {
3670 throw std::logic_error("Uninitialized definition ope was used...");
3671 }
3672
3673 // Macro reference. A left-recursive macro cannot take this path: it needs
3674 // the seed-growing below, which in turn needs its own semantic value scope
3675 // to memoise. Such a macro forms a scope like a plain rule does.
3676 if (outer_->is_macro && !outer_->is_left_recursive) {
3677 c.rule_stack.push_back(outer_);
3678 auto len = ope_->parse(s, n, vs, c, dt);
3679 c.rule_stack.pop_back();
3680 return len;
3681 }
3682
3683 size_t len;
3684 std::any val;
3685
3686 // Shared parse body: invokes enter/leave callbacks, parses the rule's
3687 // operator, handles actions/predicates/errors, and calls reduce.
3688 // Returns {parse_len, parse_val}.
3689 auto do_parse = [&]() {
3690 size_t parse_len;
3691 std::any parse_val;
3692
3693 if (outer_->enter) { outer_->enter(c, s, n, dt); }
3694 auto &chvs = c.push_semantic_values_scope();
3695 auto se = scope_exit([&]() {
3697 if (outer_->leave) { outer_->leave(c, s, n, parse_len, parse_val, dt); }
3698 });
3699
3700 c.rule_stack.push_back(outer_);
3701 if (outer_->no_whitespace) {
3702 {
3704 auto se2 = scope_exit([&]() { c.in_token_boundary_count--; });
3705 parse_len = ope_->parse(s, n, chvs, c, dt);
3706 }
3707 if (success(parse_len)) {
3708 auto wl = c.skip_whitespace(s + parse_len, n - parse_len, chvs, dt);
3709 if (fail(wl)) {
3710 parse_len = wl;
3711 } else {
3712 parse_len += wl;
3713 }
3714 }
3715 } else {
3716 parse_len = ope_->parse(s, n, chvs, c, dt);
3717 }
3718 c.rule_stack.pop_back();
3719
3720 if (success(parse_len)) {
3721 chvs.sv_ = std::string_view(s, parse_len);
3722 chvs.name_ = outer_->name;
3723
3724 auto ope_ptr = ope_.get();
3725 if (ope_ptr->is_token_boundary) {
3726 ope_ptr = static_cast<const peg::TokenBoundary *>(ope_ptr)->ope_.get();
3727 }
3728 if (!ope_ptr->is_choice_like) {
3729 chvs.choice_count_ = 0;
3730 chvs.choice_ = 0;
3731 }
3732
3733 std::string msg;
3734 std::any predicate_data;
3735 if (outer_->predicate) {
3736 if (!outer_->predicate(chvs, dt, msg, predicate_data)) {
3737 if ((c.log || c.error_reporter) && !msg.empty() &&
3738 c.error_info.message_pos < s) {
3739 c.error_info.message_pos = s;
3740 c.error_info.message = msg;
3741 c.error_info.label = outer_->name;
3742 }
3743 parse_len = static_cast<size_t>(-1);
3744 }
3745 }
3746
3747 if (success(parse_len)) {
3748 if (!c.recovered) { parse_val = reduce(chvs, dt, predicate_data); }
3749 } else {
3750 if ((c.log || c.error_reporter) && !msg.empty() &&
3751 c.error_info.message_pos < s) {
3752 c.error_info.message_pos = s;
3753 c.error_info.message = msg;
3754 c.error_info.label = outer_->name;
3755 }
3756 }
3757 } else {
3758 if ((c.log || c.error_reporter) && !outer_->error_message.empty() &&
3759 c.error_info.message_pos < s) {
3760 c.error_info.message_pos = s;
3762 resolve_capture_placeholders(outer_->error_message, c);
3763 c.error_info.label = outer_->name;
3764 }
3765 }
3766
3767 return std::make_pair(parse_len, std::move(parse_val));
3768 };
3769
3770 if (outer_->is_left_recursive) {
3771 // A macro grows one seed per instantiation: Sum(D) and Sum(L) are
3772 // different rules as far as the memo is concerned.
3773 auto lr_rule = Context::LRRule(outer_, c.top_macro_inst());
3774 auto lr_key = Context::LRKey(lr_rule, s);
3775
3776 // Check LR memo first
3777 auto it = c.lr_memo.find(lr_key);
3778 if (it != c.lr_memo.end()) {
3779 if (success(it->second.len)) {
3780 len = it->second.len;
3781 val = it->second.val;
3782 } else {
3783 len = static_cast<size_t>(-1);
3784 }
3785 // Record that this rule's lr_memo was accessed.
3786 // Any LR rule currently seeding will know we're in its cycle.
3787 c.lr_refs_hit.insert(lr_rule);
3788 } else {
3789 // Seed with FAIL
3790 c.lr_memo[lr_key] = {static_cast<size_t>(-1), {}};
3791
3792 // Mark as active seed (protects our lr_memo from inner growers)
3793 c.lr_active_seeds.insert(lr_key);
3794 auto seed_guard = scope_exit([&]() { c.lr_active_seeds.erase(lr_key); });
3795
3796 // Track which LR rules are referenced during our parse
3797 // to identify cycle members
3798 auto saved_refs = std::move(c.lr_refs_hit);
3799 c.lr_refs_hit.clear();
3800
3801 // Initial parse (self-references will hit the FAIL seed)
3802 auto [initial_len, initial_val] = do_parse();
3803
3804 // Rules whose lr_memo was hit during our parse are in our cycle.
3805 // If we detected cycle members, we ourselves are also part of
3806 // the cycle, so add self — this lets parent seeders see us as
3807 // a transitive cycle member.
3808 auto cycle_rules = c.lr_refs_hit;
3809 if (!cycle_rules.empty()) { cycle_rules.insert(lr_rule); }
3810
3811 // Restore parent's refs and propagate cycle info upward
3812 c.lr_refs_hit = std::move(saved_refs);
3813 c.lr_refs_hit.insert(cycle_rules.begin(), cycle_rules.end());
3814
3815 if (!success(initial_len)) {
3816 // Keep FAIL in lr_memo so we don't re-seed
3817 len = static_cast<size_t>(-1);
3818 } else {
3819 // Got initial seed, now grow
3820 len = initial_len;
3821 val = std::move(initial_val);
3822 c.lr_memo[lr_key] = {len, val};
3823
3824 while (true) {
3825 // Clear this rule's packrat cache. A macro is never written there
3826 // (that cache is keyed by rule id alone, which cannot tell two
3827 // instantiations apart), so there is nothing to clear for one.
3828 if (!outer_->is_macro) { c.clear_packrat_cache(s, outer_->id); }
3829
3830 // Clear lr_memo for cycle-dependent rules at this position,
3831 // but NOT for rules currently in their own seeding phase
3832 // (lr_active_seeds) — those are outer growers we must not
3833 // interfere with.
3834 for (auto memo_it = c.lr_memo.begin(); memo_it != c.lr_memo.end();) {
3835 if (memo_it->first.second == s && memo_it->first.first != lr_rule &&
3836 cycle_rules.count(memo_it->first.first) &&
3837 !c.lr_active_seeds.count(memo_it->first)) {
3838 memo_it = c.lr_memo.erase(memo_it);
3839 } else {
3840 ++memo_it;
3841 }
3842 }
3843
3844 auto [new_len, new_val] = do_parse();
3845
3846 if (!success(new_len) || new_len <= len) {
3847 break; // No improvement, done growing
3848 }
3849
3850 len = new_len;
3851 val = std::move(new_val);
3852 c.lr_memo[lr_key] = {len, val};
3853 }
3854 }
3855
3856 // Write final result to packrat cache (lr_memo entry is kept as
3857 // the primary lookup for LR rules at this position)
3858 if (success(len) && !outer_->is_macro) {
3859 c.write_packrat_cache(s, outer_->id, len, val);
3860 }
3861 }
3862 } else {
3863 if (c.enablePackratParsing) {
3864 // Packrat cache acts as re-entry guard (pre-registered as
3865 // failure before fn is called).
3866 c.packrat(s, outer_->id, len, val, [&](std::any &a_val) {
3867 auto [parse_len, parse_val] = do_parse();
3868 len = parse_len;
3869 if (success(len)) { a_val = std::move(parse_val); }
3870 });
3871 } else {
3872 // Without packrat, use lr_memo as re-entry guard to prevent
3873 // stack overflow from undetected left recursion.
3874 auto guard_key = Context::LRKey({outer_, c.top_macro_inst()}, s);
3875 if (c.lr_memo.count(guard_key)) {
3876 len = static_cast<size_t>(-1);
3877 } else {
3878 c.lr_memo[guard_key] = {static_cast<size_t>(-1), {}};
3879 auto [parse_len, parse_val] = do_parse();
3880 len = parse_len;
3881 val = std::move(parse_val);
3882 c.lr_memo.erase(guard_key);
3883 }
3884 }
3885 }
3886
3887 if (success(len)) {
3888 if (!outer_->ignoreSemanticValue) {
3889 vs.emplace_back(std::move(val));
3890 vs.tags.emplace_back(str2tag(outer_->name));
3891 }
3892 }
3893
3894 return len;
3895}
3896
3897inline std::any Holder::reduce(SemanticValues &vs, std::any &dt,
3898 const std::any &predicate_data) const {
3899 if (outer_->action && !outer_->disable_action) {
3900 return outer_->action(vs, dt, predicate_data);
3901 } else if (vs.empty()) {
3902 return std::any();
3903 } else {
3904 return std::move(vs.front());
3905 }
3906}
3907
3908inline const std::string &Holder::name() const { return outer_->name; }
3909
3910inline const std::string &Holder::trace_name() const {
3911 std::call_once(trace_name_init_,
3912 [this]() { trace_name_ = "[" + outer_->name + "]"; });
3913 return trace_name_;
3914}
3915
3916// Key a macro instantiation by what each argument denotes rather than by the
3917// node that spells it: `M(N)` written at two call sites builds two Reference
3918// nodes for the same rule N, and those are the same instantiation.
3919inline std::vector<const void *>
3921 const std::vector<std::shared_ptr<Ope>> &args) {
3922 std::vector<const void *> key;
3923 key.reserve(args.size() + 1);
3924 key.push_back(def);
3925 for (const auto &arg : args) {
3926 auto ref = dynamic_cast<Reference *>(arg.get());
3927 key.push_back(ref && ref->rule_ ? static_cast<const void *>(ref->rule_)
3928 : static_cast<const void *>(arg.get()));
3929 }
3930 return key;
3931}
3932
3933inline size_t Reference::parse_core(const char *s, size_t n, SemanticValues &vs,
3934 Context &c, std::any &dt) const {
3935 auto save_ignore_trace_state = c.ignore_trace_state;
3936 if (rule_ && rule_->ignoreSemanticValue) {
3938 }
3939 auto se =
3940 scope_exit([&]() { c.ignore_trace_state = save_ignore_trace_state; });
3941
3942 if (rule_) {
3943 // Reference rule
3944 if (rule_->is_macro) {
3945 // Macro
3946 FindReference vis(c.top_args(), c.rule_stack.back()->params);
3947
3948 // Collect arguments
3949 std::vector<std::shared_ptr<Ope>> args;
3950 for (const auto &arg : args_) {
3951 arg->accept(vis);
3952 args.emplace_back(std::move(vis.found_ope));
3953 }
3954
3955 auto inst = rule_->is_left_recursive
3957 : 0;
3958 c.push_args(std::move(args), inst);
3959 auto se = scope_exit([&]() { c.pop_args(); });
3960 return rule_->holder_->parse(s, n, vs, c, dt);
3961 } else {
3962 // Definition
3963 c.push_args(std::vector<std::shared_ptr<Ope>>());
3964 auto se2 = scope_exit([&]() { c.pop_args(); });
3965 return rule_->holder_->parse(s, n, vs, c, dt);
3966 }
3967 } else {
3968 // Reference parameter in macro
3969 const auto &args = c.top_args();
3970 return args[iarg_]->parse(s, n, vs, c, dt);
3971 }
3972}
3973
3974inline std::shared_ptr<Ope> Reference::get_core_operator() const {
3975 return rule_->holder_;
3976}
3977
3978inline size_t BackReference::parse_core(const char *s, size_t n,
3979 SemanticValues &vs, Context &c,
3980 std::any &dt) const {
3981 for (auto it = c.capture_entries.rbegin(); it != c.capture_entries.rend();
3982 ++it) {
3983 if (it->first == name_) {
3984 const auto &lit = it->second;
3985 std::once_flag init_is_word;
3986 auto is_word = false;
3987 static const std::string empty;
3988 return parse_literal(s, n, vs, c, dt, lit, init_is_word, is_word, false,
3989 empty);
3990 }
3991 }
3992
3993 c.error_info.message_pos = s;
3994 c.error_info.message = "undefined back reference '$" + name_ + "'...";
3995 return static_cast<size_t>(-1);
3996}
3997
3998inline Definition &
4000 if (rule_.is_macro) {
4001 // Reference parameter in macro
4002 const auto &args = c.top_args();
4003 auto iarg = dynamic_cast<Reference &>(*binop_).iarg_;
4004 auto arg = args[iarg];
4005 return *dynamic_cast<Reference &>(*arg).rule_;
4006 }
4007
4008 return *dynamic_cast<Reference &>(*binop_).rule_;
4009}
4010
4011inline size_t PrecedenceClimbing::parse_expression(const char *s, size_t n,
4012 SemanticValues &vs,
4013 Context &c, std::any &dt,
4014 size_t min_prec) const {
4015 auto len = atom_->parse(s, n, vs, c, dt);
4016 if (fail(len)) { return len; }
4017
4018 std::string tok;
4019 auto &rule = get_reference_for_binop(c);
4020 auto action = std::move(rule.action);
4021
4022 rule.action = [&](SemanticValues &vs2, std::any &dt2,
4023 const std::any &predicate_data2) {
4024 tok = vs2.token();
4025 if (action) {
4026 return action(vs2, dt2, predicate_data2);
4027 } else if (!vs2.empty()) {
4028 return vs2[0];
4029 }
4030 return std::any();
4031 };
4032 auto action_se = scope_exit([&]() { rule.action = std::move(action); });
4033
4034 auto i = len;
4035 while (i < n) {
4036 std::vector<std::any> save_values(vs.begin(), vs.end());
4037 auto save_tokens = vs.tokens;
4038
4039 auto chvs = c.push_semantic_values_scope();
4040 auto chlen = binop_->parse(s + i, n - i, chvs, c, dt);
4042
4043 if (fail(chlen)) { break; }
4044
4045 auto it = info_.find(tok);
4046 if (it == info_.end()) { break; }
4047
4048 auto level = std::get<0>(it->second);
4049 auto assoc = std::get<1>(it->second);
4050
4051 if (level < min_prec) { break; }
4052
4053 vs.emplace_back(std::move(chvs[0]));
4054 i += chlen;
4055
4056 auto next_min_prec = level;
4057 if (assoc == 'L') { next_min_prec = level + 1; }
4058
4059 chvs = c.push_semantic_values_scope();
4060 chlen = parse_expression(s + i, n - i, chvs, c, dt, next_min_prec);
4062
4063 if (fail(chlen)) {
4064 vs.assign(save_values.begin(), save_values.end());
4065 vs.tokens = save_tokens;
4066 i = chlen;
4067 break;
4068 }
4069
4070 vs.emplace_back(std::move(chvs[0]));
4071 i += chlen;
4072
4073 std::any val;
4074 if (rule_.action) {
4075 vs.sv_ = std::string_view(s, i);
4076 static const std::any empty_predicate_data;
4077 val = rule_.action(vs, dt, empty_predicate_data);
4078 } else if (!vs.empty()) {
4079 val = vs[0];
4080 }
4081 vs.clear();
4082 vs.emplace_back(std::move(val));
4083 }
4084
4085 return i;
4086}
4087
4088inline size_t Recovery::parse_core(const char *s, size_t n,
4089 SemanticValues & /*vs*/, Context &c,
4090 std::any & /*dt*/) const {
4091 const auto &rule = dynamic_cast<Reference &>(*ope_);
4092
4093 // Custom error message
4094 if (c.log || c.error_reporter) {
4095 auto label = dynamic_cast<Reference *>(rule.args_[0].get());
4096 if (label && !label->rule_->error_message.empty()) {
4097 c.error_info.message_pos = s;
4099 resolve_capture_placeholders(label->rule_->error_message, c);
4100 c.error_info.label = label->rule_->name;
4101 }
4102 }
4103
4104 // Recovery
4105 auto len = static_cast<size_t>(-1);
4106 {
4107 auto save_log = c.log;
4108 auto save_reporter = c.error_reporter;
4109 c.log = nullptr;
4110 c.error_reporter = nullptr;
4111 auto se = scope_exit([&]() {
4112 c.log = save_log;
4113 c.error_reporter = save_reporter;
4114 });
4115
4116 SemanticValues dummy_vs;
4117 std::any dummy_dt;
4118
4119 len = rule.parse(s, n, dummy_vs, c, dummy_dt);
4120 }
4121
4122 if (success(len)) {
4123 c.recovered = true;
4124
4125 if (c.log || c.error_reporter) {
4126 c.error_info.output_log(c.log, c.error_reporter, c.s, c.l);
4127 c.error_info.clear();
4128 }
4129 }
4130
4131 // Cut
4132 if (!c.cut_stack.empty()) {
4133 c.cut_stack.back() = true;
4134
4135 if (c.cut_stack.size() == 1) {
4136 // TODO: Remove unneeded entries in packrat memoise table
4137 }
4138 }
4139
4140 return len;
4141}
4142
4143inline void Sequence::accept(Visitor &v) { v.visit(*this); }
4144inline void PrioritizedChoice::accept(Visitor &v) { v.visit(*this); }
4145inline void Repetition::accept(Visitor &v) { v.visit(*this); }
4146inline void AndPredicate::accept(Visitor &v) { v.visit(*this); }
4147inline void NotPredicate::accept(Visitor &v) { v.visit(*this); }
4148inline void Dictionary::accept(Visitor &v) { v.visit(*this); }
4149inline void LiteralString::accept(Visitor &v) { v.visit(*this); }
4150inline void CharacterClass::accept(Visitor &v) { v.visit(*this); }
4151inline void Character::accept(Visitor &v) { v.visit(*this); }
4152inline void AnyCharacter::accept(Visitor &v) { v.visit(*this); }
4153inline void CaptureScope::accept(Visitor &v) { v.visit(*this); }
4154inline void Capture::accept(Visitor &v) { v.visit(*this); }
4155inline void TokenBoundary::accept(Visitor &v) { v.visit(*this); }
4156inline void Ignore::accept(Visitor &v) { v.visit(*this); }
4157inline void User::accept(Visitor &v) { v.visit(*this); }
4158inline void WeakHolder::accept(Visitor &v) { v.visit(*this); }
4159inline void Holder::accept(Visitor &v) { v.visit(*this); }
4160inline void Reference::accept(Visitor &v) { v.visit(*this); }
4161inline void Whitespace::accept(Visitor &v) { v.visit(*this); }
4162inline void BackReference::accept(Visitor &v) { v.visit(*this); }
4163inline void PrecedenceClimbing::accept(Visitor &v) { v.visit(*this); }
4164inline void Recovery::accept(Visitor &v) { v.visit(*this); }
4165inline void Cut::accept(Visitor &v) { v.visit(*this); }
4166
4168 auto p = static_cast<void *>(ope.outer_);
4169 if (ids.count(p)) { return; }
4170 auto id = ids.size();
4171 ids[p] = id;
4172 ope.outer_->id = id;
4173 ope.ope_->accept(*this);
4174}
4175
4177 if (ope.rule_) {
4178 for (const auto &arg : ope.args_) {
4179 arg->accept(*this);
4180 }
4181 ope.rule_->accept(*this);
4182 }
4183}
4184
4186 ope.atom_->accept(*this);
4187 ope.binop_->accept(*this);
4188}
4189
4191 if (ope.is_macro_) {
4192 for (const auto &arg : ope.args_) {
4193 arg->accept(*this);
4194 }
4195 } else {
4196 has_rule_ = true;
4197 }
4198}
4199
4201 if (ope.is_macro_) {
4202 ope.rule_->accept(*this);
4203 for (const auto &arg : ope.args_) {
4204 arg->accept(*this);
4205 }
4206 }
4207}
4208
4210 result = ope.rule_ && ope.rule_->can_be_empty;
4211}
4212
4214 // Macro parameter reference: what it denotes lives in an enclosing
4215 // instantiation (e.g. B(X) <- C(X) where X is itself a param ref).
4216 auto param = !ope.rule_ && !macro_args_stack_.empty()
4218 : ResolvedArg{};
4219
4220 if (ope.name_ == name_) {
4221 error_s = ope.s_;
4222 } else if (param.ope) {
4224 if (done_ == false) { return; }
4225 } else if (ope.is_macro_ &&
4227 // Unbounded instantiation chain; stop descending.
4228 } else if (ope.rule_ &&
4229 refs_
4230 .emplace(ope.rule_, ope.is_macro_ ? intern_macro_inst(ope) : 0)
4231 .second) {
4232 if (ope.is_macro_) { macro_args_stack_.push_back(&ope.args_); }
4233 ope.rule_->accept(*this);
4234 if (ope.is_macro_) { macro_args_stack_.pop_back(); }
4235 if (done_ == false) { return; }
4236 }
4237 // If the referenced rule can match empty, don't mark as done —
4238 // the sequence may continue past this element to find LR.
4239 if (!ope.rule_ && !macro_args_stack_.empty()) {
4240 if (param.ope) {
4241 // ComputeCanBeEmpty never consults the frame stack, so the scope it
4242 // runs in cannot matter.
4244 param.ope->accept(cbe);
4245 done_ = !cbe.result;
4246 } else {
4247 done_ = true;
4248 }
4249 } else {
4250 done_ = !(ope.rule_ && ope.rule_->can_be_empty);
4251 }
4252}
4253
4255 // Resolve bare parameter references to what the enclosing instantiation was
4256 // given, so a macro passing its own parameter through interns to the same
4257 // instantiation instead of a fresh one at every nesting level.
4258 std::vector<std::shared_ptr<Ope>> args;
4259 args.reserve(ope.args_.size());
4260 for (const auto &arg : ope.args_) {
4261 auto ref = dynamic_cast<Reference *>(arg.get());
4262 auto resolved = ref && !ref->rule_ && !macro_args_stack_.empty()
4263 ? resolve_macro_arg(ref->iarg_).ope
4264 : nullptr;
4265 args.push_back(resolved ? resolved : arg);
4266 }
4267 auto [it, inserted] = macro_inst_ids_.emplace(macro_inst_key(ope.rule_, args),
4269 if (inserted) { next_macro_inst_++; }
4270 return it->second;
4271}
4272
4273inline void
4275 // The frames below the one holding it are the scope it was written in.
4276 // `W(X) <- Y(X / 'x')` passes Y an argument whose own `X` means W's
4277 // parameter, not Y's -- leaving Y's frame visible would resolve that `X`
4278 // right back to `X / 'x'`, forever.
4279 auto saved = macro_args_stack_;
4280 auto se = scope_exit([&]() { macro_args_stack_ = std::move(saved); });
4281 macro_args_stack_.resize(arg.depth);
4282 arg.ope->accept(*this);
4283}
4284
4287 for (int i = static_cast<int>(macro_args_stack_.size()) - 1; i >= 0; i--) {
4288 auto &args = *macro_args_stack_[i];
4289 if (iarg >= args.size()) { return {}; }
4290 auto ref = dynamic_cast<Reference *>(args[iarg].get());
4291 if (ref && !ref->rule_) {
4292 // Another param ref — resolve using parent level's args
4293 iarg = ref->iarg_;
4294 continue;
4295 }
4296 return {args[iarg], static_cast<size_t>(i)};
4297 }
4298 return {};
4299}
4300
4302 auto save_is_empty = false;
4303 const char *save_error_s = nullptr;
4304 std::string save_error_name;
4305
4306 auto it = ope.opes_.begin();
4307 while (it != ope.opes_.end()) {
4308 (*it)->accept(*this);
4309 if (!is_empty) {
4310 ++it;
4311 while (it != ope.opes_.end()) {
4313 (*it)->accept(vis);
4314 if (vis.has_error) {
4315 is_empty = true;
4316 error_s = vis.error_s;
4317 error_name = vis.error_name;
4318 }
4319 ++it;
4320 }
4321 return;
4322 }
4323
4324 save_is_empty = is_empty;
4325 save_error_s = error_s;
4326 save_error_name = error_name;
4327
4328 is_empty = false;
4329 error_name.clear();
4330 ++it;
4331 }
4332
4333 is_empty = save_is_empty;
4334 error_s = save_error_s;
4335 error_name = save_error_name;
4336}
4337
4339 auto it = std::find_if(refs_.begin(), refs_.end(),
4340 [&](const std::pair<const char *, std::string> &ref) {
4341 return ope.name_ == ref.second;
4342 });
4343 if (it != refs_.end()) { return; }
4344
4345 if (ope.rule_) {
4346 refs_.emplace_back(ope.s_, ope.name_);
4347 ope.rule_->accept(*this);
4348 refs_.pop_back();
4349 }
4350}
4351
4353 auto it = std::find_if(refs_.begin(), refs_.end(),
4354 [&](const std::pair<const char *, std::string> &ref) {
4355 return ope.name_ == ref.second;
4356 });
4357 if (it != refs_.end()) { return; }
4358
4359 if (ope.rule_) {
4360 auto it = has_error_cache_.find(ope.name_);
4361 if (it != has_error_cache_.end()) {
4362 has_error = it->second;
4363 } else {
4364 refs_.emplace_back(ope.s_, ope.name_);
4365 ope.rule_->accept(*this);
4366 refs_.pop_back();
4368 }
4369 }
4370
4371 if (ope.is_macro_) {
4372 for (const auto &arg : ope.args_) {
4373 arg->accept(*this);
4374 }
4375 }
4376}
4377
4379 auto it = std::find(params_.begin(), params_.end(), ope.name_);
4380 if (it != params_.end()) { return; }
4381
4382 if (!grammar_.count(ope.name_)) {
4383 error_s[ope.name_] = ope.s_;
4384 error_message[ope.name_] = "'" + ope.name_ + "' is not defined.";
4385 } else {
4386 if (!referenced.count(ope.name_)) { referenced.insert(ope.name_); }
4387 const auto &rule = grammar_.at(ope.name_);
4388 if (rule.is_macro) {
4389 if (!ope.is_macro_ || ope.args_.size() != rule.params.size()) {
4390 error_s[ope.name_] = ope.s_;
4391 error_message[ope.name_] = "incorrect number of arguments.";
4392 }
4393 } else if (ope.is_macro_) {
4394 error_s[ope.name_] = ope.s_;
4395 error_message[ope.name_] = "'" + ope.name_ + "' is not macro.";
4396 }
4397 for (const auto &arg : ope.args_) {
4398 arg->accept(*this);
4399 }
4400 }
4401}
4402
4404 if (!ope.rule_) {
4405 // Macro parameter reference — can't predict what it will match
4406 result_.any_char = true;
4407 return;
4408 }
4409
4410 auto it = cache_.find(ope.rule_);
4411 FirstSet computed;
4412 const FirstSet *rule_fs;
4413 if (it != cache_.end()) {
4414 rule_fs = &it->second;
4415 } else {
4416 if (!refs_.insert(ope.rule_).second) {
4417 cycle_count_++; // cycle / left recursion
4418 return;
4419 }
4420 auto save = std::exchange(result_, FirstSet{});
4421 auto saved_cycle_count = cycle_count_;
4422 ope.rule_->accept(*this);
4423 computed = std::move(result_);
4424 result_ = std::move(save);
4425 refs_.erase(ope.rule_);
4426 if (cycle_count_ == saved_cycle_count) {
4427 // Cycle-free: cached value is complete and safe to reuse.
4428 it = cache_.try_emplace(ope.rule_, std::move(computed)).first;
4429 rule_fs = &it->second;
4430 } else {
4431 // Cycle was hit during this rule's computation — its result may be
4432 // missing contributions from rules that were on the call stack.
4433 // Use the value here but do not cache it for other call contexts.
4434 rule_fs = &computed;
4435 }
4436 }
4437
4438 result_.merge(*rule_fs);
4439 if (!result_.first_literal) {
4440 result_.first_literal = rule_fs->first_literal;
4441 }
4442 if (!result_.first_rule) {
4443 result_.first_rule = rule_fs->first_rule
4444 ? rule_fs->first_rule
4445 : (ope.rule_->is_token() ? ope.rule_ : nullptr);
4446 }
4447}
4448
4450 if (!ope.rule_) { return; }
4451 ope.rule_->accept(*this); // re-entry is guarded at the rule's Holder
4452}
4453
4454// Guard rule setup by Definition so a SetupFirstSets shared across all rules
4455// visits each rule's body at most once for the whole grammar. Without this the
4456// per-rule setup re-walks every reachable rule once per referencing rule, which
4457// is O(N^2) for grammars with dense cross-references.
4459 if (!visited_rules_.insert(ope.outer_).second) { return; }
4460 ope.ope_->accept(*this);
4461}
4462
4464 ope.kw_guard_.reset();
4466 for (const auto &op : ope.opes_) {
4467 op->accept(*this);
4468 }
4469}
4470
4472 // Detect pattern: NotPredicate(Reference→PrioritizedChoice<literals>)
4473 // TokenBoundary(Sequence[CharacterClass,
4474 // Repetition(CharacterClass)])
4475 // This is the pattern used by: PlainIdentifier <- !ReservedKeyword
4476 // <[a-z_]i[a-z0-9_]i*>
4477 if (seq.opes_.size() != 2) { return; }
4478
4479 // Child 0 must be NotPredicate
4480 auto *not_pred = dynamic_cast<NotPredicate *>(seq.opes_[0].get());
4481 if (!not_pred) { return; }
4482
4483 // NotPredicate's child must be Reference to a rule
4484 auto *ref = dynamic_cast<Reference *>(not_pred->ope_.get());
4485 if (!ref || !ref->rule_) { return; }
4486
4487 // The referenced rule's inner operator (Holder) must contain
4488 // PrioritizedChoice
4489 auto *holder = dynamic_cast<Holder *>(ref->get_core_operator().get());
4490 if (!holder) { return; }
4491 auto *choice = dynamic_cast<PrioritizedChoice *>(holder->ope_.get());
4492 if (!choice) { return; }
4493
4494 // Extract keywords from PrioritizedChoice alternatives
4495 std::vector<std::string> exact_keywords;
4496 std::vector<std::string> prefix_keywords;
4497
4498 for (const auto &alt : choice->opes_) {
4499 auto *lit = dynamic_cast<LiteralString *>(alt.get());
4500 if (lit) {
4501 if (!lit->ignore_case_) { return; }
4502 exact_keywords.push_back(to_lower(lit->lit_));
4503 continue;
4504 }
4505 // Check for compound keyword (Sequence of LiteralStrings)
4506 auto *sub_seq = dynamic_cast<Sequence *>(alt.get());
4507 if (sub_seq && !sub_seq->opes_.empty()) {
4508 auto *first_lit = dynamic_cast<LiteralString *>(sub_seq->opes_[0].get());
4509 if (first_lit) {
4510 auto all_ignore_case_lits =
4511 std::all_of(sub_seq->opes_.begin(), sub_seq->opes_.end(),
4512 [](const auto &child) {
4513 auto *l = dynamic_cast<LiteralString *>(child.get());
4514 return l && l->ignore_case_;
4515 });
4516 if (all_ignore_case_lits) {
4517 prefix_keywords.push_back(to_lower(first_lit->lit_));
4518 continue;
4519 }
4520 }
4521 }
4522 // Unrecognized alternative — bail out
4523 return;
4524 }
4525
4526 if (exact_keywords.empty()) { return; }
4527
4528 // Child 1 must be TokenBoundary
4529 auto *tb = dynamic_cast<TokenBoundary *>(seq.opes_[1].get());
4530 if (!tb) { return; }
4531
4532 // TokenBoundary content: Sequence[CharacterClass, Repetition(CharacterClass)]
4533 // or just CharacterClass (single char identifier)
4534 CharacterClass *first_cc = nullptr;
4535 CharacterClass *rest_cc = nullptr;
4536
4537 auto *inner_seq = dynamic_cast<Sequence *>(tb->ope_.get());
4538 if (inner_seq && inner_seq->opes_.size() == 2) {
4539 first_cc = dynamic_cast<CharacterClass *>(inner_seq->opes_[0].get());
4540 auto *rep = dynamic_cast<Repetition *>(inner_seq->opes_[1].get());
4541 if (rep) { rest_cc = dynamic_cast<CharacterClass *>(rep->ope_.get()); }
4542 }
4543
4544 if (!first_cc || !rest_cc) { return; }
4545 if (!first_cc->is_ascii_only() || !rest_cc->is_ascii_only()) { return; }
4546
4547 // All conditions met — set up the fast path
4548 auto kw = std::make_unique<KeywordGuardData>();
4549 kw->identifier_first = first_cc->ascii_bitset();
4550 kw->identifier_rest = rest_cc->ascii_bitset();
4551
4552 // Compute keyword length range for early-out in hot path
4553 size_t min_len = SIZE_MAX, max_len = 0;
4554 for (const auto &k : exact_keywords) {
4555 min_len = std::min(min_len, k.size());
4556 max_len = std::max(max_len, k.size());
4557 }
4558 for (const auto &k : prefix_keywords) {
4559 min_len = std::min(min_len, k.size());
4560 max_len = std::max(max_len, k.size());
4561 }
4562 kw->min_keyword_len = min_len;
4563 kw->max_keyword_len = max_len;
4564
4565 kw->exact_keywords = std::move(exact_keywords);
4566 kw->prefix_keywords = std::move(prefix_keywords);
4567 seq.kw_guard_ = std::move(kw);
4568}
4569
4570// Compute which rules benefit from packrat memoization.
4571// A rule benefits if it's reachable from 2+ alternatives of the same
4572// PrioritizedChoice (backtracking will re-visit it at the same position).
4574 std::call_once(packrat_filter_init_, [&]() {
4575 auto def_count = definition_ids_.size();
4576 if (def_count == 0) { return; }
4577
4578 // Collect rule IDs that can be invoked at the *same start position* as
4579 // the given Ope subtree (leftmost reachability). A packrat cache hit
4580 // requires the same rule to be queried twice at the same position, and
4581 // in a PEG that only happens when alternatives of a choice share a
4582 // leftmost prefix — rules reachable only past a consuming element can
4583 // never be re-queried by a sibling alternative.
4584 struct CollectLeftmostRules : public TraversalVisitor {
4586 std::vector<bool> reachable; // indexed by def_id
4587 std::vector<bool>
4588 visited_rules; // indexed by def_id; guards Holder cycles
4589
4590 CollectLeftmostRules(size_t n)
4591 : reachable(n, false), visited_rules(n, false) {}
4592
4593 // Collect from the position element `from` starts at: element `from`
4594 // itself, plus what follows for as long as elements can match empty —
4595 // only up to (and including) the first one that must consume input.
4596 void collect(const std::vector<std::shared_ptr<Ope>> &opes, size_t from) {
4597 for (auto i = from; i < opes.size(); i++) {
4598 opes[i]->accept(*this);
4599 ComputeCanBeEmpty empty_vis;
4600 opes[i]->accept(empty_vis);
4601 if (!empty_vis.result) { break; }
4602 }
4603 }
4604
4605 void visit(Sequence &ope) override { collect(ope.opes_, 0); }
4606 void visit(Holder &ope) override {
4607 auto id = ope.outer_->id;
4608 if (id < reachable.size()) {
4609 reachable[id] = true;
4610
4611 // Grammars built directly via the combinator API embed rules through
4612 // WeakHolder rather than Reference, so a recursive rule forms a
4613 // Holder cycle with no Reference to break it. Guard re-entry to avoid
4614 // infinite recursion (reachability is monotone, so revisiting a rule
4615 // we have already traversed adds nothing).
4616 if (visited_rules[id]) { return; }
4617 visited_rules[id] = true;
4618 }
4619 ope.ope_->accept(*this);
4620 }
4621 void visit(Reference &ope) override {
4622 if (ope.rule_ && ope.rule_->id < reachable.size() &&
4623 !reachable[ope.rule_->id]) {
4624 reachable[ope.rule_->id] = true;
4625 ope.rule_->accept(*this);
4626 }
4627 }
4628 };
4629
4630 // Find rules that benefit: queried by 2+ alternatives of the same choice
4631 // at the same position
4632 std::vector<bool> benefits(def_count, false);
4633
4634 struct FindBacktrackRules : public TraversalVisitor {
4636 std::vector<bool> &benefits;
4637 size_t def_count;
4638 std::vector<bool> visited_rules; // indexed by def_id
4639
4640 FindBacktrackRules(std::vector<bool> &b, size_t n)
4641 : benefits(b), def_count(n), visited_rules(n, false) {}
4642
4643 using Elements = std::vector<std::shared_ptr<Ope>>;
4644
4645 // An alternative's top-level elements, so a shared prefix can be walked
4646 // element by element. By value: this runs once per grammar.
4647 static Elements elements_of(const std::shared_ptr<Ope> &alt) {
4648 if (auto *seq = dynamic_cast<Sequence *>(alt.get())) {
4649 return seq->opes_;
4650 }
4651 return {alt};
4652 }
4653
4654 // `group` holds alternatives that agree on their first `k` elements, so
4655 // every one of them reaches element k at the same input position — that
4656 // is exactly when a packrat cache entry can hit. k == 0 is the plain
4657 // "alternatives of one choice" case; deeper k is what a shared prefix
4658 // like `'(' _ PATTERN _ ',' _` hides.
4659 void mark_aligned(const std::vector<Elements> &group, size_t k) {
4660 if (group.size() < 2) { return; }
4661
4662 std::vector<std::vector<bool>> reachable;
4663 reachable.reserve(group.size());
4664 for (const auto &seq : group) {
4665 CollectLeftmostRules clr(def_count);
4666 clr.collect(seq, k);
4667 reachable.push_back(std::move(clr.reachable));
4668 }
4669 for (size_t id = 0; id < def_count; id++) {
4670 size_t count = 0;
4671 for (const auto &alt : reachable) {
4672 if (alt[id]) { count++; }
4673 }
4674 if (count >= 2) { benefits[id] = true; }
4675 }
4676
4677 // Only alternatives that also agree on element k stay aligned past it.
4678 std::map<std::string, std::vector<Elements>> aligned;
4679 for (const auto &seq : group) {
4680 if (k < seq.size()) {
4681 aligned[OpeSignature::get(*seq[k])].push_back(seq);
4682 }
4683 }
4684 for (const auto &[sig, sub] : aligned) {
4685 mark_aligned(sub, k + 1);
4686 }
4687 }
4688
4689 void visit(PrioritizedChoice &ope) override {
4690 std::vector<Elements> group;
4691 group.reserve(ope.opes_.size());
4692 for (const auto &op : ope.opes_) {
4693 group.push_back(elements_of(op));
4694 }
4695 mark_aligned(group, 0);
4696
4697 // Recurse into alternatives
4698 for (auto &op : ope.opes_) {
4699 op->accept(*this);
4700 }
4701 }
4702 void visit(Holder &ope) override {
4703 auto id = ope.outer_->id;
4704 if (id < visited_rules.size() && !visited_rules[id]) {
4705 visited_rules[id] = true;
4706 ope.ope_->accept(*this);
4707 }
4708 }
4709 void visit(Reference &ope) override {
4710 if (ope.rule_) { ope.rule_->accept(*this); }
4711 }
4712 };
4713
4714 FindBacktrackRules finder(benefits, def_count);
4715 holder_->accept(finder);
4716 if (whitespaceOpe) { whitespaceOpe->accept(finder); }
4717 if (wordOpe) { wordOpe->accept(finder); }
4718
4719 // Left-recursive rules read and write the packrat cache directly during
4720 // seed-growing, so they must stay in the cached set. Macros are the
4721 // exception: they use lr_memo only, keyed by instantiation.
4722 for (const auto &[ptr, id] : definition_ids_) {
4723 auto *def = static_cast<Definition *>(ptr);
4724 if (def->is_left_recursive && !def->is_macro && id < def_count) {
4725 benefits[id] = true;
4726 }
4727 }
4728
4729 // Compact index: def_id -> slot in the cache tables (-1 = guard only)
4730 packrat_index_.assign(def_count, -1);
4731 int32_t k = 0;
4732 for (size_t id = 0; id < def_count; id++) {
4733 if (benefits[id]) { packrat_index_[id] = k++; }
4734 }
4735 packrat_cached_count_ = static_cast<size_t>(k);
4736 });
4737}
4738
4740 // Check if the reference is a macro parameter
4741 auto found_param = false;
4742 for (size_t i = 0; i < params_.size(); i++) {
4743 const auto &param = params_[i];
4744 if (param == ope.name_) {
4745 ope.iarg_ = i;
4746 found_param = true;
4747 break;
4748 }
4749 }
4750
4751 // Check if the reference is a definition rule
4752 if (!found_param && grammar_.count(ope.name_)) {
4753 auto &rule = grammar_.at(ope.name_);
4754 ope.rule_ = &rule;
4755 }
4756
4757 for (const auto &arg : ope.args_) {
4758 arg->accept(*this);
4759 }
4760}
4761
4763 for (size_t i = 0; i < args_.size(); i++) {
4764 const auto &name = params_[i];
4765 if (name == ope.name_) {
4766 found_ope = args_[i];
4767 return;
4768 }
4769 }
4770 found_ope = ope.shared_from_this();
4771}
4772
4773/*-----------------------------------------------------------------------------
4774 * Grammar serialization
4775 *
4776 * Serialize a compiled Grammar (the operator tree) to a byte blob and back,
4777 * letting an application skip the meta-parse on startup by embedding a
4778 * prebuilt blob. Structure only: semantic callbacks (actions / enter / leave /
4779 * predicate, attached by enable_ast() etc.) are NOT serialized and must be
4780 * re-applied after deserialize. References resolve by name (no pointer fixup);
4781 * first-sets and keyword guards are recomputed on load (O(N)). The
4782 * `precedence` instruction is supported (its operator table is structural).
4783 * Grammars using the `User` operator or a Capture with a match action are
4784 * rejected. The blob is specific to this peglib version's layout.
4785 *---------------------------------------------------------------------------*/
4786
4811
4812 struct Writer {
4813 std::vector<uint8_t> b;
4814 void u8(uint8_t v) { b.push_back(v); }
4815 void u32(uint32_t v) {
4816 for (int i = 0; i < 4; i++)
4817 b.push_back((v >> (8 * i)) & 0xff);
4818 }
4819 void u64(uint64_t v) {
4820 for (int i = 0; i < 8; i++)
4821 b.push_back((v >> (8 * i)) & 0xff);
4822 }
4823 void str(const std::string &s) {
4824 u32((uint32_t)s.size());
4825 b.insert(b.end(), s.begin(), s.end());
4826 }
4827 };
4828
4829 static void write_ope(Writer &w, const std::shared_ptr<Ope> &o) {
4830 if (!o) {
4831 w.u8(T_Null);
4832 return;
4833 }
4834 Ope *p = o.get();
4835 if (auto x = dynamic_cast<Sequence *>(p)) {
4836 w.u8(T_Sequence);
4837 w.u32((uint32_t)x->opes_.size());
4838 for (auto &c : x->opes_)
4839 write_ope(w, c);
4840 } else if (auto x = dynamic_cast<PrioritizedChoice *>(p)) {
4841 w.u8(T_Choice);
4842 w.u8(x->for_label_ ? 1 : 0);
4843 w.u32((uint32_t)x->opes_.size());
4844 for (auto &c : x->opes_)
4845 write_ope(w, c);
4846 } else if (auto x = dynamic_cast<Repetition *>(p)) {
4847 w.u8(T_Repetition);
4848 w.u64(x->min_);
4849 w.u64(x->max_);
4850 write_ope(w, x->ope_);
4851 } else if (auto x = dynamic_cast<AndPredicate *>(p)) {
4852 w.u8(T_And);
4853 write_ope(w, x->ope_);
4854 } else if (auto x = dynamic_cast<NotPredicate *>(p)) {
4855 w.u8(T_Not);
4856 write_ope(w, x->ope_);
4857 } else if (auto x = dynamic_cast<Dictionary *>(p)) {
4858 w.u8(T_Dictionary);
4859 w.u8(x->trie_.ignore_case_ ? 1 : 0);
4860 // Recover words in their original choice-index order. The Trie stores
4861 // each full word's id (its index in the constructor vector), which
4862 // parse_core reports as vs.choice(). Iterating dic_ directly yields
4863 // sorted key order and would renumber the choices, so place each word at
4864 // its id.
4865 std::vector<std::string> words(x->trie_.items_count());
4866 for (auto &kv : x->trie_.dic_)
4867 if (kv.second.match && kv.second.id < words.size())
4868 words[kv.second.id] = kv.first;
4869 w.u32((uint32_t)words.size());
4870 for (auto &s : words)
4871 w.str(s);
4872 } else if (auto x = dynamic_cast<LiteralString *>(p)) {
4873 w.u8(T_Literal);
4874 w.u8(x->ignore_case_ ? 1 : 0);
4875 w.str(x->lit_);
4876 } else if (auto x = dynamic_cast<CharacterClass *>(p)) {
4877 w.u8(T_CharClass);
4878 w.u8(x->negated_ ? 1 : 0);
4879 w.u8(x->ignore_case_ ? 1 : 0);
4880 w.u32((uint32_t)x->ranges_.size());
4881 for (auto &r : x->ranges_) {
4882 w.u32((uint32_t)r.first);
4883 w.u32((uint32_t)r.second);
4884 }
4885 } else if (auto x = dynamic_cast<Character *>(p)) {
4886 w.u8(T_Char);
4887 w.u32((uint32_t)x->ch_);
4888 } else if (dynamic_cast<AnyCharacter *>(p)) {
4889 w.u8(T_AnyChar);
4890 } else if (auto x = dynamic_cast<CaptureScope *>(p)) {
4891 w.u8(T_CaptureScope);
4892 write_ope(w, x->ope_);
4893 } else if (auto x = dynamic_cast<Capture *>(p)) {
4894 if (x->match_action_) {
4895 throw std::runtime_error(
4896 "GrammarBlob: Capture with a match action is not serializable");
4897 }
4898 w.u8(T_Capture);
4899 write_ope(w, x->ope_);
4900 } else if (auto x = dynamic_cast<TokenBoundary *>(p)) {
4902 write_ope(w, x->ope_);
4903 } else if (auto x = dynamic_cast<Ignore *>(p)) {
4904 w.u8(T_Ignore);
4905 write_ope(w, x->ope_);
4906 } else if (auto x = dynamic_cast<BackReference *>(p)) {
4907 w.u8(T_BackRef);
4908 w.str(x->name_);
4909 } else if (auto x = dynamic_cast<Reference *>(p)) {
4910 w.u8(T_Reference);
4911 w.u8(x->is_macro_ ? 1 : 0);
4912 w.str(x->name_);
4913 w.u32((uint32_t)x->args_.size());
4914 for (auto &a : x->args_)
4915 write_ope(w, a);
4916 } else if (auto x = dynamic_cast<Whitespace *>(p)) {
4917 w.u8(T_Whitespace);
4918 write_ope(w, x->ope_);
4919 } else if (auto x = dynamic_cast<Recovery *>(p)) {
4920 w.u8(T_Recovery);
4921 write_ope(w, x->ope_);
4922 } else if (dynamic_cast<Cut *>(p)) {
4923 w.u8(T_Cut);
4924 } else if (auto x = dynamic_cast<PrecedenceClimbing *>(p)) {
4926 write_ope(w, x->atom_);
4927 write_ope(w, x->binop_);
4928 w.u32((uint32_t)x->info_.size());
4929 for (auto &[key, pri] : x->info_) {
4930 w.str(std::string(key));
4931 w.u64((uint64_t)pri.first);
4932 w.u8((uint8_t)pri.second);
4933 }
4934 } else {
4935 throw std::runtime_error(
4936 "GrammarBlob: operator not serializable (a custom User operator or "
4937 "a Capture with a match action)");
4938 }
4939 }
4940
4941 struct Reader {
4942 const uint8_t *p, *end;
4943 uint8_t u8() {
4944 if (p >= end)
4945 throw std::runtime_error("GrammarBlob: unexpected end of blob");
4946 return *p++;
4947 }
4948 uint32_t u32() {
4949 uint32_t v = 0;
4950 for (int i = 0; i < 4; i++)
4951 v |= (uint32_t)u8() << (8 * i);
4952 return v;
4953 }
4954 uint64_t u64() {
4955 uint64_t v = 0;
4956 for (int i = 0; i < 8; i++)
4957 v |= (uint64_t)u8() << (8 * i);
4958 return v;
4959 }
4960 std::string str() {
4961 uint32_t n = u32();
4962 std::string s((const char *)p, (const char *)p + n);
4963 p += n;
4964 return s;
4965 }
4966 };
4967
4968 static std::shared_ptr<Ope> read_ope(Reader &r, Grammar &g,
4969 Definition *owner) {
4970 switch (r.u8()) {
4971 case T_Null: return nullptr;
4972 case T_Sequence: {
4973 uint32_t n = r.u32();
4974 std::vector<std::shared_ptr<Ope>> v;
4975 for (uint32_t i = 0; i < n; i++)
4976 v.push_back(read_ope(r, g, owner));
4977 return std::make_shared<Sequence>(std::move(v));
4978 }
4979 case T_Choice: {
4980 bool fl = r.u8();
4981 uint32_t n = r.u32();
4982 std::vector<std::shared_ptr<Ope>> v;
4983 for (uint32_t i = 0; i < n; i++)
4984 v.push_back(read_ope(r, g, owner));
4985 auto c = std::make_shared<PrioritizedChoice>(std::move(v));
4986 c->for_label_ = fl;
4987 return c;
4988 }
4989 case T_Repetition: {
4990 uint64_t mn = r.u64(), mx = r.u64();
4991 auto o = read_ope(r, g, owner);
4992 return std::make_shared<Repetition>(o, mn, mx);
4993 }
4994 case T_And: return std::make_shared<AndPredicate>(read_ope(r, g, owner));
4995 case T_Not: return std::make_shared<NotPredicate>(read_ope(r, g, owner));
4996 case T_Dictionary: {
4997 bool ic = r.u8();
4998 uint32_t n = r.u32();
4999 std::vector<std::string> words;
5000 for (uint32_t i = 0; i < n; i++)
5001 words.push_back(r.str());
5002 return std::make_shared<Dictionary>(words, ic);
5003 }
5004 case T_Literal: {
5005 bool ic = r.u8();
5006 std::string s = r.str();
5007 return std::make_shared<LiteralString>(std::move(s), ic);
5008 }
5009 case T_CharClass: {
5010 bool neg = r.u8(), ic = r.u8();
5011 uint32_t n = r.u32();
5012 std::vector<std::pair<char32_t, char32_t>> ranges;
5013 for (uint32_t i = 0; i < n; i++) {
5014 auto lo = r.u32(), hi = r.u32();
5015 ranges.emplace_back((char32_t)lo, (char32_t)hi);
5016 }
5017 return std::make_shared<CharacterClass>(ranges, neg, ic);
5018 }
5019 case T_Char: return std::make_shared<Character>((char32_t)r.u32());
5020 case T_AnyChar: return std::make_shared<AnyCharacter>();
5021 case T_CaptureScope:
5022 return std::make_shared<CaptureScope>(read_ope(r, g, owner));
5023 case T_Capture: {
5024 auto o = read_ope(r, g, owner);
5025 return std::make_shared<Capture>(o, nullptr);
5026 }
5027 case T_TokenBoundary:
5028 return std::make_shared<TokenBoundary>(read_ope(r, g, owner));
5029 case T_Ignore: return std::make_shared<Ignore>(read_ope(r, g, owner));
5030 case T_BackRef: return std::make_shared<BackReference>(r.str());
5031 case T_Reference: {
5032 bool im = r.u8();
5033 std::string nm = r.str();
5034 uint32_t n = r.u32();
5035 std::vector<std::shared_ptr<Ope>> args;
5036 for (uint32_t i = 0; i < n; i++)
5037 args.push_back(read_ope(r, g, owner));
5038 return std::make_shared<Reference>(g, nm, nullptr, im, args);
5039 }
5040 case T_Whitespace:
5041 return std::make_shared<Whitespace>(read_ope(r, g, owner));
5042 case T_Recovery: return std::make_shared<Recovery>(read_ope(r, g, owner));
5043 case T_Cut: return std::make_shared<Cut>();
5044 case T_PrecedenceClimbing: {
5045 if (!owner) {
5046 throw std::runtime_error(
5047 "GrammarBlob: 'precedence' operator outside a rule body");
5048 }
5049 auto atom = read_ope(r, g, owner);
5050 auto binop = read_ope(r, g, owner);
5051 uint32_t n = r.u32();
5052 auto pc = std::make_shared<PrecedenceClimbing>(
5053 atom, binop, PrecedenceClimbing::BinOpeInfo{}, *owner);
5054 // info_ keys are string_views; back them with owned strings whose
5055 // addresses stay stable (reserve avoids reallocation, and the node is
5056 // never moved once held by shared_ptr).
5057 pc->info_keys_.reserve(n);
5058 for (uint32_t i = 0; i < n; i++) {
5059 std::string key = r.str();
5060 auto level = (size_t)r.u64();
5061 auto assoc = (char)r.u8();
5062 pc->info_keys_.push_back(std::move(key));
5063 pc->info_[pc->info_keys_.back()] = std::pair(level, assoc);
5064 }
5065 return pc;
5066 }
5067 default: throw std::runtime_error("GrammarBlob: bad operator tag");
5068 }
5069 }
5070
5071 static const uint32_t MAGIC = 0x50454732; // "PEG2"
5072
5073 static std::vector<uint8_t> serialize(const Grammar &g,
5074 const std::string &start) {
5075 Writer w;
5076 w.u32(MAGIC);
5077 w.str(start);
5078 w.u32((uint32_t)g.size());
5079 // Grammar is an unordered_map, whose iteration order is implementation
5080 // defined: walking it directly yields different bytes for the same grammar
5081 // on different standard libraries, so a blob generated on one platform
5082 // cannot be byte-compared on another. Emit the definitions by name.
5083 // deserialize() rebuilds the map from the names, so the order carries no
5084 // meaning of its own.
5085 std::vector<const Grammar::value_type *> defs;
5086 defs.reserve(g.size());
5087 for (auto &kv : g)
5088 defs.push_back(&kv);
5089 std::sort(defs.begin(), defs.end(),
5090 [](const auto *a, const auto *b) { return a->first < b->first; });
5091 for (auto *kv : defs) {
5092 const auto &name = kv->first;
5093 const auto &def = kv->second;
5094 w.str(name);
5095 uint8_t flags =
5096 (def.ignoreSemanticValue ? 1 : 0) | (def.is_macro ? 2 : 0) |
5097 (def.no_ast_opt ? 4 : 0) | (def.eoi_check ? 8 : 0) |
5098 (def.enablePackratParsing ? 16 : 0) |
5099 (def.is_left_recursive ? 32 : 0) | (def.can_be_empty ? 64 : 0) |
5100 (def.disable_action ? 128 : 0);
5101 w.u8(flags);
5102 uint8_t flags2 = (def.no_whitespace ? 1 : 0);
5103 w.u8(flags2);
5104 w.u32((uint32_t)def.params.size());
5105 for (auto &s : def.params)
5106 w.str(s);
5107 w.str(def.ast_name);
5108 w.str(def.error_message);
5109 write_ope(w, const_cast<Definition &>(def).get_core_operator());
5110 }
5111 return std::move(w.b);
5112 }
5113
5114 static std::shared_ptr<Grammar> deserialize(const std::vector<uint8_t> &blob,
5115 std::string &start_out) {
5116 Reader r{blob.data(), blob.data() + blob.size()};
5117 if (r.u32() != MAGIC)
5118 throw std::runtime_error("GrammarBlob: bad magic / not a grammar blob");
5119 start_out = r.str();
5120 uint32_t ndef = r.u32();
5121 auto g = std::make_shared<Grammar>();
5122 // Create each Definition before reading its body: a PrecedenceClimbing node
5123 // needs a stable reference to its owning rule at construction. Grammar is a
5124 // node-based map, so references stay valid as later rules are inserted.
5125 for (uint32_t i = 0; i < ndef; i++) {
5126 std::string name = r.str();
5127 uint8_t flags = r.u8();
5128 uint8_t flags2 = r.u8();
5129 uint32_t np = r.u32();
5130 std::vector<std::string> params;
5131 for (uint32_t k = 0; k < np; k++)
5132 params.push_back(r.str());
5133 std::string ast_name = r.str();
5134 std::string err = r.str();
5135
5136 auto &def = (*g)[name];
5137 def.name = name;
5138 def.ignoreSemanticValue = flags & 1;
5139 def.is_macro = flags & 2;
5140 def.no_ast_opt = flags & 4;
5141 def.eoi_check = flags & 8;
5142 def.enablePackratParsing = flags & 16;
5143 def.is_left_recursive = flags & 32;
5144 def.can_be_empty = flags & 64;
5145 def.disable_action = flags & 128;
5146 def.no_whitespace = flags2 & 1;
5147 def.params = std::move(params);
5148 def.ast_name = std::move(ast_name);
5149 def.error_message = std::move(err);
5150
5151 auto body = read_ope(r, *g, &def);
5152 def <= body;
5153 }
5154 for (auto &x : *g) {
5155 LinkReferences vis(*g, x.second.params);
5156 x.second.accept(vis);
5157 // TraversalVisitor descends only into a PrecedenceClimbing's atom_. In
5158 // the from-source path binop_ is linked while the body is still a
5159 // Sequence, before precedence lowering; a deserialized node is built
5160 // already lowered so its binop_ reference must be linked explicitly here.
5161 auto core = x.second.get_core_operator();
5162 if (auto pc = std::dynamic_pointer_cast<PrecedenceClimbing>(core)) {
5163 pc->binop_->accept(vis);
5164 }
5165 }
5166 {
5167 SetupFirstSets vis; // shared across rules -> O(N)
5168 for (auto &x : *g)
5169 x.second.accept(vis);
5170 }
5171 // Re-derive automatic whitespace/word skipping on the start rule from the
5172 // %whitespace / %word definitions, exactly as ParserGenerator does. Sharing
5173 // the (already linked and first-set) definition operators avoids leaving
5174 // references inside the skipping ope unlinked, and keeps the blob smaller.
5175 if (g->count(WHITESPACE_DEFINITION_NAME)) {
5176 (*g)[start_out].whitespaceOpe =
5177 wsp((*g)[WHITESPACE_DEFINITION_NAME].get_core_operator());
5178 }
5179 if (g->count(WORD_DEFINITION_NAME)) {
5180 (*g)[start_out].wordOpe = (*g)[WORD_DEFINITION_NAME].get_core_operator();
5181 }
5182 return g;
5183 }
5184};
5185
5186/*-----------------------------------------------------------------------------
5187 * PEG parser generator
5188 *---------------------------------------------------------------------------*/
5189
5190using Rules = std::unordered_map<std::string, std::shared_ptr<Ope>>;
5191
5193public:
5195 std::shared_ptr<Grammar> grammar;
5196 std::string start;
5198 };
5199
5200 static ParserContext parse(const char *s, size_t n, const Rules &rules,
5201 Log log, std::string_view start,
5202 bool enable_left_recursion = true) {
5203 return get_instance().perform_core(s, n, rules, log, std::string(start),
5204 enable_left_recursion);
5205 }
5206
5207 // For debugging purpose
5208 static bool parse_test(const char *d, const char *s) {
5209 Data data;
5210 std::any dt = &data;
5211
5212 auto n = strlen(s);
5213 auto r = get_instance().g[d].parse(s, n, dt);
5214 return r.ret && r.len == n;
5215 }
5216
5217#if defined(__cpp_lib_char8_t)
5218 static bool parse_test(const char *d, const char8_t *s) {
5219 return parse_test(d, reinterpret_cast<const char *>(s));
5220 }
5221#endif
5222
5223private:
5225 static ParserGenerator instance;
5226 return instance;
5227 }
5228
5230 make_grammar();
5231 setup_actions();
5232 // Apply First-Set filtering to the bootstrap meta-grammar itself so that
5233 // parsing a grammar (the bulk of load_grammar) skips alternatives whose
5234 // next byte cannot match. This is safe -- First-Set filtering only skips
5235 // alternatives that would have failed anyway, so no semantic action that
5236 // would have committed is skipped (unlike packrat, which is unsound here).
5237 {
5238 SetupFirstSets vis;
5239 for (auto &x : g) {
5240 x.second.accept(vis);
5241 }
5242 }
5243 }
5244
5246 std::string type;
5247 std::any data;
5248 std::string_view sv;
5249 };
5250
5251 struct Data {
5252 std::shared_ptr<Grammar> grammar;
5253 std::string start;
5254 const char *start_pos = nullptr;
5255
5256 std::vector<std::pair<std::string, const char *>> duplicates_of_definition;
5257
5258 std::vector<std::pair<std::string, const char *>> duplicates_of_instruction;
5259 std::map<std::string, std::vector<Instruction>> instructions;
5260
5261 std::vector<std::pair<std::string, const char *>> undefined_back_references;
5262 std::vector<std::set<std::string_view>> captures_stack{{}};
5263
5264 std::set<std::string_view> captures_in_current_definition;
5266
5267 Data() : grammar(std::make_shared<Grammar>()) {}
5268 };
5269
5270 class SyntaxErrorException : public std::runtime_error {
5271 public:
5272 SyntaxErrorException(const char *what_arg, std::pair<size_t, size_t> r)
5273 : std::runtime_error(what_arg), r_(r) {}
5274
5275 std::pair<size_t, size_t> line_info() const { return r_; }
5276
5277 private:
5278 std::pair<size_t, size_t> r_;
5279 };
5280
5282 // Setup PEG syntax parser
5283 g["Grammar"] <= seq(g["Spacing"], oom(g["Definition"]), g["EndOfFile"]);
5284 // Left-factored: parse the rule name (IdentCont) once, then optionally the
5285 // macro parameter list. `opt(Parameters)` pushes a value only for a macro
5286 // (so the value layout matches the old two-alternative form), and Spacing
5287 // (~, no value) consumes the gap before LEFTARROW that Identifier used to.
5288 g["Definition"] <= seq(g["Ignore"], g["IdentCont"], opt(g["Parameters"]),
5289 g["Spacing"], g["LEFTARROW"], g["Expression"],
5290 opt(g["Instruction"]));
5291 g["Expression"] <= seq(g["Sequence"], zom(seq(g["SLASH"], g["Sequence"])));
5292 g["Sequence"] <= zom(cho(g["CUT"], g["Prefix"]));
5293 g["Prefix"] <= seq(opt(cho(g["AND"], g["NOT"])), g["SuffixWithLabel"]);
5294 g["SuffixWithLabel"] <=
5295 seq(g["Suffix"], opt(seq(g["LABEL"], g["Identifier"])));
5296 g["Suffix"] <= seq(g["Primary"], opt(g["Loop"]));
5297 g["Loop"] <= cho(g["QUESTION"], g["STAR"], g["PLUS"], g["Repetition"]);
5298 // Left-factored: a macro reference (`Name(args)`) and a plain reference
5299 // (`Name`) share the leading `Ignore IdentCont`, so parse it once and let
5300 // `opt(Arguments)` decide. opt() pushes the argument list only for a macro
5301 // reference, so vs.size() distinguishes the two in the action.
5302 g["Primary"] <=
5303 cho(seq(g["Ignore"], g["IdentCont"], opt(g["Arguments"]), g["Spacing"],
5304 npd(seq(opt(g["Parameters"]), g["LEFTARROW"]))),
5305 seq(g["OPEN"], g["Expression"], g["CLOSE"]),
5306 seq(g["BeginTok"], g["Expression"], g["EndTok"]), g["CapScope"],
5307 seq(g["BeginCap"], g["Expression"], g["EndCap"]), g["BackRef"],
5308 g["DictionaryI"], g["LiteralI"], g["Dictionary"], g["Literal"],
5309 g["NegatedClassI"], g["NegatedClass"], g["ClassI"], g["Class"],
5310 g["DOT"]);
5311
5312 g["Identifier"] <= seq(g["IdentCont"], g["Spacing"]);
5313 g["IdentCont"] <= tok(seq(g["IdentStart"], zom(g["IdentRest"])));
5314
5315 const static std::vector<std::pair<char32_t, char32_t>> range = {
5316 {0x0080, 0xFFFF}};
5317 g["IdentStart"] <= seq(npd(lit(u8(u8"↑"))), npd(lit(u8(u8"⇑"))),
5318 cho(cls("a-zA-Z_%"), cls(range)));
5319
5320 g["IdentRest"] <= cho(g["IdentStart"], cls("0-9"));
5321
5322 g["Dictionary"] <= seq(g["LiteralD"], oom(seq(g["PIPE"], g["LiteralD"])));
5323
5324 g["DictionaryI"] <=
5325 seq(g["LiteralID"], oom(seq(g["PIPE"], g["LiteralID"])));
5326
5327 auto lit_ope = cho(seq(cls("'"), tok(zom(seq(npd(cls("'")), g["Char"]))),
5328 cls("'"), g["Spacing"]),
5329 seq(cls("\""), tok(zom(seq(npd(cls("\"")), g["Char"]))),
5330 cls("\""), g["Spacing"]));
5331 g["Literal"] <= lit_ope;
5332 g["LiteralD"] <= lit_ope;
5333
5334 auto lit_case_ignore_ope =
5335 cho(seq(cls("'"), tok(zom(seq(npd(cls("'")), g["Char"]))), lit("'i"),
5336 g["Spacing"]),
5337 seq(cls("\""), tok(zom(seq(npd(cls("\"")), g["Char"]))), lit("\"i"),
5338 g["Spacing"]));
5339 g["LiteralI"] <= lit_case_ignore_ope;
5340 g["LiteralID"] <= lit_case_ignore_ope;
5341
5342 // NOTE: The original Brian Ford's paper uses 'zom' instead of 'oom'.
5343 g["Class"] <= seq(chr('['), npd(chr('^')),
5344 tok(oom(seq(npd(chr(']')), g["Range"]))), chr(']'),
5345 g["Spacing"]);
5346 g["ClassI"] <= seq(chr('['), npd(chr('^')),
5347 tok(oom(seq(npd(chr(']')), g["Range"]))), lit("]i"),
5348 g["Spacing"]);
5349
5350 g["NegatedClass"] <= seq(lit("[^"),
5351 tok(oom(seq(npd(chr(']')), g["Range"]))), chr(']'),
5352 g["Spacing"]);
5353 g["NegatedClassI"] <= seq(lit("[^"),
5354 tok(oom(seq(npd(chr(']')), g["Range"]))),
5355 lit("]i"), g["Spacing"]);
5356
5357 // NOTE: This is different from The original Brian Ford's paper, and this
5358 // modification allows us to specify `[+-]` as a valid char class.
5359 g["Range"] <= cho(seq(g["Char"], chr('-'), npd(chr(']')), g["Char"]),
5360 g["ClassEscape"], g["PosixClass"], g["Char"]);
5361
5362 g["ClassEscape"] <= seq(chr('\\'), cls("dDwWsS"));
5363 g["PosixClass"] <=
5364 seq(lit("[:"), opt(chr('^')), oom(cls("a-z")), lit(":]"));
5365
5366 g["Char"] <=
5367 cho(seq(chr('\\'), cls("fnrtv'\"[]\\^-")),
5368 seq(chr('\\'), cls("0-3"), cls("0-7"), cls("0-7")),
5369 seq(chr('\\'), cls("0-7"), opt(cls("0-7"))),
5370 seq(lit("\\x"), cls("0-9a-fA-F"), opt(cls("0-9a-fA-F"))),
5371 seq(lit("\\u"),
5372 cho(seq(cho(seq(chr('0'), cls("0-9a-fA-F")), lit("10")),
5373 rep(cls("0-9a-fA-F"), 4, 4)),
5374 rep(cls("0-9a-fA-F"), 4, 5))),
5375 seq(npd(chr('\\')), dot()));
5376
5377 g["Repetition"] <=
5378 seq(g["BeginBracket"], g["RepetitionRange"], g["EndBracket"]);
5379 g["RepetitionRange"] <= cho(seq(g["Number"], g["COMMA"], g["Number"]),
5380 seq(g["Number"], g["COMMA"]), g["Number"],
5381 seq(g["COMMA"], g["Number"]));
5382 g["Number"] <= seq(oom(cls("0-9")), g["Spacing"]);
5383
5384 g["CapScope"] <= seq(g["BeginCapScope"], g["Expression"], g["EndCapScope"]);
5385
5386 g["LEFTARROW"] <= seq(cho(lit("<-"), lit(u8(u8"←"))), g["Spacing"]);
5387 ~g["SLASH"] <= seq(chr('/'), g["Spacing"]);
5388 ~g["PIPE"] <= seq(chr('|'), g["Spacing"]);
5389 g["AND"] <= seq(chr('&'), g["Spacing"]);
5390 g["NOT"] <= seq(chr('!'), g["Spacing"]);
5391 g["QUESTION"] <= seq(chr('?'), g["Spacing"]);
5392 g["STAR"] <= seq(chr('*'), g["Spacing"]);
5393 g["PLUS"] <= seq(chr('+'), g["Spacing"]);
5394 ~g["OPEN"] <= seq(chr('('), g["Spacing"]);
5395 ~g["CLOSE"] <= seq(chr(')'), g["Spacing"]);
5396 g["DOT"] <= seq(chr('.'), g["Spacing"]);
5397
5398 g["CUT"] <= seq(lit(u8(u8"↑")), g["Spacing"]);
5399 ~g["LABEL"] <= seq(cho(chr('^'), lit(u8(u8"⇑"))), g["Spacing"]);
5400
5401 ~g["Spacing"] <= zom(cho(g["Space"], g["Comment"]));
5402 g["Comment"] <= seq(chr('#'), zom(seq(npd(g["EndOfLine"]), dot())),
5403 opt(g["EndOfLine"]));
5404 g["Space"] <= cho(chr(' '), chr('\t'), g["EndOfLine"]);
5405 g["EndOfLine"] <= cho(lit("\r\n"), chr('\n'), chr('\r'));
5406 g["EndOfFile"] <= npd(dot());
5407
5408 ~g["BeginTok"] <= seq(chr('<'), g["Spacing"]);
5409 ~g["EndTok"] <= seq(chr('>'), g["Spacing"]);
5410
5411 ~g["BeginCapScope"] <= seq(chr('$'), chr('('), g["Spacing"]);
5412 ~g["EndCapScope"] <= seq(chr(')'), g["Spacing"]);
5413
5414 g["BeginCap"] <= seq(chr('$'), tok(g["IdentCont"]), chr('<'), g["Spacing"]);
5415 ~g["EndCap"] <= seq(chr('>'), g["Spacing"]);
5416
5417 g["BackRef"] <= seq(chr('$'), tok(g["IdentCont"]), g["Spacing"]);
5418
5419 g["IGNORE"] <= chr('~');
5420
5421 g["Ignore"] <= opt(g["IGNORE"]);
5422 g["Parameters"] <= seq(g["OPEN"], g["Identifier"],
5423 zom(seq(g["COMMA"], g["Identifier"])), g["CLOSE"]);
5424 g["Arguments"] <= seq(g["OPEN"], g["Expression"],
5425 zom(seq(g["COMMA"], g["Expression"])), g["CLOSE"]);
5426 ~g["COMMA"] <= seq(chr(','), g["Spacing"]);
5427
5428 // Instruction grammars
5429 g["Instruction"] <=
5430 seq(g["BeginBracket"],
5431 opt(seq(g["InstructionItem"], zom(seq(g["InstructionItemSeparator"],
5432 g["InstructionItem"])))),
5433 g["EndBracket"]);
5434 g["InstructionItem"] <= cho(g["PrecedenceClimbing"], g["ErrorMessage"],
5435 g["NoAstOpt"], g["NoWhitespace"], g["AstName"]);
5436 ~g["InstructionItemSeparator"] <= seq(chr(';'), g["Spacing"]);
5437
5438 ~g["SpacesZom"] <= zom(g["Space"]);
5439 ~g["SpacesOom"] <= oom(g["Space"]);
5440 ~g["BeginBracket"] <= seq(chr('{'), g["Spacing"]);
5441 ~g["EndBracket"] <= seq(chr('}'), g["Spacing"]);
5442
5443 // PrecedenceClimbing instruction
5444 g["PrecedenceClimbing"] <=
5445 seq(lit("precedence"), g["SpacesOom"], g["PrecedenceInfo"],
5446 zom(seq(g["SpacesOom"], g["PrecedenceInfo"])), g["SpacesZom"]);
5447 g["PrecedenceInfo"] <=
5448 seq(g["PrecedenceAssoc"],
5449 oom(seq(ign(g["SpacesOom"]), g["PrecedenceOpe"])));
5450 g["PrecedenceOpe"] <=
5451 cho(seq(cls("'"),
5452 tok(zom(seq(npd(cho(g["Space"], cls("'"))), g["Char"]))),
5453 cls("'")),
5454 seq(cls("\""),
5455 tok(zom(seq(npd(cho(g["Space"], cls("\""))), g["Char"]))),
5456 cls("\"")),
5457 tok(oom(seq(npd(cho(g["PrecedenceAssoc"], g["Space"], chr('}'))),
5458 dot()))));
5459 g["PrecedenceAssoc"] <= cls("LR");
5460
5461 // Error message instruction
5462 g["ErrorMessage"] <= seq(lit("error_message"), g["SpacesOom"],
5463 g["LiteralD"], g["SpacesZom"]);
5464
5465 // No Ast node optimization instruction
5466 g["NoAstOpt"] <= seq(lit("no_ast_opt"), g["SpacesZom"]);
5467
5468 // No whitespace skipping instruction
5469 g["NoWhitespace"] <= seq(lit("no_whitespace"), g["SpacesZom"]);
5470
5471 // AST node name override instruction: `{ ast_name: NodeTag }`
5472 g["AstName"] <= seq(lit("ast_name"), g["SpacesZom"], lit(":"),
5473 g["SpacesZom"], g["Identifier"], g["SpacesZom"]);
5474
5475 // Set definition names
5476 for (auto &x : g) {
5477 x.second.name = x.first;
5478 }
5479 }
5480
5482 g["Definition"] = [&](const SemanticValues &vs, std::any &dt) {
5483 auto &data = *std::any_cast<Data *>(dt);
5484
5485 // Macro iff the optional Parameters matched: its value (the parameter
5486 // name list) then sits at vs[2]. A plain definition has LEFTARROW's value
5487 // there instead.
5488 auto is_macro = vs[2].type() == typeid(std::vector<std::string>);
5489 auto ignore = std::any_cast<bool>(vs[0]);
5490 auto name = std::any_cast<std::string>(vs[1]);
5491
5492 std::vector<std::string> params;
5493 std::shared_ptr<Ope> ope;
5494 auto has_instructions = false;
5495
5496 if (is_macro) {
5497 params = std::any_cast<std::vector<std::string>>(vs[2]);
5498 ope = std::any_cast<std::shared_ptr<Ope>>(vs[4]);
5499 if (vs.size() == 6) { has_instructions = true; }
5500 } else {
5501 ope = std::any_cast<std::shared_ptr<Ope>>(vs[3]);
5502 if (vs.size() == 5) { has_instructions = true; }
5503 }
5504
5505 if (has_instructions) {
5506 auto index = is_macro ? 5 : 4;
5507 std::unordered_set<std::string> types;
5508 for (const auto &instruction :
5509 std::any_cast<std::vector<Instruction>>(vs[index])) {
5510 const auto &type = instruction.type;
5511 if (types.find(type) == types.end()) {
5512 data.instructions[name].push_back(instruction);
5513 types.insert(instruction.type);
5514 } else {
5515 data.duplicates_of_instruction.emplace_back(type,
5516 instruction.sv.data());
5517 }
5518 }
5519 }
5520
5521 auto &grammar = *data.grammar;
5522 if (!grammar.count(name)) {
5523 auto &rule = grammar[name];
5524 rule <= ope;
5525 rule.name = name;
5526 rule.s_ = vs.sv().data();
5527 rule.line_ = line_info(vs.ss, rule.s_);
5528 rule.ignoreSemanticValue = ignore;
5529 rule.is_macro = is_macro;
5530 rule.params = params;
5531
5532 // Reserved `%`-prefixed rules (%whitespace, %word, ...) are directives,
5533 // not parseable entry points, so they must not become the start rule.
5534 if (data.start.empty() && name[0] != '%') {
5535 data.start = rule.name;
5536 data.start_pos = rule.s_;
5537 }
5538 } else {
5539 data.duplicates_of_definition.emplace_back(name, vs.sv().data());
5540 }
5541 };
5542
5543 g["Definition"].enter = [](const Context & /*c*/, const char * /*s*/,
5544 size_t /*n*/, std::any &dt) {
5545 auto &data = *std::any_cast<Data *>(dt);
5546 data.captures_in_current_definition.clear();
5547 };
5548
5549 g["Expression"] = [&](const SemanticValues &vs) {
5550 if (vs.size() == 1) {
5551 return std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5552 } else {
5553 std::vector<std::shared_ptr<Ope>> opes;
5554 for (auto i = 0u; i < vs.size(); i++) {
5555 opes.emplace_back(std::any_cast<std::shared_ptr<Ope>>(vs[i]));
5556 }
5557 const std::shared_ptr<Ope> ope =
5558 std::make_shared<PrioritizedChoice>(opes);
5559 return ope;
5560 }
5561 };
5562
5563 g["Sequence"] = [&](const SemanticValues &vs) {
5564 if (vs.empty()) {
5565 return npd(lit(""));
5566 } else if (vs.size() == 1) {
5567 return std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5568 } else {
5569 std::vector<std::shared_ptr<Ope>> opes;
5570 for (const auto &x : vs) {
5571 opes.emplace_back(std::any_cast<std::shared_ptr<Ope>>(x));
5572 }
5573 const std::shared_ptr<Ope> ope = std::make_shared<Sequence>(opes);
5574 return ope;
5575 }
5576 };
5577
5578 g["Prefix"] = [&](const SemanticValues &vs) {
5579 std::shared_ptr<Ope> ope;
5580 if (vs.size() == 1) {
5581 ope = std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5582 } else {
5583 assert(vs.size() == 2);
5584 auto tok = std::any_cast<char>(vs[0]);
5585 ope = std::any_cast<std::shared_ptr<Ope>>(vs[1]);
5586 if (tok == '&') {
5587 ope = apd(ope);
5588 } else { // '!'
5589 ope = npd(ope);
5590 }
5591 }
5592 return ope;
5593 };
5594
5595 g["SuffixWithLabel"] = [&](const SemanticValues &vs, std::any &dt) {
5596 auto ope = std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5597 if (vs.size() == 1) {
5598 return ope;
5599 } else {
5600 assert(vs.size() == 2);
5601 auto &data = *std::any_cast<Data *>(dt);
5602 const auto &ident = std::any_cast<std::string>(vs[1]);
5603 auto label = ref(*data.grammar, ident, vs.sv().data(), false, {});
5604 auto recovery = rec(ref(*data.grammar, RECOVER_DEFINITION_NAME,
5605 vs.sv().data(), true, {label}));
5606 return cho4label_(ope, recovery);
5607 }
5608 };
5609
5610 struct Loop {
5611 enum class Type { opt = 0, zom, oom, rep };
5612 Type type;
5613 std::pair<size_t, size_t> range;
5614 };
5615
5616 g["Suffix"] = [&](const SemanticValues &vs) {
5617 auto ope = std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5618 if (vs.size() == 1) {
5619 return ope;
5620 } else {
5621 assert(vs.size() == 2);
5622 auto loop = std::any_cast<Loop>(vs[1]);
5623 switch (loop.type) {
5624 case Loop::Type::opt: return opt(ope);
5625 case Loop::Type::zom: return zom(ope);
5626 case Loop::Type::oom: return oom(ope);
5627 default: // Regex-like repetition
5628 return rep(ope, loop.range.first, loop.range.second);
5629 }
5630 }
5631 };
5632
5633 g["Loop"] = [&](const SemanticValues &vs) {
5634 switch (vs.choice()) {
5635 case 0: // Option
5636 return Loop{Loop::Type::opt, std::pair<size_t, size_t>()};
5637 case 1: // Zero or More
5638 return Loop{Loop::Type::zom, std::pair<size_t, size_t>()};
5639 case 2: // One or More
5640 return Loop{Loop::Type::oom, std::pair<size_t, size_t>()};
5641 default: // Regex-like repetition
5642 return Loop{Loop::Type::rep,
5643 std::any_cast<std::pair<size_t, size_t>>(vs[0])};
5644 }
5645 };
5646
5647 g["Primary"] = [&](const SemanticValues &vs, std::any &dt) {
5648 auto &data = *std::any_cast<Data *>(dt);
5649
5650 switch (vs.choice()) {
5651 case 0: { // Reference / Macro reference (left-factored)
5652 // Macro reference iff opt(Arguments) matched and pushed the arg list.
5653 auto is_macro = vs.size() > 2;
5654 auto ignore = std::any_cast<bool>(vs[0]);
5655 const auto &ident = std::any_cast<std::string>(vs[1]);
5656
5657 std::vector<std::shared_ptr<Ope>> args;
5658 if (is_macro) {
5659 args = std::any_cast<std::vector<std::shared_ptr<Ope>>>(vs[2]);
5660 }
5661
5662 auto ope = ref(*data.grammar, ident, vs.sv().data(), is_macro, args);
5663 if (ident == RECOVER_DEFINITION_NAME) { ope = rec(ope); }
5664
5665 if (ignore) {
5666 return ign(ope);
5667 } else {
5668 return ope;
5669 }
5670 }
5671 case 1: { // (Expression)
5672 return std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5673 }
5674 case 2: { // TokenBoundary
5675 return tok(std::any_cast<std::shared_ptr<Ope>>(vs[0]));
5676 }
5677 case 3: { // CaptureScope
5678 return csc(std::any_cast<std::shared_ptr<Ope>>(vs[0]));
5679 }
5680 case 4: { // Capture
5681 const auto &name = std::any_cast<std::string_view>(vs[0]);
5682 auto ope = std::any_cast<std::shared_ptr<Ope>>(vs[1]);
5683
5684 data.captures_stack.back().insert(name);
5685 data.captures_in_current_definition.insert(name);
5686
5687 return cap(ope, [name](const char *a_s, size_t a_n, Context &c) {
5688 c.capture_entries.emplace_back(name, std::string(a_s, a_n));
5689 });
5690 }
5691 default: {
5692 return std::any_cast<std::shared_ptr<Ope>>(vs[0]);
5693 }
5694 }
5695 };
5696
5697 g["IdentCont"] = [](const SemanticValues &vs) {
5698 return std::string(vs.sv().data(), vs.sv().length());
5699 };
5700
5701 g["Dictionary"] = [](const SemanticValues &vs) {
5702 auto items = vs.transform<std::string>();
5703 return dic(items, false);
5704 };
5705 g["DictionaryI"] = [](const SemanticValues &vs) {
5706 auto items = vs.transform<std::string>();
5707 return dic(items, true);
5708 };
5709
5710 g["Literal"] = [](const SemanticValues &vs) {
5711 const auto &tok = vs.tokens.front();
5712 return lit(resolve_escape_sequence(tok.data(), tok.size()));
5713 };
5714 g["LiteralI"] = [](const SemanticValues &vs) {
5715 const auto &tok = vs.tokens.front();
5716 return liti(resolve_escape_sequence(tok.data(), tok.size()));
5717 };
5718 g["LiteralD"] = [](const SemanticValues &vs) {
5719 auto &tok = vs.tokens.front();
5720 return resolve_escape_sequence(tok.data(), tok.size());
5721 };
5722 g["LiteralID"] = [](const SemanticValues &vs) {
5723 auto &tok = vs.tokens.front();
5724 return resolve_escape_sequence(tok.data(), tok.size());
5725 };
5726
5727 // A Range produces either a single range (std::pair) or a range list
5728 // (std::vector<std::pair>) for `\d`-style escapes and POSIX classes.
5729 auto collect_ranges = [](const SemanticValues &vs) {
5730 std::vector<std::pair<char32_t, char32_t>> ranges;
5731 for (const auto &v : vs) {
5732 if (v.type() == typeid(std::pair<char32_t, char32_t>)) {
5733 ranges.push_back(std::any_cast<std::pair<char32_t, char32_t>>(v));
5734 } else {
5735 const auto &vec =
5736 std::any_cast<const std::vector<std::pair<char32_t, char32_t>> &>(
5737 v);
5738 ranges.insert(ranges.end(), vec.begin(), vec.end());
5739 }
5740 }
5741 return ranges;
5742 };
5743
5744 g["Class"] = [collect_ranges](const SemanticValues &vs) {
5745 return cls(collect_ranges(vs));
5746 };
5747 g["ClassI"] = [collect_ranges](const SemanticValues &vs) {
5748 return cls(collect_ranges(vs), true);
5749 };
5750 g["NegatedClass"] = [collect_ranges](const SemanticValues &vs) {
5751 return ncls(collect_ranges(vs));
5752 };
5753 g["NegatedClassI"] = [collect_ranges](const SemanticValues &vs) {
5754 return ncls(collect_ranges(vs), true);
5755 };
5756 g["Range"] = [](const SemanticValues &vs) -> std::any {
5757 switch (vs.choice()) {
5758 case 0: {
5759 auto s1 = std::any_cast<std::string>(vs[0]);
5760 auto s2 = std::any_cast<std::string>(vs[1]);
5761 auto cp1 = decode_codepoint(s1.data(), s1.length());
5762 auto cp2 = decode_codepoint(s2.data(), s2.length());
5763 if (cp1 > cp2) {
5764 throw SyntaxErrorException("characer range is out of order...",
5765 vs.line_info());
5766 }
5767 return std::pair(cp1, cp2);
5768 }
5769 case 1: // ClassEscape
5770 case 2: // PosixClass
5771 return vs[0];
5772 case 3: {
5773 auto s = std::any_cast<std::string>(vs[0]);
5774 auto cp = decode_codepoint(s.data(), s.length());
5775 return std::pair(cp, cp);
5776 }
5777 }
5778 return std::pair<char32_t, char32_t>(0, 0);
5779 };
5780 g["ClassEscape"] = [](const SemanticValues &vs) {
5781 auto ch = vs.sv()[1];
5782 const char *name = nullptr;
5783 switch (ch) {
5784 case 'd':
5785 case 'D': name = "digit"; break;
5786 case 's':
5787 case 'S': name = "space"; break;
5788 default: name = "word"; break;
5789 }
5790 auto ranges = *predefined_character_class(name);
5791 if (ch == 'D' || ch == 'S' || ch == 'W') {
5792 ranges = complement_character_ranges(ranges);
5793 }
5794 return ranges;
5795 };
5796 g["PosixClass"] = [](const SemanticValues &vs) {
5797 auto sv = vs.sv(); // `[:name:]` or `[:^name:]`
5798 auto negated = sv[2] == '^';
5799 auto name = sv.substr(negated ? 3 : 2, sv.size() - (negated ? 5 : 4));
5800 auto ranges = predefined_character_class(name);
5801 if (!ranges) {
5802 auto msg = "invalid POSIX character class '" + std::string(name) + "'";
5803 throw SyntaxErrorException(msg.c_str(), vs.line_info());
5804 }
5805 return negated ? complement_character_ranges(*ranges) : *ranges;
5806 };
5807 g["Char"] = [](const SemanticValues &vs) {
5808 return resolve_escape_sequence(vs.sv().data(), vs.sv().length());
5809 };
5810
5811 g["RepetitionRange"] = [&](const SemanticValues &vs) {
5812 switch (vs.choice()) {
5813 case 0: { // Number COMMA Number
5814 auto min = std::any_cast<size_t>(vs[0]);
5815 auto max = std::any_cast<size_t>(vs[1]);
5816 return std::pair(min, max);
5817 }
5818 case 1: // Number COMMA
5819 return std::pair(std::any_cast<size_t>(vs[0]),
5820 std::numeric_limits<size_t>::max());
5821 case 2: { // Number
5822 auto n = std::any_cast<size_t>(vs[0]);
5823 return std::pair(n, n);
5824 }
5825 default: // COMMA Number
5826 return std::pair(std::numeric_limits<size_t>::min(),
5827 std::any_cast<size_t>(vs[0]));
5828 }
5829 };
5830 g["Number"] = [&](const SemanticValues &vs) {
5831 return vs.token_to_number<size_t>();
5832 };
5833
5834 g["CapScope"].enter = [](const Context & /*c*/, const char * /*s*/,
5835 size_t /*n*/, std::any &dt) {
5836 auto &data = *std::any_cast<Data *>(dt);
5837 data.captures_stack.emplace_back();
5838 };
5839 g["CapScope"].leave = [](const Context & /*c*/, const char * /*s*/,
5840 size_t /*n*/, size_t /*matchlen*/,
5841 std::any & /*value*/, std::any &dt) {
5842 auto &data = *std::any_cast<Data *>(dt);
5843 data.captures_stack.pop_back();
5844 };
5845
5846 g["AND"] = [](const SemanticValues &vs) { return *vs.sv().data(); };
5847 g["NOT"] = [](const SemanticValues &vs) { return *vs.sv().data(); };
5848 g["QUESTION"] = [](const SemanticValues &vs) { return *vs.sv().data(); };
5849 g["STAR"] = [](const SemanticValues &vs) { return *vs.sv().data(); };
5850 g["PLUS"] = [](const SemanticValues &vs) { return *vs.sv().data(); };
5851
5852 g["DOT"] = [](const SemanticValues & /*vs*/) { return dot(); };
5853
5854 g["CUT"] = [](const SemanticValues & /*vs*/) { return cut(); };
5855
5856 g["BeginCap"] = [](const SemanticValues &vs) { return vs.token(); };
5857
5858 g["BackRef"] = [&](const SemanticValues &vs, std::any &dt) {
5859 auto &data = *std::any_cast<Data *>(dt);
5860
5861 // Undefined back reference check
5862 {
5863 auto found = false;
5864 auto it = data.captures_stack.rbegin();
5865 while (it != data.captures_stack.rend()) {
5866 if (it->find(vs.token()) != it->end()) {
5867 found = true;
5868 break;
5869 }
5870 ++it;
5871 }
5872 if (!found) {
5873 auto ptr = vs.token().data() - 1; // include '$' symbol
5874 data.undefined_back_references.emplace_back(vs.token(), ptr);
5875 }
5876 }
5877
5878 // NOTE: Disable packrat parsing if a back reference is not defined in
5879 // captures in the current definition rule.
5880 if (data.captures_in_current_definition.find(vs.token()) ==
5881 data.captures_in_current_definition.end()) {
5882 data.enablePackratParsing = false;
5883 }
5884
5885 return bkr(vs.token_to_string());
5886 };
5887
5888 g["Ignore"] = [](const SemanticValues &vs) { return vs.size() > 0; };
5889
5890 g["Parameters"] = [](const SemanticValues &vs) {
5891 return vs.transform<std::string>();
5892 };
5893
5894 g["Arguments"] = [](const SemanticValues &vs) {
5895 return vs.transform<std::shared_ptr<Ope>>();
5896 };
5897
5898 g["PrecedenceClimbing"] = [](const SemanticValues &vs) {
5900 size_t level = 1;
5901 for (const auto &v : vs) {
5902 auto tokens = std::any_cast<std::vector<std::string_view>>(v);
5903 auto assoc = tokens[0][0];
5904 for (size_t i = 1; i < tokens.size(); i++) {
5905 binOpeInfo[tokens[i]] = std::pair(level, assoc);
5906 }
5907 level++;
5908 }
5909 Instruction instruction;
5910 instruction.type = "precedence";
5911 instruction.data = binOpeInfo;
5912 instruction.sv = vs.sv();
5913 return instruction;
5914 };
5915 g["PrecedenceInfo"] = [](const SemanticValues &vs) {
5916 return vs.transform<std::string_view>();
5917 };
5918 g["PrecedenceOpe"] = [](const SemanticValues &vs) { return vs.token(); };
5919 g["PrecedenceAssoc"] = [](const SemanticValues &vs) { return vs.token(); };
5920
5921 g["ErrorMessage"] = [](const SemanticValues &vs) {
5922 Instruction instruction;
5923 instruction.type = "error_message";
5924 instruction.data = std::any_cast<std::string>(vs[0]);
5925 instruction.sv = vs.sv();
5926 return instruction;
5927 };
5928
5929 g["NoAstOpt"] = [](const SemanticValues &vs) {
5930 Instruction instruction;
5931 instruction.type = "no_ast_opt";
5932 instruction.sv = vs.sv();
5933 return instruction;
5934 };
5935
5936 g["NoWhitespace"] = [](const SemanticValues &vs) {
5937 Instruction instruction;
5938 instruction.type = "no_whitespace";
5939 instruction.sv = vs.sv();
5940 return instruction;
5941 };
5942
5943 g["AstName"] = [](const SemanticValues &vs) {
5944 Instruction instruction;
5945 instruction.type = "ast_name";
5946 instruction.data = std::any_cast<std::string>(vs[0]);
5947 instruction.sv = vs.sv();
5948 return instruction;
5949 };
5950
5951 g["Instruction"] = [](const SemanticValues &vs) {
5952 return vs.transform<Instruction>();
5953 };
5954 }
5955
5958 const char *s, Log log) {
5959 try {
5960 auto &seq = dynamic_cast<Sequence &>(*rule.get_core_operator());
5961 auto atom = seq.opes_[0];
5962 auto &rep = dynamic_cast<Repetition &>(*seq.opes_[1]);
5963 auto &seq1 = dynamic_cast<Sequence &>(*rep.ope_);
5964 auto binop = seq1.opes_[0];
5965 auto atom1 = seq1.opes_[1];
5966
5967 auto atom_name = dynamic_cast<Reference &>(*atom).name_;
5968 auto binop_name = dynamic_cast<Reference &>(*binop).name_;
5969 auto atom1_name = dynamic_cast<Reference &>(*atom1).name_;
5970
5971 if (!rep.is_zom() || atom_name != atom1_name || atom_name == binop_name) {
5972 if (log) {
5973 auto line = line_info(s, rule.s_);
5974 log(line.first, line.second,
5975 "'precedence' instruction cannot be applied to '" + rule.name +
5976 "'.",
5977 "");
5978 }
5979 return false;
5980 }
5981
5982 rule.holder_->ope_ = pre(atom, binop, info, rule);
5983 rule.disable_action = true;
5984 } catch (...) {
5985 if (log) {
5986 auto line = line_info(s, rule.s_);
5987 log(line.first, line.second,
5988 "'precedence' instruction cannot be applied to '" + rule.name +
5989 "'.",
5990 "");
5991 }
5992 return false;
5993 }
5994 return true;
5995 }
5996
5997 ParserContext perform_core(const char *s, size_t n, const Rules &rules,
5998 Log log, std::string requested_start,
5999 bool enable_left_recursion = true) {
6000 Data data;
6001 auto &grammar = *data.grammar;
6002
6003 // Built-in macros
6004 {
6005 // `%recover`
6006 {
6007 auto &rule = grammar[RECOVER_DEFINITION_NAME];
6008 rule <= ref(grammar, "x", "", false, {});
6009 rule.name = RECOVER_DEFINITION_NAME;
6010 rule.s_ = "[native]";
6011 rule.ignoreSemanticValue = true;
6012 rule.is_macro = true;
6013 rule.params = {"x"};
6014 }
6015 }
6016
6017 try {
6018 std::any dt = &data;
6019 auto r = g["Grammar"].parse(s, n, dt, nullptr, log);
6020
6021 if (!r.ret) {
6022 if (log) {
6023 if (r.error_info.message_pos) {
6024 auto line = line_info(s, r.error_info.message_pos);
6025 log(line.first, line.second, r.error_info.message,
6026 r.error_info.label);
6027 } else {
6028 auto line = line_info(s, r.error_info.error_pos);
6029 log(line.first, line.second, "syntax error", r.error_info.label);
6030 }
6031 }
6032 return {};
6033 }
6034 } catch (const SyntaxErrorException &e) {
6035 if (log) {
6036 auto line = e.line_info();
6037 log(line.first, line.second, e.what(), "");
6038 }
6039 return {};
6040 }
6041
6042 // User provided rules
6043 for (auto [user_name, user_rule] : rules) {
6044 auto name = user_name;
6045 auto ignore = false;
6046 if (!name.empty() && name[0] == '~') {
6047 ignore = true;
6048 name.erase(0, 1);
6049 }
6050 if (!name.empty()) {
6051 auto &rule = grammar[name];
6052 rule <= user_rule;
6053 rule.name = name;
6054 rule.ignoreSemanticValue = ignore;
6055 }
6056 }
6057
6058 // Check duplicated definitions
6059 auto ret = true;
6060
6061 if (!data.duplicates_of_definition.empty()) {
6062 for (const auto &[name, ptr] : data.duplicates_of_definition) {
6063 if (log) {
6064 auto line = line_info(s, ptr);
6065 log(line.first, line.second,
6066 "the definition '" + name + "' is already defined.", "");
6067 }
6068 }
6069 ret = false;
6070 }
6071
6072 // Check duplicated instructions
6073 if (!data.duplicates_of_instruction.empty()) {
6074 for (const auto &[type, ptr] : data.duplicates_of_instruction) {
6075 if (log) {
6076 auto line = line_info(s, ptr);
6077 log(line.first, line.second,
6078 "the instruction '" + type + "' is already defined.", "");
6079 }
6080 }
6081 ret = false;
6082 }
6083
6084 // Check undefined back references
6085 if (!data.undefined_back_references.empty()) {
6086 for (const auto &[name, ptr] : data.undefined_back_references) {
6087 if (log) {
6088 auto line = line_info(s, ptr);
6089 log(line.first, line.second,
6090 "the back reference '" + name + "' is undefined.", "");
6091 }
6092 }
6093 ret = false;
6094 }
6095
6096 // Set root definition
6097 auto start = data.start;
6098
6099 if (!requested_start.empty()) {
6100 if (grammar.count(requested_start)) {
6101 start = requested_start;
6102 } else {
6103 if (log) {
6104 auto line = line_info(s, s);
6105 log(line.first, line.second,
6106 "the specified start rule '" + requested_start +
6107 "' is undefined.",
6108 "");
6109 }
6110 ret = false;
6111 }
6112 }
6113
6114 if (!ret) { return {}; }
6115
6116 auto &start_rule = grammar[start];
6117
6118 // Check if the start rule has ignore operator
6119 {
6120 if (start_rule.ignoreSemanticValue) {
6121 if (log) {
6122 auto line = line_info(s, start_rule.s_);
6123 log(line.first, line.second,
6124 "ignore operator cannot be applied to '" + start_rule.name + "'.",
6125 "");
6126 }
6127 ret = false;
6128 }
6129 }
6130
6131 if (!ret) { return {}; }
6132
6133 // Check missing definitions
6134 auto referenced = std::unordered_set<std::string>{
6138 start_rule.name,
6139 };
6140
6141 for (auto &[_, rule] : grammar) {
6142 ReferenceChecker vis(grammar, rule.params);
6143 rule.accept(vis);
6144 referenced.insert(vis.referenced.begin(), vis.referenced.end());
6145 for (const auto &[name, ptr] : vis.error_s) {
6146 if (log) {
6147 auto line = line_info(s, ptr);
6148 log(line.first, line.second, vis.error_message[name], "");
6149 }
6150 ret = false;
6151 }
6152 }
6153
6154 for (auto &[name, rule] : grammar) {
6155 if (!referenced.count(name)) {
6156 if (log) {
6157 auto line = line_info(s, rule.s_);
6158 auto msg = "'" + name + "' is not referenced.";
6159 log(line.first, line.second, msg, "");
6160 }
6161 }
6162 }
6163
6164 if (!ret) { return {}; }
6165
6166 // Link references
6167 for (auto &x : grammar) {
6168 auto &rule = x.second;
6169 LinkReferences vis(grammar, rule.params);
6170 rule.accept(vis);
6171 }
6172
6173 // Compute can_be_empty for each rule (fixed-point iteration)
6174 {
6175 bool changed = true;
6176 while (changed) {
6177 changed = false;
6178 for (auto &[name, rule] : grammar) {
6180 rule.accept(vis);
6181 if (vis.result != rule.can_be_empty) {
6182 rule.can_be_empty = vis.result;
6183 changed = true;
6184 }
6185 }
6186 }
6187 }
6188
6189 // Check left recursion
6190 if (enable_left_recursion) {
6191 for (auto &[name, rule] : grammar) {
6192 DetectLeftRecursion vis(name);
6193 rule.accept(vis);
6194 if (vis.error_s) { rule.is_left_recursive = true; }
6195 }
6196 } else {
6197 ret = true;
6198
6199 for (auto &[name, rule] : grammar) {
6200 DetectLeftRecursion vis(name);
6201 rule.accept(vis);
6202 if (vis.error_s) {
6203 if (log) {
6204 auto line = line_info(s, vis.error_s);
6205 log(line.first, line.second, "'" + name + "' is left recursive.",
6206 "");
6207 }
6208 ret = false;
6209 }
6210 }
6211
6212 if (!ret) { return {}; }
6213 }
6214
6215 // Check infinite loop
6216 if (detect_infiniteLoop(data, start_rule, log, s)) { return {}; }
6217
6218 // Automatic whitespace skipping
6219 if (grammar.count(WHITESPACE_DEFINITION_NAME)) {
6220 for (auto &x : grammar) {
6221 auto &rule = x.second;
6222 auto ope = rule.get_core_operator();
6223 if (IsLiteralToken::check(*ope)) { rule <= tok(ope); }
6224 }
6225
6226 auto &rule = grammar[WHITESPACE_DEFINITION_NAME];
6227 start_rule.whitespaceOpe = wsp(rule.get_core_operator());
6228
6229 if (detect_infiniteLoop(data, rule, log, s)) { return {}; }
6230 }
6231
6232 // Word expression
6233 if (grammar.count(WORD_DEFINITION_NAME)) {
6234 auto &rule = grammar[WORD_DEFINITION_NAME];
6235 start_rule.wordOpe = rule.get_core_operator();
6236
6237 if (detect_infiniteLoop(data, rule, log, s)) { return {}; }
6238 }
6239
6240 // Apply instructions
6241 for (const auto &[name, instructions] : data.instructions) {
6242 auto &rule = grammar[name];
6243
6244 for (const auto &instruction : instructions) {
6245 if (instruction.type == "precedence") {
6246 const auto &info =
6247 std::any_cast<PrecedenceClimbing::BinOpeInfo>(instruction.data);
6248
6249 if (!apply_precedence_instruction(rule, info, s, log)) { return {}; }
6250 } else if (instruction.type == "error_message") {
6251 rule.error_message = std::any_cast<std::string>(instruction.data);
6252 } else if (instruction.type == "no_ast_opt") {
6253 rule.no_ast_opt = true;
6254 } else if (instruction.type == "no_whitespace") {
6255 rule.no_whitespace = true;
6256 } else if (instruction.type == "ast_name") {
6257 rule.ast_name = std::any_cast<std::string>(instruction.data);
6258 }
6259 }
6260 }
6261
6262 // Setup First-Set and ISpan optimizations. A single visitor is shared
6263 // across all rules so its first-set cache and visited-rule set persist:
6264 // each rule's first-sets are computed once (O(N)) instead of re-walking
6265 // every reachable rule once per referencing rule (O(N^2)).
6266 {
6267 SetupFirstSets vis;
6268 for (auto &x : grammar) {
6269 x.second.accept(vis);
6270 }
6271 }
6272
6273 return {data.grammar, start, data.enablePackratParsing};
6274 }
6275
6276 bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log,
6277 const char *s) const {
6278 std::vector<std::pair<const char *, std::string>> refs;
6279 std::unordered_map<std::string, bool> has_error_cache;
6280 DetectInfiniteLoop vis(data.start_pos, rule.name, refs, has_error_cache);
6281 rule.accept(vis);
6282 if (vis.has_error) {
6283 if (log) {
6284 auto line = line_info(s, vis.error_s);
6285 log(line.first, line.second,
6286 "infinite loop is detected in '" + vis.error_name + "'.", "");
6287 }
6288 return true;
6289 }
6290 return false;
6291 }
6292
6294};
6295
6296/*-----------------------------------------------------------------------------
6297 * AST
6298 *---------------------------------------------------------------------------*/
6299
6300template <typename Annotation> struct AstBase : public Annotation {
6301 AstBase(const char *path, size_t line, size_t column, const char *name,
6302 const std::vector<std::shared_ptr<AstBase>> &nodes,
6303 size_t position = 0, size_t length = 0, size_t choice_count = 0,
6304 size_t choice = 0, bool preserve_position = false)
6305 : path(path ? path : ""), line(line), column(column), name(name),
6311
6312 AstBase(const char *path, size_t line, size_t column, const char *name,
6313 const std::string_view &token, size_t position = 0, size_t length = 0,
6314 size_t choice_count = 0, size_t choice = 0,
6315 bool preserve_position = false)
6316 : path(path ? path : ""), line(line), column(column), name(name),
6322
6334
6335 const std::string path;
6336 const size_t line = 1;
6337 const size_t column = 1;
6338
6339 const std::string name;
6340 size_t position;
6341 size_t length;
6342 const size_t choice_count;
6343 const size_t choice;
6344 const std::string original_name;
6346 const size_t original_choice;
6347 const unsigned int tag;
6348 const unsigned int original_tag;
6349
6350 const bool is_token;
6352 const std::string_view token;
6353
6354 std::vector<std::shared_ptr<AstBase<Annotation>>> nodes;
6355 std::weak_ptr<AstBase<Annotation>> parent;
6356
6357 std::string token_to_string() const {
6358 assert(is_token);
6359 return std::string(token);
6360 }
6361
6362 template <typename T> T token_to_number() const {
6363 return token_to_number_<T>(token);
6364 }
6365};
6366
6367template <typename T>
6368void ast_to_s_core(const std::shared_ptr<T> &ptr, std::string &s, int level,
6369 std::function<std::string(const T &ast, int level)> fn) {
6370 const auto &ast = *ptr;
6371 for (auto i = 0; i < level; i++) {
6372 s += " ";
6373 }
6374 auto name = ast.original_name;
6375 if (ast.original_choice_count > 0) {
6376 name += "/" + std::to_string(ast.original_choice);
6377 }
6378 if (ast.name != ast.original_name) { name += "[" + ast.name + "]"; }
6379 if (ast.is_token) {
6380 s += "- " + name + " (";
6381 s += ast.token;
6382 s += ")\n";
6383 } else {
6384 s += "+ " + name + "\n";
6385 }
6386 if (fn) { s += fn(ast, level + 1); }
6387 for (const auto &node : ast.nodes) {
6388 ast_to_s_core(node, s, level + 1, fn);
6389 }
6390}
6391
6392template <typename T>
6393std::string
6394ast_to_s(const std::shared_ptr<T> &ptr,
6395 std::function<std::string(const T &ast, int level)> fn = nullptr) {
6396 std::string s;
6397 ast_to_s_core(ptr, s, 0, fn);
6398 return s;
6399}
6400
6402 AstOptimizer(bool mode, const std::vector<std::string> &rules = {})
6403 : mode_(mode), rules_(rules) {}
6404
6405 template <typename T>
6406 std::shared_ptr<T> optimize(std::shared_ptr<T> original,
6407 std::shared_ptr<T> parent = nullptr) {
6408 auto found =
6409 std::find(rules_.begin(), rules_.end(), original->name) != rules_.end();
6410 auto opt = mode_ ? !found : found;
6411
6412 if (opt && original->nodes.size() == 1) {
6413 auto child = optimize(original->nodes[0], parent);
6414 auto pos =
6415 child->preserve_position ? child->position : original->position;
6416 auto len = child->preserve_position ? child->length : original->length;
6417 auto ast = std::make_shared<T>(*child, original->name.data(), pos, len,
6418 original->choice_count, original->choice);
6419 for (auto &node : ast->nodes) {
6420 node->parent = ast;
6421 }
6422 return ast;
6423 }
6424
6425 auto ast = std::make_shared<T>(*original);
6426 ast->parent = parent;
6427 ast->nodes.clear();
6428 for (const auto &node : original->nodes) {
6429 auto child = optimize(node, ast);
6430 ast->nodes.push_back(child);
6431 }
6432 return ast;
6433 }
6434
6435private:
6436 const bool mode_;
6437 const std::vector<std::string> rules_;
6438};
6439
6440struct EmptyType {};
6441using Ast = AstBase<EmptyType>;
6442
6443template <typename T = Ast> void add_ast_action(Definition &rule) {
6444 rule.action = [&](const SemanticValues &vs) {
6445 auto line = vs.line_info();
6446
6447 // `{ ast_name: X }` overrides the node's name/tag (falls back to the
6448 // rule's own name when unset).
6449 const char *node_name =
6450 rule.ast_name.empty() ? rule.name.data() : rule.ast_name.data();
6451
6452 if (rule.is_token()) {
6453 return std::make_shared<T>(
6454 vs.path, line.first, line.second, node_name, vs.token(),
6455 std::distance(vs.ss, vs.sv().data()), vs.sv().length(),
6456 vs.choice_count(), vs.choice(), rule.no_ast_opt);
6457 }
6458
6459 auto ast = std::make_shared<T>(vs.path, line.first, line.second, node_name,
6460 vs.transform<std::shared_ptr<T>>(),
6461 std::distance(vs.ss, vs.sv().data()),
6462 vs.sv().length(), vs.choice_count(),
6463 vs.choice(), rule.no_ast_opt);
6464
6465 for (auto &node : ast->nodes) {
6466 node->parent = ast;
6467 }
6468 return ast;
6469 };
6470}
6471
6472#define PEG_EXPAND(...) __VA_ARGS__
6473#define PEG_CONCAT(a, b) a##b
6474#define PEG_CONCAT2(a, b) PEG_CONCAT(a, b)
6475
6476#define PEG_PICK( \
6477 a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, \
6478 a17, a18, a19, a20, a21, a22, a23, a24, a25, a26, a27, a28, a29, a30, a31, \
6479 a32, a33, a34, a35, a36, a37, a38, a39, a40, a41, a42, a43, a44, a45, a46, \
6480 a47, a48, a49, a50, a51, a52, a53, a54, a55, a56, a57, a58, a59, a60, a61, \
6481 a62, a63, a64, a65, a66, a67, a68, a69, a70, a71, a72, a73, a74, a75, a76, \
6482 a77, a78, a79, a80, a81, a82, a83, a84, a85, a86, a87, a88, a89, a90, a91, \
6483 a92, a93, a94, a95, a96, a97, a98, a99, a100, ...) \
6484 a100
6485
6486#define PEG_COUNT(...) \
6487 PEG_EXPAND(PEG_PICK( \
6488 __VA_ARGS__, 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, \
6489 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, \
6490 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, \
6491 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, \
6492 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, \
6493 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0))
6494
6495#define PEG_DEF_1(r) \
6496 peg::Definition r; \
6497 r.name = #r; \
6498 peg::add_ast_action(r);
6499
6500#define PEG_DEF_2(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_1(__VA_ARGS__))
6501#define PEG_DEF_3(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_2(__VA_ARGS__))
6502#define PEG_DEF_4(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_3(__VA_ARGS__))
6503#define PEG_DEF_5(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_4(__VA_ARGS__))
6504#define PEG_DEF_6(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_5(__VA_ARGS__))
6505#define PEG_DEF_7(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_6(__VA_ARGS__))
6506#define PEG_DEF_8(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_7(__VA_ARGS__))
6507#define PEG_DEF_9(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_8(__VA_ARGS__))
6508#define PEG_DEF_10(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_9(__VA_ARGS__))
6509#define PEG_DEF_11(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_10(__VA_ARGS__))
6510#define PEG_DEF_12(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_11(__VA_ARGS__))
6511#define PEG_DEF_13(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_12(__VA_ARGS__))
6512#define PEG_DEF_14(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_13(__VA_ARGS__))
6513#define PEG_DEF_15(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_14(__VA_ARGS__))
6514#define PEG_DEF_16(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_15(__VA_ARGS__))
6515#define PEG_DEF_17(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_16(__VA_ARGS__))
6516#define PEG_DEF_18(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_17(__VA_ARGS__))
6517#define PEG_DEF_19(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_18(__VA_ARGS__))
6518#define PEG_DEF_20(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_19(__VA_ARGS__))
6519#define PEG_DEF_21(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_20(__VA_ARGS__))
6520#define PEG_DEF_22(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_21(__VA_ARGS__))
6521#define PEG_DEF_23(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_22(__VA_ARGS__))
6522#define PEG_DEF_24(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_23(__VA_ARGS__))
6523#define PEG_DEF_25(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_24(__VA_ARGS__))
6524#define PEG_DEF_26(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_25(__VA_ARGS__))
6525#define PEG_DEF_27(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_26(__VA_ARGS__))
6526#define PEG_DEF_28(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_27(__VA_ARGS__))
6527#define PEG_DEF_29(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_28(__VA_ARGS__))
6528#define PEG_DEF_30(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_29(__VA_ARGS__))
6529#define PEG_DEF_31(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_30(__VA_ARGS__))
6530#define PEG_DEF_32(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_31(__VA_ARGS__))
6531#define PEG_DEF_33(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_32(__VA_ARGS__))
6532#define PEG_DEF_34(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_33(__VA_ARGS__))
6533#define PEG_DEF_35(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_34(__VA_ARGS__))
6534#define PEG_DEF_36(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_35(__VA_ARGS__))
6535#define PEG_DEF_37(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_36(__VA_ARGS__))
6536#define PEG_DEF_38(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_37(__VA_ARGS__))
6537#define PEG_DEF_39(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_38(__VA_ARGS__))
6538#define PEG_DEF_40(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_39(__VA_ARGS__))
6539#define PEG_DEF_41(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_40(__VA_ARGS__))
6540#define PEG_DEF_42(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_41(__VA_ARGS__))
6541#define PEG_DEF_43(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_42(__VA_ARGS__))
6542#define PEG_DEF_44(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_43(__VA_ARGS__))
6543#define PEG_DEF_45(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_44(__VA_ARGS__))
6544#define PEG_DEF_46(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_45(__VA_ARGS__))
6545#define PEG_DEF_47(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_46(__VA_ARGS__))
6546#define PEG_DEF_48(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_47(__VA_ARGS__))
6547#define PEG_DEF_49(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_48(__VA_ARGS__))
6548#define PEG_DEF_50(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_49(__VA_ARGS__))
6549#define PEG_DEF_51(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_50(__VA_ARGS__))
6550#define PEG_DEF_52(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_51(__VA_ARGS__))
6551#define PEG_DEF_53(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_52(__VA_ARGS__))
6552#define PEG_DEF_54(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_53(__VA_ARGS__))
6553#define PEG_DEF_55(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_54(__VA_ARGS__))
6554#define PEG_DEF_56(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_55(__VA_ARGS__))
6555#define PEG_DEF_57(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_56(__VA_ARGS__))
6556#define PEG_DEF_58(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_57(__VA_ARGS__))
6557#define PEG_DEF_59(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_58(__VA_ARGS__))
6558#define PEG_DEF_60(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_59(__VA_ARGS__))
6559#define PEG_DEF_61(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_60(__VA_ARGS__))
6560#define PEG_DEF_62(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_61(__VA_ARGS__))
6561#define PEG_DEF_63(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_62(__VA_ARGS__))
6562#define PEG_DEF_64(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_63(__VA_ARGS__))
6563#define PEG_DEF_65(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_64(__VA_ARGS__))
6564#define PEG_DEF_66(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_65(__VA_ARGS__))
6565#define PEG_DEF_67(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_66(__VA_ARGS__))
6566#define PEG_DEF_68(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_67(__VA_ARGS__))
6567#define PEG_DEF_69(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_68(__VA_ARGS__))
6568#define PEG_DEF_70(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_69(__VA_ARGS__))
6569#define PEG_DEF_71(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_70(__VA_ARGS__))
6570#define PEG_DEF_72(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_71(__VA_ARGS__))
6571#define PEG_DEF_73(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_72(__VA_ARGS__))
6572#define PEG_DEF_74(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_73(__VA_ARGS__))
6573#define PEG_DEF_75(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_74(__VA_ARGS__))
6574#define PEG_DEF_76(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_75(__VA_ARGS__))
6575#define PEG_DEF_77(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_76(__VA_ARGS__))
6576#define PEG_DEF_78(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_77(__VA_ARGS__))
6577#define PEG_DEF_79(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_78(__VA_ARGS__))
6578#define PEG_DEF_80(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_79(__VA_ARGS__))
6579#define PEG_DEF_81(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_80(__VA_ARGS__))
6580#define PEG_DEF_82(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_81(__VA_ARGS__))
6581#define PEG_DEF_83(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_82(__VA_ARGS__))
6582#define PEG_DEF_84(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_83(__VA_ARGS__))
6583#define PEG_DEF_85(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_84(__VA_ARGS__))
6584#define PEG_DEF_86(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_85(__VA_ARGS__))
6585#define PEG_DEF_87(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_86(__VA_ARGS__))
6586#define PEG_DEF_88(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_87(__VA_ARGS__))
6587#define PEG_DEF_89(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_88(__VA_ARGS__))
6588#define PEG_DEF_90(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_89(__VA_ARGS__))
6589#define PEG_DEF_91(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_90(__VA_ARGS__))
6590#define PEG_DEF_92(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_91(__VA_ARGS__))
6591#define PEG_DEF_93(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_92(__VA_ARGS__))
6592#define PEG_DEF_94(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_93(__VA_ARGS__))
6593#define PEG_DEF_95(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_94(__VA_ARGS__))
6594#define PEG_DEF_96(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_95(__VA_ARGS__))
6595#define PEG_DEF_97(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_96(__VA_ARGS__))
6596#define PEG_DEF_98(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_97(__VA_ARGS__))
6597#define PEG_DEF_99(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_98(__VA_ARGS__))
6598#define PEG_DEF_100(r1, ...) PEG_EXPAND(PEG_DEF_1(r1) PEG_DEF_99(__VA_ARGS__))
6599
6600#define AST_DEFINITIONS(...) \
6601 PEG_EXPAND(PEG_CONCAT2(PEG_DEF_, PEG_COUNT(__VA_ARGS__))(__VA_ARGS__))
6602
6603/*-----------------------------------------------------------------------------
6604 * parser
6605 *---------------------------------------------------------------------------*/
6606
6607class parser {
6608public:
6609 parser() = default;
6610
6611 parser(const char *s, size_t n, const Rules &rules,
6612 std::string_view start = {}) {
6613 load_grammar(s, n, rules, start);
6614 }
6615
6616 parser(const char *s, size_t n, std::string_view start = {})
6617 : parser(s, n, Rules(), start) {}
6618
6619 parser(std::string_view sv, const Rules &rules, std::string_view start = {})
6620 : parser(sv.data(), sv.size(), rules, start) {}
6621
6622 parser(std::string_view sv, std::string_view start = {})
6623 : parser(sv.data(), sv.size(), Rules(), start) {}
6624
6625#if defined(__cpp_lib_char8_t)
6626 parser(std::u8string_view sv, const Rules &rules, std::string_view start = {})
6627 : parser(reinterpret_cast<const char *>(sv.data()), sv.size(), rules,
6628 start) {}
6629
6630 parser(std::u8string_view sv, std::string_view start = {})
6631 : parser(reinterpret_cast<const char *>(sv.data()), sv.size(), Rules(),
6632 start) {}
6633#endif
6634
6635 operator bool() const { return grammar_ != nullptr; }
6636
6637 bool load_grammar(const char *s, size_t n, const Rules &rules,
6638 std::string_view start = {}) {
6639 auto cxt =
6640 ParserGenerator::parse(s, n, rules, log_, start, enableLeftRecursion_);
6641 grammar_ = cxt.grammar;
6642 start_ = cxt.start;
6643 enablePackratParsing_ = cxt.enablePackratParsing;
6644 return grammar_ != nullptr;
6645 }
6646
6647 bool load_grammar(const char *s, size_t n, std::string_view start = {}) {
6648 return load_grammar(s, n, Rules(), start);
6649 }
6650
6651 bool load_grammar(std::string_view sv, const Rules &rules,
6652 std::string_view start = {}) {
6653 return load_grammar(sv.data(), sv.size(), rules, start);
6654 }
6655
6656 bool load_grammar(std::string_view sv, std::string_view start = {}) {
6657 return load_grammar(sv.data(), sv.size(), Rules(), start);
6658 }
6659
6660 // Serialize the loaded grammar to a portable byte blob (see GrammarBlob).
6661 // Semantic callbacks are not included; throws if the grammar is not
6662 // serializable (uses the `User` operator or a Capture with a match action).
6663 std::vector<uint8_t> serialize_grammar() const {
6665 }
6666
6667 // Load a grammar from a blob produced by serialize_grammar() / GrammarBlob,
6668 // skipping the meta-parse. Re-apply enable_ast() etc. afterwards as needed.
6669 bool load_blob(const std::vector<uint8_t> &blob) {
6670 try {
6672 } catch (const std::exception &) { return false; }
6673 if (grammar_ != nullptr) {
6674 // Symmetry with load_grammar(): restore the parser-level packrat flag
6675 // from the blob so a later enable_packrat_parsing() re-applies it
6676 // instead of resetting the start rule to the false member default.
6677 enablePackratParsing_ = (*grammar_)[start_].enablePackratParsing;
6678 }
6679 return grammar_ != nullptr;
6680 }
6681
6682 bool parse_n(const char *s, size_t n, const char *path = nullptr) const {
6683 if (grammar_ != nullptr) {
6684 const auto &rule = (*grammar_)[start_];
6685 auto result = rule.parse(s, n, path, log_, error_reporter_);
6686 return post_process(s, n, result);
6687 }
6688 return false;
6689 }
6690
6691 bool parse_n(const char *s, size_t n, std::any &dt,
6692 const char *path = nullptr) const {
6693 if (grammar_ != nullptr) {
6694 const auto &rule = (*grammar_)[start_];
6695 auto result = rule.parse(s, n, dt, path, log_, error_reporter_);
6696 return post_process(s, n, result);
6697 }
6698 return false;
6699 }
6700
6701 template <typename T>
6702 bool parse_n(const char *s, size_t n, T &val,
6703 const char *path = nullptr) const {
6704 if (grammar_ != nullptr) {
6705 const auto &rule = (*grammar_)[start_];
6706 auto result =
6707 rule.parse_and_get_value(s, n, val, path, log_, error_reporter_);
6708 return post_process(s, n, result);
6709 }
6710 return false;
6711 }
6712
6713 template <typename T>
6714 bool parse_n(const char *s, size_t n, std::any &dt, T &val,
6715 const char *path = nullptr) const {
6716 if (grammar_ != nullptr) {
6717 const auto &rule = (*grammar_)[start_];
6718 auto result =
6719 rule.parse_and_get_value(s, n, dt, val, path, log_, error_reporter_);
6720 return post_process(s, n, result);
6721 }
6722 return false;
6723 }
6724
6725 bool parse(std::string_view sv, const char *path = nullptr) const {
6726 return parse_n(sv.data(), sv.size(), path);
6727 }
6728
6729 bool parse(std::string_view sv, std::any &dt,
6730 const char *path = nullptr) const {
6731 return parse_n(sv.data(), sv.size(), dt, path);
6732 }
6733
6734 template <typename T>
6735 bool parse(std::string_view sv, T &val, const char *path = nullptr) const {
6736 return parse_n(sv.data(), sv.size(), val, path);
6737 }
6738
6739 template <typename T>
6740 bool parse(std::string_view sv, std::any &dt, T &val,
6741 const char *path = nullptr) const {
6742 return parse_n(sv.data(), sv.size(), dt, val, path);
6743 }
6744
6745#if defined(__cpp_lib_char8_t)
6746 bool parse(std::u8string_view sv, const char *path = nullptr) const {
6747 return parse_n(reinterpret_cast<const char *>(sv.data()), sv.size(), path);
6748 }
6749
6750 bool parse(std::u8string_view sv, std::any &dt,
6751 const char *path = nullptr) const {
6752 return parse_n(reinterpret_cast<const char *>(sv.data()), sv.size(), dt,
6753 path);
6754 }
6755
6756 template <typename T>
6757 bool parse(std::u8string_view sv, T &val, const char *path = nullptr) const {
6758 return parse_n(reinterpret_cast<const char *>(sv.data()), sv.size(), val,
6759 path);
6760 }
6761
6762 template <typename T>
6763 bool parse(std::u8string_view sv, std::any &dt, T &val,
6764 const char *path = nullptr) const {
6765 return parse_n(reinterpret_cast<const char *>(sv.data()), sv.size(), dt,
6766 val, path);
6767 }
6768#endif
6769
6770 Definition &operator[](const char *s) { return (*grammar_)[s]; }
6771
6772 const Definition &operator[](const char *s) const { return (*grammar_)[s]; }
6773
6774 const Grammar &get_grammar() const { return *grammar_; }
6775
6777 if (grammar_ != nullptr) {
6778 auto &rule = (*grammar_)[start_];
6779 rule.eoi_check = false;
6780 }
6781 }
6782
6783 void enable_left_recursion(bool enable = true) {
6784 enableLeftRecursion_ = enable;
6785 }
6786
6788 if (grammar_ != nullptr) {
6789 auto &rule = (*grammar_)[start_];
6790 rule.enablePackratParsing = enablePackratParsing_;
6791 }
6792 }
6793
6794 void enable_trace(TracerEnter tracer_enter, TracerLeave tracer_leave) {
6795 if (grammar_ != nullptr) {
6796 auto &rule = (*grammar_)[start_];
6797 rule.tracer_enter = tracer_enter;
6798 rule.tracer_leave = tracer_leave;
6799 }
6800 }
6801
6802 void enable_trace(TracerEnter tracer_enter, TracerLeave tracer_leave,
6803 TracerStartOrEnd tracer_start,
6804 TracerStartOrEnd tracer_end) {
6805 if (grammar_ != nullptr) {
6806 auto &rule = (*grammar_)[start_];
6807 rule.tracer_enter = tracer_enter;
6808 rule.tracer_leave = tracer_leave;
6809 rule.tracer_start = tracer_start;
6810 rule.tracer_end = tracer_end;
6811 }
6812 }
6813
6814 void set_verbose_trace(bool verbose_trace) {
6815 if (grammar_ != nullptr) {
6816 auto &rule = (*grammar_)[start_];
6817 rule.verbose_trace = verbose_trace;
6818 }
6819 }
6820
6821 template <typename T = Ast> parser &enable_ast() {
6822 for (auto &[_, rule] : *grammar_) {
6823 if (!rule.action) { add_ast_action<T>(rule); }
6824 }
6825 return *this;
6826 }
6827
6828 template <typename T>
6829 std::shared_ptr<T> optimize_ast(std::shared_ptr<T> ast,
6830 bool opt_mode = true) const {
6831 return AstOptimizer(opt_mode, get_no_ast_opt_rules()).optimize(ast);
6832 }
6833
6834 void set_logger(Log log) { log_ = log; }
6835
6836 // Receive structured error information instead of (or in addition to) the
6837 // formatted string passed to the logger.
6839 error_reporter_ = reporter;
6840 }
6841
6843 std::function<void(size_t line, size_t col, const std::string &msg)>
6844 log) {
6845 log_ = [log](size_t line, size_t col, const std::string &msg,
6846 const std::string & /*rule*/) { log(line, col, msg); };
6847 }
6848
6849private:
6850 bool post_process(const char *s, size_t n, Definition::Result &r) const {
6851 if ((log_ || error_reporter_) && !r.ret) {
6853 }
6854 return r.ret && !r.recovered;
6855 }
6856
6857 std::vector<std::string> get_no_ast_opt_rules() const {
6858 std::vector<std::string> rules;
6859 for (auto &[name, rule] : *grammar_) {
6860 // The optimizer keeps nodes by their emitted name, so honor the
6861 // `ast_name` override when present (else the rule's own name).
6862 if (rule.no_ast_opt) {
6863 rules.push_back(rule.ast_name.empty() ? name : rule.ast_name);
6864 }
6865 }
6866 return rules;
6867 }
6868
6869 std::shared_ptr<Grammar> grammar_;
6870 std::string start_;
6875};
6876
6877/*-----------------------------------------------------------------------------
6878 * enable_tracing
6879 *---------------------------------------------------------------------------*/
6880
6881inline void enable_tracing(parser &parser, std::ostream &os) {
6883 [&](auto &ope, auto s, auto, auto &, auto &c, auto &, auto &trace_data) {
6884 auto prev_pos = std::any_cast<size_t>(trace_data);
6885 auto pos = static_cast<size_t>(s - c.s);
6886 auto backtrack = (pos < prev_pos ? "*" : "");
6887 std::string indent;
6888 auto level = c.trace_ids.size() - 1;
6889 while (level--) {
6890 indent += "│";
6891 }
6892 std::string name;
6893 {
6894 name = peg::TraceOpeName::get(const_cast<peg::Ope &>(ope));
6895
6896 auto lit = dynamic_cast<const peg::LiteralString *>(&ope);
6897 if (lit) { name += " '" + peg::escape_characters(lit->lit_) + "'"; }
6898 }
6899 os << "E " << pos + 1 << backtrack << "\t" << indent << "┌" << name
6900 << " #" << c.trace_ids.back() << std::endl;
6901 trace_data = static_cast<size_t>(pos);
6902 },
6903 [&](auto &ope, auto s, auto, auto &sv, auto &c, auto &, auto len,
6904 auto &) {
6905 auto pos = static_cast<size_t>(s - c.s);
6906 if (len != static_cast<size_t>(-1)) { pos += len; }
6907 std::string indent;
6908 auto level = c.trace_ids.size() - 1;
6909 while (level--) {
6910 indent += "│";
6911 }
6912 auto ret = len != static_cast<size_t>(-1) ? "└o " : "└x ";
6913 auto name = peg::TraceOpeName::get(const_cast<peg::Ope &>(ope));
6914 std::stringstream choice;
6915 if (sv.choice_count() > 0) {
6916 choice << " " << sv.choice() << "/" << sv.choice_count();
6917 }
6918 std::string token;
6919 if (!sv.tokens.empty()) {
6920 token += ", token '";
6921 token += sv.tokens[0];
6922 token += "'";
6923 }
6924 std::string matched;
6925 if (peg::success(len) &&
6926 peg::TokenChecker::is_token(const_cast<peg::Ope &>(ope))) {
6927 matched = ", match '" + peg::escape_characters(s, len) + "'";
6928 }
6929 os << "L " << pos + 1 << "\t" << indent << ret << name << " #"
6930 << c.trace_ids.back() << choice.str() << token << matched
6931 << std::endl;
6932 },
6933 [&](auto &trace_data) { trace_data = static_cast<size_t>(0); },
6934 [&](auto &) {});
6935}
6936
6937/*-----------------------------------------------------------------------------
6938 * enable_profiling
6939 *---------------------------------------------------------------------------*/
6940
6941inline void enable_profiling(parser &parser, std::ostream &os) {
6942 struct Stats {
6943 struct Item {
6944 std::string name;
6945 size_t success;
6946 size_t fail;
6947 };
6948 std::vector<Item> items;
6949 std::map<std::string, size_t> index;
6950 size_t total = 0;
6951 std::chrono::steady_clock::time_point start;
6952 };
6953
6955 [&](auto &ope, auto, auto, auto &, auto &, auto &, std::any &trace_data) {
6956 if (auto holder = dynamic_cast<const peg::Holder *>(&ope)) {
6957 auto &stats = *std::any_cast<Stats *>(trace_data);
6958
6959 auto &name = holder->name();
6960 if (stats.index.find(name) == stats.index.end()) {
6961 stats.index[name] = stats.index.size();
6962 stats.items.push_back({name, 0, 0});
6963 }
6964 stats.total++;
6965 }
6966 },
6967 [&](auto &ope, auto, auto, auto &, auto &, auto &, auto len,
6968 std::any &trace_data) {
6969 if (auto holder = dynamic_cast<const peg::Holder *>(&ope)) {
6970 auto &stats = *std::any_cast<Stats *>(trace_data);
6971
6972 auto &name = holder->name();
6973 auto index = stats.index[name];
6974 auto &stat = stats.items[index];
6975 if (len != static_cast<size_t>(-1)) {
6976 stat.success++;
6977 } else {
6978 stat.fail++;
6979 }
6980
6981 if (index == 0) {
6982 auto end = std::chrono::steady_clock::now();
6983 auto nano = std::chrono::duration_cast<std::chrono::microseconds>(
6984 end - stats.start)
6985 .count();
6986 auto sec = nano / 1000000.0;
6987 os << "duration: " << sec << "s (" << nano << "µs)" << std::endl
6988 << std::endl;
6989
6990 char buff[BUFSIZ];
6991 size_t total_success = 0;
6992 size_t total_fail = 0;
6993 for (auto &[name, success, fail] : stats.items) {
6994 total_success += success;
6995 total_fail += fail;
6996 }
6997
6998 os << " id total % success fail "
6999 "definition"
7000 << std::endl;
7001
7002 auto grand_total = total_success + total_fail;
7003 snprintf(buff, BUFSIZ, "%4s %10zu %5s %10zu %10zu %s", "",
7004 grand_total, "", total_success, total_fail,
7005 "Total counters");
7006 os << buff << std::endl;
7007
7008 snprintf(buff, BUFSIZ, "%4s %10s %5s %10.2f %10.2f %s", "", "",
7009 "", total_success * 100.0 / grand_total,
7010 total_fail * 100.0 / grand_total, "% success/fail");
7011 os << buff << std::endl << std::endl;
7012 ;
7013
7014 size_t id = 0;
7015 for (auto &[name, success, fail] : stats.items) {
7016 auto total = success + fail;
7017 auto ratio = total * 100.0 / stats.total;
7018 snprintf(buff, BUFSIZ, "%4zu %10zu %5.2f %10zu %10zu %s", id,
7019 total, ratio, success, fail, name.c_str());
7020 os << buff << std::endl;
7021 id++;
7022 }
7023 }
7024 }
7025 },
7026 [&](auto &trace_data) {
7027 auto stats = new Stats{};
7028 stats->start = std::chrono::steady_clock::now();
7029 trace_data = stats;
7030 },
7031 [&](auto &trace_data) {
7032 auto stats = std::any_cast<Stats *>(trace_data);
7033 delete stats;
7034 });
7035}
7036} // namespace peg
Definition peglib.h:696
void operator=(F fn)
Definition peglib.h:701
Action()=default
Action(Action &&rhs)=default
Fty make_adaptor(F fn)
Definition peglib.h:715
std::function< std::any(SemanticValues &vs, std::any &dt, const std::any &predicate_data)> Fty
Definition peglib.h:712
std::any operator()(SemanticValues &vs, std::any &dt, const std::any &predicate_data) const
Definition peglib.h:706
Fty fn_
Definition peglib.h:731
Action(F fn)
Definition peglib.h:700
Action & operator=(const Action &rhs)=default
Definition peglib.h:1660
AndPredicate(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1662
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1664
std::shared_ptr< Ope > ope_
Definition peglib.h:1678
void accept(Visitor &v) override
Definition peglib.h:4146
Definition peglib.h:1874
size_t parse_core(const char *s, size_t n, SemanticValues &, Context &c, std::any &) const override
Definition peglib.h:1876
void accept(Visitor &v) override
Definition peglib.h:4152
Definition peglib.h:2056
std::string name_
Definition peglib.h:2067
BackReference(const std::string &name)
Definition peglib.h:2060
BackReference(std::string &&name)
Definition peglib.h:2058
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:3978
void accept(Visitor &v) override
Definition peglib.h:4162
Definition peglib.h:1889
void accept(Visitor &v) override
Definition peglib.h:4153
CaptureScope(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1891
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1893
std::shared_ptr< Ope > ope_
Definition peglib.h:1903
Definition peglib.h:1906
MatchAction match_action_
Definition peglib.h:1923
std::function< void(const char *s, size_t n, Context &c)> MatchAction
Definition peglib.h:1908
std::shared_ptr< Ope > ope_
Definition peglib.h:1922
void accept(Visitor &v) override
Definition peglib.h:4154
Capture(const std::shared_ptr< Ope > &ope, MatchAction ma)
Definition peglib.h:1910
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1913
Definition peglib.h:1744
bool negated_
Definition peglib.h:1841
bool ignore_case_
Definition peglib.h:1842
friend struct GrammarBlob
Definition peglib.h:1805
std::vector< std::pair< char32_t, char32_t > > ranges_
Definition peglib.h:1840
CharacterClass(const std::string &s, bool negated, bool ignore_case)
Definition peglib.h:1746
void setup_ascii_bitset()
Definition peglib.h:1822
size_t parse_core(const char *s, size_t n, SemanticValues &, Context &c, std::any &) const override
Definition peglib.h:1773
bool in_range(const std::pair< char32_t, char32_t > &range, char32_t cp) const
Definition peglib.h:1812
CharacterClass(const std::vector< std::pair< char32_t, char32_t > > &ranges, bool negated, bool ignore_case)
Definition peglib.h:1766
bool is_ascii_only_
Definition peglib.h:1844
bool is_ascii_only() const
Definition peglib.h:1808
friend struct OpeSignature
Definition peglib.h:1806
friend struct ComputeFirstSet
Definition peglib.h:1804
const std::bitset< 256 > & ascii_bitset() const
Definition peglib.h:1809
void accept(Visitor &v) override
Definition peglib.h:4150
std::bitset< 256 > ascii_bitset_
Definition peglib.h:1843
Definition peglib.h:1847
Character(char32_t ch)
Definition peglib.h:1849
char32_t ch_
Definition peglib.h:1870
void accept(Visitor &v) override
Definition peglib.h:4151
size_t parse_core(const char *s, size_t n, SemanticValues &, Context &c, std::any &) const override
Definition peglib.h:1851
Definition peglib.h:1013
size_t in_token_boundary_count
Definition peglib.h:1035
std::vector< Definition * > rule_stack
Definition peglib.h:1025
void trace_leave(const Ope &ope, const char *a_s, size_t n, const SemanticValues &vs, std::any &dt, size_t len)
Definition peglib.h:3524
std::vector< std::pair< std::string_view, std::string > > capture_entries
Definition peglib.h:1042
std::once_flag source_line_index_init_
Definition peglib.h:1358
std::map< LRKey, LRMemo > lr_memo
Definition peglib.h:1070
std::shared_ptr< Ope > wordOpe
Definition peglib.h:1040
std::map< std::vector< const void * >, size_t > macro_inst_ids
Definition peglib.h:1081
void trace_enter(const Ope &ope, const char *a_s, size_t n, const SemanticValues &vs, std::any &dt)
Definition peglib.h:3518
TracerEnter tracer_enter
Definition peglib.h:1118
std::vector< bool > cut_stack
Definition peglib.h:1044
size_t skip_whitespace(const char *a_s, size_t n, SemanticValues &vs, std::any &dt)
Definition peglib.h:3475
const std::vector< std::shared_ptr< Ope > > & top_args() const
Definition peglib.h:1273
std::vector< bool > cache_success
Definition peglib.h:1051
ErrorReporter error_reporter
Definition peglib.h:1129
Context operator=(const Context &)=delete
std::shared_ptr< Ope > whitespaceOpe
Definition peglib.h:1037
void clear_packrat_cache(const char *pos, size_t def_id)
Definition peglib.h:1091
const size_t def_count
Definition peglib.h:1046
const bool has_tracer
Definition peglib.h:1120
Context(Context &&)=delete
const bool verbose_trace
Definition peglib.h:1122
Log log
Definition peglib.h:1128
std::vector< std::unique_ptr< SemanticValues > > value_stack
Definition peglib.h:1022
size_t top_macro_inst() const
Definition peglib.h:1277
std::vector< PackratStats > * packrat_stats
Definition peglib.h:1175
const char * s
Definition peglib.h:1016
std::pair< LRRule, const char * > LRKey
Definition peglib.h:1068
size_t next_trace_id
Definition peglib.h:1355
PackratCache cache_values
Definition peglib.h:1056
SemanticValues & push_semantic_values_scope()
Definition peglib.h:1241
void pop_semantic_values_scope()
Definition peglib.h:1263
bool is_traceable(const Ope &ope) const
Definition peglib.h:3531
size_t packrat_cached_count
Definition peglib.h:1049
std::vector< const char * > active_pos
Definition peglib.h:1054
const char * path
Definition peglib.h:1015
std::set< LRKey > lr_active_seeds
Definition peglib.h:1078
std::any trace_data
Definition peglib.h:1121
TracerLeave tracer_leave
Definition peglib.h:1119
void push_args(std::vector< std::shared_ptr< Ope > > &&args, size_t macro_inst=0)
Definition peglib.h:1266
Snapshot snapshot(const SemanticValues &vs) const
Definition peglib.h:1304
std::vector< size_t > trace_ids
Definition peglib.h:1356
const std::vector< int32_t > * packrat_index
Definition peglib.h:1048
Context(const char *path, const char *s, size_t l, size_t def_count, std::shared_ptr< Ope > whitespaceOpe, std::shared_ptr< Ope > wordOpe, bool enablePackratParsing, TracerEnter tracer_enter, TracerLeave tracer_leave, std::any trace_data, bool verbose_trace, Log log, ErrorReporter error_reporter=nullptr, const std::vector< int32_t > *packrat_index=nullptr, size_t packrat_cached_count=0)
Definition peglib.h:1131
void write_packrat_cache(const char *pos, size_t def_id, size_t len, const std::any &val)
Definition peglib.h:1104
size_t value_stack_size
Definition peglib.h:1023
const size_t l
Definition peglib.h:1017
void pop_args()
Definition peglib.h:1271
ErrorInfo error_info
Definition peglib.h:1019
std::vector< bool > cache_registered
Definition peglib.h:1050
bool in_whitespace
Definition peglib.h:1038
std::vector< ArgsFrame > args_stack
Definition peglib.h:1033
std::pair< size_t, size_t > line_info(const char *cur) const
Definition peglib.h:1336
int32_t cache_slot(size_t def_id) const
Definition peglib.h:1086
std::vector< size_t > source_line_index
Definition peglib.h:1359
size_t intern_macro_inst(std::vector< const void * > &&key)
Definition peglib.h:1286
bool recovered
Definition peglib.h:1020
~Context()
Definition peglib.h:1161
void packrat(const char *a_s, size_t def_id, size_t &len, std::any &val, T fn)
Definition peglib.h:1178
const bool enablePackratParsing
Definition peglib.h:1047
std::pair< const Definition *, size_t > LRRule
Definition peglib.h:1067
size_t next_macro_inst_
Definition peglib.h:1082
void rollback(SemanticValues &vs, const Snapshot &snap)
Definition peglib.h:1309
Context(const Context &)=delete
void set_error_pos(const char *a_s, const char *literal=nullptr)
Definition peglib.h:3484
bool ignore_trace_state
Definition peglib.h:1357
unsigned char tolower_table[256]
Definition peglib.h:1126
std::set< LRRule > lr_refs_hit
Definition peglib.h:1074
Definition peglib.h:2114
void accept(Visitor &v) override
Definition peglib.h:4165
size_t parse_core(const char *, size_t, SemanticValues &, Context &c, std::any &) const override
Definition peglib.h:2116
Definition peglib.h:3004
std::shared_ptr< Ope > wordOpe
Definition peglib.h:3194
bool is_macro
Definition peglib.h:3196
bool ignoreSemanticValue
Definition peglib.h:3192
bool eoi_check
Definition peglib.h:3215
Predicate predicate
Definition peglib.h:3183
Definition & operator<=(const std::shared_ptr< Ope > &ope)
Definition peglib.h:3028
std::function< void(const Context &c, const char *s, size_t n, size_t matchlen, std::any &value, std::any &dt)> leave
Definition peglib.h:3191
void initialize_packrat_filter() const
Definition peglib.h:4573
Definition()
Definition peglib.h:3013
bool is_left_recursive
Definition peglib.h:3199
bool disable_action
Definition peglib.h:3198
TracerEnter tracer_enter
Definition peglib.h:3202
std::vector< std::string > params
Definition peglib.h:3197
bool no_whitespace
Definition peglib.h:3210
std::once_flag packrat_filter_init_
Definition peglib.h:3312
Definition & operator~()
Definition peglib.h:3163
bool enablePackratParsing
Definition peglib.h:3195
std::pair< size_t, size_t > line_
Definition peglib.h:3181
friend class ParserGenerator
Definition peglib.h:3223
std::once_flag is_token_init_
Definition peglib.h:3307
TracerStartOrEnd tracer_end
Definition peglib.h:3206
std::vector< Context::PackratStats > packrat_stats_
Definition peglib.h:3219
Result parse(const char *s, size_t n, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3033
std::once_flag definition_ids_init_
Definition peglib.h:3310
std::vector< int32_t > packrat_index_
Definition peglib.h:3313
bool collect_packrat_stats
Definition peglib.h:3218
Result parse(const char *s, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3041
bool no_ast_opt
Definition peglib.h:3209
Definition & operator,(T fn)
Definition peglib.h:3158
Result parse_and_get_value(const char *s, std::any &dt, T &val, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3095
Result parse(const char *s, size_t n, std::any &dt, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3047
friend class Reference
Definition peglib.h:3222
Result parse_and_get_value(const char *s, size_t n, T &val, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3062
void operator=(Action a)
Definition peglib.h:3156
std::unordered_map< void *, size_t > definition_ids_
Definition peglib.h:3311
std::once_flag assign_id_to_definition_init_
Definition peglib.h:3309
TracerLeave tracer_leave
Definition peglib.h:3203
size_t id
Definition peglib.h:3185
bool can_be_empty
Definition peglib.h:3200
Result parse(const char *s, std::any &dt, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3054
std::shared_ptr< Ope > whitespaceOpe
Definition peglib.h:3193
bool is_token() const
Definition peglib.h:3172
Result parse_and_get_value(const char *s, size_t n, std::any &dt, T &val, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3083
std::string ast_name
Definition peglib.h:3212
Result parse_core(const char *s, size_t n, SemanticValues &vs, std::any &dt, const char *path, Log log, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3240
Definition & operator=(Definition &&rhs)
bool is_token_
Definition peglib.h:3308
Definition(const Definition &rhs)
Definition peglib.h:3015
Definition & operator=(const Definition &rhs)
size_t packrat_cached_count_
Definition peglib.h:3314
void accept(Ope::Visitor &v)
Definition peglib.h:3168
bool verbose_trace
Definition peglib.h:3204
std::string name
Definition peglib.h:3179
std::shared_ptr< Holder > holder_
Definition peglib.h:3306
std::string error_message
Definition peglib.h:3208
std::function< void(const Context &c, const char *s, size_t n, std::any &dt)> enter
Definition peglib.h:3188
TracerStartOrEnd tracer_start
Definition peglib.h:3205
Action action
Definition peglib.h:3186
void initialize_definition_ids() const
Definition peglib.h:3228
std::shared_ptr< Ope > get_core_operator() const
Definition peglib.h:3170
Result parse_and_get_value(const char *s, T &val, const char *path=nullptr, Log log=nullptr, ErrorReporter error_reporter=nullptr) const
Definition peglib.h:3075
Definition(const std::shared_ptr< Ope > &ope)
Definition peglib.h:3019
const char * s_
Definition peglib.h:3180
Definition peglib.h:1703
Dictionary(const std::vector< std::string > &v, bool ignore_case)
Definition peglib.h:1705
void accept(Visitor &v) override
Definition peglib.h:4148
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:3550
Trie trie_
Definition peglib.h:1715
Definition peglib.h:1989
Holder(Definition *outer)
Definition peglib.h:1991
const std::string & name() const
Definition peglib.h:3908
Definition * outer_
Definition peglib.h:2005
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:3667
const std::string & trace_name() const
Definition peglib.h:3910
void accept(Visitor &v) override
Definition peglib.h:4159
std::string trace_name_
Definition peglib.h:2007
friend class Definition
Definition peglib.h:2009
std::once_flag trace_name_init_
Definition peglib.h:2006
std::any reduce(SemanticValues &vs, std::any &dt, const std::any &predicate_data) const
Definition peglib.h:3897
std::shared_ptr< Ope > ope_
Definition peglib.h:2004
Definition peglib.h:1940
void accept(Visitor &v) override
Definition peglib.h:4156
Ignore(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1942
std::shared_ptr< Ope > ope_
Definition peglib.h:1953
size_t parse_core(const char *s, size_t n, SemanticValues &, Context &c, std::any &dt) const override
Definition peglib.h:1944
Definition peglib.h:1719
void accept(Visitor &v) override
Definition peglib.h:4149
bool ignore_case_
Definition peglib.h:1737
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:3595
std::string lower_lit_
Definition peglib.h:1738
std::string lit_
Definition peglib.h:1736
LiteralString(std::string &&s, bool ignore_case)
Definition peglib.h:1721
std::once_flag init_is_word_
Definition peglib.h:1739
bool is_word_
Definition peglib.h:1740
LiteralString(const std::string &s, bool ignore_case)
Definition peglib.h:1726
Definition peglib.h:1681
std::shared_ptr< Ope > ope_
Definition peglib.h:1700
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1685
NotPredicate(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1683
void accept(Visitor &v) override
Definition peglib.h:4147
Definition peglib.h:1365
bool is_choice_like
Definition peglib.h:1377
bool is_token_boundary
Definition peglib.h:1376
virtual ~Ope()=default
size_t parse(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const
Definition peglib.h:3539
virtual size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const =0
virtual void accept(Visitor &v)=0
Definition peglib.h:895
size_t initial_capacity_
Definition peglib.h:1007
void erase(size_t key)
Definition peglib.h:954
std::vector< Slot > slots_
Definition peglib.h:1008
std::vector< std::any > vals_
Definition peglib.h:1009
static size_t mix(size_t key)
Definition peglib.h:979
static constexpr size_t kEmpty
Definition peglib.h:971
void insert_or_assign(size_t key, size_t len, const std::any &val)
Definition peglib.h:923
void grow()
Definition peglib.h:986
bool find(size_t key, size_t &len, std::any &val) const
Definition peglib.h:903
PackratCache(size_t expected_entries)
Definition peglib.h:897
size_t used_
Definition peglib.h:1010
static constexpr size_t kTombstone
Definition peglib.h:972
std::pair< size_t, size_t > r_
Definition peglib.h:5278
std::pair< size_t, size_t > line_info() const
Definition peglib.h:5275
SyntaxErrorException(const char *what_arg, std::pair< size_t, size_t > r)
Definition peglib.h:5272
ParserContext perform_core(const char *s, size_t n, const Rules &rules, Log log, std::string requested_start, bool enable_left_recursion=true)
Definition peglib.h:5997
bool apply_precedence_instruction(Definition &rule, const PrecedenceClimbing::BinOpeInfo &info, const char *s, Log log)
Definition peglib.h:5956
void make_grammar()
Definition peglib.h:5281
Grammar g
Definition peglib.h:6293
ParserGenerator()
Definition peglib.h:5229
static bool parse_test(const char *d, const char *s)
Definition peglib.h:5208
static ParserContext parse(const char *s, size_t n, const Rules &rules, Log log, std::string_view start, bool enable_left_recursion=true)
Definition peglib.h:5200
bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log, const char *s) const
Definition peglib.h:6276
static ParserGenerator & get_instance()
Definition peglib.h:5224
void setup_actions()
Definition peglib.h:5481
Definition peglib.h:2070
std::shared_ptr< Ope > atom_
Definition peglib.h:2086
std::map< std::string_view, std::pair< size_t, char > > BinOpeInfo
Definition peglib.h:2072
PrecedenceClimbing(const std::shared_ptr< Ope > &atom, const std::shared_ptr< Ope > &binop, const BinOpeInfo &info, const Definition &rule)
Definition peglib.h:2074
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:2079
const Definition & rule_
Definition peglib.h:2093
std::shared_ptr< Ope > binop_
Definition peglib.h:2087
Definition & get_reference_for_binop(Context &c) const
Definition peglib.h:3999
BinOpeInfo info_
Definition peglib.h:2088
void accept(Visitor &v) override
Definition peglib.h:4163
std::vector< std::string > info_keys_
Definition peglib.h:2092
size_t parse_expression(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt, size_t min_prec) const
Definition peglib.h:4011
Definition peglib.h:734
Predicate()=default
bool operator()(const SemanticValues &vs, const std::any &dt, std::string &msg, std::any &predicate_data) const
Definition peglib.h:744
Predicate & operator=(const Predicate &rhs)=default
Fty make_adaptor(F fn)
Definition peglib.h:753
Fty fn_
Definition peglib.h:765
Predicate(Predicate &&rhs)=default
Predicate(F fn)
Definition peglib.h:738
void operator=(F fn)
Definition peglib.h:739
std::function< bool(const SemanticValues &vs, const std::any &dt, std::string &msg, std::any &predicate_data)> Fty
Definition peglib.h:750
Definition peglib.h:1495
PrioritizedChoice(bool for_label, const Args &...args)
Definition peglib.h:1498
size_t size() const
Definition peglib.h:1573
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1512
void accept(Visitor &v) override
Definition peglib.h:4144
bool for_label_
Definition peglib.h:1576
std::vector< std::shared_ptr< Ope > > opes_
Definition peglib.h:1575
PrioritizedChoice(const std::vector< std::shared_ptr< Ope > > &opes)
Definition peglib.h:1503
std::vector< FirstSet > first_sets_
Definition peglib.h:1577
PrioritizedChoice(std::vector< std::shared_ptr< Ope > > &&opes)
Definition peglib.h:1507
Definition peglib.h:2102
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:4088
void accept(Visitor &v) override
Definition peglib.h:4164
Recovery(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2104
std::shared_ptr< Ope > ope_
Definition peglib.h:2111
Definition peglib.h:2014
const std::string name_
Definition peglib.h:2029
Definition * rule_
Definition peglib.h:2035
std::shared_ptr< Ope > get_core_operator() const
Definition peglib.h:3974
const char * s_
Definition peglib.h:2030
void accept(Visitor &v) override
Definition peglib.h:4160
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:3933
const bool is_macro_
Definition peglib.h:2032
const std::vector< std::shared_ptr< Ope > > args_
Definition peglib.h:2033
size_t iarg_
Definition peglib.h:2036
const Grammar & grammar_
Definition peglib.h:2028
Reference(const Grammar &grammar, const std::string &name, const char *s, bool is_macro, const std::vector< std::shared_ptr< Ope > > &args)
Definition peglib.h:2016
Definition peglib.h:1580
static std::shared_ptr< Repetition > zom(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1639
static std::shared_ptr< Repetition > opt(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1649
bool is_zom() const
Definition peglib.h:1635
const std::bitset< 256 > * span_bitset_
Definition peglib.h:1656
Repetition(const std::shared_ptr< Ope > &ope, size_t min, size_t max)
Definition peglib.h:1582
std::shared_ptr< Ope > ope_
Definition peglib.h:1653
size_t max_
Definition peglib.h:1655
void accept(Visitor &v) override
Definition peglib.h:4145
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1585
size_t min_
Definition peglib.h:1654
static std::shared_ptr< Repetition > oom(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1644
Definition peglib.h:1397
Sequence(std::vector< std::shared_ptr< Ope > > &&opes)
Definition peglib.h:1403
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1405
std::unique_ptr< KeywordGuardData > kw_guard_
Definition peglib.h:1430
std::vector< std::shared_ptr< Ope > > opes_
Definition peglib.h:1426
std::optional< size_t > parse_keyword_guarded(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const
Definition peglib.h:1433
void accept(Visitor &v) override
Definition peglib.h:4143
Sequence(const Args &...args)
Definition peglib.h:1400
Sequence(const std::vector< std::shared_ptr< Ope > > &opes)
Definition peglib.h:1402
friend struct SetupFirstSets
Definition peglib.h:1429
Definition peglib.h:1926
void accept(Visitor &v) override
Definition peglib.h:4155
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:3602
std::shared_ptr< Ope > ope_
Definition peglib.h:1937
TokenBoundary(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1928
Definition peglib.h:448
friend struct GrammarBlob
Definition peglib.h:504
size_t max_len_
Definition peglib.h:519
std::map< std::string, Info, std::less<> > dic_
Definition peglib.h:515
size_t match(const char *text, size_t text_len, size_t &id) const
Definition peglib.h:472
friend struct ComputeFirstSet
Definition peglib.h:503
Trie(const std::vector< std::string > &items, bool ignore_case)
Definition peglib.h:450
size_t size() const
Definition peglib.h:500
bool ignore_case_
Definition peglib.h:517
size_t items_count_
Definition peglib.h:518
size_t items_count() const
Definition peglib.h:501
Definition peglib.h:1959
std::function< size_t(const char *s, size_t n, SemanticValues &vs, std::any &dt)> fn_
Definition peglib.h:1970
void accept(Visitor &v) override
Definition peglib.h:4157
User(Parser fn)
Definition peglib.h:1961
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &, std::any &dt) const override
Definition peglib.h:1962
Definition peglib.h:1973
WeakHolder(const std::shared_ptr< Ope > &ope)
Definition peglib.h:1975
void accept(Visitor &v) override
Definition peglib.h:4158
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:1977
std::weak_ptr< Ope > weak_
Definition peglib.h:1986
Definition peglib.h:2039
std::shared_ptr< Ope > ope_
Definition peglib.h:2053
size_t parse_core(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt) const override
Definition peglib.h:2043
void accept(Visitor &v) override
Definition peglib.h:4161
Whitespace(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2041
Definition peglib.h:6607
parser(const char *s, size_t n, std::string_view start={})
Definition peglib.h:6616
Log log_
Definition peglib.h:6873
bool enablePackratParsing_
Definition peglib.h:6872
parser(const char *s, size_t n, const Rules &rules, std::string_view start={})
Definition peglib.h:6611
bool parse_n(const char *s, size_t n, std::any &dt, T &val, const char *path=nullptr) const
Definition peglib.h:6714
std::string start_
Definition peglib.h:6870
const Grammar & get_grammar() const
Definition peglib.h:6774
std::shared_ptr< Grammar > grammar_
Definition peglib.h:6869
bool parse_n(const char *s, size_t n, std::any &dt, const char *path=nullptr) const
Definition peglib.h:6691
void set_logger(Log log)
Definition peglib.h:6834
bool enableLeftRecursion_
Definition peglib.h:6871
bool load_grammar(std::string_view sv, std::string_view start={})
Definition peglib.h:6656
void enable_packrat_parsing()
Definition peglib.h:6787
parser & enable_ast()
Definition peglib.h:6821
void set_error_reporter(ErrorReporter reporter)
Definition peglib.h:6838
std::vector< uint8_t > serialize_grammar() const
Definition peglib.h:6663
parser(std::string_view sv, const Rules &rules, std::string_view start={})
Definition peglib.h:6619
void disable_eoi_check()
Definition peglib.h:6776
bool load_grammar(const char *s, size_t n, std::string_view start={})
Definition peglib.h:6647
std::shared_ptr< T > optimize_ast(std::shared_ptr< T > ast, bool opt_mode=true) const
Definition peglib.h:6829
void set_verbose_trace(bool verbose_trace)
Definition peglib.h:6814
ErrorReporter error_reporter_
Definition peglib.h:6874
void enable_left_recursion(bool enable=true)
Definition peglib.h:6783
parser()=default
const Definition & operator[](const char *s) const
Definition peglib.h:6772
bool parse_n(const char *s, size_t n, T &val, const char *path=nullptr) const
Definition peglib.h:6702
bool parse(std::string_view sv, std::any &dt, const char *path=nullptr) const
Definition peglib.h:6729
parser(std::string_view sv, std::string_view start={})
Definition peglib.h:6622
void set_logger(std::function< void(size_t line, size_t col, const std::string &msg)> log)
Definition peglib.h:6842
bool load_grammar(const char *s, size_t n, const Rules &rules, std::string_view start={})
Definition peglib.h:6637
void enable_trace(TracerEnter tracer_enter, TracerLeave tracer_leave)
Definition peglib.h:6794
bool load_blob(const std::vector< uint8_t > &blob)
Definition peglib.h:6669
bool parse(std::string_view sv, std::any &dt, T &val, const char *path=nullptr) const
Definition peglib.h:6740
bool post_process(const char *s, size_t n, Definition::Result &r) const
Definition peglib.h:6850
std::vector< std::string > get_no_ast_opt_rules() const
Definition peglib.h:6857
bool load_grammar(std::string_view sv, const Rules &rules, std::string_view start={})
Definition peglib.h:6651
bool parse(std::string_view sv, T &val, const char *path=nullptr) const
Definition peglib.h:6735
Definition & operator[](const char *s)
Definition peglib.h:6770
bool parse_n(const char *s, size_t n, const char *path=nullptr) const
Definition peglib.h:6682
bool parse(std::string_view sv, const char *path=nullptr) const
Definition peglib.h:6725
void enable_trace(TracerEnter tracer_enter, TracerLeave tracer_leave, TracerStartOrEnd tracer_start, TracerStartOrEnd tracer_end)
Definition peglib.h:6802
Definition peglib.h:561
Definition filter_string.h:27
std::string escape_characters(const char *s, size_t n)
Definition peglib.h:227
size_t parse_literal(const char *s, size_t n, SemanticValues &vs, Context &c, std::any &dt, const std::string &lit, std::once_flag &init_is_word, bool &is_word, bool ignore_case, const std::string &lower_lit)
Definition peglib.h:3321
static const char * WORD_DEFINITION_NAME
Definition peglib.h:2998
const char * u8(const T *s)
Definition peglib.h:219
std::shared_ptr< Ope > ref(const Grammar &grammar, const std::string &name, const char *s, bool is_macro, const std::vector< std::shared_ptr< Ope > > &args)
Definition peglib.h:2230
size_t encode_codepoint(char32_t cp, char *buff)
Definition peglib.h:120
std::shared_ptr< Ope > cut()
Definition peglib.h:2255
std::function< size_t(const char *s, size_t n, SemanticValues &vs, std::any &dt)> Parser
Definition peglib.h:1956
std::shared_ptr< Ope > tok(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2215
std::shared_ptr< Ope > csc(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2206
bool decode_codepoint(const char *s8, size_t l, size_t &bytes, char32_t &cp)
Definition peglib.h:157
std::function< void(size_t line, size_t col, const std::string &msg, const std::string &rule)> Log
Definition peglib.h:778
size_t codepoint_count(const char *s8, size_t l)
Definition peglib.h:106
std::shared_ptr< Ope > apd(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2159
std::pair< int, size_t > parse_octal_number(const char *s, size_t n, size_t i)
Definition peglib.h:284
std::u32string decode(const char *s8, size_t l)
Definition peglib.h:206
std::pair< size_t, size_t > line_info(const char *start, const char *cur)
Definition peglib.h:529
std::shared_ptr< Ope > rec(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2251
std::function< void( const Ope &ope, const char *s, size_t n, const SemanticValues &vs, const Context &c, const std::any &dt, size_t, std::any &trace_data)> TracerLeave
Definition peglib.h:882
std::string resolve_capture_placeholders(const std::string &msg, const Context &c)
Definition peglib.h:3630
std::shared_ptr< Ope > cls(const std::string &s)
Definition peglib.h:2180
std::shared_ptr< Ope > wsp(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2236
bool fail(size_t len)
Definition peglib.h:773
T token_to_number_(std::string_view sv)
Definition peglib.h:421
std::shared_ptr< Ope > pre(const std::shared_ptr< Ope > &atom, const std::shared_ptr< Ope > &binop, const PrecedenceClimbing::BinOpeInfo &info, const Definition &rule)
Definition peglib.h:2244
bool is_digit(char c, int &v)
Definition peglib.h:265
std::shared_ptr< Ope > dic(const std::vector< std::string > &v, bool ignore_case)
Definition peglib.h:2167
std::shared_ptr< Ope > liti(std::string &&s)
Definition peglib.h:2176
std::shared_ptr< Ope > ign(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2219
std::unordered_map< std::string, Definition > Grammar
Definition peglib.h:2012
std::vector< const void * > macro_inst_key(const Definition *def, const std::vector< std::shared_ptr< Ope > > &args)
Definition peglib.h:3920
size_t codepoint_length(const char *s8, size_t l)
Definition peglib.h:90
static const char * WHITESPACE_DEFINITION_NAME
Definition peglib.h:2997
std::string resolve_escape_sequence(const char *s, size_t n)
Definition peglib.h:295
std::shared_ptr< Ope > lit(std::string &&s)
Definition peglib.h:2172
std::shared_ptr< Ope > cho4label_(Args &&...args)
Definition peglib.h:2137
std::shared_ptr< Ope > dot()
Definition peglib.h:2204
std::unordered_map< std::string, std::shared_ptr< Ope > > Rules
Definition peglib.h:5190
void enable_profiling(parser &parser, std::ostream &os)
Definition peglib.h:6941
std::function< void( const Ope &name, const char *s, size_t n, const SemanticValues &vs, const Context &c, const std::any &dt, std::any &trace_data)> TracerEnter
Definition peglib.h:878
std::shared_ptr< Ope > chr(char32_t dt)
Definition peglib.h:2200
bool is_hex(char c, int &v)
Definition peglib.h:251
std::string ast_to_s(const std::shared_ptr< T > &ptr, std::function< std::string(const T &ast, int level)> fn=nullptr)
Definition peglib.h:6394
std::shared_ptr< Ope > opt(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2150
std::function< void(std::any &trace_data)> TracerStartOrEnd
Definition peglib.h:886
std::shared_ptr< Ope > oom(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2146
std::vector< std::pair< char32_t, char32_t > > complement_character_ranges(const std::vector< std::pair< char32_t, char32_t > > &ranges)
Definition peglib.h:405
std::shared_ptr< Ope > cho(Args &&...args)
Definition peglib.h:2132
std::shared_ptr< Ope > rep(const std::shared_ptr< Ope > &ope, size_t min, size_t max)
Definition peglib.h:2154
constexpr unsigned int str2tag_core(const char *s, size_t l, unsigned int h)
Definition peglib.h:550
std::shared_ptr< Ope > npd(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2163
void ast_to_s_core(const std::shared_ptr< T > &ptr, std::string &s, int level, std::function< std::string(const T &ast, int level)> fn)
Definition peglib.h:6368
constexpr unsigned int str2tag(std::string_view sv)
Definition peglib.h:557
std::shared_ptr< Ope > seq(Args &&...args)
Definition peglib.h:2128
bool success(size_t len)
Definition peglib.h:771
std::shared_ptr< Ope > ncls(const std::string &s)
Definition peglib.h:2190
std::pair< int, size_t > parse_hex_number(const char *s, size_t n, size_t i)
Definition peglib.h:273
std::shared_ptr< Ope > cap(const std::shared_ptr< Ope > &ope, Capture::MatchAction ma)
Definition peglib.h:2210
void add_ast_action(Definition &rule)
Definition peglib.h:6443
AstBase< EmptyType > Ast
Definition filter_string.h:30
static const char * RECOVER_DEFINITION_NAME
Definition peglib.h:2999
std::any call(F fn, Args &&...args)
Definition peglib.h:671
std::shared_ptr< Ope > zom(const std::shared_ptr< Ope > &ope)
Definition peglib.h:2142
std::function< void(const ErrorReport &report)> ErrorReporter
Definition peglib.h:798
std::shared_ptr< Ope > bkr(std::string &&name)
Definition peglib.h:2240
const std::vector< std::pair< char32_t, char32_t > > * predefined_character_class(std::string_view name)
Definition peglib.h:381
std::shared_ptr< Ope > usr(std::function< size_t(const char *s, size_t n, SemanticValues &vs, std::any &dt)> fn)
Definition peglib.h:2224
std::string to_lower(std::string s)
Definition peglib.h:437
void enable_tracing(parser &parser, std::ostream &os)
Definition peglib.h:6881
#define CPPPEGLIB_HEURISTIC_ERROR_TOKEN_MAX_CHAR_COUNT
Definition peglib.h:18
Definition clipboard_testing.h:11
Definition peglib.h:2350
void visit(Holder &ope) override
Definition peglib.h:4167
std::unordered_map< void *, size_t > ids
Definition peglib.h:2357
Definition peglib.h:6300
const size_t column
Definition peglib.h:6337
AstBase(const AstBase &ast, const char *original_name, size_t position=0, size_t length=0, size_t original_choice_count=0, size_t original_choice=0)
Definition peglib.h:6323
AstBase(const char *path, size_t line, size_t column, const char *name, const std::vector< std::shared_ptr< AstBase > > &nodes, size_t position=0, size_t length=0, size_t choice_count=0, size_t choice=0, bool preserve_position=false)
Definition peglib.h:6301
std::weak_ptr< AstBase< EmptyType > > parent
Definition peglib.h:6355
const std::string name
Definition peglib.h:6339
T token_to_number() const
Definition peglib.h:6362
const bool is_token
Definition peglib.h:6350
const size_t line
Definition peglib.h:6336
size_t length
Definition peglib.h:6341
AstBase(const char *path, size_t line, size_t column, const char *name, const std::string_view &token, size_t position=0, size_t length=0, size_t choice_count=0, size_t choice=0, bool preserve_position=false)
Definition peglib.h:6312
const unsigned int original_tag
Definition peglib.h:6348
const size_t choice
Definition peglib.h:6343
size_t position
Definition peglib.h:6340
const size_t original_choice_count
Definition peglib.h:6345
const std::string_view token
Definition peglib.h:6352
std::vector< std::shared_ptr< AstBase< EmptyType > > > nodes
Definition peglib.h:6354
const size_t choice_count
Definition peglib.h:6342
const size_t original_choice
Definition peglib.h:6346
const std::string path
Definition peglib.h:6335
std::string token_to_string() const
Definition peglib.h:6357
const unsigned int tag
Definition peglib.h:6347
const std::string original_name
Definition peglib.h:6344
const bool preserve_position
Definition peglib.h:6351
Definition peglib.h:6401
const bool mode_
Definition peglib.h:6436
const std::vector< std::string > rules_
Definition peglib.h:6437
std::shared_ptr< T > optimize(std::shared_ptr< T > original, std::shared_ptr< T > parent=nullptr)
Definition peglib.h:6406
AstOptimizer(bool mode, const std::vector< std::string > &rules={})
Definition peglib.h:6402
Definition peglib.h:2506
void visit(Repetition &ope) override
Definition peglib.h:2525
void visit(BackReference &) override
Definition peglib.h:2535
void visit(Cut &) override
Definition peglib.h:2536
void visit(LiteralString &ope) override
Definition peglib.h:2529
void visit(NotPredicate &) override
Definition peglib.h:2527
bool result
Definition peglib.h:2509
void visit(Dictionary &) override
Definition peglib.h:2528
void visit(User &) override
Definition peglib.h:2533
void visit(Character &) override
Definition peglib.h:2531
void visit(AndPredicate &) override
Definition peglib.h:2526
void visit(Sequence &ope) override
Definition peglib.h:2511
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2518
void visit(AnyCharacter &) override
Definition peglib.h:2532
void visit(CharacterClass &) override
Definition peglib.h:2530
Definition peglib.h:2846
void visit(User &) override
Definition peglib.h:2939
ComputeFirstSet(FirstSetCache &cache)
Definition peglib.h:2952
void visit(BackReference &) override
Definition peglib.h:2941
void visit(AndPredicate &) override
Definition peglib.h:2881
void visit(NotPredicate &) override
Definition peglib.h:2882
FirstSetCache & cache_
Definition peglib.h:2957
void visit(Cut &) override
Definition peglib.h:2942
void visit(LiteralString &ope) override
Definition peglib.h:2895
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2868
void visit(Repetition &ope) override
Definition peglib.h:2877
void visit(Dictionary &ope) override
Definition peglib.h:2883
std::unordered_map< const Definition *, FirstSet > FirstSetCache
Definition peglib.h:2950
void visit(AnyCharacter &) override
Definition peglib.h:2938
void visit(CharacterClass &ope) override
Definition peglib.h:2908
std::unordered_set< const Definition * > refs_
Definition peglib.h:2958
FirstSet result_
Definition peglib.h:2954
void visit(Character &ope) override
Definition peglib.h:2931
void visit(Sequence &ope) override
Definition peglib.h:2849
size_t cycle_count_
Definition peglib.h:2959
Definition peglib.h:1029
std::vector< std::shared_ptr< Ope > > args
Definition peglib.h:1030
size_t macro_inst
Definition peglib.h:1031
Definition peglib.h:1059
std::any val
Definition peglib.h:1061
size_t len
Definition peglib.h:1060
Definition peglib.h:1171
size_t misses
Definition peglib.h:1173
size_t hits
Definition peglib.h:1172
Definition peglib.h:1294
std::string_view sv_sv
Definition peglib.h:1298
size_t sv_tags_size
Definition peglib.h:1296
size_t sv_tokens_size
Definition peglib.h:1297
size_t capture_size
Definition peglib.h:1301
size_t choice
Definition peglib.h:1300
size_t choice_count
Definition peglib.h:1299
size_t sv_size
Definition peglib.h:1295
Definition peglib.h:3006
bool ret
Definition peglib.h:3007
size_t len
Definition peglib.h:3009
ErrorInfo error_info
Definition peglib.h:3010
bool recovered
Definition peglib.h:3008
Definition peglib.h:2678
void visit(Repetition &ope) override
Definition peglib.h:2704
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2698
DetectInfiniteLoop(std::vector< std::pair< const char *, std::string > > &refs, std::unordered_map< std::string, bool > &has_error_cache)
Definition peglib.h:2688
std::unordered_map< std::string, bool > & has_error_cache_
Definition peglib.h:2725
void visit(Sequence &ope) override
Definition peglib.h:2692
bool has_error
Definition peglib.h:2719
std::vector< std::pair< const char *, std::string > > & refs_
Definition peglib.h:2724
const char * error_s
Definition peglib.h:2720
DetectInfiniteLoop(const char *s, const std::string &name, std::vector< std::pair< const char *, std::string > > &refs, std::unordered_map< std::string, bool > &has_error_cache)
Definition peglib.h:2681
std::string error_name
Definition peglib.h:2721
std::shared_ptr< Ope > ope
Definition peglib.h:2476
size_t depth
Definition peglib.h:2477
Definition peglib.h:2424
bool done_
Definition peglib.h:2502
void visit(AnyCharacter &) override
Definition peglib.h:2465
void visit(Sequence &ope) override
Definition peglib.h:2429
static const size_t max_macro_inst_depth
Definition peglib.h:2495
void visit(AndPredicate &ope) override
Definition peglib.h:2453
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2440
std::set< std::pair< const Definition *, size_t > > refs_
Definition peglib.h:2499
void visit(BackReference &) override
Definition peglib.h:2468
const char * error_s
Definition peglib.h:2471
size_t next_macro_inst_
Definition peglib.h:2501
void visit(Repetition &ope) override
Definition peglib.h:2449
void visit_in_defining_scope(const ResolvedArg &arg)
Definition peglib.h:4274
size_t intern_macro_inst(const Reference &ope)
Definition peglib.h:4254
void visit(Cut &) override
Definition peglib.h:2469
ResolvedArg resolve_macro_arg(size_t iarg) const
Definition peglib.h:4286
void visit(Character &) override
Definition peglib.h:2464
std::string name_
Definition peglib.h:2498
std::map< std::vector< const void * >, size_t > macro_inst_ids_
Definition peglib.h:2500
void visit(LiteralString &ope) override
Definition peglib.h:2462
void visit(CharacterClass &) override
Definition peglib.h:2463
DetectLeftRecursion(const std::string &name)
Definition peglib.h:2427
void visit(Dictionary &) override
Definition peglib.h:2461
void visit(NotPredicate &ope) override
Definition peglib.h:2457
std::vector< const std::vector< std::shared_ptr< Ope > > * > macro_args_stack_
Definition peglib.h:2503
void visit(User &) override
Definition peglib.h:2466
Definition peglib.h:6440
Definition peglib.h:805
std::vector< std::pair< const char *, const Definition * > > expected_tokens
Definition peglib.h:807
std::string replace_all(std::string str, const std::string &from, const std::string &to) const
Definition peglib.h:862
void clear()
Definition peglib.h:814
const char * message_pos
Definition peglib.h:808
int cast_char(char c) const
Definition peglib.h:835
std::string heuristic_error_token(const char *s, size_t n, const char *pos) const
Definition peglib.h:837
const char * last_output_pos
Definition peglib.h:811
void output_log(const Log &log, const char *s, size_t n)
Definition peglib.h:828
bool keep_previous_token
Definition peglib.h:812
void add(const char *error_literal, const Definition *error_rule)
Definition peglib.h:821
std::string message
Definition peglib.h:809
std::string label
Definition peglib.h:810
const char * error_pos
Definition peglib.h:806
Definition peglib.h:787
std::string label
Definition peglib.h:795
size_t position
Definition peglib.h:790
std::vector< std::string > expected_literals
Definition peglib.h:792
size_t col
Definition peglib.h:789
std::string message
Definition peglib.h:794
std::vector< std::string > expected_rules
Definition peglib.h:793
size_t line
Definition peglib.h:788
std::string unexpected_token
Definition peglib.h:791
Definition peglib.h:2405
void visit(LiteralString &ope) override
Definition peglib.h:2408
static const char * token(Ope &ope)
Definition peglib.h:2414
void visit(TokenBoundary &ope) override
Definition peglib.h:2409
const char * token_
Definition peglib.h:2421
void visit(Ignore &ope) override
Definition peglib.h:2410
void visit(Recovery &ope) override
Definition peglib.h:2412
Definition peglib.h:2759
const std::vector< std::string > & params_
Definition peglib.h:2840
void visit(Repetition &ope) override
Definition peglib.h:2782
void visit(WeakHolder &ope) override
Definition peglib.h:2819
void visit(Character &ope) override
Definition peglib.h:2801
void visit(CharacterClass &ope) override
Definition peglib.h:2798
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2774
void visit(Ignore &ope) override
Definition peglib.h:2815
void visit(Cut &ope) override
Definition peglib.h:2834
void visit(AnyCharacter &ope) override
Definition peglib.h:2802
void visit(LiteralString &ope) override
Definition peglib.h:2795
void visit(Recovery &ope) override
Definition peglib.h:2830
void visit(Holder &ope) override
Definition peglib.h:2820
const std::vector< std::shared_ptr< Ope > > & args_
Definition peglib.h:2839
void visit(Dictionary &ope) override
Definition peglib.h:2794
void visit(Whitespace &ope) override
Definition peglib.h:2822
void visit(TokenBoundary &ope) override
Definition peglib.h:2811
std::shared_ptr< Ope > found_ope
Definition peglib.h:2836
void visit(NotPredicate &ope) override
Definition peglib.h:2790
FindReference(const std::vector< std::shared_ptr< Ope > > &args, const std::vector< std::string > &params)
Definition peglib.h:2762
void visit(Sequence &ope) override
Definition peglib.h:2766
void visit(AndPredicate &ope) override
Definition peglib.h:2786
void visit(Capture &ope) override
Definition peglib.h:2807
void visit(CaptureScope &ope) override
Definition peglib.h:2803
void visit(PrecedenceClimbing &ope) override
Definition peglib.h:2826
Definition peglib.h:1477
const char * first_literal
Definition peglib.h:1483
void merge(const FirstSet &other)
Definition peglib.h:1487
bool any_char
Definition peglib.h:1482
std::bitset< 256 > chars
Definition peglib.h:1480
bool can_be_empty
Definition peglib.h:1481
const Definition * first_rule
Definition peglib.h:1484
Definition peglib.h:4941
uint32_t u32()
Definition peglib.h:4948
const uint8_t * p
Definition peglib.h:4942
const uint8_t * end
Definition peglib.h:4942
std::string str()
Definition peglib.h:4960
uint64_t u64()
Definition peglib.h:4954
uint8_t u8()
Definition peglib.h:4943
Definition peglib.h:4812
std::vector< uint8_t > b
Definition peglib.h:4813
void u64(uint64_t v)
Definition peglib.h:4819
void u8(uint8_t v)
Definition peglib.h:4814
void str(const std::string &s)
Definition peglib.h:4823
void u32(uint32_t v)
Definition peglib.h:4815
Definition peglib.h:4787
Tag
Definition peglib.h:4788
@ T_Reference
Definition peglib.h:4804
@ T_Whitespace
Definition peglib.h:4805
@ T_PrecedenceClimbing
Definition peglib.h:4808
@ T_AnyChar
Definition peglib.h:4798
@ T_Dictionary
Definition peglib.h:4794
@ T_Not
Definition peglib.h:4793
@ T_BackRef
Definition peglib.h:4803
@ T_And
Definition peglib.h:4792
@ T_Sequence
Definition peglib.h:4789
@ T_TokenBoundary
Definition peglib.h:4801
@ T_Cut
Definition peglib.h:4807
@ T_Capture
Definition peglib.h:4800
@ T_Choice
Definition peglib.h:4790
@ T_CharClass
Definition peglib.h:4796
@ T_Recovery
Definition peglib.h:4806
@ T_Repetition
Definition peglib.h:4791
@ T_Char
Definition peglib.h:4797
@ T_Null
Definition peglib.h:4809
@ T_Literal
Definition peglib.h:4795
@ T_CaptureScope
Definition peglib.h:4799
@ T_Ignore
Definition peglib.h:4802
static std::shared_ptr< Ope > read_ope(Reader &r, Grammar &g, Definition *owner)
Definition peglib.h:4968
static void write_ope(Writer &w, const std::shared_ptr< Ope > &o)
Definition peglib.h:4829
static std::shared_ptr< Grammar > deserialize(const std::vector< uint8_t > &blob, std::string &start_out)
Definition peglib.h:5114
static const uint32_t MAGIC
Definition peglib.h:5071
static std::vector< uint8_t > serialize(const Grammar &g, const std::string &start)
Definition peglib.h:5073
Definition peglib.h:2637
std::string error_name
Definition peglib.h:2667
void visit(Sequence &ope) override
Definition peglib.h:4301
bool is_empty
Definition peglib.h:2665
void visit(Repetition &ope) override
Definition peglib.h:2651
const char * error_s
Definition peglib.h:2666
void visit(NotPredicate &) override
Definition peglib.h:2659
std::vector< std::pair< const char *, std::string > > & refs_
Definition peglib.h:2674
void visit(LiteralString &ope) override
Definition peglib.h:2660
void visit(AndPredicate &) override
Definition peglib.h:2658
std::unordered_map< std::string, bool > & has_error_cache_
Definition peglib.h:2675
void set_error()
Definition peglib.h:2670
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2645
HasEmptyElement(std::vector< std::pair< const char *, std::string > > &refs, std::unordered_map< std::string, bool > &has_error_cache)
Definition peglib.h:2640
Definition peglib.h:2360
void visit(Dictionary &) override
Definition peglib.h:2370
void visit(LiteralString &) override
Definition peglib.h:2371
bool result_
Definition peglib.h:2380
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2363
static bool check(Ope &ope)
Definition peglib.h:2373
Definition peglib.h:1382
std::bitset< 256 > identifier_rest
Definition peglib.h:1384
std::bitset< 256 > identifier_first
Definition peglib.h:1383
size_t max_keyword_len
Definition peglib.h:1388
size_t min_keyword_len
Definition peglib.h:1387
std::vector< std::string > exact_keywords
Definition peglib.h:1385
std::vector< std::string > prefix_keywords
Definition peglib.h:1386
static bool matches_any(const std::vector< std::string > &keywords, std::string_view input)
Definition peglib.h:1390
Definition peglib.h:2746
const std::vector< std::string > & params_
Definition peglib.h:2756
Grammar & grammar_
Definition peglib.h:2755
void visit(Reference &ope) override
Definition peglib.h:4739
LinkReferences(Grammar &grammar, const std::vector< std::string > &params)
Definition peglib.h:2749
Definition peglib.h:2544
void opaque(const void *p)
Definition peglib.h:2632
void visit(Reference &ope) override
Definition peglib.h:2576
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2549
void visit(Capture &ope) override
Definition peglib.h:2560
void unary(const char *tag, Ope &inner)
Definition peglib.h:2622
void visit(TokenBoundary &ope) override
Definition peglib.h:2561
void visit(WeakHolder &ope) override
Definition peglib.h:2569
void visit(Sequence &ope) override
Definition peglib.h:2548
void visit(User &ope) override
Definition peglib.h:2601
void visit(AndPredicate &ope) override
Definition peglib.h:2557
std::string s
Definition peglib.h:2546
void visit(BackReference &ope) override
Definition peglib.h:2602
void visit(CaptureScope &ope) override
Definition peglib.h:2559
void visit(NotPredicate &ope) override
Definition peglib.h:2558
static std::string get(Ope &ope)
Definition peglib.h:2606
void visit(AnyCharacter &) override
Definition peglib.h:2599
void visit(Recovery &ope) override
Definition peglib.h:2564
void visit(Character &ope) override
Definition peglib.h:2596
void visit(Repetition &ope) override
Definition peglib.h:2550
void visit(CharacterClass &ope) override
Definition peglib.h:2587
void visit(LiteralString &ope) override
Definition peglib.h:2584
void wrap(Ope &inner)
Definition peglib.h:2627
void visit(Whitespace &ope) override
Definition peglib.h:2563
void visit(Cut &ope) override
Definition peglib.h:2604
void visit(Dictionary &ope) override
Definition peglib.h:2600
void visit(Holder &ope) override
Definition peglib.h:2568
void group(const char *tag, const std::vector< std::shared_ptr< Ope > > &v)
Definition peglib.h:2613
void visit(Ignore &ope) override
Definition peglib.h:2562
void visit(PrecedenceClimbing &ope) override
Definition peglib.h:2603
Definition peglib.h:2260
virtual void visit(WeakHolder &)
Definition peglib.h:2277
virtual void visit(TokenBoundary &)
Definition peglib.h:2274
virtual void visit(Repetition &)
Definition peglib.h:2264
virtual void visit(Dictionary &)
Definition peglib.h:2267
virtual void visit(Character &)
Definition peglib.h:2270
virtual ~Visitor()
Definition peglib.h:2261
virtual void visit(AndPredicate &)
Definition peglib.h:2265
virtual void visit(LiteralString &)
Definition peglib.h:2268
virtual void visit(Reference &)
Definition peglib.h:2279
virtual void visit(CharacterClass &)
Definition peglib.h:2269
virtual void visit(PrioritizedChoice &)
Definition peglib.h:2263
virtual void visit(Ignore &)
Definition peglib.h:2275
virtual void visit(PrecedenceClimbing &)
Definition peglib.h:2282
virtual void visit(CaptureScope &)
Definition peglib.h:2272
virtual void visit(Sequence &)
Definition peglib.h:2262
virtual void visit(Holder &)
Definition peglib.h:2278
virtual void visit(Capture &)
Definition peglib.h:2273
virtual void visit(NotPredicate &)
Definition peglib.h:2266
virtual void visit(BackReference &)
Definition peglib.h:2281
virtual void visit(Cut &)
Definition peglib.h:2284
virtual void visit(AnyCharacter &)
Definition peglib.h:2271
virtual void visit(Whitespace &)
Definition peglib.h:2280
virtual void visit(Recovery &)
Definition peglib.h:2283
virtual void visit(User &)
Definition peglib.h:2276
Definition peglib.h:974
size_t len
Definition peglib.h:976
size_t key
Definition peglib.h:975
Definition peglib.h:5251
Data()
Definition peglib.h:5267
std::vector< std::pair< std::string, const char * > > duplicates_of_definition
Definition peglib.h:5256
bool enablePackratParsing
Definition peglib.h:5265
std::map< std::string, std::vector< Instruction > > instructions
Definition peglib.h:5259
std::string start
Definition peglib.h:5253
std::vector< std::pair< std::string, const char * > > duplicates_of_instruction
Definition peglib.h:5258
const char * start_pos
Definition peglib.h:5254
std::set< std::string_view > captures_in_current_definition
Definition peglib.h:5264
std::vector< std::pair< std::string, const char * > > undefined_back_references
Definition peglib.h:5261
std::shared_ptr< Grammar > grammar
Definition peglib.h:5252
std::vector< std::set< std::string_view > > captures_stack
Definition peglib.h:5262
Definition peglib.h:5245
std::any data
Definition peglib.h:5247
std::string type
Definition peglib.h:5246
std::string_view sv
Definition peglib.h:5248
Definition peglib.h:5194
std::shared_ptr< Grammar > grammar
Definition peglib.h:5195
bool enablePackratParsing
Definition peglib.h:5197
std::string start
Definition peglib.h:5196
Definition peglib.h:2728
std::unordered_set< std::string > referenced
Definition peglib.h:2739
std::unordered_map< std::string, const char * > error_s
Definition peglib.h:2737
const std::vector< std::string > & params_
Definition peglib.h:2743
std::unordered_map< std::string, std::string > error_message
Definition peglib.h:2738
ReferenceChecker(const Grammar &grammar, const std::vector< std::string > &params)
Definition peglib.h:2731
const Grammar & grammar_
Definition peglib.h:2742
void visit(Reference &ope) override
Definition peglib.h:4378
Definition peglib.h:574
std::pair< size_t, size_t > line_info() const
Definition peglib.h:3380
std::string token_to_string(size_t id=0) const
Definition peglib.h:609
std::vector< std::string_view > tokens
Definition peglib.h:600
size_t choice_
Definition peglib.h:664
Context * c_
Definition peglib.h:661
std::string name_
Definition peglib.h:665
friend class Holder
Definition peglib.h:658
friend class Sequence
Definition peglib.h:655
std::string_view token(size_t id=0) const
Definition peglib.h:602
SemanticValues()=default
std::string_view sv() const
Definition peglib.h:583
std::string_view sv_
Definition peglib.h:662
size_t choice() const
Definition peglib.h:597
T token_to_number() const
Definition peglib.h:613
const char * ss
Definition peglib.h:580
size_t choice_count_
Definition peglib.h:663
friend class Dictionary
Definition peglib.h:654
size_t choice_count() const
Definition peglib.h:594
std::vector< T > transform(size_t beg=0, size_t end=static_cast< size_t >(-1)) const
Definition peglib.h:619
const char * path
Definition peglib.h:579
std::vector< unsigned int > tags
Definition peglib.h:588
const std::string & name() const
Definition peglib.h:586
friend class Repetition
Definition peglib.h:657
friend class PrecedenceClimbing
Definition peglib.h:659
SemanticValues(Context *c)
Definition peglib.h:576
friend class Context
Definition peglib.h:653
friend class PrioritizedChoice
Definition peglib.h:656
Definition peglib.h:2962
void setup_keyword_guarded_identifier(Sequence &ope)
Definition peglib.h:4471
void visit(Repetition &ope) override
Definition peglib.h:2980
ComputeFirstSet::FirstSetCache first_set_cache_
Definition peglib.h:2990
void visit(Sequence &ope) override
Definition peglib.h:4463
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2968
std::unordered_set< const Definition * > visited_rules_
Definition peglib.h:2991
Definition peglib.h:2383
bool has_rule_
Definition peglib.h:2402
bool has_token_boundary_
Definition peglib.h:2401
void visit(TokenBoundary &) override
Definition peglib.h:2386
void visit(WeakHolder &) override
Definition peglib.h:2389
void visit(NotPredicate &) override
Definition peglib.h:2388
void visit(AndPredicate &) override
Definition peglib.h:2387
static bool is_token(Ope &ope)
Definition peglib.h:2392
Definition peglib.h:2313
void visit(Recovery &) override
Definition peglib.h:2337
void visit(Cut &) override
Definition peglib.h:2338
void visit(Holder &ope) override
Definition peglib.h:2332
void visit(User &) override
Definition peglib.h:2330
void visit(NotPredicate &) override
Definition peglib.h:2320
void visit(TokenBoundary &) override
Definition peglib.h:2328
void visit(LiteralString &) override
Definition peglib.h:2322
void visit(AnyCharacter &) override
Definition peglib.h:2325
void visit(Whitespace &) override
Definition peglib.h:2334
void visit(WeakHolder &) override
Definition peglib.h:2331
void visit(Repetition &) override
Definition peglib.h:2318
void visit(Character &) override
Definition peglib.h:2324
void visit(CharacterClass &) override
Definition peglib.h:2323
void visit(Reference &) override
Definition peglib.h:2333
static std::string get(Ope &ope)
Definition peglib.h:2340
const char * name_
Definition peglib.h:2347
void visit(Capture &) override
Definition peglib.h:2327
void visit(CaptureScope &) override
Definition peglib.h:2326
void visit(PrecedenceClimbing &) override
Definition peglib.h:2336
void visit(Sequence &) override
Definition peglib.h:2316
void visit(PrioritizedChoice &) override
Definition peglib.h:2317
void visit(Ignore &) override
Definition peglib.h:2329
void visit(AndPredicate &) override
Definition peglib.h:2319
void visit(BackReference &) override
Definition peglib.h:2335
void visit(Dictionary &) override
Definition peglib.h:2321
Definition peglib.h:2287
void visit(TokenBoundary &ope) override
Definition peglib.h:2304
void visit(Recovery &ope) override
Definition peglib.h:2309
void visit(PrioritizedChoice &ope) override
Definition peglib.h:2294
void visit(Capture &ope) override
Definition peglib.h:2303
void visit(Whitespace &ope) override
Definition peglib.h:2308
void visit(PrecedenceClimbing &ope) override
Definition peglib.h:2310
void visit(Repetition &ope) override
Definition peglib.h:2299
void visit(CaptureScope &ope) override
Definition peglib.h:2302
void visit(AndPredicate &ope) override
Definition peglib.h:2300
void visit(Sequence &ope) override
Definition peglib.h:2289
void visit(WeakHolder &ope) override
Definition peglib.h:2306
void visit(NotPredicate &ope) override
Definition peglib.h:2301
void visit(Ignore &ope) override
Definition peglib.h:2305
void visit(Holder &ope) override
Definition peglib.h:2307
Definition peglib.h:507
bool match
Definition peglib.h:509
size_t id
Definition peglib.h:510
bool done
Definition peglib.h:508
Definition peglib.h:685
Definition peglib.h:61
bool execute_on_destruction
Definition peglib.h:83
scope_exit(scope_exit &&rhs)
Definition peglib.h:65
EF exit_function
Definition peglib.h:82
~scope_exit()
Definition peglib.h:71
scope_exit(EF &&f)
Definition peglib.h:62
scope_exit(const scope_exit &)=delete
void operator=(const scope_exit &)=delete
scope_exit & operator=(scope_exit &&)=delete
void release()
Definition peglib.h:75