@@ -10,11 +10,10 @@ namespace ctll {
1010
1111struct empty_subject { };
1212
13- template <bool Result, typename Subject> struct parse_result {
14- constexpr inline CTLL_FORCE_INLINE operator bool () const noexcept {
15- return Result;
16- }
17- using output_type = Subject;
13+ enum class decision {
14+ reject,
15+ accept,
16+ undecided
1817};
1918
2019#if !__cpp_nontype_template_parameter_class
@@ -25,6 +24,10 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
2524 static inline constexpr auto grammar = augment_grammar<Grammar>();
2625 static inline constexpr auto select_action = augment_actions<IngoreUnknownActions, ActionSelector>();
2726
27+ template <size_t Pos, typename Stack = void , typename Subject = void , decision Decision = decision::undecided> struct seed ;
28+
29+ template <size_t Pos> struct placeholder { };
30+
2831 template <size_t Pos> static constexpr auto get_current_term () noexcept {
2932 if constexpr (Pos < input.size ()) {
3033 return term<input[Pos]>{};
@@ -46,17 +49,17 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
4649 // if rule is accept => return true and subject
4750 template <size_t Pos, typename Terminal, typename Stack, typename Subject>
4851 static constexpr auto move (ctll::accept, Terminal, Stack, Subject) noexcept {
49- return parse_result< true , Subject>();
52+ return seed<Pos, Stack, Subject, decision::accept >();
5053 }
5154 // if rule is reject => return false and subject
5255 template <size_t Pos, typename Terminal, typename Stack, typename Subject>
5356 static constexpr auto move (ctll::reject, Terminal, Stack, Subject) noexcept {
54- return parse_result< false , Subject>();
57+ return seed<Pos, Stack, Subject, decision::reject >();
5558 }
5659 // if rule is pop_input => move to next character
5760 template <size_t Pos, typename Terminal, typename Stack, typename Subject>
5861 static constexpr auto move (ctll::pop_input, Terminal, Stack stack, Subject subject) noexcept {
59- return decide <Pos+1 >(stack, subject );
62+ return seed <Pos+1 , Stack, Subject, decision::undecided>( );
6063 }
6164 // if rule is string => push it to the front of stack
6265 template <size_t Pos, typename ... Content, typename Terminal, typename Stack, typename Subject>
@@ -72,13 +75,13 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
7275 // and push string without the character (quick LL(1))
7376 template <size_t Pos, auto V, typename ... Content, typename Stack, typename Subject>
7477 static constexpr auto move (ctll::list<term<V>, Content...> string, term<V>, Stack stack, Subject subject) noexcept {
75- return decide <Pos+1 > (push_front (list<Content...>(), stack), subject );
78+ return seed <Pos+1 , decltype (push_front (list<Content...>(), stack)), Subject, decision::undecided>( );
7679 }
7780 // if rule is string with any character at the beginning (compatible with current term<T>) => move to next character
7881 // and push string without the character (quick LL(1))
7982 template <size_t Pos, auto V, typename ... Content, auto T, typename Stack, typename Subject>
8083 static constexpr auto move (ctll::list<anything, Content...> string, term<T>, Stack stack, Subject subject) noexcept {
81- return decide <Pos+1 > (push_front (list<Content...>(), stack), subject );
84+ return seed <Pos+1 , decltype (push_front (list<Content...>(), stack)), Subject, decision::undecided>( );
8285 }
8386 // decide if we need to take action or move
8487 template <size_t Pos, typename Stack, typename Subject> static constexpr auto decide (Stack previous_stack, Subject previous_subject) noexcept {
@@ -93,7 +96,7 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
9396
9497 // in case that semantic action is error => reject input
9598 if constexpr (std::is_same_v<ctll::reject, decltype (subject)>) {
96- return parse_result< false , Subject>();
99+ return seed<Pos, Stack, Subject, decision::reject >();
97100 } else {
98101 return decide<Pos>(stack, subject);
99102 }
@@ -104,10 +107,42 @@ template <typename Grammar, basic_fixed_string input, typename ActionSelector =
104107 return move<Pos>(rule, current_term, stack, previous_subject);
105108 }
106109 }
110+ // helper type for trampoline
111+ template <size_t Pos, typename Stack, typename Subject, decision Decision> struct seed {
112+ constexpr inline CTLL_FORCE_INLINE operator bool () const noexcept {
113+ return Decision == decision::accept;
114+ }
115+
116+ using output_type = Subject;
117+
118+ static constexpr auto parse () noexcept {
119+ return decide<Pos>(Stack{}, Subject{});
120+ }
121+
122+ template <size_t RPos> constexpr auto operator +(placeholder<RPos>) const noexcept {
123+ if constexpr (Decision == decision::reject) {
124+ return *this ;
125+ } else if constexpr (Decision == decision::accept) {
126+ return *this ;
127+ } else {
128+ return decltype (seed<RPos, Stack, Subject, Decision>::parse ()){};
129+ }
130+ }
131+ };
132+
133+ // trampolines with folded expression
134+ template <typename Subject, size_t ... Pos> static constexpr auto trampoline_decide (Subject default_subject, std::index_sequence<Pos...>) noexcept {
135+ // Pos+1 is needed as we want to finish calculation with epsilons on stack
136+ return (seed<0 , decltype (grammar.start_stack ), Subject, decision::undecided>::parse () + ... + placeholder<Pos+1 >());
137+ }
138+
139+ template <typename Subject = empty_subject> static constexpr auto trampoline_decide (Subject subject = {}) noexcept {
140+ return trampoline_decide (subject, std::make_index_sequence<input.size ()>());
141+ }
107142
108- template <typename Subject = empty_subject> using output = decltype (decide< 0 >(grammar.start_stack, Subject()));
109- static inline constexpr bool correct = decide< 0 >(grammar.start_stack, empty_subject());
110- template <typename Subject = empty_subject> static inline constexpr bool correct_with = decide< 0 >(grammar.start_stack, Subject());
143+ template <typename Subject = empty_subject> using output = decltype (trampoline_decide( Subject()));
144+ static inline constexpr bool correct = trampoline_decide( empty_subject());
145+ template <typename Subject = empty_subject> static inline constexpr bool correct_with = trampoline_decide( Subject());
111146};
112147
113148} // end of ctll namespace
0 commit comments