asar coverage - build #259


src/asar/
File: src/asar/math_ast.h
Date: 2025-02-26 19:38:12
Lines:
170/215
79.1%
Functions:
49/50
98.0%
Branches:
183/319
57.4%

Line Branch Exec Source
1 #include <memory>
2 #include <variant>
3 #include <vector>
4 #include "libstr.h"
5 #include "asar.h" // todo assembleblock.h sux
6 #include "assembleblock.h"
7 #include "errors.h"
8 using std::unique_ptr;
9
10 enum class math_val_type {
11 floating,
12 integer,
13 string,
14 // a resolved label with a name and value. used for datasize() and whatnot
15 identifier,
16 };
17
18 inline int64_t float_to_int(double f) {
19 // TODO: throw error on overflow?
20 return (int64_t)f;
21 }
22
23
38/82
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 525 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 9 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 18 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 9 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 9 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 9 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 6 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 6 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 24 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 24 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 24 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 6 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 6 times.
✗ Branch 35 not taken.
✓ Branch 36 taken 9 times.
✗ Branch 37 not taken.
✓ Branch 38 taken 9 times.
✗ Branch 39 not taken.
✓ Branch 40 taken 6 times.
✗ Branch 41 not taken.
✓ Branch 42 taken 6 times.
✗ Branch 43 not taken.
✓ Branch 44 taken 3 times.
✗ Branch 45 not taken.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✓ Branch 48 taken 3 times.
✗ Branch 49 not taken.
✓ Branch 50 taken 12 times.
✗ Branch 51 not taken.
✓ Branch 52 taken 9 times.
✗ Branch 53 not taken.
✓ Branch 54 taken 9 times.
✗ Branch 55 not taken.
✓ Branch 56 taken 9 times.
✗ Branch 57 not taken.
✓ Branch 58 taken 9 times.
✗ Branch 59 not taken.
✓ Branch 60 taken 9 times.
✗ Branch 61 not taken.
✓ Branch 62 taken 9 times.
✗ Branch 63 not taken.
✓ Branch 64 taken 9 times.
✗ Branch 65 not taken.
✓ Branch 66 taken 6 times.
✗ Branch 67 not taken.
✓ Branch 68 taken 6 times.
✗ Branch 69 not taken.
✓ Branch 70 taken 6 times.
✗ Branch 71 not taken.
✓ Branch 72 taken 6 times.
✗ Branch 73 not taken.
✓ Branch 74 taken 6 times.
✗ Branch 75 not taken.
✓ Branch 76 taken 6 times.
✗ Branch 77 not taken.
✓ Branch 78 taken 3 times.
✗ Branch 79 not taken.
✓ Branch 80 taken 7461 times.
✗ Branch 81 not taken.
73632 class math_val {
24 public:
25 math_val_type m_type;
26 union {
27 double double_;
28 int64_t int_;
29 } m_numeric_val;
30 // slightly hacky but this is used for both labelname in case of
31 // m_type=identifier, and string value in case of m_type=string
32 string m_string_val;
33
34 math_val() {
35 m_type = math_val_type::integer;
36 m_numeric_val.int_ = 0;
37 }
38
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
318 math_val(double v) {
39 384 m_type = math_val_type::floating;
40 198 m_numeric_val.double_ = v;
41 252 }
42
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23415 times.
✗ Branch 3 not taken.
55671 math_val(int64_t v) {
43 64353 m_type = math_val_type::integer;
44 32274 m_numeric_val.int_ = v;
45 40449 }
46
1/2
✓ Branch 0 taken 1707 times.
✗ Branch 1 not taken.
3418 math_val(string v) {
47
1/2
✓ Branch 0 taken 1707 times.
✗ Branch 1 not taken.
3418 m_type = math_val_type::string;
48
1/2
✓ Branch 0 taken 1711 times.
✗ Branch 1 not taken.
1711 m_string_val = v;
49
4/8
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 525 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 936 times.
✗ Branch 7 not taken.
5125 }
50
51 // TODO: make all these conversions print the current type aswell instead of just expected type
52 35466 double get_double() const {
53
3/5
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 33597 times.
✓ Branch 2 taken 1485 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
35466 switch(m_type) {
54 384 case math_val_type::floating:
55 384 return m_numeric_val.double_;
56 33597 case math_val_type::integer:
57 33597 return (double)m_numeric_val.int_;
58 1485 case math_val_type::identifier:
59 1485 return (double)get_integer();
60 case math_val_type::string:
61 asar_throw_error(2, error_type_block, error_id_expected_number);
62 }
63 }
64
65 32463 int64_t get_integer() const {
66
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 30695 times.
✓ Branch 2 taken 1768 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
32463 switch(m_type) {
67 case math_val_type::floating:
68 return float_to_int(m_numeric_val.double_);
69 30695 case math_val_type::integer:
70 30695 return m_numeric_val.int_;
71 1768 case math_val_type::identifier:
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1768 times.
1768 if(!labels.exists(m_string_val))
73 // i'm not sure if it's even possible to reach here, anything
74 // that constructs identifiers should already check for existence...
75 asar_throw_error(2, error_type_block, error_id_label_not_found, m_string_val.data());
76 1768 return labels.find(m_string_val).pos;
77 case math_val_type::string:
78 asar_throw_error(2, error_type_block, error_id_expected_number);
79 }
80 }
81 432 const string& get_str() const {
82
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
432 if(m_type == math_val_type::string) return m_string_val;
83 asar_throw_error(2, error_type_block, error_id_expected_string);
84 }
85 1218 const string& get_identifier() const {
86
1/2
✓ Branch 0 taken 1218 times.
✗ Branch 1 not taken.
1218 if(m_type == math_val_type::identifier) return m_string_val;
87 asar_throw_error(2, error_type_block, error_id_expected_ident);
88 }
89
90 444 bool get_bool() const {
91
2/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 432 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
444 switch(m_type) {
92 12 case math_val_type::floating:
93 12 return get_double() != 0.0;
94 432 case math_val_type::integer:
95 case math_val_type::identifier:
96 432 return get_integer() != 0;
97 case math_val_type::string:
98 return get_str().length() != 0;
99 }
100 }
101 };
102
103 // any info that's necessary during evaluation
104 17469 class math_eval_context {
105 public:
106 // TODO would it be faster to make this a reference? does that avoid any significant copies?
107 std::vector<math_val> userfunc_params;
108 };
109
110 class math_ast_node {
111 public:
112 virtual math_val evaluate(const math_eval_context&) const = 0;
113 // 0 - no label, 1 - static label, 3 - nonstatic label.
114 // (maybe tracking forwardlabel too would be good?)
115 virtual int has_label() const = 0;
116 68576 virtual ~math_ast_node() = default;
117 };
118
119 enum class math_binop_type {
120 pow, // **
121 mul, // *
122 div, // /
123 mod, // %
124 add, // +
125 sub, // -
126 shift_left, // <<
127 shift_right, // >>
128 bit_and, // &
129 bit_or, // |
130 bit_xor, // ^
131 logical_and, // &&
132 logical_or, // ||
133 comp_ge, // >=
134 comp_le, // <=
135 comp_gt, // >
136 comp_lt, // <
137 comp_eq, // ==
138 comp_ne, // !=
139 };
140
141 template<typename T>
142 15654 T evaluate_binop_arithmetic(T lhs, T rhs, math_binop_type type) {
143
3/4
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 6051 times.
✓ Branch 2 taken 1578 times.
✗ Branch 3 not taken.
15654 switch(type) {
144 396 case math_binop_type::mul: return lhs * rhs;
145 12102 case math_binop_type::add: return lhs + rhs;
146 3156 case math_binop_type::sub: return lhs - rhs;
147 default:
148 // this should never happen
149 __builtin_trap();
150 }
151 }
152 template<typename T>
153 14388 bool evaluate_binop_compare(T lhs, T rhs, math_binop_type type) {
154
6/7
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 462 times.
✓ Branch 3 taken 5448 times.
✓ Branch 4 taken 1146 times.
✓ Branch 5 taken 66 times.
✗ Branch 6 not taken.
14388 switch(type) {
155 72 case math_binop_type::comp_ge: return lhs >= rhs;
156 72 case math_binop_type::comp_le: return lhs <= rhs;
157 924 case math_binop_type::comp_gt: return lhs > rhs;
158 10896 case math_binop_type::comp_lt: return lhs < rhs;
159 2292 case math_binop_type::comp_eq: return lhs == rhs;
160 132 case math_binop_type::comp_ne: return lhs != rhs;
161 default:
162 // this should never happen
163 __builtin_trap();
164 }
165 }
166
167 15087 static math_val evaluate_binop(math_val lhs, math_val rhs, math_binop_type type) {
168 // todo: do this a bit smarter (bit_ops shouldn't cast int->float->int)
169
3/4
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 15027 times.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
15117 if(lhs.m_type == math_val_type::floating) rhs = math_val(rhs.get_double());
170
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14991 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
15045 else if(rhs.m_type == math_val_type::floating) lhs = math_val(lhs.get_double());
171
4/12
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 7827 times.
✓ Branch 10 taken 7194 times.
✗ Branch 11 not taken.
15087 switch(type) {
172 36 case math_binop_type::pow: return math_val(pow(lhs.get_double(), rhs.get_double()));
173 30 case math_binop_type::div:
174
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
30 if(rhs.get_double() == 0.0)
175 6 asar_throw_error(2, error_type_block, error_id_division_by_zero);
176 24 return math_val(lhs.get_double() / rhs.get_double());
177 case math_binop_type::mod:
178 if(rhs.get_double() == 0.0)
179 asar_throw_error(2, error_type_block, error_id_division_by_zero);
180 // TODO: negative semantics
181 if(lhs.m_type == math_val_type::floating) {
182 return math_val(fmod(lhs.get_double(), rhs.get_double()));
183 } else {
184 return math_val(lhs.get_integer() % rhs.get_integer());
185 }
186 break;
187
188 case math_binop_type::shift_left:
189 {
190 int64_t rhs_v = rhs.get_integer();
191 if(rhs_v < 0)
192 asar_throw_error(2, error_type_block, error_id_negative_shift);
193 return math_val(lhs.get_integer() << (uint64_t)rhs_v);
194 }
195 case math_binop_type::shift_right:
196 {
197 int64_t rhs_v = rhs.get_integer();
198 if(rhs_v < 0)
199 asar_throw_error(2, error_type_block, error_id_negative_shift);
200 return math_val(lhs.get_integer() >> (uint64_t)rhs_v);
201 }
202
203 case math_binop_type::bit_and: return math_val(lhs.get_integer() & rhs.get_integer());
204 case math_binop_type::bit_or: return math_val(lhs.get_integer() | rhs.get_integer());
205 case math_binop_type::bit_xor: return math_val(lhs.get_integer() ^ rhs.get_integer());
206
207 case math_binop_type::logical_and:
208 case math_binop_type::logical_or:
209 asar_throw_error(2, error_type_block, error_id_internal_error, "evaluate_binop() on logical ops loses short-circuiting");
210
211 7827 case math_binop_type::mul:
212 case math_binop_type::add:
213 case math_binop_type::sub:
214 // TODO error on string (also TODO support string +)
215
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 7785 times.
7827 if(lhs.m_type == math_val_type::floating)
216 42 return math_val(evaluate_binop_arithmetic<double>(lhs.get_double(), rhs.get_double(), type));
217 else
218 7785 return math_val(evaluate_binop_arithmetic<int64_t>(lhs.get_integer(), rhs.get_integer(), type));
219
220 7194 case math_binop_type::comp_ge:
221 case math_binop_type::comp_le:
222 case math_binop_type::comp_gt:
223 case math_binop_type::comp_lt:
224 case math_binop_type::comp_eq:
225 case math_binop_type::comp_ne:
226
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 7140 times.
7194 if(lhs.m_type == math_val_type::floating)
227 54 return math_val((int64_t)evaluate_binop_compare<double>(lhs.get_double(), rhs.get_double(), type));
228 else
229 7140 return math_val((int64_t)evaluate_binop_compare<int64_t>(lhs.get_integer(), rhs.get_integer(), type));
230 }
231 }
232
233 class math_ast_binop : public math_ast_node {
234 public:
235 unique_ptr<math_ast_node> m_left, m_right;
236 math_binop_type m_type;
237 7513 math_ast_binop(std::unique_ptr<math_ast_node> left_in, std::unique_ptr<math_ast_node> right_in, math_binop_type type_in)
238 15022 : m_left(std::move(left_in)), m_right(std::move(right_in)), m_type(type_in) {}
239
240
241 14980 math_val evaluate(const math_eval_context& ctx) const {
242
1/2
✓ Branch 0 taken 7492 times.
✗ Branch 1 not taken.
14980 math_val lhs = m_left->evaluate(ctx);
243
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 14962 times.
14980 if(m_type == math_binop_type::logical_or) {
244
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 if(lhs.get_bool() == true) return math_val((int64_t)true);
245
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 math_val rhs = m_right->evaluate(ctx);
246
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return math_val((int64_t)rhs.get_bool());
247 9 }
248
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14926 times.
14962 if(m_type == math_binop_type::logical_and) {
249
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
36 if(lhs.get_bool() == false) return math_val((int64_t)false);
250
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 math_val rhs = m_right->evaluate(ctx);
251
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 return math_val((int64_t)rhs.get_bool());
252 18 }
253
2/2
✓ Branch 0 taken 14925 times.
✓ Branch 1 taken 1 times.
14926 math_val rhs = m_right->evaluate(ctx);
254
5/6
✓ Branch 0 taken 14925 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14922 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 7461 times.
✓ Branch 5 taken 3 times.
29856 return evaluate_binop(lhs, rhs, m_type);
255 7495 }
256
257 14980 int has_label() const {
258 14980 return m_left->has_label() | m_right->has_label();
259 }
260 };
261
262 enum class math_unop_type {
263 neg,
264 bit_not,
265 bank_extract,
266 };
267
268 class math_ast_unop : public math_ast_node {
269 public:
270 unique_ptr<math_ast_node> m_arg;
271 math_unop_type m_type;
272 48 math_ast_unop(std::unique_ptr<math_ast_node> arg_in, math_unop_type type_in)
273 96 : m_arg(std::move(arg_in)), m_type(type_in) {}
274 84 math_val evaluate(const math_eval_context& ctx) const {
275
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 math_val arg = m_arg->evaluate(ctx);
276
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
84 switch(m_type) {
277 72 case math_unop_type::neg:
278
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
72 if(arg.m_type == math_val_type::floating) return math_val(-arg.get_double());
279
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 else return math_val(-arg.get_integer());
280 case math_unop_type::bit_not: return math_val(~arg.get_integer());
281
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 case math_unop_type::bank_extract: return math_val(arg.get_integer() >> 16);
282 }
283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 }
284 84 int has_label() const {
285 84 return m_arg->has_label();
286 }
287 };
288
289 class math_ast_literal : public math_ast_node {
290 math_val m_value;
291 public:
292
5/10
✓ Branch 0 taken 24594 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 525 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 23415 times.
✗ Branch 9 not taken.
72870 math_ast_literal(math_val value) : m_value(value) {}
293 48558 math_val evaluate(const math_eval_context& ctx) const { return m_value; }
294 48558 int has_label() const { return 0; }
295 };
296
297 class math_ast_label : public math_ast_node {
298 string m_labelname;
299 // current namespace when this label was referenced
300 string m_cur_ns;
301 public:
302 // this should be the output of labelname() already
303 1944 math_ast_label(string labelname)
304 2919 : m_labelname(labelname)
305 // this is initialized with the global ns
306
2/4
✓ Branch 0 taken 1944 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1944 times.
✗ Branch 3 not taken.
2913 , m_cur_ns(ns) {}
307
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 930 times.
1944 math_val evaluate(const math_eval_context& ctx) const {
308
11/14
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1866 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 939 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 39 times.
✓ Branch 9 taken 936 times.
✓ Branch 10 taken 30 times.
✓ Branch 11 taken 945 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1944 if(m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
309
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
90 math_val v = math_val(m_cur_ns + m_labelname);
310 60 v.m_type = math_val_type::identifier;
311 30 return v;
312 30 }
313
2/2
✓ Branch 0 taken 1876 times.
✓ Branch 1 taken 8 times.
1884 else if(labels.exists(m_labelname)) {
314
2/4
✓ Branch 0 taken 940 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 940 times.
✗ Branch 3 not taken.
2812 math_val v = math_val(m_labelname);
315 1876 v.m_type = math_val_type::identifier;
316 940 return v;
317 940 }
318 else {
319 // i think in this context we always should throw???
320 8 asar_throw_error(2, error_type_block, error_id_label_not_found, m_labelname.data());
321 }
322 }
323
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 930 times.
1944 int has_label() const {
324
11/14
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1866 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 939 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 39 times.
✓ Branch 9 taken 936 times.
✓ Branch 10 taken 30 times.
✓ Branch 11 taken 945 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1944 if(m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
325
3/6
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
90 return labels.find(m_cur_ns + m_labelname).is_static ? 1 : 3;
326 }
327
2/2
✓ Branch 0 taken 1876 times.
✓ Branch 1 taken 8 times.
1884 else if(labels.exists(m_labelname)) {
328
2/2
✓ Branch 0 taken 937 times.
✓ Branch 1 taken 939 times.
1876 return labels.find(m_labelname).is_static ? 1 : 3;
329 }
330 // otherwise, non-static label
331 5 return 3;
332 }
333 };
334
335 class math_builtin_function {
336 using callable_t = math_val(*)(const std::vector<math_val>& args);
337 callable_t inner;
338 int m_has_label;
339 public:
340 8580 math_builtin_function(callable_t c, int l = 0) : inner(c), m_has_label(l) {}
341 2514 math_val call(const std::vector<math_val>& args) const {
342 2514 return inner(args);
343 }
344 1257 int has_label() const {
345 2514 return m_has_label;
346 }
347 };
348
349 54 class math_user_function {
350 int m_arg_count;
351 unique_ptr<math_ast_node> m_func_body;
352 public:
353 54 math_user_function(std::unique_ptr<math_ast_node> body, size_t arg_count)
354 108 : m_arg_count(arg_count), m_func_body(std::move(body)) {}
355
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
66 math_val call(const std::vector<math_val>& args) const {
356 33 math_eval_context new_ctx;
357
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 new_ctx.userfunc_params = args;
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if(args.size() != m_arg_count)
359 asar_throw_error(2, error_type_block, error_id_argument_count, m_arg_count, (int)args.size());
360
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
132 return m_func_body->evaluate(new_ctx);
361 33 }
362 66 int has_label() const {
363 66 return m_func_body->has_label();
364 }
365 };
366
367 class math_function_ref {
368 std::variant<const math_builtin_function*, const math_user_function*> inner;
369 public:
370 2520 math_function_ref(const math_builtin_function& fn) : inner(&fn) {}
371 66 math_function_ref(const math_user_function& fn) : inner(&fn) {}
372 2580 math_val call(const std::vector<math_val>& args) const {
373
2/2
✓ Branch 0 taken 1281 times.
✓ Branch 1 taken 9 times.
9021 return std::visit([&](auto& i) { return i->call(args); }, inner);
374 }
375 2580 int has_label() const {
376
1/2
✓ Branch 0 taken 1290 times.
✗ Branch 1 not taken.
6450 return std::visit([&](auto& i) { return i->has_label(); }, inner);
377 }
378 };
379
380 extern std::unordered_map<string, math_user_function> user_functions;
381 extern const std::unordered_map<string, math_builtin_function> builtin_functions;
382
383 class math_ast_function_call : public math_ast_node {
384 std::vector<unique_ptr<math_ast_node>> m_arguments;
385 math_function_ref m_func;
386 2586 static math_function_ref lookup_fname(string const& function_name) {
387
4/4
✓ Branch 0 taken 1326 times.
✓ Branch 1 taken 1260 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 1260 times.
2586 if(auto it = user_functions.find(function_name); it != user_functions.end()) {
388 66 return it->second;
389
2/4
✓ Branch 0 taken 2520 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1260 times.
✗ Branch 3 not taken.
2520 } else if(auto it = builtin_functions.find(function_name); it != builtin_functions.end()) {
390 2520 return it->second;
391 } else {
392 asar_throw_error(2, error_type_block, error_id_function_not_found, function_name.data());
393 }
394 }
395
396 public:
397 2586 math_ast_function_call(std::vector<std::unique_ptr<math_ast_node>> args, string function_name)
398 2586 : m_arguments(std::move(args))
399
3/6
✓ Branch 0 taken 1344 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1242 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1293 times.
✗ Branch 5 not taken.
5172 , m_func(lookup_fname(function_name)) {}
400 2580 math_val evaluate(const math_eval_context& ctx) const {
401 1290 std::vector<math_val> arg_vals;
402
2/2
✓ Branch 0 taken 3132 times.
✓ Branch 1 taken 2580 times.
5712 for(auto const& p : m_arguments) {
403
2/4
✓ Branch 0 taken 3132 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1566 times.
✗ Branch 3 not taken.
4698 arg_vals.push_back(p->evaluate(ctx));
404 }
405
2/2
✓ Branch 0 taken 2562 times.
✓ Branch 1 taken 18 times.
5142 return m_func.call(arg_vals);
406 2580 }
407 2580 int has_label() const {
408 2580 int out = m_func.has_label();
409
2/2
✓ Branch 0 taken 3132 times.
✓ Branch 1 taken 2580 times.
5712 for(auto const& p : m_arguments) {
410
1/2
✓ Branch 0 taken 1566 times.
✗ Branch 1 not taken.
3132 out |= p->has_label();
411 }
412 2580 return out;
413 }
414 };
415
416 // only for use inside user function definitions
417 class math_ast_function_argument : public math_ast_node {
418 size_t m_arg_idx;
419 public:
420 162 math_ast_function_argument(size_t arg_idx) : m_arg_idx(arg_idx) {}
421
422 102 math_val evaluate(const math_eval_context& ctx) const {
423 102 return ctx.userfunc_params[m_arg_idx];
424 }
425
426 // if a function is called with a label as an argument, that gets checked by
427 // the function call node, not here
428 102 int has_label() const { return 0; }
429 };
430
431