HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
template.hpp
1// Copyright 2019 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Foundation/expression.hpp"
7#include "TTauri/Foundation/strings.hpp"
8#include "TTauri/Foundation/algorithm.hpp"
9#include "TTauri/Foundation/ResourceView.hpp"
10
11namespace tt {
12
13struct template_node;
14
17 using const_iterator = typename std::string_view::const_iterator;
18
19 statement_stack_type statement_stack;
20
21 parse_location location;
22 const_iterator index;
23 const_iterator last;
24
25 std::optional<const_iterator> text_segment_start;
26
31
32 template_parse_context() = delete;
34 template_parse_context &operator=(template_parse_context const &other) = delete;
36 template_parse_context &operator=(template_parse_context &&other) = delete;
37 ~template_parse_context() = default;
38
39 template_parse_context(URL const &url, const_iterator first, const_iterator last);
40
41 [[nodiscard]] char const& operator*() const noexcept {
42 return *index;
43 }
44
45 [[nodiscard]] bool atEOF() const noexcept {
46 return index == last;
47 }
48
49 template_parse_context& operator++() noexcept {
50 tt_assume(!atEOF());
51 location += *index;
52 ++index;
53 return *this;
54 }
55
56 template_parse_context& operator+=(ssize_t x) noexcept {
57 for (ssize_t i = 0; i != x; ++i) {
58 ++(*this);
59 }
60 return *this;
61 }
62
63 bool starts_with(std::string_view text) const noexcept {
64 return ::tt::starts_with(index, last, text.begin(), text.end());
65 }
66
67 bool starts_with_and_advance_over(std::string_view text) noexcept {
68 if (starts_with(text)) {
69 *this += ssize(text);
70 return true;
71 } else {
72 return false;
73 }
74 }
75
76 bool advance_to(std::string_view text) noexcept {
77 while (!atEOF()) {
78 if (starts_with(text)) {
79 return true;
80 }
81 ++(*this);
82 }
83 return false;
84 }
85
86 bool advance_over(std::string_view text) noexcept {
87 if (advance_to(text)) {
88 *this += ssize(text);
89 return true;
90 } else {
91 return false;
92 }
93 }
94
95 std::unique_ptr<expression_node> parse_expression(std::string_view end_text);
96
97 std::unique_ptr<expression_node> parse_expression_and_advance_over(std::string_view end_text);
98
99 template<typename T, typename... Args>
100 void push(Args &&... args) {
101 statement_stack.push_back(std::make_unique<T>(std::forward<Args>(args)...));
102 }
103
104 [[nodiscard]] bool append(std::unique_ptr<template_node> x) noexcept;
105
106 template<typename T, typename... Args>
107 [[nodiscard]] bool append(Args &&... args) noexcept {
108 if (statement_stack.size() > 0) {
109 return append(std::make_unique<T>(std::forward<Args>(args)...));
110 } else {
111 return false;
112 }
113 }
114
119 [[nodiscard]] bool pop() noexcept;
120
121 void start_of_text_segment(int back_track = 0) noexcept;
122 void end_of_text_segment();
123
124 [[nodiscard]] bool top_statement_is_do() const noexcept;
125
126 [[nodiscard]] bool found_elif(parse_location location, std::unique_ptr<expression_node> expression) noexcept;
127
128 [[nodiscard]] bool found_else(parse_location location) noexcept;
129
130 [[nodiscard]] bool found_while(parse_location location, std::unique_ptr<expression_node> expression) noexcept;
131
132 void include(parse_location location, std::unique_ptr<expression_node> expression);
133};
134
136 using statement_vector = typename std::vector<std::unique_ptr<template_node>>;
137
138 parse_location location;
139
140 template_node(parse_location location) :
141 location(std::move(location)) {}
142
143 virtual ~template_node() {}
144
147 [[nodiscard]] virtual bool append(std::unique_ptr<template_node> x) noexcept { return false; }
148
151 [[nodiscard]] virtual bool should_left_align() const noexcept { return true; }
152
155 virtual void left_align() noexcept {}
156
157 [[nodiscard]] virtual bool found_elif(parse_location _location, std::unique_ptr<expression_node> expression) noexcept { return false; }
158 [[nodiscard]] virtual bool found_else(parse_location _location) noexcept { return false;}
159 [[nodiscard]] virtual bool found_while(parse_location _location, std::unique_ptr<expression_node> expression) noexcept { return false; }
160
161 virtual void post_process(expression_post_process_context &context) {}
162
171 [[nodiscard]] virtual datum evaluate(expression_evaluation_context &context) {
172 tt_no_default;
173 }
174
175 [[nodiscard]] std::string evaluate_output(expression_evaluation_context &context) {
176 auto tmp = evaluate(context);
177 if (tmp.is_break()) {
178 TTAURI_THROW(invalid_operation_error("Found #break not inside a loop statement.").set_location(location));
179
180 } else if (tmp.is_continue()) {
181 TTAURI_THROW(invalid_operation_error("Found #continue not inside a loop statement.").set_location(location));
182
183 } else if (tmp.is_undefined()) {
184 return std::move(context.output);
185
186 } else {
187 TTAURI_THROW(invalid_operation_error("Found #return not inside a function.").set_location(location));
188 }
189 }
190
191 [[nodiscard]] std::string evaluate_output() {
192 auto context = expression_evaluation_context{};
193 return evaluate_output(context);
194 }
195
196 [[nodiscard]] virtual std::string string() const noexcept {
197 return "<template_node>";
198 }
199
200 [[nodiscard]] friend std::string to_string(template_node const &lhs) noexcept {
201 return lhs.string();
202 }
203
204 friend std::ostream &operator<<(std::ostream &lhs, template_node const &rhs) {
205 return lhs << to_string(rhs);
206 }
207
208 static void append_child(statement_vector &children, std::unique_ptr<template_node> new_child) {
209 if (ssize(children) > 0 && new_child->should_left_align()) {
210 children.back()->left_align();
211 }
212 children.push_back(std::move(new_child));
213 }
214
215 [[nodiscard]] static datum evaluate_expression_without_output(expression_evaluation_context &context, expression_node const &expression, parse_location const &location) {
216 try {
217 return expression.evaluate_without_output(context);
218 } catch (error &e) {
219 e.merge_location(location);
220 throw;
221 }
222 }
223
224 [[nodiscard]] static datum evaluate_expression(expression_evaluation_context &context, expression_node const &expression, parse_location const &location) {
225 try {
226 return expression.evaluate(context);
227 } catch (error &e) {
228 e.merge_location(location);
229 throw;
230 }
231 }
232
233 static void post_process_expression(expression_post_process_context &context, expression_node &expression, parse_location const &location) {
234 try {
235 return expression.post_process(context);
236 } catch (error &e) {
237 e.merge_location(location);
238 throw;
239 }
240 }
241
242
243 [[nodiscard]] static datum evaluate_children(expression_evaluation_context &context, statement_vector const &children) {
244 for (ttlet &child: children) {
245 ttlet tmp = child->evaluate(context);
246 if (!tmp.is_undefined()) {
247 return tmp;
248 }
249 }
250 return {};
251 }
252};
253
254
255std::unique_ptr<template_node> parse_template(template_parse_context &context);
256
257inline std::unique_ptr<template_node> parse_template(URL url, std::string_view::const_iterator first, std::string_view::const_iterator last) {
258 auto context = template_parse_context(std::move(url), first, last);
259 auto e = parse_template(context);
260 return e;
261}
262
263inline std::unique_ptr<template_node> parse_template(URL url, std::string_view text) {
264 return parse_template(std::move(url), text.cbegin(), text.cend());
265}
266
267inline std::unique_ptr<template_node> parse_template(URL url) {
268 ttlet fv = url.loadView();
269 ttlet sv = fv->string_view();
270
271 return parse_template(std::move(url), sv.cbegin(), sv.cend());
272}
273
274
275
276}
STL namespace.
Definition exceptions.hpp:154
Definition expression.hpp:20
Definition expression.hpp:216
Definition expression.hpp:321
Definition parse_location.hpp:15
Definition template.hpp:15
expression_post_process_context post_process_context
Post process context is used to record functions that are defined in the template being parsed.
Definition template.hpp:30
bool pop() noexcept
Handle #end statement.
Definition template.hpp:135
virtual bool should_left_align() const noexcept
Should any spaces on the left side of a statement be removed?
Definition template.hpp:151
virtual bool append(std::unique_ptr< template_node > x) noexcept
Append a template-piece to the current template.
Definition template.hpp:147
virtual datum evaluate(expression_evaluation_context &context)
Evaluate the template.
Definition template.hpp:171
virtual void left_align() noexcept
Remove any trailing spaces or tabs after a new-line.
Definition template.hpp:155
Definition URL.hpp:45
T move(T... args)
T push_back(T... args)
T size(T... args)
T to_string(T... args)