asar coverage - build #209


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-02-22 21:34:57
Lines:
443/488
90.8%
Functions:
83/105
79.0%
Branches:
446/744
59.9%

Line Branch Exec Source
1 #include "platform/file-helpers.h"
2 #include "asar.h"
3 #include "virtualfile.h"
4 #include "assembleblock.h"
5 #include "macro.h"
6 #include "asar_math.h"
7 #include "table.h"
8 #include "unicode.h"
9 #include <cmath>
10 #include <functional>
11 #include <algorithm>
12
13 static const char * str;
14 //save before calling eval if needed after
15 static const char * current_user_function_name;
16
17 static double getnumcore();
18 static double getnum();
19 static double eval(int depth);
20
21 //label (bool foundLabel) (bool forwardLabel)
22 //userfunction
23
24 bool foundlabel;
25 // WARNING: this flag is only correctly set in pass 0, as forward labels are
26 // always non-static but we don't know when we hit forward-labels past pass 0
27 bool foundlabel_static;
28 // only set in pass 0
29 bool forwardlabel;
30
31 struct cachedfile {
32 string filename;
33 virtual_file_handle filehandle;
34 size_t filesize;
35 bool used;
36 };
37
38 #define numcachedfiles 16
39
40 static cachedfile cachedfiles[numcachedfiles];
41 static int cachedfileindex = 0;
42
43 // Opens a file, trying to open it from cache first
44
45 168 static cachedfile * opencachedfile(string fname, bool should_error)
46 {
47 84 cachedfile * cachedfilehandle = nullptr;
48
49
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 const char* current_file = get_current_file_name();
50
51 // RPG Hacker: Only using a combined path here because that should
52 // hopefully result in a unique string for every file, whereas
53 // fname could be a relative path, which isn't guaranteed to be unique.
54 // Note that this does not affect how we open the file - this is
55 // handled by the filesystem and uses our include paths etc.
56
2/4
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
168 string combinedname = filesystem->create_absolute_path(dir(current_file), fname);
57
58
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 54 times.
1104 for (int i = 0; i < numcachedfiles; i++)
59 {
60
6/6
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 828 times.
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 108 times.
✓ Branch 4 taken 57 times.
✓ Branch 5 taken 468 times.
1050 if (cachedfiles[i].used && cachedfiles[i].filename == combinedname)
61 {
62 114 cachedfilehandle = &cachedfiles[i];
63 57 break;
64 }
65 }
66
67
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 57 times.
84 if (cachedfilehandle == nullptr)
68 {
69
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (cachedfiles[cachedfileindex].used)
70 {
71 filesystem->close_file(cachedfiles[cachedfileindex].filehandle);
72 cachedfiles[cachedfileindex].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
73 cachedfiles[cachedfileindex].used = false;
74 }
75
76 54 cachedfilehandle = &cachedfiles[cachedfileindex];
77 }
78
79
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (cachedfilehandle != nullptr)
80 {
81
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 114 times.
168 if (!cachedfilehandle->used)
82 {
83
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 cachedfilehandle->filehandle = filesystem->open_file(fname, current_file);
84
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 30 times.
54 if (cachedfilehandle->filehandle != INVALID_VIRTUAL_FILE_HANDLE)
85 {
86 24 cachedfilehandle->used = true;
87
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 cachedfilehandle->filename = combinedname;
88
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 cachedfilehandle->filesize = filesystem->get_file_size(cachedfilehandle->filehandle);
89 24 cachedfileindex++;
90 // randomdude999: when we run out of cached files, just start overwriting ones from the start
91
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (cachedfileindex >= numcachedfiles) cachedfileindex = 0;
92 }
93 }
94 }
95
96
5/6
✓ Branch 0 taken 99 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 84 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
168 if ((cachedfilehandle == nullptr || cachedfilehandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) && should_error)
97 {
98 asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), fname.data());
99 }
100
101 168 return cachedfilehandle;
102 168 }
103
104
105 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
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
30 labels.each([&selected_label, label](const char *key, snes_label current_label){
151
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 6 times.
90 if(label < current_label.id && current_label.id < selected_label.id){
152 18 selected_label = current_label;
153 }
154 90 });
155
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
30 if(selected_label.id == 0xFFFFFF) asar_throw_warning(2, warning_id_datasize_last_label, name);
156
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
30 if(selected_label.pos-label_data.pos > 0xFFFF) asar_throw_warning(2, warning_id_datasize_exceeds_size, name);
157 30 return selected_label.pos-label_data.pos;
158 }
159
160
161 444 string get_string_argument()
162 {
163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 444 times.
444 while (*str==' ') str++;
164
1/2
✓ Branch 0 taken 444 times.
✗ Branch 1 not taken.
444 if (*str=='"')
165 {
166 444 const char * strpos = str + 1;
167
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
222 while (*str!='"' && *str!='\0') str++;
168 444 str = strchr(str + 1, '"');
169
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
444 string tempname(strpos , (int)(str - strpos));
170 444 str++;
171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 444 times.
444 while (*str==' ') str++; //eat space
172
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
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 //need a better way to do this to make sure it is useful...
328 //foundlabel=true; //Going to consider this an implicit label because we don't really have a better system
329 18 return realsnespos;
330 }
331
332 72 double asar_pc_wrapper()
333 {
334 // while this really should set foundlabel, not doing it right now for symmetry with realbase.
335 // we should rework the way foundlabel works anyways.
336 //foundlabel = true;
337 72 return snespos;
338 }
339
340 132 template <int count> double asar_read()
341 {
342 132 int target = get_double_argument();
343 132 int addr=snestopc_pick(target);
344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
132 if(has_next_parameter())
345 {
346 double default_value = get_double_argument();
347 if (addr<0) return default_value;
348 else if (addr+count>romlen_r) return default_value;
349 }
350 else
351 {
352
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());
353
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
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());
354 }
355
356 60 unsigned int value = 0;
357
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 60 times.
312 for(int i = 0; i < count; i++)
358 {
359 192 value |= romdata_r[addr+i] << (8 * i);
360 }
361 120 return value;
362 }
363
364 216 template <int count> double asar_canread()
365 {
366 108 int length = count;
367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
108 if(!length)
368 {
369 length = get_double_argument();
370 }
371 216 int addr=snestopc_pick(get_double_argument());
372
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;
373 108 else return 1;
374 }
375
376 168 template <size_t count> double asar_readfile()
377 {
378 static_assert(count && count <= 4, "invalid count"); //1-4 inclusive
379
380
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
168 string name = get_string_argument();
381
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 require_next_parameter();
382
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 size_t offset = get_double_argument();
383
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
168 bool should_error = !has_next_parameter();
384
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);
385
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 48 times.
168 if(!should_error)
386 {
387
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
72 double default_value = get_double_argument();
388
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;
389
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
60 if (offset < 0 || offset + count > fhandle->filesize) return default_value;
390 }
391 else
392 {
393
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());
394
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());
395 }
396
397 132 unsigned char data[4] = { 0, 0, 0, 0 };
398
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
132 filesystem->read_file(fhandle->filehandle, data, offset, count);
399
400 66 unsigned int value = 0;
401
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 66 times.
348 for(size_t i = 0; i < count; i++)
402 {
403 216 value |= data[i] << (8 * i);
404 }
405
406 132 return value;
407 168 }
408
409 84 template <size_t count> double asar_canreadfile()
410 {
411
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
84 string name = get_string_argument();
412
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 require_next_parameter();
413
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 size_t offset = get_double_argument();
414 42 size_t length = count;
415 if(!count)
416 {
417
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 require_next_parameter();
418
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 length = get_double_argument();
419 }
420
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);
421
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;
422
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
72 if (offset < 0 || offset + length > fhandle->filesize) return 0;
423 24 return 1;
424 84 }
425
426 // 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
427 36 static double asar_filestatus()
428 {
429
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);
430
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)
431 {
432
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (filesystem->get_last_error() == vfe_doesnt_exist)
433 {
434 9 return 1;
435 }
436 else
437 {
438 return 2;
439 }
440 }
441 9 return 0;
442 }
443
444 // Returns the size of the specified file.
445 6 static double asar_filesize()
446 {
447
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 string name = get_string_argument();
448
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);
449
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());
450 6 return (double)fhandle->filesize;
451 6 }
452
453 // Checks whether the specified define is defined.
454 156 static double asar_isdefined()
455 {
456
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());
457 }
458
459 // RPG Hacker: What exactly makes this function overly complicated, you ask?
460 // Well, it converts a double to a string and then back to a double.
461 // It was the quickest reliable solution I could find, though, so there's that.
462 12 static double asar_round()
463 {
464
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 double number = get_double_argument();
465
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 require_next_parameter();
466
467 // Hue hue hue... ass!
468 // OK, sorry, I apologize.
469
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());
470
471 // Some hacky shenanigans with variables going on here
472
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 const char * strbackup = str;
473 12 str = asstring;
474
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 double asdouble = (double)getnum();
475 12 str = strbackup;
476
477 12 return asdouble;
478 12 }
479
480 1068 static double asar_structsize_wrapper()
481 {
482
1/2
✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
1068 string symbol = get_symbol_argument();
483
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 18 times.
1068 if(symbol == "..."){
484
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);
485
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(...)");
486 1038 return numvarargs;
487 }
488
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return (double)struct_size(symbol);
489 1068 }
490
491 18 static double asar_objectsize_wrapper()
492 {
493
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());
494 }
495
496 30 static double asar_datasize_wrapper()
497 {
498
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());
499 }
500
501 36 static double asar_stringsequal()
502 {
503
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 string string1 = get_string_argument();
504
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 require_next_parameter();
505
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);
506 36 }
507
508 18 static double asar_stringsequalnocase()
509 {
510
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 string string1 = get_string_argument();
511
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 require_next_parameter();
512
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);
513 18 }
514
515 static double asar_char()
516 {
517 string string1 = get_string_argument();
518 require_next_parameter();
519 int offset = get_double_argument();
520 if(offset >= string1.length()) asar_throw_error(2, error_type_block, error_id_oob, offset, string1.length());
521 return string1[offset];
522 }
523
524 static double asar_strlen()
525 {
526 return get_string_argument().length();
527 }
528
529 102 string copy_arg()
530 {
531
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 90 times.
102 if(*str == '"')
532 {
533
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 string t = "\"";
534
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() + "\"");
535 12 }
536
537 45 string result;
538 45 bool is_symbolic = true;
539 45 int parlevel=0;
540 45 int i = 0;
541
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] != ')'))
542 {
543 90 is_symbolic &= is_ualnum(str[i]);
544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(str[i] == '(') parlevel++;
545
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 else if(str[i] == ')') parlevel--;
546 90 i++;
547 }
548
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);
549 90 str += i;
550
551
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(!is_symbolic)
552 {
553 const char *oldstr=str;
554 str = (const char *)result;
555 result = ftostr(eval(0));
556 str = oldstr;
557 }
558
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 return result;
559 90 }
560
561 assocarr<double (*)()> builtin_functions =
562 {
563 {"sqrt", asar_unary_wrapper<sqrt>},
564 {"sin", asar_unary_wrapper<sin>},
565 {"cos", asar_unary_wrapper<cos>},
566 {"tan", asar_unary_wrapper<tan>},
567 {"asin", asar_unary_wrapper<asin>},
568 {"acos", asar_unary_wrapper<acos>},
569 {"atan", asar_unary_wrapper<atan>},
570 {"arcsin", asar_unary_wrapper<asin>},
571 {"arccos", asar_unary_wrapper<acos>},
572 {"arctan", asar_unary_wrapper<atan>},
573 {"log", asar_unary_wrapper<log>},
574 {"log10", asar_unary_wrapper<log10>},
575 {"log2", asar_unary_wrapper<log2>},
576
577 {"ceil", asar_unary_wrapper<ceil>},
578 {"floor", asar_unary_wrapper<floor>},
579
580 {"read1", asar_read<1>}, //This handles the safe and unsafe variant
581 {"read2", asar_read<2>},
582 {"read3", asar_read<3>},
583 {"read4", asar_read<4>},
584 {"canread", asar_canread<0>},
585 {"canread1", asar_canread<1>},
586 {"canread2", asar_canread<2>},
587 {"canread3", asar_canread<3>},
588 {"canread4", asar_canread<4>},
589
590 {"readfile1", asar_readfile<1>},
591 {"readfile2", asar_readfile<2>},
592 {"readfile3", asar_readfile<3>},
593 {"readfile4", asar_readfile<4>},
594 {"canreadfile", asar_canreadfile<0>},
595 {"canreadfile1", asar_canreadfile<1>},
596 {"canreadfile2", asar_canreadfile<2>},
597 {"canreadfile3", asar_canreadfile<3>},
598 {"canreadfile4", asar_canreadfile<4>},
599
600 {"filesize", asar_filesize},
601 {"getfilestatus", asar_filestatus},
602
603 {"defined", asar_isdefined},
604
605 {"snestopc", asar_snestopc_wrapper},
606 {"pctosnes", asar_pctosnes_wrapper},
607 {"realbase", asar_realbase_wrapper},
608 {"pc", asar_pc_wrapper},
609
610 {"max", asar_binary_wrapper<asar_max>},
611 {"min", asar_binary_wrapper<asar_min>},
612 {"clamp", asar_clamp},
613
614 {"safediv", asar_safediv},
615
616 {"select", asar_select},
617 {"bank", asar_unary_wrapper<asar_bank>},
618 {"not", asar_unary_wrapper<std::logical_not<unsigned int>>},
619 {"equal", asar_binary_wrapper<std::equal_to<double>>},
620 {"notequal", asar_binary_wrapper<std::not_equal_to<double>>},
621 {"less", asar_binary_wrapper<std::less<double>>},
622 {"lessequal", asar_binary_wrapper<std::less_equal<double>>},
623 {"greater", asar_binary_wrapper<std::greater<double>>},
624 {"greaterequal", asar_binary_wrapper<std::greater_equal<double>>},
625
626 {"and", asar_binary_wrapper<std::logical_and<unsigned int>>},
627 {"or", asar_binary_wrapper<std::logical_or<unsigned int>>},
628 {"nand", asar_binary_wrapper<asar_logical_nand>},
629 {"nor", asar_binary_wrapper<asar_logical_nor>},
630 {"xor", asar_binary_wrapper<asar_logical_xor>},
631
632 {"round", asar_round},
633
634 {"sizeof", asar_structsize_wrapper},
635 {"objectsize", asar_objectsize_wrapper},
636 {"datasize", asar_datasize_wrapper},
637
638 {"stringsequal", asar_stringsequal},
639 {"stringsequalnocase", asar_stringsequalnocase},
640 {"char", asar_char},
641 {"stringlength", asar_strlen}
642 };
643
644 assocarr<double (*)()> functions;
645
646 struct funcdat {
647 autoptr<char*> name;
648 int numargs;
649 autoptr<char*> argbuf;//this one isn't used, it's just to free it up
650 autoptr<char**> arguments;
651 autoptr<char*> content;
652 };
653 static assocarr<funcdat> user_functions;
654
655 66 static double asar_call_user_function()
656 {
657 33 autoarray<string> args;
658
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 funcdat &user_function = user_functions[current_user_function_name];
659 33 string real_content;
660
661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 while (*str==' ') str++;
662 66 bool has_next = *str != ')';
663
664
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 66 times.
168 for (int i=0;i<user_function.numargs;i++)
665 {
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if(!has_next)
667 {
668 asar_throw_error(2, error_type_block, error_id_expected_parameter, current_user_function_name);
669 }
670
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();
671
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
102 has_next = has_next_parameter();
672 }
673
674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if(has_next)
675 {
676 asar_throw_error(2, error_type_block, error_id_unexpected_parameter, current_user_function_name);
677 }
678
679
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 66 times.
318 for(int i=0; user_function.content[i]; i++)
680 {
681
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 114 times.
252 if(!is_ualpha(user_function.content[i]))
682 {
683
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
138 real_content += user_function.content[i];
684 138 continue;
685 }
686 57 bool found = false;
687
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 114 times.
312 for (int j=0;user_function.arguments[j];j++)
688 {
689 //this should *always* have a null term or another character after
690 198 bool potential_arg = stribegin(user_function.content+i, user_function.arguments[j]);
691 198 int next_char = i+strlen(user_function.arguments[j]);
692
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]))
693 {
694
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];
695 102 i = next_char - 1;
696 51 found = true;
697 }
698 }
699
700
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 102 times.
114 if(!found){
701
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 12 times.
120 for(; is_ualnum(user_function.content[i]); i++){
702
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
108 real_content += user_function.content[i];
703 }
704
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 real_content += user_function.content[i];
705 }
706 }
707
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
66 const char * oldstr=str;
708 66 str = (const char *)real_content;
709
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 double result = eval(0);
710 66 str = oldstr;
711 66 return result;
712 66 }
713
714 108 void createuserfunc(const char * name, const char * arguments, const char * content)
715 {
716
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);
717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if(functions.exists(name)) //functions holds both types.
718 {
719 asar_throw_error(0, error_type_block, error_id_function_redefined, name);
720 }
721 108 funcdat& user_function=user_functions[name];
722 108 user_function.name= duplicate_string(name);
723 108 user_function.argbuf= duplicate_string(arguments);
724 108 user_function.arguments=split(user_function.argbuf, ',', &(user_function.numargs));
725 108 user_function.content= duplicate_string(content);
726
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 108 times.
270 for (int i=0;user_function.arguments[i];i++)
727 {
728
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 162 times.
432 for(int j=0;user_function.arguments[j];j++)
729 {
730
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]))
731 {
732 asar_throw_error(0, error_type_block, error_id_duplicate_param_name, user_function.arguments[i], name);
733 }
734 }
735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 162 times.
162 if (!confirmname(user_function.arguments[i]))
736 {
737 user_functions.remove(name);
738 asar_throw_error(0, error_type_block, error_id_invalid_param_name);
739 }
740 }
741
742 108 functions[name] = asar_call_user_function;
743 108 }
744
745 inline const long hextable[] = {
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,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
748 -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,
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,10,11,12,13,14,15,-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 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
756 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
757 };
758
759 51664 static double getnumcore()
760 {
761
2/2
✓ Branch 0 taken 13897 times.
✓ Branch 1 taken 37767 times.
51664 if (*str=='$')
762 {
763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13897 times.
13897 if (!is_xdigit(*++str)) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
764 6994 uint64_t ret = 0;
765
2/2
✓ Branch 0 taken 47598 times.
✓ Branch 1 taken 13897 times.
61495 while (hextable[0 + *str] >= 0) {
766 47598 ret = (ret << 4) | hextable[0 + *str++];
767 }
768 13897 return ret;
769 }
770
8/8
✓ Branch 0 taken 33635 times.
✓ Branch 1 taken 4132 times.
✓ Branch 2 taken 16835 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 16826 times.
✓ Branch 6 taken 2080 times.
✓ Branch 7 taken 16826 times.
37767 if (is_ualpha(*str) || *str=='.' || *str=='?')
771 {
772 4156 const char * start=str;
773
6/6
✓ Branch 0 taken 17950 times.
✓ Branch 1 taken 17962 times.
✓ Branch 2 taken 294 times.
✓ Branch 3 taken 4156 times.
✓ Branch 4 taken 15886 times.
✓ Branch 5 taken 2080 times.
35912 while (is_ualnum(*str) || *str == '.') str++;
774 4156 int len=(int)(str-start);
775
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 4156 times.
4264 while (*str==' ') str++;
776
2/2
✓ Branch 0 taken 2478 times.
✓ Branch 1 taken 1678 times.
4156 if (*str=='(')
777 {
778 2478 str++;
779 // RPG Hacker: This is only here to assure that all strings are still
780 // alive in memory when we call our functions further down
781 double result;
782 while (true)
783 {
784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2478 times.
2478 while (*str==' ') str++;
785
1/2
✓ Branch 0 taken 1239 times.
✗ Branch 1 not taken.
1239 string function_name = string(start, len);
786
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))
787 {
788 2478 current_user_function_name = function_name;
789
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]();
790 }
791 else
792 {
793 str++;
794 break;
795 }
796
797
1/2
✓ Branch 0 taken 2460 times.
✗ Branch 1 not taken.
2460 if (*str==')')
798 {
799 2460 str++;
800 1230 return result;
801 }
802 asar_throw_error(2, error_type_block, error_id_malformed_function_call);
803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1230 times.
2478 }
804
805 asar_throw_error(2, error_type_block, error_id_function_not_found, start);
806 }
807 else
808 {
809 1678 foundlabel=true;
810
811 841 const char *old_start = start;
812
2/2
✓ Branch 0 taken 836 times.
✓ Branch 1 taken 5 times.
1678 snes_label label_data = labelval(&start);
813 1670 int i=(int)label_data.pos;
814 1670 foundlabel_static &= label_data.is_static;
815
2/2
✓ Branch 0 taken 834 times.
✓ Branch 1 taken 836 times.
1670 if(str < start)
816 {
817
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
120 if ((str = strchr(str, '[')))
818 {
819
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
102 string struct_name = substr(old_start, (int)(str - old_start));
820 102 str++;
821
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));
822 102 }
823 }
824
825 1670 str=start;
826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1670 times.
1670 if (i==-1) {
827 foundlabel_static = false;
828 forwardlabel=true;
829 }
830 1670 return (int)i&0xFFFFFF;
831 }
832 }
833
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 16607 times.
16826 if (*str=='(')
834 {
835 438 str++;
836 438 double rval=eval(0);
837
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);
838 438 str++;
839 438 return rval;
840 }
841
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 16595 times.
16607 if (*str=='%')
842 {
843
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);
844 24 return strtoull(str+1, const_cast<char**>(&str), 2);
845 }
846
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 16265 times.
16595 if (*str=='\'')
847 {
848
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);
849 int orig_val;
850 660 str++;
851
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 str += utf8_val(&orig_val, str);
852
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);
853
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);
854
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 int64_t rval=thetable.get_val(orig_val);
855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (rval == -1)
856 {
857 // RPG Hacker: Should be fine to not check return value of codepoint_to_utf8() here, because
858 // our error cases above already made sure that orig_val contains valid data at this point.
859 string u8_str;
860 codepoint_to_utf8(&u8_str, orig_val);
861 asar_throw_error(2, error_type_block, error_id_undefined_char, u8_str.data());
862 }
863 660 str++;
864 660 return rval;
865 }
866
2/2
✓ Branch 0 taken 32459 times.
✓ Branch 1 taken 30 times.
32489 if (is_digit(*str))
867 {
868 16250 const char* end = str;
869
6/6
✓ Branch 0 taken 37144 times.
✓ Branch 1 taken 37161 times.
✓ Branch 2 taken 162 times.
✓ Branch 3 taken 32459 times.
✓ Branch 4 taken 20952 times.
✓ Branch 5 taken 16250 times.
74305 while (is_digit(*end) || *end == '.') end++;
870 16250 string number;
871
1/2
✓ Branch 0 taken 16250 times.
✗ Branch 1 not taken.
32459 number.assign(str, (int)(end - str));
872 32459 str = end;
873 32459 return atof(number);
874 32459 }
875 30 asar_throw_error(2, error_type_block, error_id_invalid_number);
876 }
877
878 51704 inline double sanitize(double val)
879 {
880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51704 times.
51704 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
881 51704 return val;
882 }
883
884 51760 static double getnum()
885 {
886
2/2
✓ Branch 0 taken 7056 times.
✓ Branch 1 taken 51760 times.
58816 while (*str==' ') str++;
887
2/2
✓ Branch 0 taken 13897 times.
✓ Branch 1 taken 37863 times.
51760 if(*str == '$') return sanitize(getnumcore()); //optimize for the common case
888 #define prefix(sym, func) if (*str == sym) { str+=1; double val=getnum(); return sanitize(func); }
889 #define prefix2(sym, sym2, func) if (*str == sym && *(str+1) == sym2) { str+=2; double val=getnum(); return sanitize(func); }
890
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 37791 times.
37863 prefix('-', -val);
891
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 37779 times.
37791 prefix('~', ~(int)val);
892
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 37737 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 30 times.
37779 prefix2('<', ':', (int)val>>16);
893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37767 times.
37767 prefix('+', val);
894 #undef prefix
895 #undef prefix2
896 37767 return sanitize(getnumcore());
897 }
898
899 29013 int64_t getnum(const char* instr)
900 {
901 29013 double num = math(instr);
902
2/2
✓ Branch 0 taken 14394 times.
✓ Branch 1 taken 14523 times.
28917 if(num < (double)INT64_MIN) {
903 return INT64_MIN;
904
2/2
✓ Branch 0 taken 14394 times.
✓ Branch 1 taken 14523 times.
28917 } else if(num > (double)INT64_MAX) {
905 return INT64_MAX;
906 }
907 28917 return (int64_t)num;
908 }
909
910 // RPG Hacker: Same function as above, but doesn't truncate our number via int conversion
911 5820 double getnumdouble(const char * instr)
912 {
913 5820 return math(instr);
914 }
915
916
917 12 template<asar_error_id errid> static double oper_wrapped_throw()
918 {
919 12 asar_throw_error(2, error_type_block, errid);
920 }
921
922 51738 static double eval(int depth)
923 {
924 51738 const char* posneglabel = str;
925
1/2
✓ Branch 0 taken 25938 times.
✗ Branch 1 not taken.
51738 string posnegname = posneglabelname(&posneglabel, false);
926
927
4/4
✓ Branch 0 taken 26016 times.
✓ Branch 1 taken 25722 times.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 25858 times.
51738 if (posnegname.length() > 0)
928 {
929
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;
930
931 86 str = posneglabel;
932
933 86 foundlabel=true;
934
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 13 times.
86 if (*(posneglabel-1) == '+') forwardlabel=true;
935
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);
936 86 foundlabel_static &= label_data.is_static;
937 86 return label_data.pos & 0xFFFFFF;
938 }
939
1/2
✓ Branch 0 taken 25758 times.
✗ Branch 1 not taken.
51616 notposneglabel:
940
1/2
✓ Branch 0 taken 25894 times.
✗ Branch 1 not taken.
77546 recurseblock rec;
941
2/2
✓ Branch 0 taken 51596 times.
✓ Branch 1 taken 56 times.
51652 double left=getnum();
942 double right;
943
2/2
✓ Branch 0 taken 7056 times.
✓ Branch 1 taken 51596 times.
58652 while (*str==' ') str++;
944
8/8
✓ Branch 0 taken 16126 times.
✓ Branch 1 taken 50197 times.
✓ Branch 2 taken 15199 times.
✓ Branch 3 taken 927 times.
✓ Branch 4 taken 14935 times.
✓ Branch 5 taken 264 times.
✓ Branch 6 taken 7444 times.
✓ Branch 7 taken 51 times.
66323 while (*str && *str != ')' && *str != ','&& *str != ']')
945 {
946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14884 times.
14884 while (*str==' ') str++;
947 #define oper(name, thisdepth, contents) \
948 if (!strncmp(str, name, strlen(name))) \
949 { \
950 if (depth<=thisdepth) \
951 { \
952 str+=strlen(name); \
953 right=eval(thisdepth+1); \
954 } \
955 else return left; \
956 left=contents; \
957 continue; \
958 }
959
4/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14848 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
14884 oper("**", 6, pow((double)left, (double)right));
960
4/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 14758 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
14848 oper("*", 5, left*right);
961
7/10
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 14734 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.
14758 oper("/", 5, right != 0.0 ? left / right : oper_wrapped_throw<error_id_division_by_zero>());
962
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 14734 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.
14734 oper("%", 5, right != 0.0 ? fmod((double)left, (double)right) : oper_wrapped_throw<error_id_modulo_by_zero>());
963
6/6
✓ Branch 0 taken 6010 times.
✓ Branch 1 taken 8724 times.
✓ Branch 2 taken 5950 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 5949 times.
✓ Branch 5 taken 1 times.
14734 oper("+", 4, left+right);
964
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);
965
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>());
966
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>());
967
968 //these two needed checked early to avoid bitwise from eating a operator
969
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);
970
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);
971
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);
972
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);
973
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);
974
975
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);
976
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);
977
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);
978
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);
979
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);
980
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);
981 36 asar_throw_error(2, error_type_block, error_id_unknown_operator);
982 #undef oper
983 }
984 25786 return left;
985 51738 }
986
987 //static autoptr<char*> freeme;
988 35018 double math(const char * s)
989 {
990 //free(freeme);
991 //freeme=NULL;
992 35018 foundlabel=false;
993 35018 foundlabel_static=true;
994 35018 forwardlabel=false;
995 35018 str = s;
996 35018 double rval = eval(0);
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34920 times.
34920 if (*str)
998 {
999 if (*str == ',') asar_throw_error(2, error_type_block, error_id_invalid_input);
1000 else asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
1001 }
1002 34920 return rval;
1003 }
1004
1005 2432 void initmathcore()
1006 {
1007 2432 functions.reset();
1008 2432 builtin_functions.each([](const char* key, double (*val)()) {
1009 160512 functions[key] = val;
1010 160512 });
1011 2432 user_functions.reset();
1012 2432 }
1013
1014 2402 void deinitmathcore()
1015 {
1016 //not needed
1017 2402 }
1018