asar coverage - build #325


src/asar/
File: src/asar/math_eval.cpp
Date: 2025-11-04 16:32:25
Lines:
191/223
85.7%
Functions:
26/30
86.7%
Branches:
322/516
62.4%

Line Branch Exec Source
1 #include "math_ast.h"
2 #include "asar.h"
3 #include "errors.h"
4
5 234 double math_val::get_double() const {
6
5/6
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 113 times.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
234 switch(m_type) {
7 128 case math_val_type::floating:
8 128 return m_numeric_val.double_;
9 99 case math_val_type::integer:
10 99 return (double)m_numeric_val.int_;
11 5 case math_val_type::identifier:
12 5 return (double)get_integer();
13 2 case math_val_type::string:
14 2 throw_err_block(2, err_bad_type, "number", "string");
15 }
16 // this is actually unreachable because the switch case above is
17 // exhaustive, but c++ standard allows storing invalid values inside
18 // enums, so everything except clang complains about it...
19 throw_err_block(pass, err_internal_error, "math_val invalid type");
20 }
21 21911 int64_t math_val::get_integer() const {
22
5/6
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 10622 times.
✓ Branch 2 taken 11001 times.
✓ Branch 3 taken 272 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
21911 switch(m_type) {
23 30 case math_val_type::floating:
24 // TODO: throw error on overflow?
25 30 return (int64_t)m_numeric_val.double_;
26 21340 case math_val_type::integer:
27 21340 return m_numeric_val.int_;
28 539 case math_val_type::identifier:
29
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 268 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 271 times.
539 if(!labels.exists(m_string_val)) {
30 throw_err_block(pass, err_internal_error, "evaluating nonexistent label");
31 }
32 539 return labels.find(m_string_val).pos;
33 2 case math_val_type::string:
34 2 throw_err_block(2, err_bad_type, "number", "string");
35 }
36 throw_err_block(pass, err_internal_error, "math_val invalid type");
37 }
38 357 const string &math_val::get_str() const {
39
3/3
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 183 times.
✓ Branch 2 taken 1 times.
357 if (m_type == math_val_type::string)
40 355 return m_string_val;
41 2 throw_err_block(2, err_bad_type, "string", "number"); // TODO is "number" a good name for identifier/int/float?
42 }
43
44 404 const string &math_val::get_identifier() const {
45
3/3
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 1 times.
404 if (m_type == math_val_type::identifier)
46 402 return m_string_val;
47
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 const char* type_name = (m_type == math_val_type::string) ? "string" : "number";
48 2 throw_err_block(2, err_bad_type, "identifier", type_name);
49 }
50 2850 bool math_val::get_bool() const {
51
3/5
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1424 times.
✓ Branch 2 taken 1424 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
2850 switch (m_type) {
52 4 case math_val_type::floating:
53 4 return get_double() != 0.0;
54 2846 case math_val_type::integer:
55 case math_val_type::identifier:
56 2846 return get_integer() != 0;
57 case math_val_type::string:
58 return get_str().length() != 0;
59 }
60 throw_err_block(pass, err_internal_error, "math_val invalid type");
61 }
62
63 template<typename T>
64 3980 bool evaluate_binop_compare(const T& lhs, const T& rhs, math_binop_type type) {
65
4/5
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 1812 times.
✗ Branch 4 not taken.
3980 switch(type) {
66 28 case math_binop_type::comp_ge: return lhs >= rhs;
67 16 case math_binop_type::comp_le: return lhs <= rhs;
68 312 case math_binop_type::comp_gt: return lhs > rhs;
69 3624 case math_binop_type::comp_lt: return lhs < rhs;
70 default:
71 throw_err_block(2, err_internal_error, "evaluate_binop_compare with bad type");
72 }
73 }
74
75 416 static bool evaluate_eq(math_val lhs, math_val rhs) {
76 // if only one is string, they can never be equal
77
4/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 207 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 207 times.
416 if((lhs.m_type == math_val_type::string) ^ (rhs.m_type == math_val_type::string)) {
78 2 return false;
79 }
80
3/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 207 times.
✓ Branch 2 taken 202 times.
414 if(lhs.m_type == math_val_type::string) {
81 // both strings: compare as strings
82 10 return lhs.get_str() == rhs.get_str();
83 } else {
84 // both non strings: compare as numbers
85
6/6
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 202 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 188 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 188 times.
404 if(lhs.m_type == math_val_type::floating || rhs.m_type == math_val_type::floating)
86 // one floating: compare as floats
87 28 return lhs.get_double() == rhs.get_double();
88 else
89 // both ints: compare as ints
90 376 return lhs.get_integer() == rhs.get_integer();
91 }
92 }
93
94 4988 math_val evaluate_binop(math_val lhs, math_val rhs,
95 math_binop_type type) {
96
5/6
✓ Branch 0 taken 2478 times.
✓ Branch 1 taken 2495 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 2478 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2480 times.
4988 bool has_string = (lhs.m_type == math_val_type::string) || (rhs.m_type == math_val_type::string);
97
6/6
✓ Branch 0 taken 2476 times.
✓ Branch 1 taken 2495 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 2470 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 2472 times.
4988 bool has_float = (lhs.m_type == math_val_type::floating) || (rhs.m_type == math_val_type::floating);
98
12/16
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 1952 times.
✓ Branch 10 taken 54 times.
✓ Branch 11 taken 534 times.
✓ Branch 12 taken 1990 times.
✓ Branch 13 taken 382 times.
✓ Branch 14 taken 34 times.
✗ Branch 15 not taken.
4988 switch (type) {
99 12 case math_binop_type::pow:
100 12 return math_val(pow(lhs.get_double(), rhs.get_double()));
101 16 case math_binop_type::div:
102
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
16 if (rhs.get_double() == 0.0)
103 4 throw_err_block(2, err_division_by_zero);
104 12 return math_val(lhs.get_double() / rhs.get_double());
105 2 case math_binop_type::mod:
106
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
2 if (rhs.get_double() == 0.0)
107 throw_err_block(2, err_division_by_zero);
108 // TODO: negative semantics
109 if (has_float) {
110 return math_val(fmod(lhs.get_double(), rhs.get_double()));
111 } else {
112 return math_val(lhs.get_integer() % rhs.get_integer());
113 }
114 break;
115
116 2 case math_binop_type::shift_left: {
117 2 int64_t rhs_v = rhs.get_integer();
118
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (rhs_v < 0)
119 2 throw_err_block(2, err_negative_shift);
120 return math_val(lhs.get_integer() << (uint64_t)rhs_v);
121 }
122 8 case math_binop_type::shift_right: {
123 8 int64_t rhs_v = rhs.get_integer();
124
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
8 if (rhs_v < 0)
125 2 throw_err_block(2, err_negative_shift);
126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 return math_val(lhs.get_integer() >> (uint64_t)rhs_v);
127 }
128
129 case math_binop_type::bit_and:
130 return math_val(lhs.get_integer() & rhs.get_integer());
131 2 case math_binop_type::bit_or:
132 2 return math_val(lhs.get_integer() | rhs.get_integer());
133 case math_binop_type::bit_xor:
134 return math_val(lhs.get_integer() ^ rhs.get_integer());
135
136 case math_binop_type::logical_and:
137 case math_binop_type::logical_or:
138 throw_err_block(2, err_internal_error, "evaluate_binop() on logical ops loses short-circuiting");
139
140 1952 case math_binop_type::add:
141
10/15
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1946 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
✗ Branch 14 not taken.
1952 if(has_string) return math_val(lhs.get_str() + rhs.get_str());
142
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1936 times.
1946 else if(has_float) return math_val(lhs.get_double() + rhs.get_double());
143 1936 else return math_val(lhs.get_integer() + rhs.get_integer());
144 54 case math_binop_type::mul:
145
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 46 times.
54 if(has_float) return math_val(lhs.get_double() * rhs.get_double());
146 46 else return math_val(lhs.get_integer() * rhs.get_integer());
147 534 case math_binop_type::sub:
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 534 times.
534 if(has_float) return math_val(lhs.get_double() - rhs.get_double());
149 534 else return math_val(lhs.get_integer() - rhs.get_integer());
150
151 1990 case math_binop_type::comp_ge:
152 case math_binop_type::comp_le:
153 case math_binop_type::comp_gt:
154 case math_binop_type::comp_lt:
155
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1982 times.
1990 if(has_string) return (int64_t)evaluate_binop_compare(lhs.get_str(), rhs.get_str(), type);
156
1/11
✗ Branch 0 not taken.
✓ Branch 1 taken 1982 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 not taken.
✗ Branch 10 not taken.
1982 else if(has_float) return (int64_t)evaluate_binop_compare(lhs.get_double(), rhs.get_double(), type);
157
6/9
✓ Branch 0 taken 991 times.
✓ Branch 1 taken 991 times.
✓ Branch 2 taken 991 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 991 times.
✓ Branch 5 taken 991 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 991 times.
✗ Branch 8 not taken.
1982 else return (int64_t)evaluate_binop_compare(lhs.get_integer(), rhs.get_integer(), type);
158
159
6/10
✓ Branch 0 taken 191 times.
✓ Branch 1 taken 191 times.
✓ Branch 2 taken 191 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 191 times.
✓ Branch 5 taken 191 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 191 times.
✗ Branch 9 not taken.
382 case math_binop_type::comp_eq: return (int64_t)evaluate_eq(lhs, rhs);
160
6/10
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17 times.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 17 times.
✗ Branch 9 not taken.
34 case math_binop_type::comp_ne: return (int64_t)!evaluate_eq(lhs, rhs);
161 }
162 throw_err_block(pass, err_internal_error, "evaluate_binop invalid binop");
163 }
164
165 4957 math_val math_ast_binop::evaluate(const eval_context &ctx) const {
166
2/4
✓ Branch 0 taken 2477 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2480 times.
✗ Branch 3 not taken.
4957 math_val lhs = m_left->evaluate(ctx);
167
168 // handle short-circuiting for || and &&
169
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2473 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2476 times.
4957 if (m_type == math_binop_type::logical_or) {
170
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 6 times.
8 if (lhs.get_bool() == true)
171 2 return math_val((int64_t)true);
172
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 math_val rhs = m_right->evaluate(ctx);
173
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 return math_val((int64_t)rhs.get_bool());
174 6 }
175
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 2466 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 2469 times.
4949 if (m_type == math_binop_type::logical_and) {
176
3/4
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 12 times.
14 if (lhs.get_bool() == false)
177 2 return math_val((int64_t)false);
178
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
12 math_val rhs = m_right->evaluate(ctx);
179
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 return math_val((int64_t)rhs.get_bool());
180 12 }
181
182
3/4
✓ Branch 0 taken 2466 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2468 times.
✓ Branch 3 taken 1 times.
4935 math_val rhs = m_right->evaluate(ctx);
183
7/11
✓ Branch 0 taken 2466 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2466 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4927 times.
✓ Branch 5 taken 7 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2468 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 2461 times.
✓ Branch 10 taken 7 times.
4969 return evaluate_binop(lhs, rhs, m_type);
184 4971 }
185
186 4710 int math_ast_binop::has_label() const {
187 4710 return m_left->has_label() | m_right->has_label();
188 }
189
190
191 90 int math_ast_binop::get_len(bool could_be_bank_ex) const {
192
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 60 times.
90 if(could_be_bank_ex) {
193 30 int want_rhs = 0;
194
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 9 times.
30 if(m_type == math_binop_type::div) {
195 12 want_rhs = 65536;
196
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
18 } else if(m_type == math_binop_type::shift_right) {
197 12 want_rhs = 16;
198 }
199
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 if(want_rhs) {
200 24 math_ast_node* right_ptr = m_right.get();
201
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 auto right_lit = dynamic_cast<math_ast_literal*>(right_ptr);
202
3/6
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 if(right_lit && right_lit->m_value.m_type == math_val_type::integer) {
203 24 int64_t right_val = right_lit->m_value.get_integer();
204
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if(right_val == want_rhs) return 1;
205 }
206 }
207 }
208
4/8
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 33 times.
✗ Branch 7 not taken.
66 return std::max(m_left->get_len(false), m_right->get_len(false));
209 }
210 46 math_val math_ast_unop::evaluate(const eval_context &ctx) const {
211
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
46 math_val arg = m_arg->evaluate(ctx);
212
4/8
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
46 switch (m_type) {
213 40 case math_unop_type::neg:
214
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 30 times.
40 if (arg.m_type == math_val_type::floating)
215
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 return math_val(-arg.get_double());
216 else
217
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 return math_val(-arg.get_integer());
218 case math_unop_type::bit_not:
219 return math_val(~arg.get_integer());
220 6 case math_unop_type::bank_extract:
221
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 return math_val(arg.get_integer() >> 16);
222 }
223 throw_err_block(pass, err_internal_error, "evaluate_unop invalid unop");
224 46 }
225
226 6 int math_ast_unop::has_label() const { return m_arg->has_label(); }
227
228 18 int math_ast_unop::get_len(bool could_be_bank_ex) const {
229
3/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 if (could_be_bank_ex && m_type == math_unop_type::bank_extract)
230 18 return 1;
231 return m_arg->get_len(false);
232 }
233
234 8 math_val math_ast_ternary_cond::evaluate(const eval_context& ctx) const {
235
8/12
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 1 times.
8 if(m_cond->evaluate(ctx).get_bool()) {
236 6 return m_true->evaluate(ctx);
237 } else {
238 2 return m_false->evaluate(ctx);
239 }
240 }
241
242 int math_ast_ternary_cond::has_label() const {
243 return m_cond->has_label() | m_true->has_label() | m_false->has_label();
244 }
245
246 int math_ast_ternary_cond::get_len(bool could_be_bank_ex) const {
247 return std::max(m_true->get_len(false), m_false->get_len(false));
248 }
249
250 594 math_val math_ast_label::evaluate(const eval_context &ctx) const {
251
21/30
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 282 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 299 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 13 times.
✓ Branch 9 taken 282 times.
✓ Branch 10 taken 10 times.
✓ Branch 11 taken 285 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 13 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 13 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 10 times.
✓ Branch 19 taken 3 times.
✓ Branch 20 taken 13 times.
✓ Branch 21 taken 286 times.
✓ Branch 22 taken 13 times.
✓ Branch 23 taken 286 times.
✓ Branch 24 taken 10 times.
✓ Branch 25 taken 289 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
594 if (m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
252
4/8
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
30 return math_val::make_identifier(m_cur_ns + m_labelname);
253
4/4
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 286 times.
✓ Branch 3 taken 3 times.
574 } else if (labels.exists(m_labelname)) {
254
4/8
✓ Branch 0 taken 283 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 283 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 286 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 286 times.
✗ Branch 7 not taken.
855 return math_val::make_identifier(m_labelname);
255 } else {
256 // possibly forward label, assume without namespace.
257 // TODO: this assumption can cause moving labels :)))))
258
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 5 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 not taken.
5 if(pass == 0) return math_val::make_identifier(m_labelname);
259 // if not pass 0, we know it's not a forward label and can throw the error
260 5 throw_err_block(2, err_label_not_found, m_labelname.data());
261 }
262 }
263
264 304 int math_ast_label::has_label() const {
265
19/30
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 150 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 152 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 150 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 150 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 2 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 2 times.
✓ Branch 21 taken 150 times.
✓ Branch 22 taken 2 times.
✓ Branch 23 taken 150 times.
✓ Branch 24 taken 2 times.
✓ Branch 25 taken 150 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
304 if (m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
266
7/14
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 2 times.
4 return labels.find(m_cur_ns + m_labelname).is_static ? 1 : 3;
267
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 144 times.
✓ Branch 3 taken 6 times.
300 } else if (labels.exists(m_labelname)) {
268
5/6
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 80 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
✓ Branch 4 taken 64 times.
✓ Branch 5 taken 80 times.
288 return labels.find(m_labelname).is_static ? 1 : 3;
269 }
270 // otherwise, non-static forward label
271 12 return 7;
272 }
273
274 792 int math_ast_label::get_len(bool could_be_bank_ex) const {
275 792 snes_label label;
276
21/30
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 378 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 399 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✓ Branch 7 taken 10 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 378 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 388 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 14 taken 15 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 15 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 5 times.
✓ Branch 19 taken 10 times.
✓ Branch 20 taken 15 times.
✓ Branch 21 taken 384 times.
✓ Branch 22 taken 15 times.
✓ Branch 23 taken 384 times.
✓ Branch 24 taken 5 times.
✓ Branch 25 taken 394 times.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
792 if (m_cur_ns && labels.exists(m_cur_ns + m_labelname)) {
277
4/8
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
10 label = labels.find(m_cur_ns + m_labelname);
278
6/8
✓ Branch 0 taken 388 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 337 times.
✓ Branch 3 taken 51 times.
✓ Branch 4 taken 394 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 342 times.
✓ Branch 7 taken 52 times.
782 } else if (labels.exists(m_labelname)) {
279
2/4
✓ Branch 0 taken 337 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 342 times.
✗ Branch 3 not taken.
679 label = labels.find(m_labelname);
280 103 } else return 2;
281
1/2
✓ Branch 0 taken 689 times.
✗ Branch 1 not taken.
689 return getlenforlabel(label, true);
282 }
283
284 math_function_ref
285 997 math_ast_function_call::lookup_fname(string const &function_name) {
286
4/6
✓ Branch 0 taken 496 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 501 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 486 times.
1498 if (auto it = user_functions.find(function_name);
287
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 481 times.
997 it != user_functions.end()) {
288 30 return it->second;
289
3/6
✓ Branch 0 taken 481 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 486 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 486 times.
✗ Branch 5 not taken.
1453 } else if (auto it = builtin_functions.find(function_name);
290
1/2
✓ Branch 0 taken 481 times.
✗ Branch 1 not taken.
967 it != builtin_functions.end()) {
291 967 return it->second;
292 } else {
293 throw_err_block(2, err_function_not_found, function_name.data());
294 }
295 }
296 919 math_val math_ast_function_call::evaluate(const eval_context &ctx) const {
297 919 std::vector<math_val> arg_vals;
298
4/4
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 454 times.
✓ Branch 2 taken 581 times.
✓ Branch 3 taken 459 times.
2070 for (auto const &p : m_arguments) {
299
6/7
✓ Branch 0 taken 573 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 573 times.
✓ Branch 3 taken 578 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 578 times.
✗ Branch 6 not taken.
1157 arg_vals.push_back(p->evaluate(ctx));
300 }
301
4/4
✓ Branch 0 taken 440 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 445 times.
✓ Branch 3 taken 14 times.
1798 return m_func.call(arg_vals);
302 919 }
303
304 486 int math_ast_function_call::has_label() const {
305 486 int out = m_func.has_label();
306
4/4
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 240 times.
✓ Branch 3 taken 243 times.
966 for (auto const &p : m_arguments) {
307
2/4
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 240 times.
✗ Branch 3 not taken.
480 out |= p->has_label();
308 }
309 486 return out;
310 }
311
312 96 int math_ast_function_call::get_len(bool could_be_bank_ex) const {
313 96 return m_func.get_len(m_arguments, could_be_bank_ex);
314 }
315
316 26 math_val math_user_function::call(const std::vector<math_val> &args) const {
317 26 math_ast_node::eval_context new_ctx;
318
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 new_ctx.userfunc_params = args;
319
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
26 if (args.size() != m_arg_count)
320 throw_err_block(2, err_argument_count, (int)m_arg_count, (int)args.size());
321
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
✗ Branch 3 not taken.
52 return m_func_body->evaluate(new_ctx);
322 26 }
323
324 int math_user_function::has_label() const { return m_func_body->has_label(); }
325
326 6 int math_user_function::get_len(const std::vector<owned_node> &args,
327 bool could_be_bank_ex) const {
328 // TODO: this doesn't forward could_be_bank_ex to the fn call...
329 // supporting that properly would require stringing some context through all
330 // get_len calls; supporting it less properly (making a special return value of
331 // get_len signify bankextract) could be viable tho...
332
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 int len = m_func_body->get_len(false);
333
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
6 for (auto &arg : args) {
334 len = std::max(len, arg->get_len(false));
335 }
336 6 return len;
337 }
338
339