HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
formula_evaluation_context.hpp
1// Copyright Take Vos 2020-2022.
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 "../utility/utility.hpp"
8#include "../codec/codec.hpp"
9#include "../macros.hpp"
10#include <unordered_map>
11#include <vector>
12#include <string_view>
13
14hi_export_module(hikogui.formula.formula_evaluation_context);
15
16namespace hi { inline namespace v1 {
17
20 using stack = std::vector<scope>;
21
22 ssize_t output_disable_count = 0;
23 std::string output;
24
25 stack local_stack;
26
27 struct loop_info {
28 datum count;
29 datum size;
30 datum first;
31 datum last;
32
33 loop_info(ssize_t count, ssize_t size) : count(), size(), first(), last()
34 {
35 if (count >= 0) {
36 this->count = count;
37 this->first = count == 0;
38 if (size >= 0) {
39 this->size = size;
40 this->last = count == (size - 1);
41 }
42 }
43 }
44 };
45 std::vector<loop_info> loop_stack;
46 scope globals;
47
49
52 void write(std::string_view text) noexcept
53 {
54 if (output_disable_count == 0) {
55 output += text;
56 }
57 }
58
63 {
64 return ssize(output);
65 }
66
71 {
72 hi_assert(new_size > 0);
73 hi_assert(new_size <= output_size());
74 output.resize(new_size);
75 }
76
77 void enable_output() noexcept
78 {
79 hi_assert(output_disable_count > 0);
80 output_disable_count--;
81 }
82
83 void disable_output() noexcept
84 {
85 output_disable_count++;
86 }
87
88 void loop_push(ssize_t count = -1, ssize_t size = -1) noexcept
89 {
90 loop_stack.emplace_back(count, size);
91 }
92
93 void loop_pop() noexcept
94 {
95 hi_assert(ssize(loop_stack) > 0);
96 loop_stack.pop_back();
97 }
98
99 void push()
100 {
101 local_stack.emplace_back();
102 loop_push();
103 }
104
105 void pop()
106 {
107 hi_assert(local_stack.size() > 0);
108 local_stack.pop_back();
109 loop_pop();
110 }
111
112 [[nodiscard]] bool has_locals() const noexcept
113 {
114 return local_stack.size() > 0;
115 }
116
117 scope const &locals() const
118 {
119 hi_assert(has_locals());
120 return local_stack.back();
121 }
122
123 scope &locals()
124 {
125 hi_assert(has_locals());
126 return local_stack.back();
127 }
128
129 [[nodiscard]] datum const &loop_get(std::string_view name) const
130 {
131 hi_assert(name.size() > 0);
132 if (name.back() == '$') {
133 throw operation_error(std::format("Invalid loop variable '{}'", name));
134 }
135
136 std::string_view short_name = name.substr(1);
137 auto i = loop_stack.crbegin();
138
139 while (short_name[0] == '$') {
140 if (i == loop_stack.crend() || holds_alternative<std::monostate>(i->count)) {
141 throw operation_error(std::format("Accessing loop variable {} while not in loop", name));
142 }
143
144 short_name = short_name.substr(1);
145 i++;
146 }
147
148 if (short_name == "i" || short_name == "count") {
149 return i->count;
150 } else if (short_name == "first") {
151 return i->first;
152 } else if (short_name == "size" || short_name == "length") {
154 throw operation_error(std::format("Accessing loop variable {} only available in #for loops", name));
155 }
156 return i->size;
157 } else if (short_name == "last") {
159 throw operation_error(std::format("Accessing loop variable {} only available in #for loops", name));
160 }
161 return i->last;
162 } else {
163 throw operation_error(std::format("Unknown loop variable {}", name));
164 }
165 }
166
167 [[nodiscard]] datum const &get(std::string const &name) const
168 {
169 hi_assert(name.size() > 0);
170
171 if (name[0] == '$') {
172 return loop_get(name);
173 }
174
175 if (has_locals()) {
176 hilet i = locals().find(name);
177 if (i != locals().end()) {
178 return i->second;
179 }
180 }
181
182 hilet j = globals.find(name);
183 if (j != globals.end()) {
184 return j->second;
185 }
186
187 throw operation_error(std::format("Could not find {} in local or global scope.", name));
188 }
189
190 [[nodiscard]] datum &get(std::string const &name)
191 {
192 hi_assert(name.size() > 0);
193
194 if (has_locals()) {
195 hilet i = locals().find(name);
196 if (i != locals().end()) {
197 return i->second;
198 }
199 }
200
201 hilet j = globals.find(name);
202 if (j != globals.end()) {
203 return j->second;
204 }
205
206 throw operation_error(std::format("Could not find {} in local or global scope.", name));
207 }
208
209 template<typename T>
210 void set_local(std::string const &name, T &&value)
211 {
212 locals()[name] = std::forward<T>(value);
213 }
214
215 template<typename T>
216 void set_global(std::string const &name, T &&value)
217 {
218 globals[name] = std::forward<T>(value);
219 }
220
221 datum &set(std::string const &name, datum const &value)
222 {
223 if (has_locals()) {
224 return locals()[name] = value;
225 } else {
226 return globals[name] = value;
227 }
228 }
229};
230
231}} // namespace hi::inline v1
@ end
Start from the end of the file.
@ write
Allow write access to a file.
STL namespace.
DOXYGEN BUG.
Definition algorithm.hpp:16
geometry/margins.hpp
Definition lookahead_iterator.hpp:5
std::ptrdiff_t ssize_t
Signed size/index into an array.
Definition misc.hpp:33
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
ssize_t output_size() const noexcept
Get the size of the output.
Definition formula_evaluation_context.hpp:62
void set_output_size(ssize_t new_size) noexcept
Set the size of the output.
Definition formula_evaluation_context.hpp:70
Definition formula_evaluation_context.hpp:27
T emplace_back(T... args)
T end(T... args)
T find(T... args)
T pop_back(T... args)
T crbegin(T... args)
T crend(T... args)
T size(T... args)