asar coverage - build #166


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-01-27 07:39:55
Lines:
443/489
90.6%
Functions:
83/103
80.6%
Branches:
450/771
58.4%

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