HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
formula_evaluation_context.hpp
1// Copyright Take Vos 2020.
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 "../required.hpp"
8#include "../datum.hpp"
9#include "../exception.hpp"
10#include <unordered_map>
11#include <vector>
12#include <string_view>
13
14namespace tt {
15
19
20 ssize_t output_disable_count = 0;
21 std::string output;
22
23 stack local_stack;
24
25 struct loop_info {
26 datum count;
27 datum size;
28 datum first;
29 datum last;
30
31 loop_info(ssize_t count, ssize_t size) :
32 count(), size(), first(), last()
33 {
34 if (count >= 0) {
35 this->count = count;
36 this->first = count == 0;
37 if (size >= 0) {
38 this->size = size;
39 this->last = count == (size - 1);
40 }
41 }
42 }
43 };
44 std::vector<loop_info> loop_stack;
45 scope globals;
46
48
51 void write(std::string_view text) noexcept {
52 if (output_disable_count == 0) {
53 output += text;
54 }
55 }
56
60 ssize_t output_size() const noexcept {
61 return std::ssize(output);
62 }
63
67 void set_output_size(ssize_t new_size) noexcept {
68 tt_assert(new_size > 0);
69 tt_assert(new_size <= output_size());
70 output.resize(new_size);
71 }
72
73 void enable_output() noexcept {
74 tt_assert(output_disable_count > 0);
75 output_disable_count--;
76 }
77
78 void disable_output() noexcept {
79 output_disable_count++;
80 }
81
82 void loop_push(ssize_t count = -1, ssize_t size = -1) noexcept {
83 loop_stack.emplace_back(count, size);
84 }
85
86 void loop_pop() noexcept {
87 tt_assert(std::ssize(loop_stack) > 0);
88 loop_stack.pop_back();
89 }
90
91 void push() {
92 local_stack.emplace_back();
93 loop_push();
94 }
95
96 void pop() {
97 tt_assert(local_stack.size() > 0);
98 local_stack.pop_back();
99 loop_pop();
100 }
101
102 [[nodiscard]] bool has_locals() const noexcept {
103 return local_stack.size() > 0;
104 }
105
106 scope const& locals() const {
107 tt_axiom(has_locals());
108 return local_stack.back();
109 }
110
111 scope& locals() {
112 tt_axiom(has_locals());
113 return local_stack.back();
114 }
115
116 [[nodiscard]] datum const &loop_get(std::string_view name) const {
117 tt_axiom(name.size() > 0);
118 if (name.back() == '$') {
119 throw operation_error("Invalid loop variable '{}'", name);
120 }
121
122 std::string_view short_name = name.substr(1);
123 auto i = loop_stack.crbegin();
124
125 while (short_name[0] == '$') {
126 if (i == loop_stack.crend() || i->count.is_undefined()) {
127 throw operation_error("Accessing loop variable {} while not in loop", name);
128 }
129
130 short_name = short_name.substr(1);
131 i++;
132 }
133
134 if (short_name == "i" || short_name == "count") {
135 return i->count;
136 } else if (short_name == "first") {
137 return i->first;
138 } else if (short_name == "size" || short_name == "length") {
139 if (i->size.is_undefined()) {
140 throw operation_error("Accessing loop variable {} only available in #for loops", name);
141 }
142 return i->size;
143 } else if (short_name == "last") {
144 if (i->last.is_undefined()) {
145 throw operation_error("Accessing loop variable {} only available in #for loops", name);
146 }
147 return i->last;
148 } else {
149 throw operation_error("Unknown loop variable {}", name);
150 }
151 }
152
153 [[nodiscard]] datum const& get(std::string const &name) const {
154 tt_assert(name.size() > 0);
155
156 if (name[0] == '$') {
157 return loop_get(name);
158 }
159
160 if (has_locals()) {
161 ttlet i = locals().find(name);
162 if (i != locals().end()) {
163 return i->second;
164 }
165 }
166
167 ttlet j = globals.find(name);
168 if (j != globals.end()) {
169 return j->second;
170 }
171
172 throw operation_error("Could not find {} in local or global scope.", name);
173 }
174
175 [[nodiscard]] datum &get(std::string const &name) {
176 tt_assert(name.size() > 0);
177
178 if (has_locals()) {
179 ttlet i = locals().find(name);
180 if (i != locals().end()) {
181 return i->second;
182 }
183 }
184
185 ttlet j = globals.find(name);
186 if (j != globals.end()) {
187 return j->second;
188 }
189
190 throw operation_error("Could not find {} in local or global scope.", name);
191 }
192
193 template<typename T>
194 void set_local(std::string const &name, T &&value) {
195 locals()[name] = std::forward<T>(value);
196 }
197
198 template<typename T>
199 void set_global(std::string const& name, T &&value) {
200 globals[name] = std::forward<T>(value);
201 }
202
203 datum &set(std::string const &name, datum const &value) {
204 if (has_locals()) {
205 return locals()[name] = value;
206 } else {
207 return globals[name] = value;
208 }
209 }
210};
211
212}
Definition formula_evaluation_context.hpp:16
void write(std::string_view text) noexcept
Write data to the output.
Definition formula_evaluation_context.hpp:51
void set_output_size(ssize_t new_size) noexcept
Set the size of the output.
Definition formula_evaluation_context.hpp:67
ssize_t output_size() const noexcept
Get the size of the output.
Definition formula_evaluation_context.hpp:60
Definition formula_evaluation_context.hpp:25
T back(T... args)
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)