Skip to content

Commit 3667ddf

Browse files
author
Hana Dusíková
committed
remove recursion
added trampoline (long) input test rename types
1 parent b86f7c7 commit 3667ddf

File tree

2 files changed

+60
-14
lines changed

2 files changed

+60
-14
lines changed

include/ctll/parser.hpp

Lines changed: 49 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,10 @@ namespace ctll {
1010

1111
struct 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

tests/trampoline.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#include "ctre.hpp"
2+
3+
static constexpr inline auto pattern = ctll::basic_fixed_string{"h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)h(e[ll]+o)"};
4+
5+
static constexpr inline auto a = ctll::parser<ctre::pcre, pattern>::trampoline_decide();
6+
7+
template <typename T> void identify(T) { }
8+
9+
void fnc() {
10+
identify(a);
11+
}

0 commit comments

Comments
 (0)