asar coverage - build #174


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-01-28 00:31:05
Lines:
443/491
90.2%
Functions:
83/103
80.6%
Branches:
450/783
57.5%

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