asar coverage - build #260


src/asar/
File: src/asar/asar_math.cpp
Date: 2025-02-27 15:42:33
Lines:
210/225
93.3%
Functions:
11/11
100.0%
Branches:
278/454
61.2%

Line Branch Exec Source
1 #include "asar.h"
2 #include "assembleblock.h"
3 #include "asar_math.h"
4 #include "table.h"
5 #include "unicode.h"
6 #include <cmath>
7
8 #include "math_ast.h"
9
10
11 bool foundlabel;
12 // WARNING: this flag is only correctly set in pass 0, as forward labels are
13 // always non-static but we don't know when we hit forward-labels past pass 0
14 bool foundlabel_static;
15 // only set in pass 0
16 bool forwardlabel;
17
18
19 std::unordered_map<string, math_user_function> user_functions;
20
21 // we don't need this struct to be exported
22 namespace {
23 // data necessary for parsing an expression, which might be an user function declaration
24 54 struct parse_context {
25 const char*& str;
26 // this map is empty unless declaring a function,
27 // in which case it maps argument name to argument index
28 const std::unordered_map<string, size_t> function_arg_names;
29 // these are methods to allow easier access to `str`
30 owned_node parse_atom();
31 owned_node parse_unops();
32 owned_node parse_binops(int depth = 0);
33 owned_node parse();
34 };
35 }
36
37
38 static const long hextable[] = {
39 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
40 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
41 -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
42 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
43 -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
44 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
45 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
46 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
47 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
48 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
49 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
50 };
51
52 // "atom" = literal, parenthesized expression, or label reference
53 62926 owned_node parse_context::parse_atom() {
54
2/2
✓ Branch 0 taken 20956 times.
✓ Branch 1 taken 41970 times.
62926 if(*str == '$') {
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20956 times.
20956 if (!is_xdigit(*++str)) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
56 10525 const char* start = str;
57 20956 int64_t ret = 0; // todo error on overflow?
58
2/2
✓ Branch 0 taken 66798 times.
✓ Branch 1 taken 20956 times.
87754 while (hextable[0 + *str] >= 0) {
59 66798 ret = (ret << 4) | hextable[0 + *str++];
60 }
61 20956 int len = str - start;
62 20956 int len_bytes = (len+1)/2;
63
1/2
✓ Branch 0 taken 10525 times.
✗ Branch 1 not taken.
20956 return std::make_unique<math_ast_literal>(ret, len_bytes);
64 }
65
8/8
✓ Branch 0 taken 35324 times.
✓ Branch 1 taken 6646 times.
✓ Branch 2 taken 17156 times.
✓ Branch 3 taken 528 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 17147 times.
✓ Branch 6 taken 3862 times.
✓ Branch 7 taken 17147 times.
41970 if (is_ualpha(*str) || *str=='.' || *str=='?') {
66 7720 const char * start=str;
67
6/6
✓ Branch 0 taken 31054 times.
✓ Branch 1 taken 31066 times.
✓ Branch 2 taken 3864 times.
✓ Branch 3 taken 7720 times.
✓ Branch 4 taken 27208 times.
✓ Branch 5 taken 3862 times.
62120 while (is_ualnum(*str) || *str == '.') str++;
68 7720 int len=(int)(str-start);
69
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 7720 times.
7846 while (*str==' ') str++;
70
2/2
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 5128 times.
7720 if (*str=='(') {
71
1/2
✓ Branch 0 taken 1296 times.
✗ Branch 1 not taken.
2592 str++;
72 1296 string func_name;
73
1/2
✓ Branch 0 taken 2592 times.
✗ Branch 1 not taken.
2592 func_name.assign(start, len);
74 1296 std::vector<owned_node> arguments;
75
2/2
✓ Branch 0 taken 3150 times.
✓ Branch 1 taken 2592 times.
7038 while(*str != ')') {
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3150 times.
3150 while (*str==' ') str++;
77
2/4
✓ Branch 0 taken 3150 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3150 times.
✗ Branch 3 not taken.
3150 arguments.emplace_back(parse_binops());
78 // is "invalid number" good here?
79
3/4
✓ Branch 0 taken 1251 times.
✓ Branch 1 taken 1899 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1251 times.
3150 if(*str != ',' && *str != ')') asar_throw_error(2, error_type_block, error_id_invalid_number);
80
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 2502 times.
3150 if(*str == ',') str++;
81 }
82 2592 str++;
83
1/2
✓ Branch 0 taken 2592 times.
✗ Branch 1 not taken.
2592 return std::make_unique<math_ast_function_call>(std::move(arguments), std::move(func_name));
84 2592 } else {
85
1/2
✓ Branch 0 taken 2566 times.
✗ Branch 1 not taken.
5128 string name_part(start, len);
86
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 4078 times.
5128 if(name_part == "...") {
87 // a tiny bit ugly, but whatever
88 // ...TODO also not having a constructor for identifier is ugly too
89
2/4
✓ Branch 0 taken 525 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 525 times.
✗ Branch 3 not taken.
1050 math_val value = name_part;
90 1050 value.m_type = math_val_type::identifier;
91
1/2
✓ Branch 0 taken 1050 times.
✗ Branch 1 not taken.
1050 return std::make_unique<math_ast_literal>(value);
92 525 }
93
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 3916 times.
4078 if(!function_arg_names.empty()) {
94
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 auto it = function_arg_names.find(name_part);
95
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
162 if(it != function_arg_names.end()) {
96
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
162 return std::make_unique<math_ast_function_argument>(it->second);
97 }
98 }
99
1/2
✓ Branch 0 taken 3916 times.
✗ Branch 1 not taken.
3916 string name = labelname(&start);
100 3916 str = start;
101
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 3742 times.
3916 if(*str == '[') {
102 // struct array indexing
103 174 str++;
104
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 auto index = parse_binops();
105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
174 if(*str != ']') asar_throw_error(2, error_type_block, error_id_invalid_label_missing_closer);
106
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
174 str++;
107
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
87 string subname = name;
108
2/2
✓ Branch 0 taken 168 times.
✓ Branch 1 taken 6 times.
174 if(*str == '.') {
109 // this part used to be in labelname... not sure where it really belongs....
110
6/6
✓ Branch 0 taken 504 times.
✓ Branch 1 taken 504 times.
✓ Branch 2 taken 168 times.
✓ Branch 3 taken 168 times.
✓ Branch 4 taken 420 times.
✓ Branch 5 taken 84 times.
1008 while (is_ualnum(*str) || *str == '.') {
111
1/2
✓ Branch 0 taken 840 times.
✗ Branch 1 not taken.
840 subname += *(str++);
112 }
113 }
114 // when doing base[index].sub:
115 // result = (base_addr + index*object_size(base)) + sub_offset
116 // = sub_addr + index*object_size(base)
117 // so we build a math node that represents this calculation
118
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 auto node_sub = std::make_unique<math_ast_label>(subname);
119
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 auto node_base = std::make_unique<math_ast_label>(name);
120 87 std::vector<owned_node> arg_list;
121
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 arg_list.emplace_back(std::move(node_base));
122
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 auto node_objsize = std::make_unique<math_ast_function_call>(std::move(arg_list), "objectsize");
123
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 auto node_mul = std::make_unique<math_ast_binop>(std::move(node_objsize), std::move(index), math_binop_type::mul);
124
1/2
✓ Branch 0 taken 174 times.
✗ Branch 1 not taken.
174 auto node_add = std::make_unique<math_ast_binop>(std::move(node_mul), std::move(node_sub), math_binop_type::add);
125 87 return node_add;
126 174 } else {
127
1/2
✓ Branch 0 taken 3742 times.
✗ Branch 1 not taken.
3742 return std::make_unique<math_ast_label>(name);
128 }
129 5128 }
130 }
131
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 16928 times.
17147 if(*str == '(') {
132 438 str++;
133
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
438 auto res = parse_binops();
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 438 times.
438 if(*str != ')') asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
135 438 str++;
136 219 return res;
137 438 }
138
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 16916 times.
16928 if(*str == '%') {
139
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if (str[1] != '0' && str[1] != '1') asar_throw_error(2, error_type_block, error_id_invalid_binary_value);
140 24 const char* start = str+1;
141 24 uint64_t res = strtoull(str+1, const_cast<char**>(&str), 2);
142 24 int len = str - start;
143
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 return std::make_unique<math_ast_literal>((int64_t)res, (len+7)/8);
144 }
145
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 16586 times.
16916 if (*str=='\'') {
146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (!str[1]) asar_throw_error(2, error_type_block, error_id_invalid_character);
147 int orig_val;
148 660 str++;
149
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 str += utf8_val(&orig_val, str);
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (orig_val == -1) asar_throw_error(0, error_type_block, error_id_invalid_utf8);
151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (*str != '\'') asar_throw_error(2, error_type_block, error_id_invalid_character);
152
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 int64_t rval=thetable.get_val(orig_val);
153
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (rval == -1)
154 {
155 // RPG Hacker: Should be fine to not check return value of codepoint_to_utf8() here, because
156 // our error cases above already made sure that orig_val contains valid data at this point.
157 string u8_str;
158 codepoint_to_utf8(&u8_str, orig_val);
159 asar_throw_error(2, error_type_block, error_id_undefined_char, u8_str.data());
160 }
161 660 str++;
162
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 return std::make_unique<math_ast_literal>(rval, 1);
163 }
164
2/2
✓ Branch 0 taken 32666 times.
✓ Branch 1 taken 462 times.
33128 if (is_digit(*str)) {
165 16355 const char* end = str;
166 16355 bool is_float = false;
167
6/6
✓ Branch 0 taken 37381 times.
✓ Branch 1 taken 37398 times.
✓ Branch 2 taken 156 times.
✓ Branch 3 taken 32666 times.
✓ Branch 4 taken 21087 times.
✓ Branch 5 taken 16355 times.
74779 while (is_digit(*end) || *end == '.') {
168
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 41957 times.
42113 if(*end == '.') is_float = true;
169 42113 end++;
170 }
171 16355 string number;
172
1/2
✓ Branch 0 taken 32666 times.
✗ Branch 1 not taken.
32666 number.assign(str, (int)(end - str));
173 32666 str = end;
174
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 32510 times.
32666 if(is_float) {
175 156 double res = std::atof(number);
176
1/2
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
156 return std::make_unique<math_ast_literal>(res);
177 } else {
178 32510 int64_t res = strtoll(number, nullptr, 10);
179
4/4
✓ Branch 0 taken 32492 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 16229 times.
✓ Branch 3 taken 16263 times.
32510 int len = (res >= 0x10000) ? 3 : (res >= 0x100) ? 2 : 1;
180
1/2
✓ Branch 0 taken 32510 times.
✗ Branch 1 not taken.
32510 return std::make_unique<math_ast_literal>(res, len);
181 }
182 32666 }
183
2/2
✓ Branch 0 taken 432 times.
✓ Branch 1 taken 30 times.
462 if(*str == '"') {
184 432 const char * strpos = str + 1;
185
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
216 while (*str!='"' && *str!='\0') str++;
186 432 str = strchr(str + 1, '"'); // TODO don't we have string escapes????
187
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
432 string tempname(strpos , (int)(str - strpos));
188 432 str++;
189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 432 times.
432 while (*str==' ') str++; //eat space
190
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
432 return std::make_unique<math_ast_literal>(tempname);
191 432 }
192 30 asar_throw_error(2, error_type_block, error_id_invalid_number);
193 }
194
195 63070 owned_node parse_context::parse_unops() {
196
2/2
✓ Branch 0 taken 7092 times.
✓ Branch 1 taken 63070 times.
70162 while(*str == ' ') str++;
197 // optimize for the common case
198 // TODO how much of an optimization is this really?
199
2/2
✓ Branch 0 taken 20956 times.
✓ Branch 1 taken 42114 times.
63070 if(*str == '$') return parse_atom();
200
201
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 42042 times.
42114 if(*str == '-') {
202 72 str++;
203
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
72 return std::make_unique<math_ast_unop>(parse_unops(), math_unop_type::neg);
204
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 42018 times.
42042 } else if(*str == '~') {
205 24 str++;
206
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 return std::make_unique<math_ast_unop>(parse_unops(), math_unop_type::bit_not);
207
4/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 41940 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 30 times.
42018 } else if(*str == '<' && str[1] == ':') {
208 48 str += 2;
209
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
48 return std::make_unique<math_ast_unop>(parse_unops(), math_unop_type::bank_extract);
210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41970 times.
41970 } else if(*str == '+') {
211 str++;
212 return parse_unops();
213 }
214 41970 else return parse_atom();
215 }
216
217 63018 owned_node parse_context::parse_binops(int depth) {
218 63018 const char* posneglabel = str;
219
1/2
✓ Branch 0 taken 31584 times.
✗ Branch 1 not taken.
63018 string posnegname = posneglabelname(&posneglabel, false);
220
4/4
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 62854 times.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 31534 times.
63104 if (posnegname.length() > 0 &&
221
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 86 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
164 (*posneglabel == '\0' || *posneglabel == ')')) {
222 92 str = posneglabel;
223
1/2
✓ Branch 0 taken 92 times.
✗ Branch 1 not taken.
92 return std::make_unique<math_ast_label>(posnegname);
224 }
225
226
1/2
✓ Branch 0 taken 31534 times.
✗ Branch 1 not taken.
31534 recurseblock rec;
227
228
2/2
✓ Branch 0 taken 62896 times.
✓ Branch 1 taken 30 times.
62926 owned_node left = parse_unops();
229 62896 owned_node right;
230
2/2
✓ Branch 0 taken 7092 times.
✓ Branch 1 taken 62896 times.
69988 while(*str == ' ') str++;
231
8/8
✓ Branch 0 taken 17290 times.
✓ Branch 1 taken 60424 times.
✓ Branch 2 taken 15478 times.
✓ Branch 3 taken 1812 times.
✓ Branch 4 taken 15067 times.
✓ Branch 5 taken 411 times.
✓ Branch 6 taken 7492 times.
✓ Branch 7 taken 87 times.
77714 while (*str && *str != ')' && *str != ','&& *str != ']') {
232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14980 times.
14980 while(*str == ' ') str++;
233 // TODO can we make this macro a bit nicer???
234 #define oper(name, thisdepth, contents) \
235 if (!strncmp(str, name, strlen(name))) \
236 { \
237 if (depth<=thisdepth) \
238 { \
239 str += strlen(name); \
240 right = parse_binops(thisdepth+1); \
241 left = std::make_unique<math_ast_binop>(std::move(left), std::move(right), contents); \
242 continue; \
243 } \
244 else return left; \
245 }
246
5/8
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14944 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
14998 oper("**", 6, math_binop_type::pow);
247
5/8
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 14836 times.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
14998 oper("*", 5, math_binop_type::mul);
248
5/8
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 14812 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 24 times.
✗ Branch 7 not taken.
14848 oper("/", 5, math_binop_type::div);
249
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 14812 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.
14812 oper("%", 5, math_binop_type::mod);
250
6/8
✓ Branch 0 taken 6040 times.
✓ Branch 1 taken 8772 times.
✓ Branch 2 taken 5980 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 5980 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5980 times.
✗ Branch 7 not taken.
17800 oper("+", 4, math_binop_type::add);
251
5/8
✓ Branch 0 taken 1578 times.
✓ Branch 1 taken 7194 times.
✓ Branch 2 taken 1578 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1578 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1578 times.
✗ Branch 7 not taken.
9561 oper("-", 4, math_binop_type::sub);
252
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7194 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.
7194 oper("<<", 3, math_binop_type::shift_left);
253
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7194 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.
7194 oper(">>", 3, math_binop_type::shift_right);
254
255 //these two needed checked early to avoid bitwise from eating a operator
256
6/8
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 7122 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
7212 oper("&&", 0, math_binop_type::logical_and);
257
6/8
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 7086 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
7131 oper("||", 0, math_binop_type::logical_or);
258
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7086 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.
7086 oper("&", 2, math_binop_type::bit_and);
259
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7086 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.
7086 oper("|", 2,math_binop_type::bit_or);
260
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 7086 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.
7086 oper("^", 2, math_binop_type::bit_xor);
261
262
5/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7068 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
7095 oper(">=", 1, math_binop_type::comp_ge);
263
5/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7050 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
7077 oper("<=", 1, math_binop_type::comp_le);
264
5/8
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 6636 times.
✓ Branch 2 taken 414 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 414 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 414 times.
✗ Branch 7 not taken.
7257 oper(">", 1, math_binop_type::comp_gt);
265
5/8
✓ Branch 0 taken 5400 times.
✓ Branch 1 taken 1236 times.
✓ Branch 2 taken 5400 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5400 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5400 times.
✗ Branch 7 not taken.
9336 oper("<", 1, math_binop_type::comp_lt);
266
5/8
✓ Branch 0 taken 1134 times.
✓ Branch 1 taken 102 times.
✓ Branch 2 taken 1134 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1134 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1134 times.
✗ Branch 7 not taken.
1803 oper("==", 1, math_binop_type::comp_eq);
267
5/8
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 54 times.
✗ Branch 7 not taken.
129 oper("!=", 1, math_binop_type::comp_ne);
268 48 asar_throw_error(2, error_type_block, error_id_unknown_operator);
269 #undef oper
270 }
271 31438 return left;
272 63192 }
273
274 44438 owned_node parse_context::parse() {
275 44438 auto res = parse_binops();
276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44360 times.
44360 if(*str) {
277 if(*str == ',') asar_throw_error(2, error_type_block, error_id_invalid_input);
278 else asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
279 }
280 44360 return res;
281 }
282
283 108 void createuserfunc(const char * name, const char * arguments, const char * content) {
284
10/22
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 54 times.
✓ Branch 7 taken 54 times.
✓ Branch 8 taken 54 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✓ Branch 11 taken 54 times.
✓ Branch 12 taken 54 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 54 times.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✓ Branch 17 taken 54 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
270 if(user_functions.count(name) != 0 || builtin_functions.count(name) != 0) {
285 asar_throw_error(0, error_type_block, error_id_function_redefined, name);
286 }
287
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 string arguments_buf = arguments;
288 // TODO: if we want to be more lenient with spaces in the `function`
289 // command, then we need to handle spaces inside `arguments_buf`
290 int numargs;
291
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 autoptr<char**> spl = split(arguments_buf.raw(), ',', &numargs);
292 108 size_t arg_count = numargs;
293
8/12
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 27 times.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 27 times.
✓ Branch 7 taken 27 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 54 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
135 if(numargs == 1 && spl[0] == string{""}) {
294 arg_count = 0;
295 }
296 54 std::unordered_map<string, size_t> arg_indices;
297
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 108 times.
270 for(size_t i = 0; i < arg_count; i++) {
298
1/2
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
162 string argname = spl[i];
299
3/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 81 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 81 times.
162 if(arg_indices.count(argname)) {
300 asar_throw_error(0, error_type_block, error_id_duplicate_param_name, argname.data(), name);
301 }
302
2/4
✓ Branch 0 taken 162 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 162 times.
162 if(!confirmname(argname)) {
303 asar_throw_error(0, error_type_block, error_id_invalid_param_name, argname.data());
304 }
305
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 arg_indices.emplace(std::move(argname), i);
306 162 }
307
308
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 parse_context ctx{ content, arg_indices };
309
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 auto parsed = ctx.parse();
310
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
108 math_user_function userfunc = { std::move(parsed), arg_count };
311
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 user_functions.emplace(name, std::move(userfunc));
312 162 }
313
314 35066 double math(const char * str)
315 {
316 35066 parse_context parse_ctx { str, {}};
317
2/2
✓ Branch 0 taken 35006 times.
✓ Branch 1 taken 60 times.
35066 owned_node parsed = parse_ctx.parse();
318
1/2
✓ Branch 0 taken 35006 times.
✗ Branch 1 not taken.
35006 int haslabel = parsed->has_label();
319 35006 foundlabel = haslabel > 0;
320 35006 foundlabel_static = haslabel < 2;
321
2/2
✓ Branch 0 taken 17421 times.
✓ Branch 1 taken 15 times.
35006 forwardlabel=false; // TODO
322 17570 math_eval_context ctx;
323
2/2
✓ Branch 0 taken 34974 times.
✓ Branch 1 taken 32 times.
35006 math_val rval = parsed->evaluate(ctx);
324
1/2
✓ Branch 0 taken 34974 times.
✗ Branch 1 not taken.
69948 return rval.get_double();
325 35070 }
326
327 29061 int64_t getnum(const char* instr)
328 {
329 29061 double num = math(instr);
330
2/2
✓ Branch 0 taken 14421 times.
✓ Branch 1 taken 14550 times.
28971 if(num < (double)INT64_MIN) {
331 return INT64_MIN;
332
2/2
✓ Branch 0 taken 14421 times.
✓ Branch 1 taken 14550 times.
28971 } else if(num > (double)INT64_MAX) {
333 return INT64_MAX;
334 }
335 28971 return (int64_t)num;
336 }
337
338 // RPG Hacker: Same function as above, but doesn't truncate our number via int conversion
339 5820 double getnumdouble(const char * instr)
340 {
341 5820 return math(instr);
342 }
343
344 9264 int getlen(const char * orgstr, bool optimizebankextraction) {
345 9264 parse_context parse_ctx { orgstr, {}};
346
2/2
✓ Branch 0 taken 9246 times.
✓ Branch 1 taken 18 times.
9264 owned_node parsed = parse_ctx.parse();
347
1/2
✓ Branch 0 taken 9246 times.
✗ Branch 1 not taken.
9246 int letgen = parsed->get_len(optimizebankextraction);
348 9246 return letgen;
349 9255 }
350
351 2432 void initmathcore()
352 {
353 1265 user_functions.clear();
354 2432 }
355
356 2402 void deinitmathcore()
357 {
358 //not needed
359 2402 }
360