asar coverage - build #87


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-01-19 13:47:25
Lines:
420/461
91.1%
Functions:
76/101
75.2%
Branches:
355/636
55.8%

Line Branch Exec Source
1 //Don't try using this in your own project, it's got a lot of Asar-specific tweaks. Use mathlib.cpp instead.
2 #include "platform/file-helpers.h"
3 #include "std-includes.h"
4 #include "autoarray.h"
5 #include "assocarr.h"
6 #include "libstr.h"
7 #include "libsmw.h"
8 #include "asar.h"
9 #include "virtualfile.h"
10 #include "assembleblock.h"
11 #include "macro.h"
12 #include "asar_math.h"
13 #include "warnings.h"
14 #include <math.h>
15 #include <functional>
16 #include <algorithm>
17
18 bool math_pri=true;
19 bool math_round=false;
20 extern bool suppress_all_warnings;
21
22 static const char * str;
23 //save before calling eval if needed after
24 static const char * current_user_function_name;
25
26 static double getnumcore();
27 static double getnum();
28 static double eval(int depth);
29
30 //label (bool foundLabel) (bool forwardLabel)
31 //userfunction
32
33 bool foundlabel;
34 bool foundlabel_static;
35 bool forwardlabel;
36
37 struct cachedfile {
38 string filename;
39 virtual_file_handle filehandle;
40 size_t filesize;
41 bool used;
42 };
43
44 #define numcachedfiles 16
45
46 static cachedfile cachedfiles[numcachedfiles];
47 static int cachedfileindex = 0;
48
49 // Opens a file, trying to open it from cache first
50
51 84 static cachedfile * opencachedfile(string fname, bool should_error)
52 {
53 cachedfile * cachedfilehandle = nullptr;
54
55 // RPG Hacker: Only using a combined path here because that should
56 // hopefully result in a unique string for every file, whereas
57 // fname could be a relative path, which isn't guaranteed to be unique.
58 // Note that this does not affect how we open the file - this is
59 // handled by the filesystem and uses our include paths etc.
60
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 string combinedname = filesystem->create_absolute_path(dir(thisfilename), fname);
61
62
2/2
✓ Branch 0 taken 532 times.
✓ Branch 1 taken 28 times.
560 for (int i = 0; i < numcachedfiles; i++)
63 {
64
4/4
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 428 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 48 times.
532 if (cachedfiles[i].used && cachedfiles[i].filename == combinedname)
65 {
66 56 cachedfilehandle = &cachedfiles[i];
67 break;
68 }
69 }
70
71 if (cachedfilehandle == nullptr)
72 {
73
74
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 if (cachedfiles[cachedfileindex].used)
75 {
76 filesystem->close_file(cachedfiles[cachedfileindex].filehandle);
77 cachedfiles[cachedfileindex].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
78 cachedfiles[cachedfileindex].used = false;
79 }
80
81 28 cachedfilehandle = &cachedfiles[cachedfileindex];
82 }
83
84 if (cachedfilehandle != nullptr)
85 {
86
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 56 times.
84 if (!cachedfilehandle->used)
87 {
88
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 cachedfilehandle->filehandle = filesystem->open_file(fname, thisfilename);
89
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 20 times.
28 if (cachedfilehandle->filehandle != INVALID_VIRTUAL_FILE_HANDLE)
90 {
91 8 cachedfilehandle->used = true;
92 8 cachedfilehandle->filename = combinedname;
93
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 cachedfilehandle->filesize = filesystem->get_file_size(cachedfilehandle->filehandle);
94 8 cachedfileindex++;
95 // randomdude999: when we run out of cached files, just start overwriting ones from the start
96
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (cachedfileindex >= numcachedfiles) cachedfileindex = 0;
97 }
98 }
99 }
100
101
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 64 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
84 if ((cachedfilehandle == nullptr || cachedfilehandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) && should_error)
102 {
103 asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), fname.data());
104 }
105
106 84 return cachedfilehandle;
107 84 }
108
109
110 376 void closecachedfiles()
111 {
112
2/2
✓ Branch 0 taken 6016 times.
✓ Branch 1 taken 376 times.
6392 for (int i = 0; i < numcachedfiles; i++)
113 {
114
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6008 times.
6016 if (cachedfiles[i].used)
115 {
116
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (cachedfiles[i].filehandle != INVALID_VIRTUAL_FILE_HANDLE)
117 {
118 8 filesystem->close_file(cachedfiles[i].filehandle);
119 8 cachedfiles[i].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
120 }
121
122 8 cachedfiles[i].used = false;
123 }
124 }
125
126 376 cachedfileindex = 0;
127 376 }
128
129
130 16 static int struct_size(const char *name)
131 {
132
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
16 if(pass && !structs.exists(name)) asar_throw_error(2, error_type_block, error_id_struct_not_found, name);
133
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 else if(!structs.exists(name)) return 0;
134 16 return structs.find(name).struct_size;
135 }
136
137 76 static int object_size(const char *name)
138 {
139
3/4
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
76 if(pass && !structs.exists(name)) asar_throw_error(2, error_type_block, error_id_struct_not_found, name);
140
1/2
✓ Branch 0 taken 76 times.
✗ Branch 1 not taken.
76 else if(!structs.exists(name)) return 0;
141 76 return structs.find(name).object_size;
142 }
143
144 20 static int data_size(const char *name)
145 {
146 unsigned int label;
147 20 unsigned int next_label = 0xFFFFFF;
148
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 if(!labels.exists(name)) asar_throw_error(2, error_type_block, error_id_label_not_found, name);
149 20 foundlabel = true;
150 20 snes_label label_data = labels.find(name);
151 20 foundlabel_static &= label_data.is_static;
152 20 label = label_data.pos & 0xFFFFFF;
153 20 labels.each([&next_label, label](const char *key, snes_label current_label){
154 60 current_label.pos &= 0xFFFFFF;
155
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4 times.
60 if(label < current_label.pos && current_label.pos < next_label){
156 12 next_label = current_label.pos;
157 }
158 60 });
159
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 if(next_label == 0xFFFFFF) asar_throw_warning(2, warning_id_datasize_last_label, name);
160
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
20 if(next_label-label > 0xFFFF) asar_throw_warning(2, warning_id_datasize_exceeds_size, name);
161 20 return next_label-label;
162 }
163
164
165 296 string get_string_argument()
166 {
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
296 while (*str==' ') str++;
168
1/2
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
296 if (*str=='"')
169 {
170 const char * strpos = str;
171 296 str++;
172
3/4
✓ Branch 0 taken 3788 times.
✓ Branch 1 taken 296 times.
✓ Branch 2 taken 3788 times.
✗ Branch 3 not taken.
4084 while (*str!='"' && *str!='\0' && *str!='\n') str++;
173
1/2
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
296 if (*str == '"')
174 {
175 296 string tempname(strpos, (int)(str - strpos + 1));
176 296 str++;
177
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
296 while (*str==' ') str++; //eat space
178
1/2
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
296 return string(safedequote(tempname.temp_raw()));
179 296 }
180 // RPG Hacker: AFAIK, this is never actually triggered, since unmatched quotes are already detected earlier,
181 // but since it does no harm here, I'll keep it in, just to be safe
182 else asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
183 }//make this error a better one later
184
185 asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
186 return ""; //never actually called, but I don't feel like figuring out __attribute__ ((noreturn)) on MSVC
187 }
188
189 //only returns alphanumeric (and _) starting with alpha or _
190 256 string get_symbol_argument()
191 {
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 256 times.
256 while (*str==' ') str++; //is this proper? Dunno yet.
193 const char * strpos = str;
194 // hack: for backwards compat, allow strings as symbols
195
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 248 times.
256 if(*str=='"') {
196 8 asar_throw_warning(2, warning_id_feature_deprecated, "quoted symbolic arguments", "Remove the quotations");
197 8 string arg = get_string_argument();
198 int i = 0;
199
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8 if(is_alpha(arg[i]) || arg[i] == '_') i++;
200
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 4 times.
56 while(is_alnum(arg[i]) || arg[i] == '_' || arg[i] == '.') i++;
201
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
8 if(arg[i] != '\0') asar_throw_error(2, error_type_block, error_id_invalid_label_name);
202 4 return arg;
203 8 }
204
3/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
248 if(is_alpha(*str) || *str == '_') str++;
205
6/6
✓ Branch 0 taken 284 times.
✓ Branch 1 taken 892 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 876 times.
✓ Branch 4 taken 628 times.
✓ Branch 5 taken 248 times.
1176 while (is_alnum(*str) || *str == '_' || *str == '.') str++;
206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 if(strpos == str){
207 //error nothing was read, this is a placeholder error
208 asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
209 }
210
211 248 string symbol = string(strpos, (int)(str - strpos));
212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 248 times.
248 while (*str==' ') str++; //eat spaces
213 124 return symbol;
214 248 }
215
216 568 double get_double_argument()
217 {
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 568 times.
568 while (*str==' ') str++;
219 568 double result = eval(0);
220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 568 times.
568 while (*str==' ') str++; //eat spaces
221 568 return result;
222 }
223
224 //will eat the comma
225 98 bool has_next_parameter()
226 {
227
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 68 times.
98 if (*str==',')
228 {
229 30 str++;
230 30 return true;
231 }
232 return false;
233 }
234
235 234 void require_next_parameter()
236 {
237
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if (*str==',')
238 {
239 234 str++;
240 234 return;
241 }
242 asar_throw_error(2, error_type_block, error_id_require_parameter);
243 }
244
245 4 template <typename F> double asar_unary_wrapper()
246 {
247 4 return F()(get_double_argument());
248 }
249
250 8 template <double (*F)(double)> double asar_unary_wrapper()
251 {
252 8 return F(get_double_argument());
253 }
254
255 //possibly restrict type T in the future....
256 //first a case for functors
257 88 template <typename F> double asar_binary_wrapper()
258 {
259 88 double first = get_double_argument();
260 88 require_next_parameter();
261
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
88 return F()(first, get_double_argument());
262 }
263 //this could be DRY with if constexpr....oh well
264 52 template <double (*F)(double, double)> double asar_binary_wrapper()
265 {
266 52 double first = get_double_argument();
267 52 require_next_parameter();
268 52 return F(first, get_double_argument());
269 }
270
271 double asar_bank(double a)
272 {
273 4 return (int)a >> 16;
274 }
275
276
277 double asar_logical_nand(double a, double b)
278 {
279 6 return !(a && b);
280 }
281
282
283 double asar_logical_nor(double a, double b)
284 {
285 6 return !(a || b);
286 }
287
288
289 double asar_logical_xor(double a, double b)
290 {
291 6 return !!a ^ !!b;
292 }
293
294 double asar_max(double a, double b)
295 {
296
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 return a > b ? a : b;
297 }
298
299 double asar_min(double a, double b)
300 {
301
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 return a < b ? a : b;
302 }
303
304 6 double asar_clamp()
305 {
306 6 double value = get_double_argument();
307 6 require_next_parameter();
308 6 double low = get_double_argument();
309 6 require_next_parameter();
310 6 double high = get_double_argument();
311
312 6 return asar_max(low, asar_min(high, value));
313 }
314
315 4 double asar_safediv()
316 {
317 4 double dividend = get_double_argument();
318 4 require_next_parameter();
319 4 double divisor = get_double_argument();
320 4 require_next_parameter();
321 4 double default_value = get_double_argument();
322
323
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 return divisor == 0.0 ? default_value : dividend / divisor;
324 }
325
326 22 double asar_select()
327 {
328 22 double selector = get_double_argument();
329 22 require_next_parameter();
330 22 double a = get_double_argument();
331 22 require_next_parameter();
332 22 double b = get_double_argument();
333
334
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 2 times.
22 return selector == 0.0 ? b : a;
335 }
336
337 114 double asar_snestopc_wrapper()
338 {
339 114 return snestopc(get_double_argument());
340 }
341
342 82 double asar_pctosnes_wrapper()
343 {
344 82 return pctosnes(get_double_argument());
345 }
346
347 12 double asar_realbase_wrapper()
348 {
349 //need a better way to do this to make sure it is useful...
350 //foundlabel=true; //Going to consider this an implicit label because we don't really have a better system
351 12 return realsnespos;
352 }
353
354 36 template <int count> double asar_read()
355 {
356 36 int target = get_double_argument();
357 36 int addr=snestopc_pick(target);
358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
36 if(has_next_parameter())
359 {
360 double default_value = get_double_argument();
361 if (addr<0) return default_value;
362 else if (addr+count>romlen_r) return default_value;
363 }
364 else
365 {
366
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
36 if (addr<0) asar_throw_error(2, error_type_block, error_id_snes_address_doesnt_map_to_rom, (hex6((unsigned int)target) + " in read function").data());
367
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
44 else if (addr+count>romlen_r) asar_throw_error(2, error_type_block, error_id_snes_address_out_of_bounds, (hex6(target) + " in read function").data());
368 }
369
370 unsigned int value = 0;
371
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 16 times.
112 for(int i = 0; i < count; i++)
372 {
373 80 value |= romdata_r[addr+i] << (8 * i);
374 }
375 32 return value;
376 }
377
378 48 template <int count> double asar_canread()
379 {
380 int length = count;
381 if(!length)
382 {
383 length = get_double_argument();
384 }
385 48 int addr=snestopc_pick(get_double_argument());
386
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
48 if (addr<0 || addr+length-1>=romlen_r) return 0;
387 24 else return 1;
388 }
389
390 76 template <size_t count> double asar_readfile()
391 {
392 static_assert(count && count <= 4, "invalid count"); //1-4 inclusive
393
394 76 string name = get_string_argument();
395
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
76 require_next_parameter();
396
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
76 size_t offset = get_double_argument();
397 76 bool should_error = !has_next_parameter();
398
1/2
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
76 cachedfile * fhandle = opencachedfile(name, should_error);
399
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 20 times.
76 if(!should_error)
400 {
401
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 double default_value = get_double_argument();
402
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 4 times.
36 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return default_value;
403
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
28 if (offset < 0 || offset + count > fhandle->filesize) return default_value;
404 }
405 else
406 {
407
2/10
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
40 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
408
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
40 if (offset < 0 || offset + count > fhandle->filesize) asar_throw_error(2, error_type_block, error_id_file_offset_out_of_bounds, dec(offset).data(), name.data());
409 }
410
411 56 unsigned char data[4] = { 0, 0, 0, 0 };
412
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
56 filesystem->read_file(fhandle->filehandle, data, offset, count);
413
414 unsigned int value = 0;
415
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 28 times.
140 for(size_t i = 0; i < count; i++)
416 {
417 84 value |= data[i] << (8 * i);
418 }
419
420 56 return value;
421 76 }
422
423 36 template <size_t count> double asar_canreadfile()
424 {
425 36 string name = get_string_argument();
426
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 require_next_parameter();
427
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 size_t offset = get_double_argument();
428 size_t length = count;
429 if(!count)
430 {
431
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 require_next_parameter();
432
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 length = get_double_argument();
433 }
434
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 cachedfile * fhandle = opencachedfile(name, false);
435
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 4 times.
36 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return 0;
436
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
28 if (offset < 0 || offset + length > fhandle->filesize) return 0;
437 return 1;
438 36 }
439
440 // returns 0 if the file is OK, 1 if the file doesn't exist, 2 if it couldn't be opened for some other reason
441 24 static double asar_filestatus()
442 {
443
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 cachedfile * fhandle = opencachedfile(get_string_argument(), false);
444
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
24 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE)
445 {
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (filesystem->get_last_error() == vfe_doesnt_exist)
447 {
448 return 1;
449 }
450 else
451 {
452 return 2;
453 }
454 }
455 return 0;
456 }
457
458 // Returns the size of the specified file.
459 4 static double asar_filesize()
460 {
461 4 string name = get_string_argument();
462
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 cachedfile * fhandle = opencachedfile(name, false);
463
2/10
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
4 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
464 4 return (double)fhandle->filesize;
465 4 }
466
467 // Checks whether the specified define is defined.
468 124 static double asar_isdefined()
469 {
470 124 return defines.exists(get_string_argument());
471 }
472
473 // RPG Hacker: What exactly makes this function overly complicated, you ask?
474 // Well, it converts a double to a string and then back to a double.
475 // It was the quickest reliable solution I could find, though, so there's that.
476 4 static double asar_round()
477 {
478 4 double number = get_double_argument();
479 4 require_next_parameter();
480
481 // Hue hue hue... ass!
482 // OK, sorry, I apologize.
483 4 string asstring = ftostrvar(number, get_double_argument());
484
485 // Some hacky shenanigans with variables going on here
486
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 const char * strbackup = str;
487 4 str = asstring;
488
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 double asdouble = (double)getnum();
489 4 str = strbackup;
490
491 4 return asdouble;
492 4 }
493
494 220 static double asar_structsize_wrapper()
495 {
496 220 string symbol = get_symbol_argument();
497
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 16 times.
220 if(symbol == "..."){
498
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 202 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
204 if(!inmacro) asar_throw_error(2, error_type_block, error_id_vararg_sizeof_nomacro);
499
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
202 if(numvarargs == -1) asar_throw_error(2, error_type_block, error_id_macro_not_varadic);
500 200 return numvarargs;
501 }
502
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 return (double)struct_size(symbol);
503 220 }
504
505 16 static double asar_objectsize_wrapper()
506 {
507
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 return (double)object_size(get_symbol_argument());
508 }
509
510 20 static double asar_datasize_wrapper()
511 {
512
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 return (double)data_size(get_symbol_argument());
513 }
514
515 24 static double asar_stringsequal()
516 {
517 24 string string1 = get_string_argument();
518
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 require_next_parameter();
519
3/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
60 return (strcmp(string1, get_string_argument()) == 0 ? 1.0 : 0.0);
520 24 }
521
522 12 static double asar_stringsequalnocase()
523 {
524 12 string string1 = get_string_argument();
525
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 require_next_parameter();
526
4/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
24 return (stricmp(string1, get_string_argument()) == 0 ? 1.0 : 0.0);
527 12 }
528
529 42 string copy_arg()
530 {
531
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 34 times.
42 if(*str == '"')
532 {
533 4 string t = "\"";
534
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
20 return (t += get_string_argument() + "\"");
535 8 }
536
537 17 string result;
538 bool is_symbolic = true;
539 int parlevel=0;
540 int i = 0;
541
5/6
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 34 times.
✓ Branch 5 taken 30 times.
68 while(parlevel > 0 || (str[i] != ',' && str[i] != ')'))
542 {
543 34 is_symbolic &= is_ualnum(str[i]);
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if(str[i] == '(') parlevel++;
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if(str[i] == ')') parlevel--;
546 34 i++;
547 }
548 34 result += string(str, i);
549 34 str += i;
550
551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if(!is_symbolic)
552 {
553 const char *oldstr=str;
554 str = (const char *)result;
555 result = ftostr(eval(0));
556 str = oldstr;
557 }
558 17 return result;
559 34 }
560
561 assocarr<double (*)()> builtin_functions =
562 {
563 {"sqrt", asar_unary_wrapper<sqrt>},
564 {"sin", asar_unary_wrapper<sin>},
565 {"cos", asar_unary_wrapper<cos>},
566 {"tan", asar_unary_wrapper<tan>},
567 {"asin", asar_unary_wrapper<asin>},
568 {"acos", asar_unary_wrapper<acos>},
569 {"atan", asar_unary_wrapper<atan>},
570 {"arcsin", asar_unary_wrapper<asin>},
571 {"arccos", asar_unary_wrapper<acos>},
572 {"arctan", asar_unary_wrapper<atan>},
573 {"log", asar_unary_wrapper<log>},
574 {"log10", asar_unary_wrapper<log10>},
575 {"log2", asar_unary_wrapper<log2>},
576
577 {"ceil", asar_unary_wrapper<ceil>},
578 {"floor", asar_unary_wrapper<floor>},
579
580 {"read1", asar_read<1>}, //This handles the safe and unsafe variant
581 {"read2", asar_read<2>},
582 {"read3", asar_read<3>},
583 {"read4", asar_read<4>},
584 {"canread", asar_canread<0>},
585 {"canread1", asar_canread<1>},
586 {"canread2", asar_canread<2>},
587 {"canread3", asar_canread<3>},
588 {"canread4", asar_canread<4>},
589
590 {"readfile1", asar_readfile<1>},
591 {"readfile2", asar_readfile<2>},
592 {"readfile3", asar_readfile<3>},
593 {"readfile4", asar_readfile<4>},
594 {"canreadfile", asar_canreadfile<0>},
595 {"canreadfile1", asar_canreadfile<1>},
596 {"canreadfile2", asar_canreadfile<2>},
597 {"canreadfile3", asar_canreadfile<3>},
598 {"canreadfile4", asar_canreadfile<4>},
599
600 {"filesize", asar_filesize},
601 {"getfilestatus", asar_filestatus},
602
603 {"defined", asar_isdefined},
604
605 {"snestopc", asar_snestopc_wrapper},
606 {"pctosnes", asar_pctosnes_wrapper},
607 {"realbase", asar_realbase_wrapper},
608
609 {"max", asar_binary_wrapper<asar_max>},
610 {"min", asar_binary_wrapper<asar_min>},
611 {"clamp", asar_clamp},
612
613 {"safediv", asar_safediv},
614
615 {"select", asar_select},
616 {"bank", asar_unary_wrapper<asar_bank>},
617 {"not", asar_unary_wrapper<std::logical_not<unsigned int>>},
618 {"equal", asar_binary_wrapper<std::equal_to<double>>},
619 {"notequal", asar_binary_wrapper<std::not_equal_to<double>>},
620 {"less", asar_binary_wrapper<std::less<double>>},
621 {"lessequal", asar_binary_wrapper<std::less_equal<double>>},
622 {"greater", asar_binary_wrapper<std::greater<double>>},
623 {"greaterequal", asar_binary_wrapper<std::greater_equal<double>>},
624
625 {"and", asar_binary_wrapper<std::logical_and<unsigned int>>},
626 {"or", asar_binary_wrapper<std::logical_or<unsigned int>>},
627 {"nand", asar_binary_wrapper<asar_logical_nand>},
628 {"nor", asar_binary_wrapper<asar_logical_nor>},
629 {"xor", asar_binary_wrapper<asar_logical_xor>},
630
631 {"round", asar_round},
632
633 {"sizeof", asar_structsize_wrapper},
634 {"objectsize", asar_objectsize_wrapper},
635 {"datasize", asar_datasize_wrapper},
636
637 {"stringsequal", asar_stringsequal},
638 {"stringsequalnocase", asar_stringsequalnocase}
639 };
640
641 assocarr<double (*)()> functions;
642
643 struct funcdat {
644 autoptr<char*> name;
645 int numargs;
646 autoptr<char*> argbuf;//this one isn't used, it's just to free it up
647 autoptr<char**> arguments;
648 autoptr<char*> content;
649 };
650 static assocarr<funcdat> user_functions;
651
652 30 static double asar_call_user_function()
653 {
654 15 autoarray<string> args;
655
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 funcdat &user_function = user_functions[current_user_function_name];
656 15 string real_content;
657
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 while (*str==' ') str++;
659 30 bool has_next = *str != ')';
660
661
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 30 times.
72 for (int i=0;i<user_function.numargs;i++)
662 {
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if(!has_next)
664 {
665 asar_throw_error(2, error_type_block, error_id_expected_parameter, current_user_function_name);
666 }
667
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 args[i] = copy_arg();
668 42 has_next = has_next_parameter();
669 }
670
671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if(has_next)
672 {
673 asar_throw_error(2, error_type_block, error_id_unexpected_parameter, current_user_function_name);
674 }
675
676
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 30 times.
154 for(int i=0; user_function.content[i]; i++)
677 {
678
3/4
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 50 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 74 times.
124 if(!is_alpha(user_function.content[i]) && user_function.content[i] != '_')
679 {
680 74 real_content += user_function.content[i];
681 74 continue;
682 }
683 bool found = false;
684
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 50 times.
132 for (int j=0;user_function.arguments[j];j++)
685 {
686 //this should *always* have a null term or another character after
687 82 bool potential_arg = stribegin(user_function.content+i, user_function.arguments[j]);
688 82 int next_char = i+strlen(user_function.arguments[j]);
689
4/6
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
82 if(potential_arg && (!is_alnum(user_function.content[next_char]) && user_function.content[next_char] != '_'))
690 {
691 42 real_content += args[j];
692 42 i = next_char - 1;
693 found = true;
694 }
695 }
696
697
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 42 times.
50 if(!found){
698
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 8 times.
80 for(; is_ualnum(user_function.content[i]); i++){
699 72 real_content += user_function.content[i];
700 }
701 8 real_content += user_function.content[i];
702 }
703 }
704
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 const char * oldstr=str;
705 30 str = (const char *)real_content;
706
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 double result = eval(0);
707 30 str = oldstr;
708 30 return result;
709 30 }
710
711 30 void createuserfunc(const char * name, const char * arguments, const char * content)
712 {
713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (!confirmqpar(content)) asar_throw_error(0, error_type_block, error_id_mismatched_parentheses);
714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if(functions.exists(name)) //functions holds both types.
715 {
716 //asar_throw_error(0, error_type_block, error_id_function_redefined, name);
717 asar_throw_warning(1, warning_id_feature_deprecated, "overwriting a previously defined function", "change the function name");
718 }
719 30 funcdat& user_function=user_functions[name];
720 30 user_function.name= duplicate_string(name);
721 30 user_function.argbuf= duplicate_string(arguments);
722 30 user_function.arguments=qsplit(user_function.argbuf, ",", &(user_function.numargs));
723 30 user_function.content= duplicate_string(content);
724
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 30 times.
72 for (int i=0;user_function.arguments[i];i++)
725 {
726
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 42 times.
108 for(int j=0;user_function.arguments[j];j++)
727 {
728
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
66 if(i!=j && !stricmp(user_function.arguments[i], user_function.arguments[j]))
729 {
730 asar_throw_error(0, error_type_block, error_id_duplicate_param_name, user_function.arguments[i], name);
731 }
732 }
733
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (!confirmname(user_function.arguments[i]))
734 {
735 user_functions.remove(name);
736 asar_throw_error(0, error_type_block, error_id_invalid_param_name);
737 }
738 }
739
740 30 functions[name] = asar_call_user_function;
741 30 }
742
743 1837688 static double getnumcore()
744 {
745
2/2
✓ Branch 0 taken 536 times.
✓ Branch 1 taken 1837152 times.
1837688 if (*str=='(')
746 {
747 536 str++;
748 536 double rval=eval(0);
749
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 536 times.
536 if (*str != ')') asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
750 536 str++;
751 536 return rval;
752 }
753
2/2
✓ Branch 0 taken 6898 times.
✓ Branch 1 taken 1830254 times.
1837152 if (*str=='$')
754 {
755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6898 times.
6898 if (!is_xdigit(str[1])) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
756
1/2
✓ Branch 0 taken 6898 times.
✗ Branch 1 not taken.
6898 if (to_lower(str[2])=='x') return -42;//let str get an invalid value so it'll throw an invalid operator later on
757 6898 return strtoull(str+1, const_cast<char**>(&str), 16);
758 }
759
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1830206 times.
1830254 if (*str=='%')
760 {
761
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (str[1] != '0' && str[1] != '1') asar_throw_error(2, error_type_block, error_id_invalid_binary_value);
762 48 return strtoull(str+1, const_cast<char**>(&str), 2);
763 }
764
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1830158 times.
1830206 if (*str=='\'')
765 {
766
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
48 if (!str[1] || str[2] != '\'') asar_throw_error(2, error_type_block, error_id_invalid_character);
767 48 unsigned int rval=table.table[(unsigned char)str[1]];
768 48 str+=3;
769 48 return rval;
770 }
771
2/2
✓ Branch 0 taken 1828366 times.
✓ Branch 1 taken 1792 times.
1830158 if (is_digit(*str))
772 {
773 const char* end = str;
774
4/4
✓ Branch 0 taken 6398050 times.
✓ Branch 1 taken 1828436 times.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 1828366 times.
8226486 while (is_digit(*end) || *end == '.') end++;
775 914183 string number;
776 1828366 number.assign(str, (int)(end - str));
777 1828366 str = end;
778 1828366 return atof(number);
779 1828366 }
780
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1770 times.
1792 if (is_alpha(*str) || *str=='_' || *str=='.' || *str=='?')
781 {
782 1786 const char * start=str;
783
6/6
✓ Branch 0 taken 14858 times.
✓ Branch 1 taken 2166 times.
✓ Branch 2 taken 224 times.
✓ Branch 3 taken 1942 times.
✓ Branch 4 taken 156 times.
✓ Branch 5 taken 1786 times.
17024 while (is_alnum(*str) || *str == '_' || *str == '.') str++;
784 1786 int len=(int)(str-start);
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1786 times.
1786 while (*str==' ') str++;
786
2/2
✓ Branch 0 taken 894 times.
✓ Branch 1 taken 892 times.
1786 if (*str=='(')
787 {
788 894 str++;
789 // RPG Hacker: This is only here to assure that all strings are still
790 // alive in memory when we call our functions further down
791 double result;
792 while (true)
793 {
794
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 894 times.
894 while (*str==' ') str++;
795 894 string function_name = string(start, len);
796
1/2
✓ Branch 0 taken 894 times.
✗ Branch 1 not taken.
894 if(functions.exists(function_name))
797 {
798 894 current_user_function_name = function_name;
799
3/4
✓ Branch 0 taken 894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 888 times.
✓ Branch 3 taken 6 times.
894 result = functions[function_name]();
800 }
801 else
802 {
803 str++;
804 break;
805 }
806
807
1/2
✓ Branch 0 taken 888 times.
✗ Branch 1 not taken.
888 if (*str==')')
808 {
809 888 str++;
810 return result;
811 }
812 asar_throw_error(2, error_type_block, error_id_malformed_function_call);
813 894 }
814
815 asar_throw_error(2, error_type_block, error_id_function_not_found, start);
816 }
817 else
818 {
819 892 foundlabel=true;
820
821 const char *old_start = start;
822 892 snes_label label_data = labelval(&start);
823 892 int i=(int)label_data.pos;
824 892 foundlabel_static &= label_data.is_static;
825 bool scope_passed = false;
826 bool subscript_passed = false;
827
2/2
✓ Branch 0 taken 600 times.
✓ Branch 1 taken 892 times.
2384 while (str < start)
828 {
829
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 536 times.
600 if (*str == '.') scope_passed = true;
830
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 540 times.
600 if (*(str++) == '[')
831 {
832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (subscript_passed)
833 {
834 asar_throw_error(2, error_type_block, error_id_multiple_subscript_operators);
835 break;
836 }
837 subscript_passed = true;
838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (scope_passed)
839 {
840 asar_throw_error(2, error_type_block, error_id_invalid_subscript);
841 break;
842 }
843 60 string struct_name = substr(old_start, (int)(str - old_start - 1));
844
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
60 i += (int)(eval(0) * object_size(struct_name));
845 60 }
846 }
847
848 892 str=start;
849
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 888 times.
892 if (i==-1) forwardlabel=true;
850 892 return (int)i&0xFFFFFF;
851 }
852 }
853 6 asar_throw_error(2, error_type_block, error_id_invalid_number);
854 return 0.0;
855 }
856
857 2259214 static double sanitize(double val)
858 {
859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2259214 times.
2259214 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
860
3/4
✓ Branch 0 taken 2259214 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2254284 times.
✓ Branch 3 taken 4930 times.
2259214 if (math_round && !default_math_round_off) return trunc(val); // originally used int cast, but that broke numbers > $8000_0000
861 return val;
862 }
863
864 1837756 static double getnum()
865 {
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1837756 times.
1837756 while (*str==' ') str++;
867 #define prefix(sym, func) if (*str == sym) { str+=1; double val=getnum(); return sanitize(func); }
868 #define prefix_dep(sym, func) if (*str == sym) { str+=1; asar_throw_warning(2, warning_id_feature_deprecated, "xkas style numbers ", "remove the #"); double val=getnum(); return sanitize(func); }
869 #define prefix2(sym, sym2, func) if (*str == sym && *(str+1) == sym2) { str+=2; double val=getnum(); return sanitize(func); }
870
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 1837700 times.
1837756 prefix('-', -val);
871
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1837696 times.
1837700 prefix('~', ~(int)val);
872
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1837688 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
1837696 prefix2('<', ':', (int)val>>16);
873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1837688 times.
1837688 prefix('+', val);
874
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1837682 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
1837688 prefix_dep('#' && emulatexkas, val);
875 #undef prefix
876 1837688 return sanitize(getnumcore());
877 }
878
879 75146 int64_t getnum(const char* instr)
880 {
881 75146 return getnum64(instr);
882
883 // randomdude999: perform manual bounds-checking and 2's complement,
884 // to prevent depending on UB
885 double num = math(instr);
886 if(num < 0) {
887 // manual 2's complement
888 if((-num) > (double)UINT32_MAX) {
889 // out of bounds, return closest inbounds value
890 // (this value is the most negative value possible)
891 return ((uint32_t)INT32_MAX)+1;
892 }
893 return ~((uint32_t)(-num))+1;
894 } else {
895 if(num > (double)UINT32_MAX) {
896 // out of bounds, return closest inbounds value
897 return UINT32_MAX;
898 }
899 return (uint32_t)num;
900 }
901 }
902
903 75554 int64_t getnum64(const char* instr)
904 {
905 // randomdude999: perform manual bounds-checking
906 // to prevent depending on UB
907 75554 double num = math(instr);
908
1/2
✓ Branch 0 taken 75530 times.
✗ Branch 1 not taken.
75530 if(num < (double)INT64_MIN) {
909 return INT64_MIN;
910
1/2
✓ Branch 0 taken 75530 times.
✗ Branch 1 not taken.
75530 } else if(num > (double)INT64_MAX) {
911 return INT64_MAX;
912 }
913 75530 return (int64_t)num;
914 }
915
916 // RPG Hacker: Same function as above, but doesn't truncate our number via int conversion
917 633552 double getnumdouble(const char * instr)
918 {
919 633552 return math(instr);
920 }
921
922
923 static double oper_wrapped_throw(asar_error_id errid)
924 {
925 asar_throw_error(2, error_type_block, errid);
926 return 0.0;
927 }
928
929 1627388 static double eval(int depth)
930 {
931 1627388 const char* posneglabel = str;
932 1627388 string posnegname = posneglabelname(&posneglabel, false);
933
934
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 1627276 times.
1627388 if (posnegname.length() > 0)
935 {
936
3/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
112 if (*posneglabel != '\0' && *posneglabel != ')') goto notposneglabel;
937
938 56 str = posneglabel;
939
940 56 foundlabel=true;
941
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 8 times.
56 if (*(posneglabel-1) == '+') forwardlabel=true;
942
1/2
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
56 snes_label label_data = labelval(posnegname);
943 56 foundlabel_static &= label_data.is_static;
944 56 return label_data.pos & 0xFFFFFF;
945 }
946
1/2
✓ Branch 0 taken 813666 times.
✗ Branch 1 not taken.
1627304 notposneglabel:
947
1/2
✓ Branch 0 taken 813666 times.
✗ Branch 1 not taken.
2440998 recurseblock rec;
948
2/2
✓ Branch 0 taken 1627320 times.
✓ Branch 1 taken 12 times.
1627332 double left=getnum();
949 double right;
950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1627320 times.
1627320 while (*str==' ') str++;
951
6/6
✓ Branch 0 taken 421708 times.
✓ Branch 1 taken 1627082 times.
✓ Branch 2 taken 421548 times.
✓ Branch 3 taken 160 times.
✓ Branch 4 taken 421488 times.
✓ Branch 5 taken 60 times.
2048790 while (*str && *str != ')' && *str != ','&& *str != ']')
952 {
953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 421488 times.
421488 while (*str==' ') str++;
954 // why was this an int cast
955
3/4
✓ Branch 0 taken 421488 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 420722 times.
✓ Branch 3 taken 766 times.
421488 if (math_round && !default_math_round_off) left=trunc(left);
956 #define oper(name, thisdepth, contents) \
957 if (!strncmp(str, name, strlen(name))) \
958 { \
959 if (math_pri || default_math_pri) \
960 { \
961 if (depth<=thisdepth) \
962 { \
963 str+=strlen(name); \
964 right=eval(thisdepth+1); \
965 } \
966 else return left; \
967 } \
968 else \
969 { \
970 str+=strlen(name); \
971 right=getnum(); \
972 } \
973 left=sanitize(contents); \
974 continue; \
975 }
976
9/14
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 421476 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
421488 oper("**", 4, pow((double)left, (double)right));
977
10/14
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 421452 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 8 times.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 8 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 24 times.
✗ Branch 13 not taken.
421476 oper("*", 3, left*right);
978
10/18
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 421440 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
421452 oper("/", 3, right != 0.0 ? left / right : oper_wrapped_throw(error_id_division_by_zero));
979
1/18
✗ Branch 0 not taken.
✓ Branch 1 taken 421440 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.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
421440 oper("%", 3, right != 0.0 ? fmod((double)left, (double)right) : oper_wrapped_throw(error_id_modulo_by_zero));
980
11/14
✓ Branch 0 taken 421256 times.
✓ Branch 1 taken 184 times.
✓ Branch 2 taken 210956 times.
✓ Branch 3 taken 210300 times.
✓ Branch 4 taken 668 times.
✓ Branch 5 taken 210288 times.
✓ Branch 6 taken 210956 times.
✓ Branch 7 taken 12 times.
✓ Branch 8 taken 210956 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 210288 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 421244 times.
✗ Branch 13 not taken.
421440 oper("+", 2, left+right);
981
10/14
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 44 times.
✓ Branch 4 taken 90 times.
✓ Branch 5 taken 44 times.
✓ Branch 6 taken 134 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 134 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 44 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 178 times.
✗ Branch 13 not taken.
184 oper("-", 2, left-right);
982
1/18
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
6 oper("<<", 1, right >= 0.0 ? (int64_t)left<<(uint64_t)right : oper_wrapped_throw(error_id_negative_shift));
983
1/18
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
6 oper(">>", 1, right >= 0.0 ? (int64_t)left>>(uint64_t)right : oper_wrapped_throw(error_id_negative_shift));
984
1/14
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
6 oper("&", 0, (int64_t)left&(int64_t)right);
985
1/14
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
6 oper("|", 0, (int64_t)left|(int64_t)right);
986
1/14
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
6 oper("^", 0, (int64_t)left^(int64_t)right);
987
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 asar_throw_error(2, error_type_block, error_id_unknown_operator);
988 #undef oper
989 }
990 return left;
991 1627388 }
992
993 //static autoptr<char*> freeme;
994 709106 double math(const char * s)
995 {
996 //free(freeme);
997 //freeme=NULL;
998 709106 foundlabel=false;
999 709106 foundlabel_static=true;
1000 709106 forwardlabel=false;
1001 double rval;
1002
1003
3/4
✓ Branch 0 taken 709106 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3118 times.
✓ Branch 3 taken 705988 times.
709106 if(math_pri || default_math_pri)
1004 {
1005 3118 str = s;
1006 3118 rval = eval(0);
1007 }
1008 else
1009 {
1010 705988 str = s;
1011 705988 rval = eval(0);
1012
1013 double pri_rval = NAN;
1014
1015 705970 suppress_all_warnings = true;
1016 705970 math_pri = true;
1017 try
1018 {
1019 705970 str = s;
1020
1/2
✓ Branch 0 taken 705970 times.
✗ Branch 1 not taken.
705970 pri_rval = eval(0);
1021 }
1022 catch (errfatal&) {}
1023 705970 suppress_all_warnings = false;
1024 705970 math_pri = false;
1025
1026
1/2
✓ Branch 0 taken 705970 times.
✗ Branch 1 not taken.
705970 if (pri_rval != rval)
1027 {
1028 asar_throw_warning(2, warning_id_feature_deprecated, "xkas style left to right math ", "apply order of operations");
1029 }
1030 }
1031
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 709082 times.
709088 if (*str)
1032 {
1033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (*str == ',') asar_throw_error(2, error_type_block, error_id_invalid_input);
1034 6 else asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
1035 }
1036 709082 return rval;
1037 }
1038
1039 562 void initmathcore()
1040 {
1041 562 functions.reset();
1042 562 builtin_functions.each([](const char* key, double (*val)()) {
1043 35406 functions[key] = val;
1044
1/2
✓ Branch 0 taken 35406 times.
✗ Branch 1 not taken.
53109 functions[STR "_" + key] = val;
1045 35406 });
1046 562 user_functions.reset();
1047 562 }
1048
1049 558 void deinitmathcore()
1050 {
1051 //not needed
1052 558 }
1053