asar coverage - build #78


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-01-18 12:18:33
Lines:
409/457
89.5%
Functions:
76/102
74.5%
Branches:
345/578
59.7%

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