@@ -47,7 +47,8 @@ enum class opcode : unsigned char
47
47
choice, commit, commit_back, commit_partial,
48
48
jump, call, ret, fail,
49
49
accept, accept_final, action, predicate,
50
- begin, end
50
+ capture_start, capture_end, test_condition, push_condition,
51
+ pop_condition
51
52
};
52
53
53
54
enum class immediate : unsigned short {};
@@ -114,7 +115,7 @@ struct program
114
115
case opcode::match_set: val = detail::push_back_unique (runesets, src.runesets [instr.pf .val ]); break ;
115
116
case opcode::action: val = actions.size (); actions.push_back (src.actions [instr.pf .val ]); break ;
116
117
case opcode::predicate: val = predicates.size (); predicates.push_back (src.predicates [instr.pf .val ]); break ;
117
- case opcode::end : val = captures.size (); captures.push_back (src.captures [instr.pf .val ]); break ;
118
+ case opcode::capture_end : val = captures.size (); captures.push_back (src.captures [instr.pf .val ]); break ;
118
119
default : val = (std::numeric_limits<std::size_t >::max)(); break ;
119
120
}
120
121
if (val != (std::numeric_limits<std::size_t >::max)()) {
@@ -189,7 +190,7 @@ class environment
189
190
190
191
std::vector<lug::parser*> parser_stack_;
191
192
std::vector<std::vector<std::any>> accept_stack_;
192
- std::unordered_set<std::string > conditions_;
193
+ std::unordered_set<std::string_view > conditions_;
193
194
unsigned int tab_width_ = 8 ;
194
195
unsigned int tab_alignment_ = 8 ;
195
196
@@ -241,11 +242,9 @@ class environment
241
242
void tab_width (unsigned int w) { tab_width_ = w; }
242
243
[[nodiscard]] unsigned int tab_alignment () const { return tab_alignment_; }
243
244
void tab_alignment (unsigned int a) { tab_alignment_ = a; }
244
- [[nodiscard]] bool has_condition (std::string_view c) const noexcept { return (conditions_.count (std::string{c}) > 0 ); }
245
- void set_condition (std::string_view c) { conditions_.insert (std::string{c}); }
246
- void unset_condition (std::string_view c) { conditions_.erase (std::string{c}); }
245
+ [[nodiscard]] bool has_condition (std::string_view name) const noexcept { return (conditions_.count (name) > 0 ); }
246
+ bool set_condition (std::string_view name, bool value) { if (value) { return !conditions_.emplace (name).second ; } else { return (conditions_.erase (name) > 0 ); } }
247
247
void clear_conditions () { conditions_.clear (); }
248
- template <bool B> void modify_condition (std::string_view c) { if constexpr (B) set_condition (c); else unset_condition (c); }
249
248
[[nodiscard]] std::string_view match () const ;
250
249
[[nodiscard]] syntax_position const & position_at (std::size_t index);
251
250
[[nodiscard]] unsigned int variable_instance () const { return (static_cast <unsigned int >(parse_depth ()) << 16 ) | call_depth (); }
@@ -610,37 +609,34 @@ inline constexpr directive_modifier<directives::postskip, directives::none, dire
610
609
inline constexpr directive_modifier<directives::preskip, directives::postskip, directives::eps> skip_before{};
611
610
template <unicode::ctype Property> struct ctype_combinator { void operator ()(encoder& d) const { d.match_any (Property); } };
612
611
613
- template <typename Op> struct test_condition_combinator
612
+ template <bool Value>
613
+ struct condition_test_combinator
614
614
{
615
- template <class C >
616
- [[nodiscard]] constexpr auto operator ()(C&& condition) const
615
+ [[nodiscard]] constexpr auto operator ()(std::string_view name) const noexcept
617
616
{
618
- if constexpr (std::is_invocable_r_v<bool , C, environment&>)
619
- return [c = std::decay_t <C>{std::forward<C>(condition)}](environment& envr) -> bool { return Op{}(c (envr)); };
620
- else if constexpr (std::is_invocable_r_v<bool , C>)
621
- return [c = std::decay_t <C>{std::forward<C>(condition)}](environment&) -> bool { return Op{}(c ()); };
622
- else if constexpr (std::is_same_v<std::string_view, std::decay_t <C>> || std::is_same_v<char const *, std::decay_t <C>>)
623
- return [c = std::string_view{std::forward<C>(condition)}](environment& envr) -> bool { return Op{}(envr.has_condition (c)); };
624
- else if constexpr (std::is_constructible_v<std::string, C&&>)
625
- return [c = std::string{std::forward<C>(condition)}](environment& envr) -> bool { return Op{}(envr.has_condition (c)); };
626
- else if constexpr (std::is_constructible_v<bool const &, C&&>)
627
- return [&condition](environment&) -> bool { return Op{}(condition); };
617
+ return [name](encoder& d) {
618
+ d.encode (opcode::test_condition, name, immediate{Value ? 1 : 0 });
619
+ };
628
620
}
629
621
};
630
622
631
623
template <bool Value>
632
- struct modify_condition_combinator
624
+ struct condition_block_combinator
633
625
{
634
- template <class C >
635
- [[nodiscard]] constexpr auto operator ()(C&& condition) const
626
+ struct condition_block_expression
636
627
{
637
- if constexpr (std::is_same_v<std::string_view, std::decay_t <C>> || std::is_same_v<char const *, std::decay_t <C>>)
638
- return [c = std::string_view{std::forward<C>(condition)}](environment& envr) -> bool { envr.modify_condition <Value>(c); return true ; };
639
- else if constexpr (std::is_constructible_v<std::string, C&&>)
640
- return [c = std::string{std::forward<C>(condition)}](environment& envr) -> bool { envr.modify_condition <Value>(c); return true ; };
641
- else if constexpr (std::is_constructible_v<bool &, C&&>)
642
- return [&condition](environment&) -> bool { condition = Value; return true ; };
643
- }
628
+ std::string_view name;
629
+
630
+ template <class E , class = std::enable_if_t <is_expression_v<E>>>
631
+ [[nodiscard]] constexpr auto operator [](E const & e) const
632
+ {
633
+ return [e = make_expression (e), n = name](encoder& d) {
634
+ d.encode (opcode::push_condition, n, immediate{Value ? 1 : 0 }).evaluate (e).encode (opcode::pop_condition);
635
+ };
636
+ }
637
+ };
638
+
639
+ [[nodiscard]] constexpr auto operator ()(std::string_view name) const noexcept { return condition_block_expression{name}; }
644
640
};
645
641
646
642
namespace language {
@@ -665,8 +661,8 @@ inline constexpr ctype_combinator<ctype::alpha> alpha{}; inline constexpr ctype_
665
661
inline constexpr ctype_combinator<ctype::upper> upper{}; inline constexpr ctype_combinator<ctype::digit> digit{}; inline constexpr ctype_combinator<ctype::xdigit> xdigit{};
666
662
inline constexpr ctype_combinator<ctype::space> space{}; inline constexpr ctype_combinator<ctype::blank> blank{}; inline constexpr ctype_combinator<ctype::punct> punct{};
667
663
inline constexpr ctype_combinator<ctype::graph> graph{}; inline constexpr ctype_combinator<ctype::print> print{};
668
- inline constexpr test_condition_combinator<detail::identity > when{}; inline constexpr test_condition_combinator<std::logical_not<> > unless{};
669
- inline constexpr modify_condition_combinator <true > set {}; inline constexpr modify_condition_combinator <false > unset {};
664
+ inline constexpr condition_test_combinator< true > when{}; inline constexpr condition_test_combinator< false > unless{};
665
+ inline constexpr condition_block_combinator <true > on {}; inline constexpr condition_block_combinator <false > off {};
670
666
671
667
inline constexpr struct
672
668
{
@@ -715,8 +711,8 @@ chr{};
715
711
716
712
inline constexpr struct
717
713
{
718
- [[nodiscard]] constexpr auto operator ()(std::string_view s) const { return string_expression{s}; }
719
- [[nodiscard]] constexpr auto operator ()(char const * s, std::size_t n) const { return string_expression{std::string_view{s, n}}; }
714
+ [[nodiscard]] constexpr auto operator ()(std::string_view s) const noexcept { return string_expression{s}; }
715
+ [[nodiscard]] constexpr auto operator ()(char const * s, std::size_t n) const noexcept { return string_expression{std::string_view{s, n}}; }
720
716
}
721
717
str{};
722
718
@@ -783,7 +779,7 @@ template <class E, class A, class = std::enable_if_t<is_expression_v<E>>>
783
779
{
784
780
if constexpr (std::is_invocable_v<A, environment&, syntax>) {
785
781
return [e = make_expression (e), a = std::move (a)](encoder& d) {
786
- d.skip ().encode (opcode::begin ).evaluate (e).encode (opcode::end , syntactic_capture{a});
782
+ d.skip ().encode (opcode::capture_start ).evaluate (e).encode (opcode::capture_end , syntactic_capture{a});
787
783
};
788
784
} else if constexpr (std::is_invocable_v<A, detail::dynamic_cast_if_base_of<environment&>, syntax>) {
789
785
return e < [a = std::move (a)](environment& envr, csyntax& x) {
@@ -923,7 +919,7 @@ struct parser_registers
923
919
924
920
class parser
925
921
{
926
- enum class stack_frame_type : unsigned char { backtrack, call, capture, lrcall };
922
+ enum class stack_frame_type : unsigned char { backtrack, call, capture, condition, lrcall };
927
923
enum class subject_location : std::size_t {};
928
924
struct lrmemo { std::size_t srr, sra, prec; std::ptrdiff_t pcr, pca; std::size_t rcr; std::vector<semantic_response> responses; };
929
925
static inline constexpr std::size_t lrfailcode = (std::numeric_limits<std::size_t >::max)();
@@ -943,6 +939,7 @@ class parser
943
939
std::vector<std::tuple<std::size_t , std::size_t , std::ptrdiff_t >> backtrack_stack_; // sr, rc, pc
944
940
std::vector<std::ptrdiff_t > call_stack_; // pc
945
941
std::vector<subject_location> capture_stack_; // sr
942
+ std::vector<std::pair<std::string_view, bool >> condition_stack_; // name, value
946
943
std::vector<lrmemo> lrmemo_stack_;
947
944
std::vector<semantic_response> responses_;
948
945
unsigned short prune_depth_{max_call_depth}, call_depth_{0 };
@@ -1297,7 +1294,7 @@ class parser
1297
1294
fc = imm;
1298
1295
failure:
1299
1296
for (mr = (std::max)(mr, sr), ++fc; fc > 0 ; --fc) {
1300
- if (done = cut_frame_ >= stack_frames_.size (); done) {
1297
+ if (done = ( cut_frame_ >= stack_frames_.size () ); done) {
1301
1298
registers_ = {sr, mr, rc, pc, 0 };
1302
1299
break ;
1303
1300
}
@@ -1312,6 +1309,11 @@ class parser
1312
1309
case stack_frame_type::capture: {
1313
1310
pop_stack_frame (capture_stack_, sr, mr, rc, pc), ++fc;
1314
1311
} break ;
1312
+ case stack_frame_type::condition: {
1313
+ auto const & [cond_name, cond_value] = condition_stack_.back ();
1314
+ environment_.set_condition (cond_name, cond_value);
1315
+ pop_stack_frame (condition_stack_), ++fc;
1316
+ } break ;
1315
1317
case stack_frame_type::lrcall: {
1316
1318
if (auto const & memo = lrmemo_stack_.back (); memo.sra != lrfailcode)
1317
1319
sr = memo.sra , pc = memo.pcr , rc = restore_responses_after (memo.rcr , memo.responses );
@@ -1345,11 +1347,11 @@ class parser
1345
1347
if (!accepted)
1346
1348
goto failure;
1347
1349
} break ;
1348
- case opcode::begin : {
1350
+ case opcode::capture_start : {
1349
1351
stack_frames_.push_back (stack_frame_type::capture);
1350
1352
capture_stack_.push_back (static_cast <subject_location>(sr));
1351
1353
} break ;
1352
- case opcode::end : {
1354
+ case opcode::capture_end : {
1353
1355
if (stack_frames_.empty () || stack_frames_.back () != stack_frame_type::capture)
1354
1356
goto failure;
1355
1357
auto const sr0 = static_cast <std::size_t >(capture_stack_.back ()), sr1 = sr;
@@ -1358,6 +1360,21 @@ class parser
1358
1360
goto failure;
1359
1361
rc = push_response (call_stack_.size () + lrmemo_stack_.size (), imm, {sr0, sr1 - sr0});
1360
1362
} break ;
1363
+ case opcode::test_condition: {
1364
+ if (environment_.has_condition (str) != (imm != 0 ))
1365
+ goto failure;
1366
+ } break ;
1367
+ case opcode::push_condition: {
1368
+ stack_frames_.push_back (stack_frame_type::condition);
1369
+ condition_stack_.emplace_back (str, environment_.set_condition (str, imm != 0 ));
1370
+ } break ;
1371
+ case opcode::pop_condition: {
1372
+ if (stack_frames_.empty () || stack_frames_.back () != stack_frame_type::condition)
1373
+ goto failure;
1374
+ auto const & [cond_name, cond_value] = condition_stack_.back ();
1375
+ environment_.set_condition (cond_name, cond_value);
1376
+ pop_stack_frame (condition_stack_);
1377
+ } break ;
1361
1378
default : registers_ = {sr, (std::max)(mr, sr), rc, pc, 0 }; throw bad_opcode{};
1362
1379
}
1363
1380
}
0 commit comments