asar coverage - build #262


src/asar/
File: src/asar/math_ast.h
Date: 2025-02-27 19:01:43
Lines:
218/253
86.2%
Functions:
55/56
98.2%
Branches:
239/380
62.9%

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 45 inline int64_t float_to_int(double f) {
19 // TODO: throw error on overflow?
20 90 return (int64_t)f;
21 }
22
23
35/75
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 525 times.
✓ Branch 5 taken 27 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 18 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 7718 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 15 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 9 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 9 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 9 times.
✗ Branch 20 not taken.
✓ Branch 21 taken 9 times.
✗ Branch 22 not taken.
✓ Branch 23 taken 6 times.
✗ Branch 24 not taken.
✓ Branch 25 taken 6 times.
✗ Branch 26 not taken.
✓ Branch 27 taken 24 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 24 times.
✗ Branch 30 not taken.
✓ Branch 31 taken 24 times.
✗ Branch 32 not taken.
✓ Branch 33 taken 6 times.
✗ Branch 34 not taken.
✓ Branch 35 taken 6 times.
✗ Branch 36 not taken.
✓ Branch 37 taken 9 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 9 times.
✗ Branch 40 not taken.
✓ Branch 41 taken 6 times.
✗ Branch 42 not taken.
✓ Branch 43 taken 6 times.
✗ Branch 44 not taken.
✓ Branch 45 taken 3 times.
✗ Branch 46 not taken.
✗ Branch 47 not taken.
✗ Branch 48 not taken.
✓ Branch 49 taken 3 times.
✗ Branch 50 not taken.
✓ Branch 51 taken 12 times.
✗ Branch 52 not taken.
✓ Branch 53 taken 9 times.
✗ Branch 54 not taken.
✓ Branch 55 taken 9 times.
✗ Branch 56 not taken.
✓ Branch 57 taken 9 times.
✗ Branch 58 not taken.
✓ Branch 59 taken 15 times.
✗ Branch 60 not taken.
✓ Branch 61 taken 15 times.
✗ Branch 62 not taken.
✓ Branch 63 taken 15 times.
✗ Branch 64 not taken.
✓ Branch 65 taken 15 times.
✗ Branch 66 not taken.
✓ Branch 67 taken 15 times.
✗ Branch 68 not taken.
✓ Branch 69 taken 15 times.
✗ Branch 70 not taken.
✓ Branch 71 taken 3 times.
✗ Branch 72 not taken.
✗ Branch 73 not taken.
✗ Branch 74 not taken.
80826 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 198 times.
✗ Branch 1 not taken.
762 math_val(double v) {
39 906 m_type = math_val_type::floating;
40 870 m_numeric_val.double_ = v;
41 549 }
42
3/6
✓ Branch 0 taken 339 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27397 times.
✗ Branch 5 not taken.
64750 math_val(int64_t v) {
43 73815 m_type = math_val_type::integer;
44 37023 m_numeric_val.int_ = v;
45 45560 }
46
1/2
✓ Branch 0 taken 1782 times.
✗ Branch 1 not taken.
3568 math_val(string v) {
47
1/2
✓ Branch 0 taken 1782 times.
✗ Branch 1 not taken.
3568 m_type = math_val_type::string;
48
1/2
✓ Branch 0 taken 1786 times.
✗ Branch 1 not taken.
1786 m_string_val = v;
49
4/8
✓ Branch 0 taken 270 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 957 times.
✗ Branch 7 not taken.
5350 }
50
51 // TODO: make all these conversions print the current type aswell instead of just expected type
52 36676 double get_double() const {
53
3/5
✓ Branch 0 taken 906 times.
✓ Branch 1 taken 34273 times.
✓ Branch 2 taken 1497 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
36676 switch(m_type) {
54 906 case math_val_type::floating:
55 906 return m_numeric_val.double_;
56 34273 case math_val_type::integer:
57 34273 return (double)m_numeric_val.int_;
58 1497 case math_val_type::identifier:
59 1497 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 33683 int64_t get_integer() const {
66
2/5
✗ Branch 0 not taken.
✓ Branch 1 taken 31873 times.
✓ Branch 2 taken 1810 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
33683 switch(m_type) {
67 case math_val_type::floating:
68 return float_to_int(m_numeric_val.double_);
69 31873 case math_val_type::integer:
70 31873 return m_numeric_val.int_;
71 1810 case math_val_type::identifier:
72
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1810 times.
1810 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 1810 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 540 const string& get_str() const {
82
1/2
✓ Branch 0 taken 540 times.
✗ Branch 1 not taken.
540 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 480 bool get_bool() const {
91
2/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 468 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
480 switch(m_type) {
92 12 case math_val_type::floating:
93 12 return get_double() != 0.0;
94 468 case math_val_type::integer:
95 case math_val_type::identifier:
96 468 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 17849 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 // how many bytes long should the result of this expression be?
117 virtual int get_len(bool could_be_bank_ex) const = 0;
118 81764 virtual ~math_ast_node() = default;
119 };
120
121 using owned_node = unique_ptr<math_ast_node>;
122
123 enum class math_binop_type {
124 pow, // **
125 mul, // *
126 div, // /
127 mod, // %
128 add, // +
129 sub, // -
130 shift_left, // <<
131 shift_right, // >>
132 bit_and, // &
133 bit_or, // |
134 bit_xor, // ^
135 logical_and, // &&
136 logical_or, // ||
137 comp_ge, // >=
138 comp_le, // <=
139 comp_gt, // >
140 comp_lt, // <
141 comp_eq, // ==
142 comp_ne, // !=
143 };
144
145 template<typename T>
146 15734 T evaluate_binop_arithmetic(T lhs, T rhs, math_binop_type type) {
147
3/4
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 6091 times.
✓ Branch 2 taken 1578 times.
✗ Branch 3 not taken.
15734 switch(type) {
148 396 case math_binop_type::mul: return lhs * rhs;
149 12182 case math_binop_type::add: return lhs + rhs;
150 3156 case math_binop_type::sub: return lhs - rhs;
151 default:
152 asar_throw_error(2, error_type_block, error_id_internal_error, "evaluate_binop_arithmetic with bad type");
153 }
154 }
155 template<typename T>
156 15180 bool evaluate_binop_compare(T lhs, T rhs, math_binop_type type) {
157
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 1488 times.
✓ Branch 5 taken 120 times.
✗ Branch 6 not taken.
15180 switch(type) {
158 72 case math_binop_type::comp_ge: return lhs >= rhs;
159 72 case math_binop_type::comp_le: return lhs <= rhs;
160 924 case math_binop_type::comp_gt: return lhs > rhs;
161 10896 case math_binop_type::comp_lt: return lhs < rhs;
162 2976 case math_binop_type::comp_eq: return lhs == rhs;
163 240 case math_binop_type::comp_ne: return lhs != rhs;
164 default:
165 asar_throw_error(2, error_type_block, error_id_internal_error, "evaluate_binop_compare with bad type");
166 }
167 }
168
169 15601 static math_val evaluate_binop(math_val lhs, math_val rhs, math_binop_type type) {
170 // todo: do this a bit smarter (bit_ops shouldn't cast int->float->int)
171
3/4
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 15415 times.
✓ Branch 2 taken 93 times.
✗ Branch 3 not taken.
15694 if(lhs.m_type == math_val_type::floating) rhs = math_val(rhs.get_double());
172
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 15379 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
15433 else if(rhs.m_type == math_val_type::floating) lhs = math_val(lhs.get_double());
173
7/12
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 7867 times.
✓ Branch 10 taken 7590 times.
✗ Branch 11 not taken.
15601 switch(type) {
174 36 case math_binop_type::pow: return math_val(pow(lhs.get_double(), rhs.get_double()));
175 48 case math_binop_type::div:
176
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 36 times.
48 if(rhs.get_double() == 0.0)
177 12 asar_throw_error(2, error_type_block, error_id_division_by_zero);
178 36 return math_val(lhs.get_double() / rhs.get_double());
179 case math_binop_type::mod:
180 if(rhs.get_double() == 0.0)
181 asar_throw_error(2, error_type_block, error_id_division_by_zero);
182 // TODO: negative semantics
183 if(lhs.m_type == math_val_type::floating) {
184 return math_val(fmod(lhs.get_double(), rhs.get_double()));
185 } else {
186 return math_val(lhs.get_integer() % rhs.get_integer());
187 }
188 break;
189
190 18 case math_binop_type::shift_left:
191 {
192 18 int64_t rhs_v = rhs.get_integer();
193
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if(rhs_v < 0)
194 18 asar_throw_error(2, error_type_block, error_id_negative_shift);
195 return math_val(lhs.get_integer() << (uint64_t)rhs_v);
196 }
197 36 case math_binop_type::shift_right:
198 {
199 36 int64_t rhs_v = rhs.get_integer();
200
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
36 if(rhs_v < 0)
201 18 asar_throw_error(2, error_type_block, error_id_negative_shift);
202 18 return math_val(lhs.get_integer() >> (uint64_t)rhs_v);
203 }
204
205 case math_binop_type::bit_and: return math_val(lhs.get_integer() & rhs.get_integer());
206 6 case math_binop_type::bit_or: return math_val(lhs.get_integer() | rhs.get_integer());
207 case math_binop_type::bit_xor: return math_val(lhs.get_integer() ^ rhs.get_integer());
208
209 case math_binop_type::logical_and:
210 case math_binop_type::logical_or:
211 asar_throw_error(2, error_type_block, error_id_internal_error, "evaluate_binop() on logical ops loses short-circuiting");
212
213 7867 case math_binop_type::mul:
214 case math_binop_type::add:
215 case math_binop_type::sub:
216 // TODO error on string (also TODO support string +)
217
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 7789 times.
7867 if(lhs.m_type == math_val_type::floating)
218 78 return math_val(evaluate_binop_arithmetic<double>(lhs.get_double(), rhs.get_double(), type));
219 else
220 7789 return math_val(evaluate_binop_arithmetic<int64_t>(lhs.get_integer(), rhs.get_integer(), type));
221
222 7590 case math_binop_type::comp_ge:
223 case math_binop_type::comp_le:
224 case math_binop_type::comp_gt:
225 case math_binop_type::comp_lt:
226 case math_binop_type::comp_eq:
227 case math_binop_type::comp_ne:
228
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 7446 times.
7590 if(lhs.m_type == math_val_type::floating)
229 144 return math_val((int64_t)evaluate_binop_compare<double>(lhs.get_double(), rhs.get_double(), type));
230 else
231 7446 return math_val((int64_t)evaluate_binop_compare<int64_t>(lhs.get_integer(), rhs.get_integer(), type));
232 }
233 }
234
235 class math_ast_binop : public math_ast_node {
236 public:
237 owned_node m_left, m_right;
238 math_binop_type m_type;
239 7932 math_ast_binop(owned_node left_in, owned_node right_in, math_binop_type type_in)
240 15860 : m_left(std::move(left_in)), m_right(std::move(right_in)), m_type(type_in) {}
241
242
243 15530 math_val evaluate(const math_eval_context& ctx) const {
244
1/2
✓ Branch 0 taken 7767 times.
✗ Branch 1 not taken.
15530 math_val lhs = m_left->evaluate(ctx);
245
246 // handle short-circuiting for || and &&
247
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 15494 times.
15530 if(m_type == math_binop_type::logical_or) {
248
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
36 if(lhs.get_bool() == true) return math_val((int64_t)true);
249
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 math_val rhs = m_right->evaluate(ctx);
250
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return math_val((int64_t)rhs.get_bool());
251 9 }
252
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 15440 times.
15494 if(m_type == math_binop_type::logical_and) {
253
3/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 36 times.
54 if(lhs.get_bool() == false) return math_val((int64_t)false);
254
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 math_val rhs = m_right->evaluate(ctx);
255
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 return math_val((int64_t)rhs.get_bool());
256 18 }
257
258
2/2
✓ Branch 0 taken 15439 times.
✓ Branch 1 taken 1 times.
15440 math_val rhs = m_right->evaluate(ctx);
259
5/6
✓ Branch 0 taken 15439 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15415 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 7697 times.
✓ Branch 5 taken 24 times.
30947 return evaluate_binop(lhs, rhs, m_type);
260 7791 }
261
262 15566 int has_label() const {
263 15566 return m_left->has_label() | m_right->has_label();
264 }
265
266 int get_len(bool could_be_bank_ex) const;
267 };
268
269 enum class math_unop_type {
270 neg,
271 bit_not,
272 bank_extract,
273 };
274
275 class math_ast_unop : public math_ast_node {
276 public:
277 owned_node m_arg;
278 math_unop_type m_type;
279 144 math_ast_unop(owned_node arg_in, math_unop_type type_in)
280 288 : m_arg(std::move(arg_in)), m_type(type_in) {}
281 210 math_val evaluate(const math_eval_context& ctx) const {
282
1/2
✓ Branch 0 taken 105 times.
✗ Branch 1 not taken.
210 math_val arg = m_arg->evaluate(ctx);
283
2/4
✓ Branch 0 taken 192 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
210 switch(m_type) {
284 192 case math_unop_type::neg:
285
3/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
192 if(arg.m_type == math_val_type::floating) return math_val(-arg.get_double());
286
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 else return math_val(-arg.get_integer());
287 case math_unop_type::bit_not: return math_val(~arg.get_integer());
288
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 case math_unop_type::bank_extract: return math_val(arg.get_integer() >> 16);
289 }
290
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
105 }
291 210 int has_label() const {
292 210 return m_arg->has_label();
293 }
294 54 int get_len(bool could_be_bank_ex) const {
295
3/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 27 times.
54 if(could_be_bank_ex && m_type == math_unop_type::bank_extract)
296 27 return 1;
297 return m_arg->get_len(false);
298 }
299 };
300
301 class math_ast_literal : public math_ast_node {
302 math_val m_value;
303 int m_len;
304 public:
305
6/12
✓ Branch 0 taken 29173 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 198 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 339 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 525 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 27397 times.
✗ Branch 11 not taken.
57668 math_ast_literal(math_val value, int len=0) : m_value(value), m_len(len) {}
306 50060 math_val evaluate(const math_eval_context& ctx) const { return m_value; }
307 50132 int has_label() const { return 0; }
308 7386 int get_len(bool could_be_bank_ex) const { return m_len; }
309 friend int math_ast_binop::get_len(bool) const;
310 };
311
312 class math_ast_label : public math_ast_node {
313 string m_labelname;
314 // current namespace when this label was referenced
315 string m_cur_ns;
316 public:
317 // this should be the output of labelname() already
318 4350 math_ast_label(string labelname)
319 6531 : m_labelname(labelname)
320 // this is initialized with the global ns
321
2/4
✓ Branch 0 taken 4350 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4350 times.
✗ Branch 3 not taken.
6519 , m_cur_ns(ns) {}
322
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 951 times.
1986 math_val evaluate(const math_eval_context& ctx) const {
323
11/14
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1908 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 960 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 39 times.
✓ Branch 9 taken 957 times.
✓ Branch 10 taken 30 times.
✓ Branch 11 taken 966 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1986 if(m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
324
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);
325 60 v.m_type = math_val_type::identifier;
326 30 return v;
327 30 }
328
2/2
✓ Branch 0 taken 1918 times.
✓ Branch 1 taken 8 times.
1926 else if(labels.exists(m_labelname)) {
329
2/4
✓ Branch 0 taken 961 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 961 times.
✗ Branch 3 not taken.
2875 math_val v = math_val(m_labelname);
330 1918 v.m_type = math_val_type::identifier;
331 961 return v;
332 961 }
333 else {
334 // i think in this context we always should throw???
335 8 asar_throw_error(2, error_type_block, error_id_label_not_found, m_labelname.data());
336 }
337 }
338
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 951 times.
1986 int has_label() const {
339
11/14
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1908 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 69 times.
✓ Branch 5 taken 960 times.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 9 times.
✓ Branch 8 taken 39 times.
✓ Branch 9 taken 957 times.
✓ Branch 10 taken 30 times.
✓ Branch 11 taken 966 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
1986 if(m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
340
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;
341 }
342
2/2
✓ Branch 0 taken 1918 times.
✓ Branch 1 taken 8 times.
1926 else if(labels.exists(m_labelname)) {
343
2/2
✓ Branch 0 taken 958 times.
✓ Branch 1 taken 960 times.
1918 return labels.find(m_labelname).is_static ? 1 : 3;
344 }
345 // otherwise, non-static label
346 5 return 3;
347 }
348
349 2202 int get_len(bool could_be_bank_ex) const {
350 1104 snes_label label;
351
11/14
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 2112 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✓ Branch 5 taken 1083 times.
✓ Branch 6 taken 15 times.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 45 times.
✓ Branch 9 taken 1059 times.
✓ Branch 10 taken 15 times.
✓ Branch 11 taken 1089 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
2202 if(m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
352
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 label = labels.find(m_cur_ns + m_labelname);
353 }
354
4/4
✓ Branch 0 taken 2025 times.
✓ Branch 1 taken 147 times.
✓ Branch 2 taken 941 times.
✓ Branch 3 taken 148 times.
2172 else if(labels.exists(m_labelname)) {
355
1/2
✓ Branch 0 taken 941 times.
✗ Branch 1 not taken.
1877 label = labels.find(m_labelname);
356 }
357 148 else return 2;
358
1/2
✓ Branch 0 taken 956 times.
✗ Branch 1 not taken.
1907 return getlenforlabel(label, true);
359 }
360 };
361
362 class math_builtin_function {
363 using callable_t = math_val(*)(const std::vector<math_val>& args);
364 callable_t inner;
365 int m_has_label;
366 public:
367 bool m_is_bank;
368 8778 math_builtin_function(callable_t c, int l = 0, bool is_bank = false)
369 16776 : inner(c), m_has_label(l), m_is_bank(is_bank) {}
370 2976 math_val call(const std::vector<math_val>& args) const {
371 2976 return inner(args);
372 }
373 1488 int has_label() const {
374 2976 return m_has_label;
375 }
376 };
377
378 54 class math_user_function {
379 int m_arg_count;
380 owned_node m_func_body;
381 public:
382 54 math_user_function(owned_node body, size_t arg_count)
383 108 : m_arg_count(arg_count), m_func_body(std::move(body)) {}
384
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
66 math_val call(const std::vector<math_val>& args) const {
385 33 math_eval_context new_ctx;
386
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 new_ctx.userfunc_params = args;
387
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if(args.size() != m_arg_count)
388 asar_throw_error(2, error_type_block, error_id_argument_count, m_arg_count, (int)args.size());
389
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
132 return m_func_body->evaluate(new_ctx);
390 33 }
391 66 int has_label() const {
392 66 return m_func_body->has_label();
393 }
394 };
395
396 class math_function_ref {
397 public:
398 std::variant<const math_builtin_function*, const math_user_function*> inner;
399 3216 math_function_ref(const math_builtin_function& fn) : inner(&fn) {}
400 66 math_function_ref(const math_user_function& fn) : inner(&fn) {}
401 3042 math_val call(const std::vector<math_val>& args) const {
402
2/2
✓ Branch 0 taken 1443 times.
✓ Branch 1 taken 78 times.
10569 return std::visit([&](auto& i) { return i->call(args); }, inner);
403 }
404 3042 int has_label() const {
405
1/2
✓ Branch 0 taken 1521 times.
✗ Branch 1 not taken.
7605 return std::visit([&](auto& i) { return i->has_label(); }, inner);
406 }
407 };
408
409 extern std::unordered_map<string, math_user_function> user_functions;
410 extern const std::unordered_map<string, math_builtin_function> builtin_functions;
411
412 class math_ast_function_call : public math_ast_node {
413 std::vector<owned_node> m_arguments;
414 math_function_ref m_func;
415 3282 static math_function_ref lookup_fname(string const& function_name) {
416
4/4
✓ Branch 0 taken 1674 times.
✓ Branch 1 taken 1608 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 1608 times.
3282 if(auto it = user_functions.find(function_name); it != user_functions.end()) {
417 66 return it->second;
418
2/4
✓ Branch 0 taken 3216 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1608 times.
✗ Branch 3 not taken.
3216 } else if(auto it = builtin_functions.find(function_name); it != builtin_functions.end()) {
419 3216 return it->second;
420 } else {
421 asar_throw_error(2, error_type_block, error_id_function_not_found, function_name.data());
422 }
423 }
424
425 public:
426 3282 math_ast_function_call(std::vector<owned_node> args, string function_name)
427 3282 : m_arguments(std::move(args))
428
3/6
✓ Branch 0 taken 1728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1554 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1641 times.
✗ Branch 5 not taken.
6564 , m_func(lookup_fname(function_name)) {}
429 3042 math_val evaluate(const math_eval_context& ctx) const {
430 1521 std::vector<math_val> arg_vals;
431
2/2
✓ Branch 0 taken 3864 times.
✓ Branch 1 taken 3042 times.
6906 for(auto const& p : m_arguments) {
432
2/4
✓ Branch 0 taken 3864 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1932 times.
✗ Branch 3 not taken.
5796 arg_vals.push_back(p->evaluate(ctx));
433 }
434
2/2
✓ Branch 0 taken 2886 times.
✓ Branch 1 taken 156 times.
5928 return m_func.call(arg_vals);
435 3042 }
436 3042 int has_label() const {
437 3042 int out = m_func.has_label();
438
2/2
✓ Branch 0 taken 3864 times.
✓ Branch 1 taken 3042 times.
6906 for(auto const& p : m_arguments) {
439
1/2
✓ Branch 0 taken 1932 times.
✗ Branch 1 not taken.
3864 out |= p->has_label();
440 }
441 3042 return out;
442 }
443 234 int get_len(bool could_be_bank_ex) const {
444
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 108 times.
234 if(could_be_bank_ex) {
445
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
126 auto v = std::get_if<const math_builtin_function*>(&m_func.inner);
446
3/4
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 63 times.
126 if(v && (*v)->m_is_bank) return 1;
447 }
448 // have nothing to go on, good default i guess
449 // TODO for realbase this might be wrong? bc that might be in another bank?
450
2/2
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 99 times.
198 if(m_arguments.size() == 0) return 2;
451 198 int res = 0;
452
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 198 times.
396 for(auto& v : m_arguments) {
453
1/2
✓ Branch 0 taken 198 times.
✗ Branch 1 not taken.
297 res = std::max(res, v->get_len(false));
454 }
455 198 return res;
456 }
457 };
458
459 // only for use inside user function definitions
460 class math_ast_function_argument : public math_ast_node {
461 size_t m_arg_idx;
462 public:
463 162 math_ast_function_argument(size_t arg_idx) : m_arg_idx(arg_idx) {}
464
465 102 math_val evaluate(const math_eval_context& ctx) const {
466 102 return ctx.userfunc_params[m_arg_idx];
467 }
468
469 // if a function is called with a label as an argument, that gets checked by
470 // the function call node, not here
471 102 int has_label() const { return 0; }
472 // i don't think these should ever have their len gotten?
473 int get_len(bool could_be_bank_ex) const { return 0; }
474 };
475
476 252 inline int math_ast_binop::get_len(bool could_be_bank_ex) const {
477
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 162 times.
252 if(could_be_bank_ex) {
478 45 int want_rhs = 0;
479
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 45 times.
90 if(m_type == math_binop_type::div) {
480 18 want_rhs = 65536;
481
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 18 times.
54 } else if(m_type == math_binop_type::shift_right) {
482 18 want_rhs = 16;
483 }
484
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 9 times.
45 if(want_rhs) {
485 36 math_ast_node* right_ptr = m_right.get();
486
1/2
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
72 auto right_lit = dynamic_cast<math_ast_literal*>(right_ptr);
487
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
72 if(right_lit && right_lit->m_value.m_type == math_val_type::integer) {
488 72 int64_t right_val = right_lit->m_value.get_integer();
489
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
72 if(right_val == want_rhs) return 1;
490 }
491 }
492 }
493
3/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
180 return std::max(m_left->get_len(false), m_right->get_len(false));
494 }
495