7 #include <kblib/poly_obj.h> 15 std::vector<kblib::poly_obj<Expr, 64>> children;
18 eval_context c)
const final {
24 Expr() noexcept = default;
25 Expr(const Expr& e) = default;
26 Expr(Expr&&) noexcept = default;
27 Expr& operator=(const Expr&) = default;
28 Expr& operator=(Expr&&) = default;
29 virtual ~Expr() = default;
32 using ExprList = decltype(Expr::children);
33 using Expr_t = ExprList::value_type;
35 static_assert(std::is_copy_constructible_v<Expr>);
37 struct literal_expr : Expr {
39 literal_expr(std::string s) : text(std::move(s)) {}
46 struct arg_expr : Expr {
48 arg_expr(
int a) noexcept : arg(a) {}
51 return c.args.at(kblib::to_unsigned(arg));
55 struct sarg_expr : Expr {
57 sarg_expr(std::string a) noexcept : arg(std::move(a)) {}
60 return c.args.at(kblib::to_unsigned(bm.special_argument(arg)));
69 using _l_h = std::is_convertible<decltype(std::declval<T>()(
70 std::declval<ExprList>(),
71 std::declval<const bytecode_machine&>(),
72 std::declval<eval_context>())),
75 template <
typename T,
typename = std::
void_t<>>
76 struct is_lazy_transformer :
79 public std::false_type {};
82 struct is_lazy_transformer<T, std::void_t<_l_h<T>>> :
public _l_h<T> {};
85 constexpr
bool is_lazy_transformer_v = is_lazy_transformer<T>::value;
89 template <
typename Callable,
90 typename std::enable_if_t<helpers::is_transformer_v<Callable>,
int> =
92 class eager_transformer final :
public Expr {
94 eager_transformer(Callable _c) : c(std::move(_c)) {}
96 eval_context context)
const override {
97 return c(kblib::build<argslist>(
98 children.begin(), children.end(),
99 [&](
const Expr_t& a) -> decltype(
auto) {
return a(bm, context); }));
106 template <
typename Callable,
107 typename std::enable_if_t<helpers::is_lazy_transformer_v<Callable>,
109 class lazy_transformer final :
public Expr {
111 lazy_transformer(Callable _c) : c(std::move(_c)) {}
113 eval_context context)
const override {
114 return c(children, bm, context);
121 template <
typename Callable,
typename... Ts>
122 [[nodiscard]]
auto make_eager_expr(Callable&& c, Ts&&... ts)
123 -> eager_transformer<std::decay_t<Callable>> {
124 return {std::forward<Callable>(c), {std::forward<Ts>(ts)...}};
127 template <
typename Callable,
typename... Ts>
128 [[nodiscard]]
auto make_lazy_expr(Callable&& c, Ts&&... ts)
129 -> lazy_transformer<std::decay_t<Callable>> {
130 return {std::forward<Callable>(c), {std::forward<Ts>(ts)...}};
133 using index_type = gsl::span<bytecode_op>::index_type;
135 auto do_lookup(std::string_view) -> Expr_t (*)();
137 Expr_t parse_expr(gsl::span<bytecode_op> in, index_type& consumed) {
140 literal_expr l{std::get<std::string>(in[0].data)};
141 switch (in[0].type) {
143 return Expr_t::make_aggregate<literal_expr>(
144 std::get<std::string>(in[0].data));
146 return Expr_t::make_aggregate<arg_expr>(std::get<int>(in[0].data));
148 return Expr_t::make_aggregate<sarg_expr>(
"...");
149 case op::special_argument:
150 return Expr_t::make_aggregate<sarg_expr>(
151 std::get<std::string>(in[0].data));
154 Expr_t e = do_lookup(std::get<std::string>(in[0].data))();
158 while (skip != in.extent) {
159 auto& code = in[skip];
160 if (code.type == op::call_func) {
164 e->children.push_back(parse_expr(in.subspan(skip), skip));
177 Expr_t parse_tokens(gsl::span<bytecode_op> in) {
179 Expr_t e(std::in_place);
181 index_type begin = 0;
183 while (begin != in.extent) {
184 e->children.push_back(parse_expr(in.subspan(begin), begin));
191 #endif // EXPRESSIONS_H Definition: tstrings.h:113
Definition: tstrings.h:196