HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
skeleton_parse_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 "skeleton_top_node.hpp"
8#include "skeleton_string_node.hpp"
9#include "skeleton_do_node.hpp"
10#include "../algorithm/module.hpp"
11#include "../formula/formula.hpp"
12#include "../macros.hpp"
13#include <memory>
14#include <string_view>
15#include <optional>
16#include <filesystem>
17
18namespace hi::inline v1 {
19
20[[nodiscard]] std::unique_ptr<skeleton_node> parse_skeleton(std::filesystem::path path);
21
24 using const_iterator = typename std::string_view::const_iterator;
25
26 statement_stack_type statement_stack;
27
28 parse_location location;
29 const_iterator index;
30 const_iterator last;
31
32 std::optional<const_iterator> text_segment_start;
33
37 formula_post_process_context post_process_context;
38
39 skeleton_parse_context() = delete;
41 skeleton_parse_context& operator=(skeleton_parse_context const& other) = delete;
43 skeleton_parse_context& operator=(skeleton_parse_context&& other) = delete;
44 ~skeleton_parse_context() = default;
45
46 inline skeleton_parse_context(std::filesystem::path const& path, const_iterator first, const_iterator last) :
47 location(path.string()), index(first), last(last)
48 {
49 push<skeleton_top_node>(location);
50 }
51
52 [[nodiscard]] constexpr char const& operator*() const noexcept
53 {
54 return *index;
55 }
56
57 [[nodiscard]] constexpr bool atEOF() const noexcept
58 {
59 return index == last;
60 }
61
62 constexpr skeleton_parse_context& operator++() noexcept
63 {
64 hi_assert(not atEOF());
65 location += *index;
66 ++index;
67 return *this;
68 }
69
70 constexpr skeleton_parse_context& operator+=(ssize_t x) noexcept
71 {
72 for (ssize_t i = 0; i != x; ++i) {
73 ++(*this);
74 }
75 return *this;
76 }
77
78 constexpr bool starts_with(std::string_view text) const noexcept
79 {
80 return std::string_view{index, last}.starts_with(text);
81 }
82
83 constexpr bool starts_with_and_advance_over(std::string_view text) noexcept
84 {
85 if (starts_with(text)) {
86 *this += ssize(text);
87 return true;
88 } else {
89 return false;
90 }
91 }
92
93 constexpr bool advance_to(std::string_view text) noexcept
94 {
95 while (!atEOF()) {
96 if (starts_with(text)) {
97 return true;
98 }
99 ++(*this);
100 }
101 return false;
102 }
103
104 constexpr bool advance_over(std::string_view text) noexcept
105 {
106 if (advance_to(text)) {
107 *this += ssize(text);
108 return true;
109 } else {
110 return false;
111 }
112 }
113
114 constexpr std::unique_ptr<formula_node> parse_expression(std::string_view end_text)
115 {
116 hilet formula_last = find_end_of_formula(index, last, end_text);
117
119
120 try {
121 expression = parse_formula_without_post_processing(std::string_view{index, formula_last});
122
123 } catch (std::exception const& e) {
124 throw parse_error(std::format("{}: Could not parse expression.\n{}", location, e.what()));
125 }
126
127 (*this) += std::distance(index, formula_last);
128 return expression;
129 }
130
131 constexpr std::unique_ptr<formula_node> parse_expression_and_advance_over(std::string_view end_text)
132 {
133 auto expression = parse_expression(end_text);
134
135 if (!starts_with_and_advance_over(end_text)) {
136 throw parse_error(std::format("{}: Could not find '{}' after expression", location, end_text));
137 }
138
139 return expression;
140 }
141
142 template<typename T, typename... Args>
143 constexpr void push(Args&&...args)
144 {
145 statement_stack.push_back(std::make_unique<T>(std::forward<Args>(args)...));
146 }
147
148 [[nodiscard]] constexpr bool append(std::unique_ptr<skeleton_node> x) noexcept
149 {
150 return statement_stack.back()->append(std::move(x));
151 }
152
153 template<typename T, typename... Args>
154 [[nodiscard]] constexpr bool append(Args&&...args) noexcept
155 {
156 if (statement_stack.size() > 0) {
157 return append(std::make_unique<T>(std::forward<Args>(args)...));
158 } else {
159 return false;
160 }
161 }
162
167 [[nodiscard]] constexpr bool pop() noexcept
168 {
169 if (statement_stack.size() > 0) {
170 auto tmp = std::move(statement_stack.back());
171 statement_stack.pop_back();
172 return statement_stack.back()->append(std::move(tmp));
173 } else {
174 return false;
175 }
176 }
177
178 constexpr void start_of_text_segment(int back_track = 0) noexcept
179 {
180 text_segment_start = index - back_track;
181 }
182
183 constexpr void end_of_text_segment()
184 {
185 if (text_segment_start) {
186 if (index > *text_segment_start) {
187 if (!append<skeleton_string_node>(location, std::string(*text_segment_start, index))) {
188 throw parse_error(std::format("{}: Unexpected text segment.", location));
189 }
190 }
191
192 text_segment_start = {};
193 }
194 }
195
196 [[nodiscard]] constexpr bool top_statement_is_do() const noexcept
197 {
198 if (statement_stack.size() < 1) {
199 return false;
200 }
201
202 auto const *const ptr = dynamic_cast<skeleton_do_node const *>(statement_stack.back().get());
203 return ptr != nullptr;
204 }
205
206 [[nodiscard]] constexpr bool found_elif(parse_location statement_location, std::unique_ptr<formula_node> expression) noexcept
207 {
208 if (statement_stack.size() > 0) {
209 return statement_stack.back()->found_elif(std::move(statement_location), std::move(expression));
210 } else {
211 return false;
212 }
213 }
214
215 [[nodiscard]] constexpr bool found_else(parse_location statement_location) noexcept
216 {
217 if (statement_stack.size() > 0) {
218 return statement_stack.back()->found_else(std::move(statement_location));
219 } else {
220 return false;
221 }
222 }
223
224 [[nodiscard]] constexpr bool found_while(parse_location statement_location, std::unique_ptr<formula_node> expression) noexcept
225 {
226 if (statement_stack.size() > 0) {
227 return statement_stack.back()->found_while(std::move(statement_location), std::move(expression));
228 } else {
229 return false;
230 }
231 }
232
233 inline void include(parse_location statement_location, formula_node& expression)
234 {
235 auto tmp_post_process_context = formula_post_process_context();
236 expression.post_process(tmp_post_process_context);
237
238 auto evaluation_context = formula_evaluation_context();
239 hilet argument = expression.evaluate(evaluation_context);
240
241 auto new_skeleton_path = std::filesystem::current_path();
242 if (statement_location.has_file()) {
243 // Include relative to the file that is currently parsed.
244 new_skeleton_path = statement_location.file();
245 new_skeleton_path.remove_filename();
246 }
247 new_skeleton_path /= static_cast<std::string>(argument);
248
249 if (ssize(statement_stack) > 0) {
250 if (!statement_stack.back()->append(parse_skeleton(new_skeleton_path))) {
251 throw parse_error(std::format("{}: Unexpected #include statement.", statement_location));
252 }
253 } else {
254 throw parse_error(std::format("{}: Unexpected #include statement, missing top-level", statement_location));
255 }
256 }
257};
258
259} // namespace hi::inline v1
DOXYGEN BUG.
Definition algorithm.hpp:16
constexpr std::string_view::const_iterator find_end_of_formula(std::string_view::const_iterator first, std::string_view::const_iterator last, std::string_view terminating_string) noexcept
Find the end of an formula.
Definition formula_parser.hpp:476
std::unique_ptr< formula_node > parse_formula_without_post_processing(std::string_view text)
Parse an formula.
Definition formula_parser.hpp:453
constexpr Out narrow_cast(In const &rhs) noexcept
Cast numeric values without loss of precision.
Definition cast.hpp:377
Definition parse_location.hpp:18
Definition skeleton_parse_context.hpp:22
formula_post_process_context post_process_context
Post process context is used to record functions that are defined in the template being parsed.
Definition skeleton_parse_context.hpp:37
constexpr bool pop() noexcept
Handle #end statement.
Definition skeleton_parse_context.hpp:167
T back(T... args)
T distance(T... args)
T get(T... args)
T move(T... args)
T pop_back(T... args)
T push_back(T... args)
T size(T... args)
T what(T... args)