asar coverage - build #239


src/asar/
File: src/asar/asar_math.cpp
Date: 2025-02-21 02:53:30
Lines:
445/490
90.8%
Functions:
83/105
79.0%
Branches:
443/732
60.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 24 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 1543 void closecachedfiles()
106 {
107
2/2
✓ Branch 0 taken 24688 times.
✓ Branch 1 taken 1543 times.
26231 for (int i = 0; i < numcachedfiles; i++)
108 {
109
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24664 times.
24688 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 1543 cachedfileindex = 0;
122 1543 }
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/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
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 30 labels.each([&selected_label, label](const char *key, snes_label current_label){
151
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
90 if(label < current_label.id && current_label.id < selected_label.id){
152 24 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 666 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 }
176
177 //only returns alphanumeric (and _) starting with alpha or _
178 1116 string get_symbol_argument()
179 {
180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1116 times.
1116 while (*str==' ') str++; //is this proper? Dunno yet.
181 558 const char * strpos = str;
182
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 1050 times.
1116 if(is_ualpha(*str)) str++;
183
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++;
184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1116 times.
1116 if(strpos == str){
185 //error nothing was read, this is a placeholder error
186 asar_throw_error(2, error_type_block, error_id_string_literal_not_terminated);
187 }
188
189 1116 string symbol = string(strpos, (int)(str - strpos));
190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1116 times.
1116 while (*str==' ') str++; //eat spaces
191 1116 return symbol;
192 }
193
194 1380 double get_double_argument()
195 {
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1380 times.
1380 while (*str==' ') str++;
197 1380 double result = eval(0);
198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1380 times.
1380 while (*str==' ') str++; //eat spaces
199 1380 return result;
200 }
201
202 //will eat the comma
203 252 bool has_next_parameter()
204 {
205
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 180 times.
252 if (*str==',')
206 {
207 72 str++;
208 72 return true;
209 }
210 90 return false;
211 }
212
213 570 void require_next_parameter()
214 {
215
1/2
✓ Branch 0 taken 570 times.
✗ Branch 1 not taken.
570 if (*str==',')
216 {
217 570 str++;
218 570 return;
219 }
220 asar_throw_error(2, error_type_block, error_id_require_parameter);
221 }
222
223 48 template <typename F> double asar_unary_wrapper()
224 {
225
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
48 return F()(get_double_argument());
226 }
227
228 12 template <double (*F)(double)> double asar_unary_wrapper()
229 {
230 12 return F(get_double_argument());
231 }
232
233 //possibly restrict type T in the future....
234 //first a case for functors
235 264 template <typename F> double asar_binary_wrapper()
236 {
237
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
264 double first = get_double_argument();
238
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
264 require_next_parameter();
239
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 9 times.
264 return F()(first, get_double_argument());
240 }
241 //this could be DRY with if constexpr....oh well
242 156 template <double (*F)(double, double)> double asar_binary_wrapper()
243 {
244 156 double first = get_double_argument();
245 156 require_next_parameter();
246 156 return F(first, get_double_argument());
247 }
248
249 3 double asar_bank(double a)
250 {
251 6 return (int)a >> 16;
252 }
253
254
255 9 double asar_logical_nand(double a, double b)
256 {
257
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);
258 }
259
260
261 9 double asar_logical_nor(double a, double b)
262 {
263
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);
264 }
265
266
267 9 double asar_logical_xor(double a, double b)
268 {
269 18 return !!a ^ !!b;
270 }
271
272 15 double asar_max(double a, double b)
273 {
274
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;
275 }
276
277 15 double asar_min(double a, double b)
278 {
279
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;
280 }
281
282 18 double asar_clamp()
283 {
284 18 double value = get_double_argument();
285 18 require_next_parameter();
286 18 double low = get_double_argument();
287 18 require_next_parameter();
288 18 double high = get_double_argument();
289
290 18 return asar_max(low, asar_min(high, value));
291 }
292
293 12 double asar_safediv()
294 {
295 12 double dividend = get_double_argument();
296 12 require_next_parameter();
297 12 double divisor = get_double_argument();
298 12 require_next_parameter();
299 12 double default_value = get_double_argument();
300
301
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 return divisor == 0.0 ? default_value : dividend / divisor;
302 }
303
304 48 double asar_select()
305 {
306 48 double selector = get_double_argument();
307 48 require_next_parameter();
308 48 double a = get_double_argument();
309 48 require_next_parameter();
310 48 double b = get_double_argument();
311
312
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
48 return selector == 0.0 ? b : a;
313 }
314
315 174 double asar_snestopc_wrapper()
316 {
317 174 return snestopc(get_double_argument());
318 }
319
320 126 double asar_pctosnes_wrapper()
321 {
322 126 return pctosnes(get_double_argument());
323 }
324
325 18 double asar_realbase_wrapper()
326 {
327 18 foundlabel = true;
328 18 return realsnespos;
329 }
330
331 72 double asar_pc_wrapper()
332 {
333 72 foundlabel = true;
334 72 return snespos;
335 }
336
337 132 template <int count> double asar_read()
338 {
339 132 int target = get_double_argument();
340 132 int addr=snestopc_pick(target);
341
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
132 if(has_next_parameter())
342 {
343 double default_value = get_double_argument();
344 if (addr<0) return default_value;
345 else if (addr+count>romlen_r) return default_value;
346 }
347 else
348 {
349
1/6
✗ 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.
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());
350
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
150 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());
351 }
352
353 60 unsigned int value = 0;
354
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 60 times.
312 for(int i = 0; i < count; i++)
355 {
356 192 value |= romdata_r[addr+i] << (8 * i);
357 }
358 120 return value;
359 }
360
361 216 template <int count> double asar_canread()
362 {
363 108 int length = count;
364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
108 if(!length)
365 {
366 length = get_double_argument();
367 }
368 216 int addr=snestopc_pick(get_double_argument());
369
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;
370 108 else return 1;
371 }
372
373 168 template <size_t count> double asar_readfile()
374 {
375 static_assert(count && count <= 4, "invalid count"); //1-4 inclusive
376
377
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
168 string name = get_string_argument();
378
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 require_next_parameter();
379
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 size_t offset = get_double_argument();
380
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
168 bool should_error = !has_next_parameter();
381
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
168 cachedfile * fhandle = opencachedfile(name, should_error);
382
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 48 times.
168 if(!should_error)
383 {
384
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
72 double default_value = get_double_argument();
385
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;
386
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
60 if (offset < 0 || offset + count > fhandle->filesize) return default_value;
387 }
388 else
389 {
390
2/12
✓ 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.
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());
391
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 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());
392 }
393
394 132 unsigned char data[4] = { 0, 0, 0, 0 };
395
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
132 filesystem->read_file(fhandle->filehandle, data, offset, count);
396
397 66 unsigned int value = 0;
398
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 66 times.
348 for(size_t i = 0; i < count; i++)
399 {
400 216 value |= data[i] << (8 * i);
401 }
402
403 132 return value;
404 168 }
405
406 84 template <size_t count> double asar_canreadfile()
407 {
408
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
84 string name = get_string_argument();
409
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 require_next_parameter();
410
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
84 size_t offset = get_double_argument();
411 42 size_t length = count;
412 if(!count)
413 {
414
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 require_next_parameter();
415
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
24 length = get_double_argument();
416 }
417
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);
418
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;
419
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
72 if (offset < 0 || offset + length > fhandle->filesize) return 0;
420 24 return 1;
421 84 }
422
423 // 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
424 36 static double asar_filestatus()
425 {
426
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);
427
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)
428 {
429
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (filesystem->get_last_error() == vfe_doesnt_exist)
430 {
431 9 return 1;
432 }
433 else
434 {
435 return 2;
436 }
437 }
438 9 return 0;
439 }
440
441 // Returns the size of the specified file.
442 6 static double asar_filesize()
443 {
444
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 string name = get_string_argument();
445
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);
446
2/12
✓ 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.
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());
447 6 return (double)fhandle->filesize;
448 6 }
449
450 // Checks whether the specified define is defined.
451 156 static double asar_isdefined()
452 {
453
2/4
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
156 return defines.exists(get_string_argument());
454 }
455
456 // RPG Hacker: What exactly makes this function overly complicated, you ask?
457 // Well, it converts a double to a string and then back to a double.
458 // It was the quickest reliable solution I could find, though, so there's that.
459 12 static double asar_round()
460 {
461
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 double number = get_double_argument();
462
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 require_next_parameter();
463
464 // Hue hue hue... ass!
465 // OK, sorry, I apologize.
466
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());
467
468 // Some hacky shenanigans with variables going on here
469
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 const char * strbackup = str;
470 12 str = asstring;
471
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 double asdouble = (double)getnum();
472 12 str = strbackup;
473
474 12 return asdouble;
475 12 }
476
477 1068 static double asar_structsize_wrapper()
478 {
479
1/2
✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
1068 string symbol = get_symbol_argument();
480
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 18 times.
1068 if(symbol == "..."){
481
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1044 times.
1050 if(!inmacro) asar_throw_error(2, error_type_block, error_id_vararg_sizeof_nomacro);
482
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1038 times.
1044 if(numvarargs == -1) asar_throw_error(2, error_type_block, error_id_macro_not_varadic, "sizeof(...)");
483 1038 return numvarargs;
484 }
485
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return (double)struct_size(symbol);
486 1068 }
487
488 18 static double asar_objectsize_wrapper()
489 {
490
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());
491 }
492
493 30 static double asar_datasize_wrapper()
494 {
495
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());
496 }
497
498 36 static double asar_stringsequal()
499 {
500
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 string string1 = get_string_argument();
501
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 require_next_parameter();
502
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);
503 36 }
504
505 18 static double asar_stringsequalnocase()
506 {
507
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 string string1 = get_string_argument();
508
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 require_next_parameter();
509
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);
510 18 }
511
512 static double asar_char()
513 {
514 string string1 = get_string_argument();
515 require_next_parameter();
516 int offset = get_double_argument();
517 if(offset >= string1.length()) asar_throw_error(2, error_type_block, error_id_oob, offset, string1.length());
518 return string1[offset];
519 }
520
521 static double asar_strlen()
522 {
523 return get_string_argument().length();
524 }
525
526 102 string copy_arg()
527 {
528
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 90 times.
102 if(*str == '"')
529 {
530
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 string t = "\"";
531
4/8
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
24 return (t += get_string_argument() + "\"");
532 12 }
533
534 45 string result;
535 45 bool is_symbolic = true;
536 45 int parlevel=0;
537 45 int i = 0;
538
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] != ')'))
539 {
540 90 is_symbolic &= is_ualnum(str[i]);
541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(str[i] == '(') parlevel++;
542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 else if(str[i] == ')') parlevel--;
543 90 i++;
544 }
545
2/4
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
90 result += string(str, i);
546 90 str += i;
547
548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(!is_symbolic)
549 {
550 const char *oldstr=str;
551 str = (const char *)result;
552 result = ftostr(eval(0));
553 str = oldstr;
554 }
555 45 return result;
556 90 }
557
558 assocarr<double (*)()> builtin_functions =
559 {
560 {"sqrt", asar_unary_wrapper<sqrt>},
561 {"sin", asar_unary_wrapper<sin>},
562 {"cos", asar_unary_wrapper<cos>},
563 {"tan", asar_unary_wrapper<tan>},
564 {"asin", asar_unary_wrapper<asin>},
565 {"acos", asar_unary_wrapper<acos>},
566 {"atan", asar_unary_wrapper<atan>},
567 {"arcsin", asar_unary_wrapper<asin>},
568 {"arccos", asar_unary_wrapper<acos>},
569 {"arctan", asar_unary_wrapper<atan>},
570 {"log", asar_unary_wrapper<log>},
571 {"log10", asar_unary_wrapper<log10>},
572 {"log2", asar_unary_wrapper<log2>},
573
574 {"ceil", asar_unary_wrapper<ceil>},
575 {"floor", asar_unary_wrapper<floor>},
576
577 {"read1", asar_read<1>}, //This handles the safe and unsafe variant
578 {"read2", asar_read<2>},
579 {"read3", asar_read<3>},
580 {"read4", asar_read<4>},
581 {"canread", asar_canread<0>},
582 {"canread1", asar_canread<1>},
583 {"canread2", asar_canread<2>},
584 {"canread3", asar_canread<3>},
585 {"canread4", asar_canread<4>},
586
587 {"readfile1", asar_readfile<1>},
588 {"readfile2", asar_readfile<2>},
589 {"readfile3", asar_readfile<3>},
590 {"readfile4", asar_readfile<4>},
591 {"canreadfile", asar_canreadfile<0>},
592 {"canreadfile1", asar_canreadfile<1>},
593 {"canreadfile2", asar_canreadfile<2>},
594 {"canreadfile3", asar_canreadfile<3>},
595 {"canreadfile4", asar_canreadfile<4>},
596
597 {"filesize", asar_filesize},
598 {"getfilestatus", asar_filestatus},
599
600 {"defined", asar_isdefined},
601
602 {"snestopc", asar_snestopc_wrapper},
603 {"pctosnes", asar_pctosnes_wrapper},
604 {"realbase", asar_realbase_wrapper},
605 {"pc", asar_pc_wrapper},
606
607 {"max", asar_binary_wrapper<asar_max>},
608 {"min", asar_binary_wrapper<asar_min>},
609 {"clamp", asar_clamp},
610
611 {"safediv", asar_safediv},
612
613 {"select", asar_select},
614 {"bank", asar_unary_wrapper<asar_bank>},
615 {"not", asar_unary_wrapper<std::logical_not<unsigned int>>},
616 {"equal", asar_binary_wrapper<std::equal_to<double>>},
617 {"notequal", asar_binary_wrapper<std::not_equal_to<double>>},
618 {"less", asar_binary_wrapper<std::less<double>>},
619 {"lessequal", asar_binary_wrapper<std::less_equal<double>>},
620 {"greater", asar_binary_wrapper<std::greater<double>>},
621 {"greaterequal", asar_binary_wrapper<std::greater_equal<double>>},
622
623 {"and", asar_binary_wrapper<std::logical_and<unsigned int>>},
624 {"or", asar_binary_wrapper<std::logical_or<unsigned int>>},
625 {"nand", asar_binary_wrapper<asar_logical_nand>},
626 {"nor", asar_binary_wrapper<asar_logical_nor>},
627 {"xor", asar_binary_wrapper<asar_logical_xor>},
628
629 {"round", asar_round},
630
631 {"sizeof", asar_structsize_wrapper},
632 {"objectsize", asar_objectsize_wrapper},
633 {"datasize", asar_datasize_wrapper},
634
635 {"stringsequal", asar_stringsequal},
636 {"stringsequalnocase", asar_stringsequalnocase},
637 {"char", asar_char},
638 {"stringlength", asar_strlen}
639 };
640
641 assocarr<double (*)()> functions;
642
643 struct funcdat {
644 autoptr<char*> name;
645 int numargs;
646 autoptr<char*> argbuf;//this one isn't used, it's just to free it up
647 autoptr<char**> arguments;
648 autoptr<char*> content;
649 };
650 static assocarr<funcdat> user_functions;
651
652 66 static double asar_call_user_function()
653 {
654 33 autoarray<string> args;
655
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 funcdat &user_function = user_functions[current_user_function_name];
656 33 string real_content;
657
658
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 while (*str==' ') str++;
659 66 bool has_next = *str != ')';
660
661
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 66 times.
168 for (int i=0;i<user_function.numargs;i++)
662 {
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if(!has_next)
664 {
665 asar_throw_error(2, error_type_block, error_id_expected_parameter, current_user_function_name);
666 }
667
2/4
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
153 args[i] = copy_arg();
668
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
102 has_next = has_next_parameter();
669 }
670
671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if(has_next)
672 {
673 asar_throw_error(2, error_type_block, error_id_unexpected_parameter, current_user_function_name);
674 }
675
676
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 66 times.
318 for(int i=0; user_function.content[i]; i++)
677 {
678
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 114 times.
252 if(!is_ualpha(user_function.content[i]))
679 {
680
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 real_content += user_function.content[i];
681 138 continue;
682 }
683 57 bool found = false;
684
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 114 times.
312 for (int j=0;user_function.arguments[j];j++)
685 {
686 //this should *always* have a null term or another character after
687 198 bool potential_arg = stribegin(user_function.content+i, user_function.arguments[j]);
688 198 int next_char = i+strlen(user_function.arguments[j]);
689
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]))
690 {
691
2/4
✓ Branch 0 taken 102 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
102 real_content += args[j];
692 102 i = next_char - 1;
693 51 found = true;
694 }
695 }
696
697
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 102 times.
114 if(!found){
698
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 12 times.
120 for(; is_ualnum(user_function.content[i]); i++){
699
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 real_content += user_function.content[i];
700 }
701
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 real_content += user_function.content[i];
702 }
703 }
704
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
66 const char * oldstr=str;
705 66 str = (const char *)real_content;
706
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 double result = eval(0);
707 66 str = oldstr;
708 66 return result;
709 66 }
710
711 108 void createuserfunc(const char * name, const char * arguments, const char * content)
712 {
713
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);
714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if(functions.exists(name)) //functions holds both types.
715 {
716 asar_throw_error(0, error_type_block, error_id_function_redefined, name);
717 }
718 54 funcdat& user_function=user_functions[name];
719 108 user_function.name= duplicate_string(name);
720 108 user_function.argbuf= duplicate_string(arguments);
721 108 user_function.arguments=split(user_function.argbuf, ',', &(user_function.numargs));
722 108 user_function.content= duplicate_string(content);
723
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 108 times.
270 for (int i=0;user_function.arguments[i];i++)
724 {
725
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 162 times.
432 for(int j=0;user_function.arguments[j];j++)
726 {
727
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]))
728 {
729 asar_throw_error(0, error_type_block, error_id_duplicate_param_name, user_function.arguments[i], name);
730 }
731 }
732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 162 times.
162 if (!confirmname(user_function.arguments[i]))
733 {
734 user_functions.remove(name);
735 asar_throw_error(0, error_type_block, error_id_invalid_param_name);
736 }
737 }
738
739 108 functions[name] = asar_call_user_function;
740 108 }
741
742 inline const long hextable[] = {
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, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
746 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
747 -1,-1,10,11,12,13,14,15,-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,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-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,-1,-1,-1,-1,-1,-1,-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 };
755
756 51748 static double getnumcore()
757 {
758
2/2
✓ Branch 0 taken 13903 times.
✓ Branch 1 taken 37845 times.
51748 if (*str=='$')
759 {
760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13903 times.
13903 if (!is_xdigit(*++str)) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
761 6997 uint64_t ret = 0;
762
2/2
✓ Branch 0 taken 47682 times.
✓ Branch 1 taken 13903 times.
61585 while (hextable[0 + *str] >= 0) {
763 47682 ret = (ret << 4) | hextable[0 + *str++];
764 }
765 13903 return ret;
766 }
767
8/8
✓ Branch 0 taken 33689 times.
✓ Branch 1 taken 4156 times.
✓ Branch 2 taken 16862 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 16853 times.
✓ Branch 6 taken 2092 times.
✓ Branch 7 taken 16853 times.
37845 if (is_ualpha(*str) || *str=='.' || *str=='?')
768 {
769 4180 const char * start=str;
770
6/6
✓ Branch 0 taken 18073 times.
✓ Branch 1 taken 18085 times.
✓ Branch 2 taken 294 times.
✓ Branch 3 taken 4180 times.
✓ Branch 4 taken 15997 times.
✓ Branch 5 taken 2092 times.
36158 while (is_ualnum(*str) || *str == '.') str++;
771 4180 int len=(int)(str-start);
772
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 4180 times.
4306 while (*str==' ') str++;
773
2/2
✓ Branch 0 taken 2478 times.
✓ Branch 1 taken 1702 times.
4180 if (*str=='(')
774 {
775 2478 str++;
776 // RPG Hacker: This is only here to assure that all strings are still
777 // alive in memory when we call our functions further down
778 double result;
779 while (true)
780 {
781
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2478 times.
2478 while (*str==' ') str++;
782
1/2
✓ Branch 0 taken 1239 times.
✗ Branch 1 not taken.
1239 string function_name = string(start, len);
783
2/4
✓ Branch 0 taken 2478 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2478 times.
✗ Branch 3 not taken.
2478 if(functions.exists(function_name))
784 {
785
1/2
✓ Branch 0 taken 1239 times.
✗ Branch 1 not taken.
2478 current_user_function_name = function_name;
786
4/4
✓ Branch 0 taken 2469 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 1230 times.
✓ Branch 3 taken 9 times.
2478 result = functions[function_name]();
787 }
788 else
789 {
790 str++;
791 break;
792 }
793
794
1/2
✓ Branch 0 taken 2460 times.
✗ Branch 1 not taken.
2460 if (*str==')')
795 {
796 2460 str++;
797 1230 return result;
798 }
799 asar_throw_error(2, error_type_block, error_id_malformed_function_call);
800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1230 times.
2478 }
801
802 asar_throw_error(2, error_type_block, error_id_function_not_found, start);
803 }
804 else
805 {
806 1702 foundlabel=true;
807
808 853 const char *old_start = start;
809
2/2
✓ Branch 0 taken 848 times.
✓ Branch 1 taken 5 times.
1702 snes_label label_data = labelval(&start);
810 1694 int i=(int)label_data.pos;
811 1694 foundlabel_static &= label_data.is_static;
812
2/2
✓ Branch 0 taken 846 times.
✓ Branch 1 taken 848 times.
1694 if(str < start)
813 {
814
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
120 if ((str = strchr(str, '[')))
815 {
816
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
102 string struct_name = substr(old_start, (int)(str - old_start));
817 102 str++;
818
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));
819 102 }
820 }
821
822 1694 str=start;
823
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1694 times.
1694 if (i==-1) {
824 foundlabel_static = false;
825 forwardlabel=true;
826 }
827 1694 return (int)i&0xFFFFFF;
828 }
829 }
830
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 16634 times.
16853 if (*str=='(')
831 {
832 438 str++;
833 438 double rval=eval(0);
834
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);
835 438 str++;
836 438 return rval;
837 }
838
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 16622 times.
16634 if (*str=='%')
839 {
840
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);
841 24 return strtoull(str+1, const_cast<char**>(&str), 2);
842 }
843
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 16292 times.
16622 if (*str=='\'')
844 {
845
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (!str[1]) asar_throw_error(2, error_type_block, error_id_invalid_character);
846 int orig_val;
847 660 str++;
848
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 str += utf8_val(&orig_val, str);
849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (orig_val == -1) asar_throw_error(0, error_type_block, error_id_invalid_utf8);
850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (*str != '\'') asar_throw_error(2, error_type_block, error_id_invalid_character);
851
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 int64_t rval=thetable.get_val(orig_val);
852
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (rval == -1)
853 {
854 // RPG Hacker: Should be fine to not check return value of codepoint_to_utf8() here, because
855 // our error cases above already made sure that orig_val contains valid data at this point.
856 string u8_str;
857 codepoint_to_utf8(&u8_str, orig_val);
858 asar_throw_error(2, error_type_block, error_id_undefined_char, u8_str.data());
859 }
860 660 str++;
861 660 return rval;
862 }
863
2/2
✓ Branch 0 taken 32513 times.
✓ Branch 1 taken 30 times.
32543 if (is_digit(*str))
864 {
865 16277 const char* end = str;
866
6/6
✓ Branch 0 taken 37198 times.
✓ Branch 1 taken 37215 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 32513 times.
✓ Branch 4 taken 20979 times.
✓ Branch 5 taken 16277 times.
74413 while (is_digit(*end) || *end == '.') end++;
867 16277 string number;
868
1/2
✓ Branch 0 taken 32513 times.
✗ Branch 1 not taken.
32513 number.assign(str, (int)(end - str));
869 32513 str = end;
870 32513 return atof(number);
871 32513 }
872 30 asar_throw_error(2, error_type_block, error_id_invalid_number);
873 }
874
875 51788 inline double sanitize(double val)
876 {
877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51788 times.
51788 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
878 51788 return val;
879 }
880
881 51844 static double getnum()
882 {
883
2/2
✓ Branch 0 taken 7092 times.
✓ Branch 1 taken 51844 times.
58936 while (*str==' ') str++;
884
2/2
✓ Branch 0 taken 13903 times.
✓ Branch 1 taken 37941 times.
51844 if(*str == '$') return sanitize(getnumcore()); //optimize for the common case
885 #define prefix(sym, func) if (*str == sym) { str+=1; double val=getnum(); return sanitize(func); }
886 #define prefix2(sym, sym2, func) if (*str == sym && *(str+1) == sym2) { str+=2; double val=getnum(); return sanitize(func); }
887
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 37869 times.
37941 prefix('-', -val);
888
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 37857 times.
37869 prefix('~', ~(int)val);
889
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 37815 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 30 times.
37857 prefix2('<', ':', (int)val>>16);
890
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37845 times.
37845 prefix('+', val);
891 #undef prefix
892 #undef prefix2
893 37845 return sanitize(getnumcore());
894 }
895
896 29061 int64_t getnum(const char* instr)
897 {
898 29061 double num = math(instr);
899
2/2
✓ Branch 0 taken 14418 times.
✓ Branch 1 taken 14547 times.
28965 if(num < (double)INT64_MIN) {
900 return INT64_MIN;
901
2/2
✓ Branch 0 taken 14418 times.
✓ Branch 1 taken 14547 times.
28965 } else if(num > (double)INT64_MAX) {
902 return INT64_MAX;
903 }
904 28965 return (int64_t)num;
905 }
906
907 // RPG Hacker: Same function as above, but doesn't truncate our number via int conversion
908 5820 double getnumdouble(const char * instr)
909 {
910 5820 return math(instr);
911 }
912
913
914 12 template<asar_error_id errid> static double oper_wrapped_throw()
915 {
916 12 asar_throw_error(2, error_type_block, errid);
917 }
918
919 51822 static double eval(int depth)
920 {
921 51822 const char* posneglabel = str;
922
1/2
✓ Branch 0 taken 25980 times.
✗ Branch 1 not taken.
51822 string posnegname = posneglabelname(&posneglabel, false);
923
924
2/2
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 51664 times.
51822 if (posnegname.length() > 0)
925 {
926
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;
927
928 86 str = posneglabel;
929
930 86 foundlabel=true;
931
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 13 times.
86 if (*(posneglabel-1) == '+') forwardlabel=true;
932
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);
933 86 foundlabel_static &= label_data.is_static;
934 86 return label_data.pos & 0xFFFFFF;
935 }
936
1/2
✓ Branch 0 taken 25800 times.
✗ Branch 1 not taken.
51700 notposneglabel:
937
1/2
✓ Branch 0 taken 25936 times.
✗ Branch 1 not taken.
77672 recurseblock rec;
938
2/2
✓ Branch 0 taken 51680 times.
✓ Branch 1 taken 56 times.
51736 double left=getnum();
939 double right;
940
2/2
✓ Branch 0 taken 7092 times.
✓ Branch 1 taken 51680 times.
58772 while (*str==' ') str++;
941
8/8
✓ Branch 0 taken 16162 times.
✓ Branch 1 taken 50281 times.
✓ Branch 2 taken 15235 times.
✓ Branch 3 taken 927 times.
✓ Branch 4 taken 14971 times.
✓ Branch 5 taken 264 times.
✓ Branch 6 taken 7462 times.
✓ Branch 7 taken 51 times.
66443 while (*str && *str != ')' && *str != ','&& *str != ']')
942 {
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14920 times.
14920 while (*str==' ') str++;
944 #define oper(name, thisdepth, contents) \
945 if (!strncmp(str, name, strlen(name))) \
946 { \
947 if (depth<=thisdepth) \
948 { \
949 str+=strlen(name); \
950 right=eval(thisdepth+1); \
951 } \
952 else return left; \
953 left=contents; \
954 continue; \
955 }
956
4/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14884 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
14920 oper("**", 6, pow((double)left, (double)right));
957
4/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 14794 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
14884 oper("*", 5, left*right);
958
7/10
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 14770 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 3 times.
14794 oper("/", 5, right != 0.0 ? left / right : oper_wrapped_throw<error_id_division_by_zero>());
959
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 14770 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.
14770 oper("%", 5, right != 0.0 ? fmod((double)left, (double)right) : oper_wrapped_throw<error_id_modulo_by_zero>());
960
6/6
✓ Branch 0 taken 6010 times.
✓ Branch 1 taken 8760 times.
✓ Branch 2 taken 5950 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 5949 times.
✓ Branch 5 taken 1 times.
14770 oper("+", 4, left+right);
961
4/6
✓ Branch 0 taken 1578 times.
✓ Branch 1 taken 7182 times.
✓ Branch 2 taken 1578 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1578 times.
✗ Branch 5 not taken.
8760 oper("-", 4, left-right);
962
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 7182 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.
7182 oper("<<", 3, right >= 0.0 ? (int64_t)left<<(uint64_t)right : oper_wrapped_throw<error_id_negative_shift>());
963
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 7182 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.
7182 oper(">>", 3, right >= 0.0 ? (int64_t)left>>(uint64_t)right : oper_wrapped_throw<error_id_negative_shift>());
964
965 //these two needed checked early to avoid bitwise from eating a operator
966
8/10
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 7110 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.
7191 oper("&&", 0, (int64_t)left&&(int64_t)right);
967
7/10
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 7074 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.
7110 oper("||", 0, (int64_t)left||(int64_t)right);
968
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7074 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7074 oper("&", 2, (int64_t)left&(int64_t)right);
969
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7074 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7074 oper("|", 2, (int64_t)left|(int64_t)right);
970
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 7074 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7074 oper("^", 2, (int64_t)left^(int64_t)right);
971
972
6/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7056 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.
7074 oper(">=", 1, left>=right);
973
6/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 7038 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.
7056 oper("<=", 1, left<=right);
974
6/8
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 6624 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.
7083 oper(">", 1, left>right);
975
6/8
✓ Branch 0 taken 5400 times.
✓ Branch 1 taken 1224 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.
6930 oper("<", 1, left<right);
976
6/8
✓ Branch 0 taken 1134 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 1134 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1134 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 567 times.
✓ Branch 7 taken 567 times.
1575 oper("==", 1, left==right);
977
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);
978 36 asar_throw_error(2, error_type_block, error_id_unknown_operator);
979 #undef oper
980 }
981 25828 return left;
982 51822 }
983
984 //static autoptr<char*> freeme;
985 35066 double math(const char * s)
986 {
987 //free(freeme);
988 //freeme=NULL;
989 35066 foundlabel=false;
990 35066 foundlabel_static=true;
991 35066 forwardlabel=false;
992 35066 str = s;
993 35066 double rval = eval(0);
994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34968 times.
34968 if (*str)
995 {
996 if (*str == ',') asar_throw_error(2, error_type_block, error_id_invalid_input);
997 else asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
998 }
999 34968 return rval;
1000 }
1001
1002 2432 void initmathcore()
1003 {
1004 1265 functions.reset();
1005 79454 builtin_functions.each([](const char* key, double (*val)()) {
1006 160512 functions[key] = val;
1007 160512 });
1008 1265 user_functions.reset();
1009 2432 }
1010
1011 2402 void deinitmathcore()
1012 {
1013 //not needed
1014 2402 }
1015