asar coverage - build #151


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-01-24 21:19:15
Lines:
456/496
91.9%
Functions:
82/101
81.2%
Branches:
469/835
56.2%

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 42 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
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 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
6/6
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 428 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 48 times.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 238 times.
532 if (cachedfiles[i].used && cachedfiles[i].filename == combinedname)
65 {
66 56 cachedfilehandle = &cachedfiles[i];
67 28 break;
68 }
69 }
70
71
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 28 times.
42 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
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 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
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
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
5/6
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 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
3/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
16 if(pass && !structs.exists(name)) asar_throw_error(2, error_type_block, error_id_struct_not_found, name);
133
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
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
4/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 38 times.
76 if(pass && !structs.exists(name)) asar_throw_error(2, error_type_block, error_id_struct_not_found, name);
140
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 38 times.
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
3/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
20 if(!labels.exists(name)) asar_throw_error(2, error_type_block, error_id_label_not_found, name);
149 20 foundlabel = true;
150
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
20 snes_label label_data = labels.find(name);
151 20 foundlabel_static &= label_data.is_static;
152 20 label = label_data.pos & 0xFFFFFF;
153
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
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
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
20 if(next_label == 0xFFFFFF) asar_throw_warning(2, warning_id_datasize_last_label, name);
160
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
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 148 const char * strpos = str;
171 296 str++;
172
4/6
✓ Branch 0 taken 3788 times.
✓ Branch 1 taken 296 times.
✓ Branch 2 taken 3788 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1894 times.
✗ Branch 5 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
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
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
2/4
✓ Branch 0 taken 296 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 148 times.
✗ Branch 3 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 128 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
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 asar_throw_warning(2, warning_id_feature_deprecated, "quoted symbolic arguments", "Remove the quotations");
197
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 string arg = get_string_argument();
198 4 int i = 0;
199
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 if(is_alpha(arg[i]) || arg[i] == '_') i++;
200
7/8
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 24 times.
✓ Branch 7 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
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return arg;
203 8 }
204
5/6
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 102 times.
248 if(is_alpha(*str) || *str == '_') str++;
205
8/8
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 446 times.
✓ Branch 3 taken 446 times.
✓ Branch 4 taken 628 times.
✓ Branch 5 taken 248 times.
✓ Branch 6 taken 464 times.
✓ Branch 7 taken 124 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
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
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
1/2
✓ Branch 0 taken 124 times.
✗ Branch 1 not taken.
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 34 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
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
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
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
88 double first = get_double_argument();
260
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
88 require_next_parameter();
261
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3 times.
120 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 2 double asar_bank(double a)
272 {
273 4 return (int)a >> 16;
274 }
275
276
277 3 double asar_logical_nand(double a, double b)
278 {
279
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
6 return !(a && b);
280 }
281
282
283 3 double asar_logical_nor(double a, double b)
284 {
285
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
6 return !(a || b);
286 }
287
288
289 3 double asar_logical_xor(double a, double b)
290 {
291 6 return !!a ^ !!b;
292 }
293
294 5 double asar_max(double a, double b)
295 {
296
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
10 return a > b ? a : b;
297 }
298
299 5 double asar_min(double a, double b)
300 {
301
4/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 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 11 times.
✓ Branch 1 taken 11 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/8
✗ Branch 0 not taken.
✓ Branch 1 taken 18 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.
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
6/8
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
46 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 16 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 24 int length = count;
381
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
24 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
1/2
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
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
2/4
✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
✗ Branch 3 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 9 times.
✓ Branch 3 taken 9 times.
36 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return default_value;
403
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7 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/6
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 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 28 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
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
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 18 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
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
36 cachedfile * fhandle = opencachedfile(name, false);
435
3/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 9 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 10 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
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 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
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (filesystem->get_last_error() == vfe_doesnt_exist)
447 {
448 6 return 1;
449 }
450 else
451 {
452 return 2;
453 }
454 }
455 6 return 0;
456 }
457
458 // Returns the size of the specified file.
459 4 static double asar_filesize()
460 {
461
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 string name = get_string_argument();
462
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 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
2/4
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 62 times.
✗ Branch 3 not taken.
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
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 double number = get_double_argument();
479
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 require_next_parameter();
480
481 // Hue hue hue... ass!
482 // OK, sorry, I apologize.
483
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 string asstring = ftostrvar(number, get_double_argument());
484
485 // Some hacky shenanigans with variables going on here
486
1/2
✓ Branch 0 taken 2 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
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
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
2/4
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 return (double)object_size(get_symbol_argument());
508 }
509
510 20 static double asar_datasize_wrapper()
511 {
512
2/4
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
20 return (double)data_size(get_symbol_argument());
513 }
514
515 24 static double asar_stringsequal()
516 {
517
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
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.
54 return (strcmp(string1, get_string_argument()) == 0 ? 1.0 : 0.0);
520 24 }
521
522 12 static double asar_stringsequalnocase()
523 {
524
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 string string1 = get_string_argument();
525
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 require_next_parameter();
526
3/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ 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
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 string t = "\"";
534
4/8
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
20 return (t += get_string_argument() + "\"");
535 8 }
536
537 17 string result;
538 17 bool is_symbolic = true;
539 17 int parlevel=0;
540 17 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
2/4
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
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
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
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
3/6
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✗ Branch 5 not taken.
63 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
6/6
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 37 times.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 25 times.
124 if(!is_alpha(user_function.content[i]) && user_function.content[i] != '_')
679 {
680
1/2
✓ Branch 0 taken 37 times.
✗ Branch 1 not taken.
74 real_content += user_function.content[i];
681 74 continue;
682 }
683 25 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
6/8
✓ 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.
✓ Branch 6 taken 21 times.
✓ Branch 7 taken 20 times.
82 if(potential_arg && (!is_alnum(user_function.content[next_char]) && user_function.content[next_char] != '_'))
690 {
691
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
42 real_content += args[j];
692 42 i = next_char - 1;
693 21 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
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
72 real_content += user_function.content[i];
700 }
701
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
8 real_content += user_function.content[i];
702 }
703 }
704
1/2
✓ Branch 0 taken 15 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
4/6
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 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 1837880 static double getnumcore()
744 {
745
2/2
✓ Branch 0 taken 536 times.
✓ Branch 1 taken 1837344 times.
1837880 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 6982 times.
✓ Branch 1 taken 1830362 times.
1837344 if (*str=='$')
754 {
755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6982 times.
6982 if (!is_xdigit(str[1])) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
756
2/2
✓ Branch 0 taken 3491 times.
✓ Branch 1 taken 3491 times.
6982 if (to_lower(str[2])=='x') return -42;//let str get an invalid value so it'll throw an invalid operator later on
757 6982 return strtoull(str+1, const_cast<char**>(&str), 16);
758 }
759
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 1830314 times.
1830362 if (*str=='%')
760 {
761
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
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 1830266 times.
1830314 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 1828390 times.
✓ Branch 1 taken 1876 times.
1830266 if (is_digit(*str))
772 {
773 914195 const char* end = str;
774
6/6
✓ Branch 0 taken 4113267 times.
✓ Branch 1 taken 4113267 times.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 1828390 times.
✓ Branch 4 taken 3199072 times.
✓ Branch 5 taken 914195 times.
8226534 while (is_digit(*end) || *end == '.') end++;
775 914195 string number;
776
1/2
✓ Branch 0 taken 914195 times.
✗ Branch 1 not taken.
1828390 number.assign(str, (int)(end - str));
777 1828390 str = end;
778 1828390 return atof(number);
779 1828390 }
780
9/10
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 1854 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 6 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 935 times.
✓ Branch 9 taken 3 times.
1876 if (is_alpha(*str) || *str=='_' || *str=='.' || *str=='?')
781 {
782 1870 const char * start=str;
783
8/8
✓ Branch 0 taken 8978 times.
✓ Branch 1 taken 8978 times.
✓ Branch 2 taken 1167 times.
✓ Branch 3 taken 1167 times.
✓ Branch 4 taken 192 times.
✓ Branch 5 taken 1870 times.
✓ Branch 6 taken 8043 times.
✓ Branch 7 taken 935 times.
17956 while (is_alnum(*str) || *str == '_' || *str == '.') str++;
784 1870 int len=(int)(str-start);
785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1870 times.
1870 while (*str==' ') str++;
786
2/2
✓ Branch 0 taken 894 times.
✓ Branch 1 taken 976 times.
1870 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
1/2
✓ Branch 0 taken 447 times.
✗ Branch 1 not taken.
894 string function_name = string(start, len);
796
2/4
✓ Branch 0 taken 894 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 447 times.
✗ Branch 3 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 444 return result;
811 }
812 asar_throw_error(2, error_type_block, error_id_malformed_function_call);
813
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 444 times.
894 }
814
815 asar_throw_error(2, error_type_block, error_id_function_not_found, start);
816 }
817 else
818 {
819 976 foundlabel=true;
820
821 488 const char *old_start = start;
822
1/2
✓ Branch 0 taken 488 times.
✗ Branch 1 not taken.
976 snes_label label_data = labelval(&start);
823 976 int i=(int)label_data.pos;
824 976 foundlabel_static &= label_data.is_static;
825 488 bool scope_passed = false;
826 488 bool subscript_passed = false;
827
2/2
✓ Branch 0 taken 600 times.
✓ Branch 1 taken 976 times.
2064 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 30 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
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
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 976 str=start;
849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 976 times.
976 if (i==-1) forwardlabel=true;
850 976 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 2259406 static double sanitize(double val)
858 {
859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2259406 times.
2259406 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
860
3/4
✓ Branch 0 taken 2259406 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2254476 times.
✓ Branch 3 taken 4930 times.
2259406 if (math_round && !default_math_round_off) return trunc(val); // originally used int cast, but that broke numbers > $8000_0000
861 2465 return val;
862 }
863
864 1837948 static double getnum()
865 {
866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1837948 times.
1837948 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 1837892 times.
1837948 prefix('-', -val);
871
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1837888 times.
1837892 prefix('~', ~(int)val);
872
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1837880 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
1837888 prefix2('<', ':', (int)val>>16);
873
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1837880 times.
1837880 prefix('+', val);
874
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1837874 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
1837880 prefix_dep('#' && emulatexkas, val);
875 #undef prefix
876 1837880 return sanitize(getnumcore());
877 }
878
879 75230 int64_t getnum(const char* instr)
880 {
881 75230 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 75650 int64_t getnum64(const char* instr)
904 {
905 // randomdude999: perform manual bounds-checking
906 // to prevent depending on UB
907 75650 double num = math(instr);
908
2/2
✓ Branch 0 taken 37813 times.
✓ Branch 1 taken 37813 times.
75626 if(num < (double)INT64_MIN) {
909 return INT64_MIN;
910
2/2
✓ Branch 0 taken 37813 times.
✓ Branch 1 taken 37813 times.
75626 } else if(num > (double)INT64_MAX) {
911 return INT64_MAX;
912 }
913 75626 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 1627580 static double eval(int depth)
930 {
931 1627580 const char* posneglabel = str;
932
1/2
✓ Branch 0 taken 813790 times.
✗ Branch 1 not taken.
1627580 string posnegname = posneglabelname(&posneglabel, false);
933
934
4/4
✓ Branch 0 taken 813846 times.
✓ Branch 1 taken 813734 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 813734 times.
1627580 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
2/4
✓ Branch 0 taken 56 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 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 813762 times.
✗ Branch 1 not taken.
1627524 notposneglabel:
947
1/2
✓ Branch 0 taken 813762 times.
✗ Branch 1 not taken.
2441286 recurseblock rec;
948
2/2
✓ Branch 0 taken 1627512 times.
✓ Branch 1 taken 12 times.
1627524 double left=getnum();
949 double right;
950
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1627512 times.
1627512 while (*str==' ') str++;
951
8/8
✓ Branch 0 taken 422190 times.
✓ Branch 1 taken 1626792 times.
✓ Branch 2 taken 421628 times.
✓ Branch 3 taken 562 times.
✓ Branch 4 taken 421518 times.
✓ Branch 5 taken 110 times.
✓ Branch 6 taken 210744 times.
✓ Branch 7 taken 30 times.
2048982 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.
421491 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.
421484 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.
421455 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.
526918 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.
251 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 813747 return left;
991 1627580 }
992
993 //static autoptr<char*> freeme;
994 709202 double math(const char * s)
995 {
996 //free(freeme);
997 //freeme=NULL;
998 709202 foundlabel=false;
999 709202 foundlabel_static=true;
1000 709202 forwardlabel=false;
1001 double rval;
1002
1003
3/4
✓ Branch 0 taken 709202 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3118 times.
✓ Branch 3 taken 706084 times.
709202 if(math_pri || default_math_pri)
1004 {
1005 3118 str = s;
1006 3118 rval = eval(0);
1007 }
1008 else
1009 {
1010 706084 str = s;
1011 706084 rval = eval(0);
1012
1013 353033 double pri_rval = NAN;
1014
1015 706066 suppress_all_warnings = true;
1016 706066 math_pri = true;
1017 try
1018 {
1019 706066 str = s;
1020
1/2
✓ Branch 0 taken 706066 times.
✗ Branch 1 not taken.
706066 pri_rval = eval(0);
1021 }
1022 catch (errfatal&) {}
1023 706066 suppress_all_warnings = false;
1024 706066 math_pri = false;
1025
1026
2/2
✓ Branch 0 taken 353033 times.
✓ Branch 1 taken 353033 times.
706066 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 709178 times.
709184 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 709178 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
3/6
✓ Branch 0 taken 35406 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 17703 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 17703 times.
✗ Branch 5 not taken.
35406 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