asar coverage - build #153


src/asar/
File: src/asar/asar_math.cpp
Date: 2024-01-25 19:41:38
Lines:
441/487
90.6%
Functions:
82/102
80.4%
Branches:
445/771
57.7%

Line Branch Exec Source
1 #include "platform/file-helpers.h"
2 #include "asar.h"
3 #include "virtualfile.h"
4 #include "assembleblock.h"
5 #include "macro.h"
6 #include "asar_math.h"
7 #include "table.h"
8 #include "unicode.h"
9 #include <cmath>
10 #include <functional>
11 #include <algorithm>
12
13 static const char * str;
14 //save before calling eval if needed after
15 static const char * current_user_function_name;
16
17 static double getnumcore();
18 static double getnum();
19 static double eval(int depth);
20
21 //label (bool foundLabel) (bool forwardLabel)
22 //userfunction
23
24 bool foundlabel;
25 bool foundlabel_static;
26 bool forwardlabel;
27
28 struct cachedfile {
29 string filename;
30 virtual_file_handle filehandle;
31 size_t filesize;
32 bool used;
33 };
34
35 #define numcachedfiles 16
36
37 static cachedfile cachedfiles[numcachedfiles];
38 static int cachedfileindex = 0;
39
40 // Opens a file, trying to open it from cache first
41
42 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 1463 void closecachedfiles()
103 {
104
2/2
✓ Branch 0 taken 23408 times.
✓ Branch 1 taken 1463 times.
24871 for (int i = 0; i < numcachedfiles; i++)
105 {
106
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 23384 times.
23408 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 1463 cachedfileindex = 0;
119 1463 }
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 1344 double get_double_argument()
193 {
194
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1344 times.
1344 while (*str==' ') str++;
195 1344 double result = eval(0);
196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1344 times.
1344 while (*str==' ') str++; //eat spaces
197 1344 return result;
198 }
199
200 //will eat the comma
201 216 bool has_next_parameter()
202 {
203
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 144 times.
216 if (*str==',')
204 {
205 72 str++;
206 72 return true;
207 }
208 72 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 60 template <int count> double asar_read()
331 {
332 60 int target = get_double_argument();
333 60 int addr=snestopc_pick(target);
334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
60 if(has_next_parameter())
335 {
336 double default_value = get_double_argument();
337 if (addr<0) return default_value;
338 else if (addr+count>romlen_r) return default_value;
339 }
340 else
341 {
342
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 30 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.
60 if (addr<0) asar_throw_error(2, error_type_block, error_id_snes_address_doesnt_map_to_rom, (hex((unsigned int)target, 6) + " in read function").data());
343
6/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 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.
84 else if (addr+count>romlen_r) asar_throw_error(2, error_type_block, error_id_snes_address_out_of_bounds, (hex(target, 6) + " in read function").data());
344 }
345
346 24 unsigned int value = 0;
347
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 24 times.
168 for(int i = 0; i < count; i++)
348 {
349 120 value |= romdata_r[addr+i] << (8 * i);
350 }
351 48 return value;
352 }
353
354 216 template <int count> double asar_canread()
355 {
356 108 int length = count;
357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
108 if(!length)
358 {
359 length = get_double_argument();
360 }
361 216 int addr=snestopc_pick(get_double_argument());
362
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;
363 108 else return 1;
364 }
365
366 168 template <size_t count> double asar_readfile()
367 {
368 static_assert(count && count <= 4, "invalid count"); //1-4 inclusive
369
370
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
168 string name = get_string_argument();
371
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 require_next_parameter();
372
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 size_t offset = get_double_argument();
373
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
168 bool should_error = !has_next_parameter();
374
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);
375
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 48 times.
168 if(!should_error)
376 {
377
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
72 double default_value = get_double_argument();
378
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;
379
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
60 if (offset < 0 || offset + count > fhandle->filesize) return default_value;
380 }
381 else
382 {
383
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());
384
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());
385 }
386
387 132 unsigned char data[4] = { 0, 0, 0, 0 };
388
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
132 filesystem->read_file(fhandle->filehandle, data, offset, count);
389
390 66 unsigned int value = 0;
391
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 66 times.
348 for(size_t i = 0; i < count; i++)
392 {
393 216 value |= data[i] << (8 * i);
394 }
395
396 132 return value;
397 168 }
398
399 84 template <size_t count> double asar_canreadfile()
400 {
401
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
84 string name = get_string_argument();
402
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 require_next_parameter();
403
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
84 size_t offset = get_double_argument();
404 42 size_t length = count;
405 if(!count)
406 {
407
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 require_next_parameter();
408
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 length = get_double_argument();
409 }
410
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);
411
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;
412
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
72 if (offset < 0 || offset + length > fhandle->filesize) return 0;
413 24 return 1;
414 84 }
415
416 // returns 0 if the file is OK, 1 if the file doesn't exist, 2 if it couldn't be opened for some other reason
417 36 static double asar_filestatus()
418 {
419
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);
420
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)
421 {
422
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
18 if (filesystem->get_last_error() == vfe_doesnt_exist)
423 {
424 9 return 1;
425 }
426 else
427 {
428 return 2;
429 }
430 }
431 9 return 0;
432 }
433
434 // Returns the size of the specified file.
435 6 static double asar_filesize()
436 {
437
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
6 string name = get_string_argument();
438
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);
439
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());
440 6 return (double)fhandle->filesize;
441 6 }
442
443 // Checks whether the specified define is defined.
444 156 static double asar_isdefined()
445 {
446
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());
447 }
448
449 // RPG Hacker: What exactly makes this function overly complicated, you ask?
450 // Well, it converts a double to a string and then back to a double.
451 // It was the quickest reliable solution I could find, though, so there's that.
452 12 static double asar_round()
453 {
454
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 double number = get_double_argument();
455
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 require_next_parameter();
456
457 // Hue hue hue... ass!
458 // OK, sorry, I apologize.
459
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());
460
461 // Some hacky shenanigans with variables going on here
462
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 const char * strbackup = str;
463 12 str = asstring;
464
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 double asdouble = (double)getnum();
465 12 str = strbackup;
466
467 12 return asdouble;
468 12 }
469
470 1068 static double asar_structsize_wrapper()
471 {
472
1/2
✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
1068 string symbol = get_symbol_argument();
473
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 18 times.
1068 if(symbol == "..."){
474
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);
475
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(...)");
476 1038 return numvarargs;
477 }
478
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return (double)struct_size(symbol);
479 1068 }
480
481 18 static double asar_objectsize_wrapper()
482 {
483
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());
484 }
485
486 30 static double asar_datasize_wrapper()
487 {
488
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());
489 }
490
491 36 static double asar_stringsequal()
492 {
493
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 string string1 = get_string_argument();
494
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 require_next_parameter();
495
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);
496 36 }
497
498 18 static double asar_stringsequalnocase()
499 {
500
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
18 string string1 = get_string_argument();
501
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 require_next_parameter();
502
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);
503 18 }
504
505 static double asar_char()
506 {
507 string string1 = get_string_argument();
508 require_next_parameter();
509 int offset = get_double_argument();
510 if(offset >= string1.length()) asar_throw_error(2, error_type_block, error_id_oob, offset, string1.length());
511 return string1[offset];
512 }
513
514 static double asar_strlen()
515 {
516 return get_string_argument().length();
517 }
518
519 102 string copy_arg()
520 {
521
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 90 times.
102 if(*str == '"')
522 {
523
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 string t = "\"";
524
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() + "\"");
525 12 }
526
527 45 string result;
528 45 bool is_symbolic = true;
529 45 int parlevel=0;
530 45 int i = 0;
531
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] != ')'))
532 {
533 90 is_symbolic &= is_ualnum(str[i]);
534
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(str[i] == '(') parlevel++;
535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 else if(str[i] == ')') parlevel--;
536 90 i++;
537 }
538
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);
539 90 str += i;
540
541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 if(!is_symbolic)
542 {
543 const char *oldstr=str;
544 str = (const char *)result;
545 result = ftostr(eval(0));
546 str = oldstr;
547 }
548
1/2
✓ Branch 0 taken 45 times.
✗ Branch 1 not taken.
45 return result;
549 90 }
550
551 assocarr<double (*)()> builtin_functions =
552 {
553 {"sqrt", asar_unary_wrapper<sqrt>},
554 {"sin", asar_unary_wrapper<sin>},
555 {"cos", asar_unary_wrapper<cos>},
556 {"tan", asar_unary_wrapper<tan>},
557 {"asin", asar_unary_wrapper<asin>},
558 {"acos", asar_unary_wrapper<acos>},
559 {"atan", asar_unary_wrapper<atan>},
560 {"arcsin", asar_unary_wrapper<asin>},
561 {"arccos", asar_unary_wrapper<acos>},
562 {"arctan", asar_unary_wrapper<atan>},
563 {"log", asar_unary_wrapper<log>},
564 {"log10", asar_unary_wrapper<log10>},
565 {"log2", asar_unary_wrapper<log2>},
566
567 {"ceil", asar_unary_wrapper<ceil>},
568 {"floor", asar_unary_wrapper<floor>},
569
570 {"read1", asar_read<1>}, //This handles the safe and unsafe variant
571 {"read2", asar_read<2>},
572 {"read3", asar_read<3>},
573 {"read4", asar_read<4>},
574 {"canread", asar_canread<0>},
575 {"canread1", asar_canread<1>},
576 {"canread2", asar_canread<2>},
577 {"canread3", asar_canread<3>},
578 {"canread4", asar_canread<4>},
579
580 {"readfile1", asar_readfile<1>},
581 {"readfile2", asar_readfile<2>},
582 {"readfile3", asar_readfile<3>},
583 {"readfile4", asar_readfile<4>},
584 {"canreadfile", asar_canreadfile<0>},
585 {"canreadfile1", asar_canreadfile<1>},
586 {"canreadfile2", asar_canreadfile<2>},
587 {"canreadfile3", asar_canreadfile<3>},
588 {"canreadfile4", asar_canreadfile<4>},
589
590 {"filesize", asar_filesize},
591 {"getfilestatus", asar_filestatus},
592
593 {"defined", asar_isdefined},
594
595 {"snestopc", asar_snestopc_wrapper},
596 {"pctosnes", asar_pctosnes_wrapper},
597 {"realbase", asar_realbase_wrapper},
598
599 {"max", asar_binary_wrapper<asar_max>},
600 {"min", asar_binary_wrapper<asar_min>},
601 {"clamp", asar_clamp},
602
603 {"safediv", asar_safediv},
604
605 {"select", asar_select},
606 {"bank", asar_unary_wrapper<asar_bank>},
607 {"not", asar_unary_wrapper<std::logical_not<unsigned int>>},
608 {"equal", asar_binary_wrapper<std::equal_to<double>>},
609 {"notequal", asar_binary_wrapper<std::not_equal_to<double>>},
610 {"less", asar_binary_wrapper<std::less<double>>},
611 {"lessequal", asar_binary_wrapper<std::less_equal<double>>},
612 {"greater", asar_binary_wrapper<std::greater<double>>},
613 {"greaterequal", asar_binary_wrapper<std::greater_equal<double>>},
614
615 {"and", asar_binary_wrapper<std::logical_and<unsigned int>>},
616 {"or", asar_binary_wrapper<std::logical_or<unsigned int>>},
617 {"nand", asar_binary_wrapper<asar_logical_nand>},
618 {"nor", asar_binary_wrapper<asar_logical_nor>},
619 {"xor", asar_binary_wrapper<asar_logical_xor>},
620
621 {"round", asar_round},
622
623 {"sizeof", asar_structsize_wrapper},
624 {"objectsize", asar_objectsize_wrapper},
625 {"datasize", asar_datasize_wrapper},
626
627 {"stringsequal", asar_stringsequal},
628 {"stringsequalnocase", asar_stringsequalnocase},
629 {"char", asar_char},
630 {"stringlength", asar_strlen}
631 };
632
633 assocarr<double (*)()> functions;
634
635 struct funcdat {
636 autoptr<char*> name;
637 int numargs;
638 autoptr<char*> argbuf;//this one isn't used, it's just to free it up
639 autoptr<char**> arguments;
640 autoptr<char*> content;
641 };
642 static assocarr<funcdat> user_functions;
643
644 66 static double asar_call_user_function()
645 {
646 33 autoarray<string> args;
647
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 funcdat &user_function = user_functions[current_user_function_name];
648 33 string real_content;
649
650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 while (*str==' ') str++;
651 66 bool has_next = *str != ')';
652
653
2/2
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 66 times.
168 for (int i=0;i<user_function.numargs;i++)
654 {
655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if(!has_next)
656 {
657 asar_throw_error(2, error_type_block, error_id_expected_parameter, current_user_function_name);
658 }
659
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();
660
1/2
✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
102 has_next = has_next_parameter();
661 }
662
663
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
66 if(has_next)
664 {
665 asar_throw_error(2, error_type_block, error_id_unexpected_parameter, current_user_function_name);
666 }
667
668
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 66 times.
318 for(int i=0; user_function.content[i]; i++)
669 {
670
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 114 times.
252 if(!is_ualpha(user_function.content[i]))
671 {
672
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
138 real_content += user_function.content[i];
673 138 continue;
674 }
675 57 bool found = false;
676
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 114 times.
312 for (int j=0;user_function.arguments[j];j++)
677 {
678 //this should *always* have a null term or another character after
679 198 bool potential_arg = stribegin(user_function.content+i, user_function.arguments[j]);
680 198 int next_char = i+strlen(user_function.arguments[j]);
681
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]))
682 {
683
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];
684 102 i = next_char - 1;
685 51 found = true;
686 }
687 }
688
689
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 102 times.
114 if(!found){
690
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 12 times.
120 for(; is_ualnum(user_function.content[i]); i++){
691
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
108 real_content += user_function.content[i];
692 }
693
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 real_content += user_function.content[i];
694 }
695 }
696
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
66 const char * oldstr=str;
697 66 str = (const char *)real_content;
698
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
66 double result = eval(0);
699 66 str = oldstr;
700 66 return result;
701 66 }
702
703 108 void createuserfunc(const char * name, const char * arguments, const char * content)
704 {
705
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);
706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if(functions.exists(name)) //functions holds both types.
707 {
708 asar_throw_error(0, error_type_block, error_id_function_redefined, name);
709 }
710 108 funcdat& user_function=user_functions[name];
711 108 user_function.name= duplicate_string(name);
712 108 user_function.argbuf= duplicate_string(arguments);
713 108 user_function.arguments=split(user_function.argbuf, ',', &(user_function.numargs));
714 108 user_function.content= duplicate_string(content);
715
2/2
✓ Branch 0 taken 162 times.
✓ Branch 1 taken 108 times.
270 for (int i=0;user_function.arguments[i];i++)
716 {
717
2/2
✓ Branch 0 taken 270 times.
✓ Branch 1 taken 162 times.
432 for(int j=0;user_function.arguments[j];j++)
718 {
719
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]))
720 {
721 asar_throw_error(0, error_type_block, error_id_duplicate_param_name, user_function.arguments[i], name);
722 }
723 }
724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 162 times.
162 if (!confirmname(user_function.arguments[i]))
725 {
726 user_functions.remove(name);
727 asar_throw_error(0, error_type_block, error_id_invalid_param_name);
728 }
729 }
730
731 108 functions[name] = asar_call_user_function;
732 108 }
733
734 inline const long hextable[] = {
735 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
736 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
737 -1,-1, 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,-1,10,11,12,13,14,15,-1,
738 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
739 -1,-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
740 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
741 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
742 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
743 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
744 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
745 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
746 };
747
748 51478 static double getnumcore()
749 {
750
2/2
✓ Branch 0 taken 13636 times.
✓ Branch 1 taken 37842 times.
51478 if (*str=='$')
751 {
752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13636 times.
13636 if (!is_xdigit(*++str)) asar_throw_error(2, error_type_block, error_id_invalid_hex_value);
753 6844 uint64_t ret = 0;
754
2/2
✓ Branch 0 taken 46468 times.
✓ Branch 1 taken 13636 times.
60104 while (hextable[0 + *str] >= 0) {
755 46468 ret = (ret << 4) | hextable[0 + *str++];
756 }
757 13636 return ret;
758 }
759
8/8
✓ Branch 0 taken 33900 times.
✓ Branch 1 taken 3942 times.
✓ Branch 2 taken 33894 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 33876 times.
✓ Branch 6 taken 1983 times.
✓ Branch 7 taken 16955 times.
37842 if (is_ualpha(*str) || *str=='.' || *str=='?')
760 {
761 3966 const char * start=str;
762
6/6
✓ Branch 0 taken 17418 times.
✓ Branch 1 taken 17418 times.
✓ Branch 2 taken 288 times.
✓ Branch 3 taken 3966 times.
✓ Branch 4 taken 15435 times.
✓ Branch 5 taken 1983 times.
34836 while (is_ualnum(*str) || *str == '.') str++;
763 3966 int len=(int)(str-start);
764
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 3966 times.
4074 while (*str==' ') str++;
765
2/2
✓ Branch 0 taken 2370 times.
✓ Branch 1 taken 1596 times.
3966 if (*str=='(')
766 {
767 2370 str++;
768 // RPG Hacker: This is only here to assure that all strings are still
769 // alive in memory when we call our functions further down
770 double result;
771 while (true)
772 {
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2370 times.
2370 while (*str==' ') str++;
774
1/2
✓ Branch 0 taken 1185 times.
✗ Branch 1 not taken.
2370 string function_name = string(start, len);
775
2/4
✓ Branch 0 taken 2370 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1185 times.
✗ Branch 3 not taken.
2370 if(functions.exists(function_name))
776 {
777 2370 current_user_function_name = function_name;
778
3/4
✓ Branch 0 taken 2370 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2352 times.
✓ Branch 3 taken 18 times.
2370 result = functions[function_name]();
779 }
780 else
781 {
782 str++;
783 break;
784 }
785
786
1/2
✓ Branch 0 taken 2352 times.
✗ Branch 1 not taken.
2352 if (*str==')')
787 {
788 2352 str++;
789 1176 return result;
790 }
791 asar_throw_error(2, error_type_block, error_id_malformed_function_call);
792
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1176 times.
2370 }
793
794 asar_throw_error(2, error_type_block, error_id_function_not_found, start);
795 }
796 else
797 {
798 1596 foundlabel=true;
799
800 798 const char *old_start = start;
801
2/2
✓ Branch 0 taken 795 times.
✓ Branch 1 taken 3 times.
1596 snes_label label_data = labelval(&start);
802 1590 int i=(int)label_data.pos;
803 1590 foundlabel_static &= label_data.is_static;
804
2/2
✓ Branch 0 taken 795 times.
✓ Branch 1 taken 795 times.
1590 if(str < start)
805 {
806
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
120 if ((str = strchr(str, '[')))
807 {
808
1/2
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
102 string struct_name = substr(old_start, (int)(str - old_start));
809 102 str++;
810
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));
811 102 }
812 }
813
814 1590 str=start;
815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1590 times.
1590 if (i==-1) forwardlabel=true;
816 1590 return (int)i&0xFFFFFF;
817 }
818 }
819
2/2
✓ Branch 0 taken 438 times.
✓ Branch 1 taken 33438 times.
33876 if (*str=='(')
820 {
821 438 str++;
822 438 double rval=eval(0);
823
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);
824 438 str++;
825 438 return rval;
826 }
827
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 33366 times.
33438 if (*str=='%')
828 {
829
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
72 if (str[1] != '0' && str[1] != '1') asar_throw_error(2, error_type_block, error_id_invalid_binary_value);
830 72 return strtoull(str+1, const_cast<char**>(&str), 2);
831 }
832
2/2
✓ Branch 0 taken 660 times.
✓ Branch 1 taken 32706 times.
33366 if (*str=='\'')
833 {
834
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);
835 int orig_val;
836 660 str++;
837
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 str += utf8_val(&orig_val, str);
838
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);
839
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);
840
1/2
✓ Branch 0 taken 330 times.
✗ Branch 1 not taken.
660 int64_t rval=thetable.get_val(orig_val);
841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
660 if (rval == -1)
842 {
843 // RPG Hacker: Should be fine to not check return value of codepoint_to_utf8() here, because
844 // our error cases above already made sure that orig_val contains valid data at this point.
845 string u8_str;
846 codepoint_to_utf8(&u8_str, orig_val);
847 asar_throw_error(2, error_type_block, error_id_undefined_char, u8_str.data());
848 }
849 660 str++;
850 660 return rval;
851 }
852
2/2
✓ Branch 0 taken 32676 times.
✓ Branch 1 taken 30 times.
32706 if (is_digit(*str))
853 {
854 16355 const char* end = str;
855
6/6
✓ Branch 0 taken 37991 times.
✓ Branch 1 taken 38015 times.
✓ Branch 2 taken 246 times.
✓ Branch 3 taken 32676 times.
✓ Branch 4 taken 21694 times.
✓ Branch 5 taken 16355 times.
76006 while (is_digit(*end) || *end == '.') end++;
856 16355 string number;
857
1/2
✓ Branch 0 taken 16355 times.
✗ Branch 1 not taken.
32676 number.assign(str, (int)(end - str));
858 32676 str = end;
859 32676 return atof(number);
860 32676 }
861 30 asar_throw_error(2, error_type_block, error_id_invalid_number);
862 return 0.0;
863 }
864
865 51556 inline double sanitize(double val)
866 {
867
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51556 times.
51556 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
868 51556 return val;
869 }
870
871 51610 static double getnum()
872 {
873
2/2
✓ Branch 0 taken 6966 times.
✓ Branch 1 taken 51610 times.
58576 while (*str==' ') str++;
874
2/2
✓ Branch 0 taken 13636 times.
✓ Branch 1 taken 37974 times.
51610 if(*str == '$') return sanitize(getnumcore()); //optimize for the common case
875 #define prefix(sym, func) if (*str == sym) { str+=1; double val=getnum(); return sanitize(func); }
876 #define prefix2(sym, sym2, func) if (*str == sym && *(str+1) == sym2) { str+=2; double val=getnum(); return sanitize(func); }
877
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 37866 times.
37974 prefix('-', -val);
878
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 37854 times.
37866 prefix('~', ~(int)val);
879
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 37812 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 30 times.
37854 prefix2('<', ':', (int)val>>16);
880
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37842 times.
37842 prefix('+', val);
881 #undef prefix
882 #undef prefix2
883 37842 return sanitize(getnumcore());
884 }
885
886 28903 int64_t getnum(const char* instr)
887 {
888 28903 double num = math(instr);
889
2/2
✓ Branch 0 taken 14361 times.
✓ Branch 1 taken 14446 times.
28807 if(num < (double)INT64_MIN) {
890 return INT64_MIN;
891
2/2
✓ Branch 0 taken 14361 times.
✓ Branch 1 taken 14446 times.
28807 } else if(num > (double)INT64_MAX) {
892 return INT64_MAX;
893 }
894 28807 return (int64_t)num;
895 }
896
897 // RPG Hacker: Same function as above, but doesn't truncate our number via int conversion
898 5904 double getnumdouble(const char * instr)
899 {
900 5904 return math(instr);
901 }
902
903
904 6 static double oper_wrapped_throw(asar_error_id errid)
905 {
906 6 asar_throw_error(2, error_type_block, errid);
907 return 0.0;
908 }
909
910 51552 static double eval(int depth)
911 {
912 51552 const char* posneglabel = str;
913
1/2
✓ Branch 0 taken 25820 times.
✗ Branch 1 not taken.
51552 string posnegname = posneglabelname(&posneglabel, false);
914
915
4/4
✓ Branch 0 taken 25916 times.
✓ Branch 1 taken 25636 times.
✓ Branch 2 taken 98 times.
✓ Branch 3 taken 25722 times.
51552 if (posnegname.length() > 0)
916 {
917
3/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
194 if (*posneglabel != '\0' && *posneglabel != ')') goto notposneglabel;
918
919 86 str = posneglabel;
920
921 86 foundlabel=true;
922
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 13 times.
86 if (*(posneglabel-1) == '+') forwardlabel=true;
923
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);
924 86 foundlabel_static &= label_data.is_static;
925 86 return label_data.pos & 0xFFFFFF;
926 }
927
1/2
✓ Branch 0 taken 25690 times.
✗ Branch 1 not taken.
51412 notposneglabel:
928
1/2
✓ Branch 0 taken 25776 times.
✗ Branch 1 not taken.
77242 recurseblock rec;
929
2/2
✓ Branch 0 taken 51412 times.
✓ Branch 1 taken 54 times.
51466 double left=getnum();
930 double right;
931
2/2
✓ Branch 0 taken 6966 times.
✓ Branch 1 taken 51412 times.
58378 while (*str==' ') str++;
932
8/8
✓ Branch 0 taken 16003 times.
✓ Branch 1 taken 50032 times.
✓ Branch 2 taken 15094 times.
✓ Branch 3 taken 909 times.
✓ Branch 4 taken 14830 times.
✓ Branch 5 taken 264 times.
✓ Branch 6 taken 7391 times.
✓ Branch 7 taken 51 times.
66035 while (*str && *str != ')' && *str != ','&& *str != ']')
933 {
934
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14779 times.
14779 while (*str==' ') str++;
935 #define oper(name, thisdepth, contents) \
936 if (!strncmp(str, name, strlen(name))) \
937 { \
938 if (depth<=thisdepth) \
939 { \
940 str+=strlen(name); \
941 right=eval(thisdepth+1); \
942 } \
943 else return left; \
944 left=contents; \
945 continue; \
946 }
947
4/6
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 14743 times.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
14779 oper("**", 6, pow((double)left, (double)right));
948
4/6
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 14653 times.
✓ Branch 2 taken 90 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
14743 oper("*", 5, left*right);
949
7/10
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 14629 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.
14653 oper("/", 5, right != 0.0 ? left / right : oper_wrapped_throw(error_id_division_by_zero));
950
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 14629 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.
14629 oper("%", 5, right != 0.0 ? fmod((double)left, (double)right) : oper_wrapped_throw(error_id_modulo_by_zero));
951
5/6
✓ Branch 0 taken 5995 times.
✓ Branch 1 taken 8634 times.
✓ Branch 2 taken 5935 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 5935 times.
✗ Branch 5 not taken.
14629 oper("+", 4, left+right);
952
4/6
✓ Branch 0 taken 1578 times.
✓ Branch 1 taken 7056 times.
✓ Branch 2 taken 1578 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1578 times.
✗ Branch 5 not taken.
8634 oper("-", 4, left-right);
953
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 7056 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.
7056 oper("<<", 3, right >= 0.0 ? (int64_t)left<<(uint64_t)right : oper_wrapped_throw(error_id_negative_shift));
954
1/10
✗ Branch 0 not taken.
✓ Branch 1 taken 7056 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.
7056 oper(">>", 3, right >= 0.0 ? (int64_t)left>>(uint64_t)right : oper_wrapped_throw(error_id_negative_shift));
955
956 //these two needed checked early to avoid bitwise from eating a operator
957
8/10
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 6984 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.
7065 oper("&&", 0, (int64_t)left&&(int64_t)right);
958
7/10
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 6948 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.
6984 oper("||", 0, (int64_t)left||(int64_t)right);
959
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6948 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6948 oper("&", 2, (int64_t)left&(int64_t)right);
960
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6948 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6948 oper("|", 2, (int64_t)left|(int64_t)right);
961
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6948 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6948 oper("^", 2, (int64_t)left^(int64_t)right);
962
963
6/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 6930 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.
6948 oper(">=", 1, left>=right);
964
1/8
✗ Branch 0 not taken.
✓ Branch 1 taken 6930 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.
6930 oper("<=", 1, left<=right);
965
6/8
✓ Branch 0 taken 414 times.
✓ Branch 1 taken 6516 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.
6975 oper(">", 1, left>right);
966
6/8
✓ Branch 0 taken 5364 times.
✓ Branch 1 taken 1152 times.
✓ Branch 2 taken 5364 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5364 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2682 times.
✓ Branch 7 taken 2682 times.
6813 oper("<", 1, left<right);
967
6/8
✓ Branch 0 taken 1098 times.
✓ Branch 1 taken 54 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.
1503 oper("==", 1, left==right);
968
6/8
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 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.
54 oper("!=", 1, left!=right);
969
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 asar_throw_error(2, error_type_block, error_id_unknown_operator);
970 #undef oper
971 }
972 25671 return left;
973 51552 }
974
975 //static autoptr<char*> freeme;
976 34973 double math(const char * s)
977 {
978 //free(freeme);
979 //freeme=NULL;
980 34973 foundlabel=false;
981 34973 foundlabel_static=true;
982 34973 forwardlabel=false;
983 34973 str = s;
984 34973 double rval = eval(0);
985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34877 times.
34877 if (*str)
986 {
987 if (*str == ',') asar_throw_error(2, error_type_block, error_id_invalid_input);
988 else asar_throw_error(2, error_type_block, error_id_mismatched_parentheses);
989 }
990 34877 return rval;
991 }
992
993 2293 void initmathcore()
994 {
995 2293 functions.reset();
996 2293 builtin_functions.each([](const char* key, double (*val)()) {
997 149045 functions[key] = val;
998 149045 });
999 2293 user_functions.reset();
1000 2293 }
1001
1002 2263 void deinitmathcore()
1003 {
1004 //not needed
1005 2263 }
1006