HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
formula_post_process_context.hpp
1// Copyright Take Vos 2020-2021.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "formula_evaluation_context.hpp"
8#include "../utility/utility.hpp"
9#include "../codec/codec.hpp"
10#include "../path/path.hpp"
11#include "../macros.hpp"
12#include <functional>
13#include <unordered_map>
14#include <vector>
15#include <string>
16#include <string_view>
17
18hi_export_module(hikogui.formula.formula_post_process_context);
19
20namespace hi { inline namespace v1 {
21namespace detail {
22
23[[nodiscard]] constexpr datum function_float(formula_evaluation_context& context, datum::vector_type const& args)
24{
25 if (args.size() != 1) {
26 throw operation_error(std::format("Expecting 1 argument for float() function, got {}", args.size()));
27 }
28
29 return datum{static_cast<double>(args[0])};
30}
31
32[[nodiscard]] constexpr datum function_integer(formula_evaluation_context& context, datum::vector_type const& args)
33{
34 if (args.size() != 1) {
35 throw operation_error(std::format("Expecting 1 argument for integer() function, got {}", args.size()));
36 }
37
38 return datum{static_cast<long long int>(args[0])};
39}
40
41[[nodiscard]] constexpr datum function_decimal(formula_evaluation_context& context, datum::vector_type const& args)
42{
43 if (args.size() != 1) {
44 throw operation_error(std::format("Expecting 1 argument for decimal() function, got {}", args.size()));
45 }
46
47 return datum{static_cast<decimal>(args[0])};
48}
49
50[[nodiscard]] inline datum function_string(formula_evaluation_context& context, datum::vector_type const& args)
51{
52 if (args.size() != 1) {
53 throw operation_error(std::format("Expecting 1 argument for string() function, got {}", args.size()));
54 }
55
56 return datum{static_cast<std::string>(args[0])};
57}
58
59[[nodiscard]] constexpr datum function_boolean(formula_evaluation_context& context, datum::vector_type const& args)
60{
61 if (args.size() != 1) {
62 throw operation_error(std::format("Expecting 1 argument for boolean() function, got {}", args.size()));
63 }
64
65 return datum{to_bool(args[0])};
66}
67
68[[nodiscard]] constexpr datum function_size(formula_evaluation_context& context, datum::vector_type const& args)
69{
70 if (args.size() != 1) {
71 throw operation_error(std::format("Expecting 1 argument for size() function, got {}", args.size()));
72 }
73
74 return datum{args[0].size()};
75}
76
77[[nodiscard]] inline datum function_keys(formula_evaluation_context& context, datum::vector_type const& args)
78{
79 if (args.size() != 1) {
80 throw operation_error(std::format("Expecting 1 argument for keys() function, got {}", args.size()));
81 }
82
83 return datum{args[0].keys()};
84}
85
86[[nodiscard]] inline datum function_values(formula_evaluation_context& context, datum::vector_type const& args)
87{
88 if (args.size() != 1) {
89 throw operation_error(std::format("Expecting 1 argument for values() function, got {}", args.size()));
90 }
91
92 return datum{args[0].values()};
93}
94
95[[nodiscard]] inline datum function_items(formula_evaluation_context& context, datum::vector_type const& args)
96{
97 if (args.size() != 1) {
98 throw operation_error(std::format("Expecting 1 argument for items() function, got {}", args.size()));
99 }
100
101 return datum{args[0].items()};
102}
103
104[[nodiscard]] constexpr datum function_sort(formula_evaluation_context& context, datum::vector_type const& args)
105{
106 if (args.size() != 1) {
107 throw operation_error(std::format("Expecting 1 argument for sort() function, got {}", args.size()));
108 }
109
110 if (hilet *v = get_if<datum::vector_type>(args[0])) {
111 auto r = *v;
112 std::sort(r.begin(), r.end());
113 return datum{r};
114
115 } else {
116 throw operation_error(std::format("Expecting vector argument for sort() function, got {}", args[0].type_name()));
117 }
118}
119
120[[nodiscard]] constexpr datum
121method_contains(formula_evaluation_context& context, datum const& self, datum::vector_type const& args)
122{
123 if (args.size() != 1) {
124 throw operation_error(std::format("Expecting 1 argument for .contains() method, got {}", args.size()));
125 }
126
128 return datum{self.contains(args[0])};
129
130 } else {
131 throw operation_error(
132 std::format("Expecting vector or map on left hand side for .contains() method, got {}", self.type_name()));
133 }
134}
135
136[[nodiscard]] constexpr datum method_append(formula_evaluation_context& context, datum& self, datum::vector_type const& args)
137{
138 if (args.size() != 1) {
139 throw operation_error(std::format("Expecting 1 argument for .append() method, got {}", args.size()));
140 }
141
143 self.push_back(args[0]);
144 return {};
145
146 } else {
147 throw operation_error(std::format("Expecting vector on left hand side for .append() method, got {}", self.type_name()));
148 }
149}
150
151[[nodiscard]] constexpr datum method_pop(formula_evaluation_context& context, datum& self, datum::vector_type const& args)
152{
153 if (args.size() != 0) {
154 throw operation_error(std::format("Expecting 0 arguments for .pop() method, got {}", args.size()));
155 }
156
158 auto r = self.back();
159 self.pop_back();
160 return r;
161
162 } else {
163 throw operation_error(std::format("Expecting vector on left hand side for .pop() method, got {}", self.type_name()));
164 }
165}
166
167[[nodiscard]] constexpr datum method_year(formula_evaluation_context& context, datum& self, datum::vector_type const& args)
168{
169 if (args.size() != 0) {
170 throw operation_error(std::format("Expecting 0 arguments for .year() method, got {}", args.size()));
171 }
172
174 return datum{static_cast<int>(ymd->year())};
175 } else {
176 throw operation_error(std::format("Expecting date type for .year() method, got {}", self.type_name()));
177 }
178}
179
180[[nodiscard]] constexpr datum method_quarter(formula_evaluation_context& context, datum& self, datum::vector_type const& args)
181{
182 if (args.size() != 0) {
183 throw operation_error(std::format("Expecting 0 arguments for .quarter() method, got {}", args.size()));
184 }
185
187 auto month = static_cast<unsigned>(ymd->month());
188 if (month >= 1 and month <= 3) {
189 return datum{1};
190 } else if (month >= 4 and month <= 6) {
191 return datum{2};
192 } else if (month >= 7 and month <= 9) {
193 return datum{3};
194 } else if (month >> 10 and month <= 12) {
195 return datum{4};
196 } else {
197 throw operation_error(std::format("Month {} outside of range 1-12", month));
198 }
199 } else {
200 throw operation_error(std::format("Expecting date type for .month() method, got {}", self.type_name()));
201 }
202}
203
204[[nodiscard]] constexpr datum method_month(formula_evaluation_context& context, datum& self, datum::vector_type const& args)
205{
206 if (args.size() != 0) {
207 throw operation_error(std::format("Expecting 0 arguments for .month() method, got {}", args.size()));
208 }
209
211 return datum{static_cast<unsigned>(ymd->month())};
212 } else {
213 throw operation_error(std::format("Expecting date type for .month() method, got {}", self.type_name()));
214 }
215}
216
217[[nodiscard]] constexpr datum method_day(formula_evaluation_context& context, datum& self, datum::vector_type const& args)
218{
219 if (args.size() != 0) {
220 throw operation_error(std::format("Expecting 0 arguments for .day() method, got {}", args.size()));
221 }
222
224 return datum{static_cast<unsigned>(ymd->day())};
225 } else {
226 throw operation_error(std::format("Expecting date type for .day() method, got {}", self.type_name()));
227 }
228}
229
230[[nodiscard]] constexpr std::string url_encode(std::string_view str) noexcept
231{
232 return URI::encode(str);
233}
234
235} // namespace detail
236
238 using filter_type = std::function<std::string(std::string_view)>;
240 using function_type = std::function<datum(formula_evaluation_context&, datum::vector_type const&)>;
242 using function_stack = std::vector<function_type>;
243 using method_type = std::function<datum(formula_evaluation_context&, datum&, datum::vector_type const&)>;
245
246 static inline auto global_functions = function_table{
247 {"float", detail::function_float},
248 {"integer", detail::function_integer},
249 {"decimal", detail::function_decimal},
250 {"string", detail::function_string},
251 {"boolean", detail::function_boolean},
252 {"size", detail::function_size},
253 {"keys", detail::function_keys},
254 {"values", detail::function_values},
255 {"items", detail::function_items},
256 {"sort", detail::function_sort}};
257
258 static inline auto global_methods = method_table{
259 {"append", detail::method_append},
260 {"contains", detail::method_contains},
261 {"push", detail::method_append},
262 {"pop", detail::method_pop},
263 {"year", detail::method_year},
264 {"quarter", detail::method_quarter},
265 {"month", detail::method_month},
266 {"day", detail::method_day}};
267
268 static inline auto global_filters = filter_table{{"id", make_identifier}, {"url", detail::url_encode}};
269
270 function_table functions = {};
271 function_stack super_stack = {};
272
273 [[nodiscard]] function_type get_function(std::string const& name) const noexcept
274 {
275 if (name == "super") {
276 if (super_stack.size() > 0) {
277 return super_stack.back();
278 } else {
279 return {};
280 }
281 }
282
283 hilet i = functions.find(name);
284 if (i != functions.end()) {
285 return i->second;
286 }
287
288 hilet j = global_functions.find(name);
289 if (j != global_functions.end()) {
290 return j->second;
291 }
292
293 return {};
294 }
295
296 [[nodiscard]] function_type set_function(std::string const& name, function_type func) noexcept
297 {
298 using std::swap;
299
300 swap(functions[name], func);
301 return func;
302 }
303
304 void push_super(function_type func) noexcept
305 {
306 super_stack.push_back(func);
307 }
308
309 void pop_super(void) noexcept
310 {
311 super_stack.pop_back();
312 }
313
314 [[nodiscard]] filter_type get_filter(std::string const& name) const noexcept
315 {
316 hilet i = global_filters.find(name);
317 if (i != global_filters.end()) {
318 return i->second;
319 }
320
321 return {};
322 }
323
324 [[nodiscard]] method_type get_method(std::string const& name) const noexcept
325 {
326 hilet i = global_methods.find(name);
327 if (i != global_methods.end()) {
328 return i->second;
329 }
330
331 return {};
332 }
333};
334
335}} // namespace hi::v1
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
A dynamic data type.
Definition datum.hpp:212
Definition formula_evaluation_context.hpp:18
Definition formula_post_process_context.hpp:237
static constexpr std::string encode(It first, ItEnd last) noexcept
URI encode a component.
Definition URI.hpp:758
T back(T... args)
T sort(T... args)
T swap(T... args)