asar coverage - build #260


src/asar/
File: src/asar/math_functions.cpp
Date: 2025-02-27 15:42:33
Lines:
194/231
84.0%
Functions:
75/96
78.1%
Branches:
210/390
53.8%

Line Branch Exec Source
1 #include "asar.h"
2 #include "assembleblock.h"
3 #include "math_ast.h"
4 #include "platform/file-helpers.h"
5 #include "macro.h"
6
7 namespace {
8 struct cachedfile {
9 string filename;
10 virtual_file_handle filehandle;
11 size_t filesize;
12 bool used;
13 };
14
15 #define numcachedfiles 16
16
17 cachedfile cachedfiles[numcachedfiles];
18 int cachedfileindex = 0;
19
20 // Opens a file, trying to open it from cache first
21
22 168 cachedfile * opencachedfile(string fname, bool should_error)
23 {
24 84 cachedfile * cachedfilehandle = nullptr;
25
26
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 const char* current_file = get_current_file_name();
27
28 // RPG Hacker: Only using a combined path here because that should
29 // hopefully result in a unique string for every file, whereas
30 // fname could be a relative path, which isn't guaranteed to be unique.
31 // Note that this does not affect how we open the file - this is
32 // handled by the filesystem and uses our include paths etc.
33
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);
34
35
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 54 times.
1104 for (int i = 0; i < numcachedfiles; i++)
36 {
37
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)
38 {
39 114 cachedfilehandle = &cachedfiles[i];
40 57 break;
41 }
42 }
43
44
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 57 times.
84 if (cachedfilehandle == nullptr)
45 {
46
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (cachedfiles[cachedfileindex].used)
47 {
48 filesystem->close_file(cachedfiles[cachedfileindex].filehandle);
49 cachedfiles[cachedfileindex].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
50 cachedfiles[cachedfileindex].used = false;
51 }
52
53 54 cachedfilehandle = &cachedfiles[cachedfileindex];
54 }
55
56
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if (cachedfilehandle != nullptr)
57 {
58
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 114 times.
168 if (!cachedfilehandle->used)
59 {
60
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 cachedfilehandle->filehandle = filesystem->open_file(fname, current_file);
61
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 30 times.
54 if (cachedfilehandle->filehandle != INVALID_VIRTUAL_FILE_HANDLE)
62 {
63 24 cachedfilehandle->used = true;
64
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 cachedfilehandle->filename = combinedname;
65
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 cachedfilehandle->filesize = filesystem->get_file_size(cachedfilehandle->filehandle);
66 24 cachedfileindex++;
67 // randomdude999: when we run out of cached files, just start overwriting ones from the start
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (cachedfileindex >= numcachedfiles) cachedfileindex = 0;
69 }
70 }
71 }
72
73
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)
74 {
75 asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), fname.data());
76 }
77
78 168 return cachedfilehandle;
79 168 }
80 // closecachedfiles is declared at the end of the file outside namespace{}
81
82
83
84
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1182 times.
2364 void assert_argc(const std::vector<math_val>& args, int expected_args) {
85
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2364 times.
2364 if(args.size() != expected_args) {
86 asar_throw_error(2, error_type_block, error_id_argument_count, expected_args, (int)args.size());
87 }
88 2364 }
89
90 // these templates could be implemented in a fully generic way too (without
91 // specializing per argument count), but that looks a little too cryptic to me.
92 template<math_val (*F)()>
93 180 math_val fixed_arity(const std::vector<math_val>& args) {
94 180 assert_argc(args, 0);
95 180 return F();
96 }
97 template<math_val (*F)(math_val)>
98 3540 math_val fixed_arity(const std::vector<math_val>& args) {
99 3540 assert_argc(args, 1);
100
4/4
✓ Branch 0 taken 1764 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 879 times.
✓ Branch 3 taken 6 times.
5298 return F(args[0]);
101 }
102 template<math_val (*F)(math_val,math_val)>
103 180 math_val fixed_arity(const std::vector<math_val>& args) {
104 180 assert_argc(args, 2);
105
3/6
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 45 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 45 times.
✗ Branch 5 not taken.
270 return F(args[0], args[1]);
106 }
107 template<math_val (*F)(math_val,math_val,math_val)>
108 156 math_val fixed_arity(const std::vector<math_val>& args) {
109 156 assert_argc(args, 3);
110
4/8
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 39 times.
✗ Branch 7 not taken.
186 return F(args[0], args[1], args[2]);
111 }
112
113 template<double (*F)(double)>
114 math_val fn_unary_real(const std::vector<math_val>& args) {
115 assert_argc(args, 1);
116 double val = F(args[0].get_double());
117 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
118 return val;
119 };
120
121 template<double (*F)(double)>
122 math_val fn_rounding(const std::vector<math_val>& args) {
123 assert_argc(args, 1);
124 double val = F(args[0].get_double());
125 // TODO where should we check this? math_val(double) constructor maybe?
126 if (val != val) asar_throw_error(2, error_type_block, error_id_nan);
127 return float_to_int(val);
128 };
129
130 template<math_binop_type OP>
131 192 math_val math_binop_function(const std::vector<math_val>& args) {
132 192 assert_argc(args, 2);
133
3/6
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✗ Branch 5 not taken.
288 return evaluate_binop(args[0], args[1], OP);
134 }
135
136 template<bool (*F)(bool, bool)>
137 180 math_val math_bool_binop_function(const std::vector<math_val>& args) {
138 180 assert_argc(args, 2);
139 180 return (int64_t)F(args[0].get_bool(), args[1].get_bool());
140 }
141
142
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
18 bool fn_and(bool a, bool b) { return a && b; }
143
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
18 bool fn_or(bool a, bool b) { return a || b; }
144
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
18 bool fn_nand(bool a, bool b) { return !(a && b); }
145
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
18 bool fn_nor(bool a, bool b) { return !(a || b); }
146 18 bool fn_xor(bool a, bool b) { return a ^ b; }
147
148 24 math_val fn_select(math_val cond, math_val a, math_val b) {
149
4/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 21 times.
48 return cond.get_bool() ? a : b;
150 }
151
152 template<int (*F)(int)>
153 600 math_val fn_snes_pc(math_val arg) {
154 600 return (int64_t)F(arg.get_integer());
155 }
156
157 template<int& variable>
158 90 math_val fn_pc_realbase() {
159 135 return (int64_t)variable;
160 }
161
162 6 math_val fn_bank(math_val arg) {
163 6 return (arg.get_integer() >> 16);
164 }
165
166 12 math_val fn_safediv(math_val a, math_val b, math_val default_) {
167
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if(b.get_double() == 0.0) return default_;
168
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
9 return evaluate_binop(a, b, math_binop_type::div);
169 }
170
171 48 math_val fn_not(math_val arg) {
172 48 return (int64_t)!arg.get_bool();
173 }
174
175 template<int (*F)(const char*, const char*)>
176 108 math_val fn_str_eq(math_val va, math_val vb) {
177 108 const string& a = va.get_str();
178 108 const string& b = vb.get_str();
179 108 bool result = F(a.data(), b.data()) == 0;
180 108 return (int64_t)result;
181 }
182
183 math_val fn_char(math_val str_, math_val ind_) {
184 const string& s = str_.get_str();
185 int64_t ind = ind_.get_integer();
186 if(ind < 0 || ind > s.length())
187 asar_throw_error(2, error_type_block, error_id_oob, (int)ind, s.length());
188 return (int64_t)(unsigned char)s[ind];
189 }
190 math_val fn_strlen(math_val val) {
191 return (int64_t)val.get_str().length();
192 }
193
194 template<int count>
195
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
132 math_val fn_read(const std::vector<math_val>& args) {
196
3/6
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 66 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 33 times.
132 if(args.size() < 1 || args.size() > 2) {
197 // TODO expected amount should be string to show the range
198 asar_throw_error(2, error_type_block, error_id_argument_count, 2, (int)args.size());
199 }
200
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
132 int64_t target = args[0].get_integer();
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
132 int addr = snestopc(target);
202
203
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
132 if(args.size() == 2) {
204 math_val default_val = args[1];
205 if(addr < 0) return default_val;
206 if(addr + count > romlen_r) return default_val;
207 } else {
208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
132 if (addr < 0)
209 asar_throw_error(2, error_type_block, error_id_snes_address_doesnt_map_to_rom, (hex((unsigned int)target, 6) + " in read function").data());
210
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 60 times.
132 else if (addr + count > romlen_r)
211
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
30 asar_throw_error(2, error_type_block, error_id_snes_address_out_of_bounds, (hex(target, 6) + " in read function").data());
212 }
213
214 60 int64_t value = 0;
215
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 60 times.
312 for(int i = 0; i < count; i++)
216 {
217 192 value |= romdata_r[addr+i] << (8 * i);
218 }
219 60 return value;
220 }
221 template<int count>
222 216 math_val fn_canread(const std::vector<math_val>& args) {
223 108 int64_t length = count;
224 int64_t addr;
225 if(count == 0) {
226 assert_argc(args, 2);
227 length = args[0].get_integer();
228 addr = args[1].get_integer();
229 } else {
230 216 assert_argc(args, 1);
231 216 addr = args[0].get_integer();
232 }
233 216 int addr_pc = snestopc(addr);
234
3/4
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 54 times.
216 if (addr_pc<0 || addr_pc+length-1>=romlen_r) return (int64_t)0;
235 54 else return (int64_t)1;
236 }
237
238 template<int count>
239
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
168 math_val fn_readfile(const std::vector<math_val>& args) {
240
3/6
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
168 if(args.size() < 2 || args.size() > 3) {
241 // TODO expected amount should be string to show the range
242 asar_throw_error(2, error_type_block, error_id_argument_count, 3, (int)args.size());
243 }
244
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
168 string fname = args[0].get_str();
245
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 int64_t offset = args[1].get_integer();
246 168 bool should_error = args.size() == 2;
247
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
168 cachedfile * fhandle = opencachedfile(fname, should_error);
248
249
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 48 times.
168 if(!should_error) {
250
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
36 math_val default_val = args[2];
251
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 30 times.
72 if(fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return default_val;
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
60 if(offset < 0) return default_val;
253
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
60 if(offset + count > fhandle->filesize) return default_val;
254
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
36 } else {
255
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
96 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE)
256 asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), fname.data());
257
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 48 times.
96 if (offset < 0 || offset + count > fhandle->filesize)
258 asar_throw_error(2, error_type_block, error_id_file_offset_out_of_bounds, dec(offset).data(), fname.data());
259 }
260
261 132 unsigned char data[4] = { 0, 0, 0, 0 };
262
1/2
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
132 filesystem->read_file(fhandle->filehandle, data, offset, count);
263
264 66 int64_t value = 0;
265
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 66 times.
348 for(size_t i = 0; i < count; i++)
266 {
267 216 value |= data[i] << (8 * i);
268 }
269
270 66 return value;
271 168 }
272
273 template<int count>
274
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
84 math_val fn_canreadfile(const std::vector<math_val>& args) {
275 42 string fname;
276 42 int64_t length = count;
277 int64_t offset;
278 if(count == 0) {
279
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 assert_argc(args, 3);
280
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
24 fname = args[0].get_str();
281
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 offset = args[1].get_integer();
282
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
24 length = args[2].get_integer();
283 } else {
284
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
60 assert_argc(args, 2);
285
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
60 fname = args[0].get_str();
286
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
60 offset = args[1].get_integer();
287 }
288
289
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
84 cachedfile * fhandle = opencachedfile(fname, false);
290
3/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 36 times.
84 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE) return (int64_t)0;
291
3/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24 times.
72 if (offset < 0 || offset + length > fhandle->filesize) return (int64_t)0;
292 24 return (int64_t)1;
293 84 }
294
295 30 math_val fn_min(math_val a, math_val b) {
296
3/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
45 math_val cond = evaluate_binop(a, b, math_binop_type::comp_lt);
297
4/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
60 return cond.get_bool() ? a : b;
298 15 }
299 30 math_val fn_max(math_val a, math_val b) {
300
3/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
45 math_val cond = evaluate_binop(a, b, math_binop_type::comp_gt);
301
4/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
60 return cond.get_bool() ? a : b;
302 15 }
303 18 math_val fn_clamp(math_val val, math_val lo, math_val hi) {
304 // compute temp = min(hi, val)
305
3/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
27 math_val temp = fn_min(hi, val);
306
3/6
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
36 return fn_max(lo, temp);
307 9 }
308
309 12 math_val fn_round(math_val val, math_val precision) {
310 // i used to hate the float->str->float approach, but the
311 // alternatives do end up quite messy if implemented properly
312
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 string as_str = ftostrvar(val.get_double(), precision.get_integer());
313 12 double res = std::atof(as_str);
314 18 return res;
315 12 }
316 156 math_val fn_isdefined(math_val defname) {
317 156 return (int64_t)defines.exists(defname.get_str());
318 }
319
320 6 math_val fn_filesize(math_val fname) {
321
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 string name = fname.get_str();
322
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);
323
2/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
6 if (fhandle == nullptr || fhandle->filehandle == INVALID_VIRTUAL_FILE_HANDLE)
324 asar_throw_error(2, error_type_block, vfile_error_to_error_id(asar_get_last_io_error()), name.data());
325 9 return (int64_t)fhandle->filesize;
326 6 }
327
328 36 math_val fn_filestatus(math_val fname) {
329
3/6
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
54 cachedfile * fhandle = opencachedfile(fname.get_str(), false);
330
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) {
331
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (filesystem->get_last_error() == vfe_doesnt_exist)
332 9 return (int64_t)1;
333 else return (int64_t)2;
334 }
335 9 return (int64_t)0;
336 }
337
338 1068 math_val fn_sizeof(math_val val) {
339
2/4
✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 534 times.
✗ Branch 3 not taken.
1068 string symbol = val.get_identifier();
340 // TODO: do we have a better spot where to parse this...?
341
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 18 times.
1068 if(symbol == "..."){
342
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);
343
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(...)");
344 1038 return (int64_t)numvarargs;
345 }
346
4/8
✓ 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 18 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
18 if(pass && !structs.exists(symbol)) asar_throw_error(2, error_type_block, error_id_struct_not_found, symbol.data());
347
2/4
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
18 else if(!structs.exists(symbol)) return (int64_t)0;
348
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 return (int64_t)structs.find(symbol).struct_size;
349 1068 }
350
351 120 math_val fn_objectsize(math_val val) {
352
2/4
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
120 string symbol = val.get_identifier();
353
5/8
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 96 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 96 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 60 times.
120 if(pass && !structs.exists(symbol)) asar_throw_error(2, error_type_block, error_id_struct_not_found, symbol.data());
354
2/4
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 120 times.
120 else if(!structs.exists(symbol)) return (int64_t)0;
355
1/2
✓ Branch 0 taken 120 times.
✗ Branch 1 not taken.
120 return (int64_t)structs.find(symbol).object_size;
356 120 }
357
358 30 math_val fn_datasize(math_val val) {
359
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 string name = val.get_identifier();
360 int label;
361
2/4
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
30 if(!labels.exists(name)) asar_throw_error(2, error_type_block, error_id_label_not_found, name.data());
362
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 snes_label label_data = labels.find(name);
363
364 15 label = label_data.id;
365 15 snes_label selected_label;
366 30 selected_label.id = 0xFFFFFF;
367 30 selected_label.pos = 0xFFFFFF;
368 30 labels.each([&selected_label, label](const char *key, snes_label current_label){
369
3/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
90 if(label < current_label.id && current_label.id < selected_label.id){
370 24 selected_label = current_label;
371 }
372 90 });
373
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
30 if(selected_label.id == 0xFFFFFF) asar_throw_warning(2, warning_id_datasize_last_label, name.data());
374
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
30 if(selected_label.pos-label_data.pos > 0xFFFF) asar_throw_warning(2, warning_id_datasize_exceeds_size, name.data());
375 45 return (int64_t)(selected_label.pos-label_data.pos);
376 30 }
377
378 } // namespace
379
380 1543 void closecachedfiles()
381 {
382
2/2
✓ Branch 0 taken 24688 times.
✓ Branch 1 taken 1543 times.
26231 for (int i = 0; i < numcachedfiles; i++)
383 {
384
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24664 times.
24688 if (cachedfiles[i].used)
385 {
386
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)
387 {
388 24 filesystem->close_file(cachedfiles[i].filehandle);
389 24 cachedfiles[i].filehandle = INVALID_VIRTUAL_FILE_HANDLE;
390 }
391
392 24 cachedfiles[i].used = false;
393 }
394 }
395
396 1543 cachedfileindex = 0;
397 1543 }
398
399 const std::unordered_map<string, math_builtin_function> builtin_functions = {
400 { "sqrt", fn_unary_real<sqrt> },
401 { "sin", fn_unary_real<sin> },
402 { "cos", fn_unary_real<cos> },
403 { "tan", fn_unary_real<tan> },
404 { "asin", fn_unary_real<asin> },
405 { "acos", fn_unary_real<acos> },
406 { "atan", fn_unary_real<atan> },
407 { "arcsin", fn_unary_real<asin> },
408 { "arccos", fn_unary_real<acos> },
409 { "arctan", fn_unary_real<atan> },
410 { "log", fn_unary_real<log> },
411 { "log10", fn_unary_real<log10> },
412 { "log2", fn_unary_real<log2> },
413
414 { "ceil", fn_rounding<ceil> },
415 { "floor", fn_rounding<floor> },
416
417 { "read1", fn_read<1> }, //This handles the safe and unsafe variant
418 { "read2", fn_read<2> },
419 { "read3", fn_read<3> },
420 { "read4", fn_read<4> },
421 { "canread", fn_canread<0> },
422 { "canread1", fn_canread<1> },
423 { "canread2", fn_canread<2> },
424 { "canread3", fn_canread<3> },
425 { "canread4", fn_canread<4> },
426
427 { "readfile1", fn_readfile<1> },
428 { "readfile2", fn_readfile<2> },
429 { "readfile3", fn_readfile<3> },
430 { "readfile4", fn_readfile<4> },
431 { "canreadfile", fn_canreadfile<0> },
432 { "canreadfile1", fn_canreadfile<1> },
433 { "canreadfile2", fn_canreadfile<2> },
434 { "canreadfile3", fn_canreadfile<3> },
435 { "canreadfile4", fn_canreadfile<4> },
436
437 { "filesize", fixed_arity<fn_filesize> },
438 { "getfilestatus", fixed_arity<fn_filestatus> },
439
440 { "defined", fixed_arity<fn_isdefined> },
441
442 { "snestopc", fixed_arity<fn_snes_pc<snestopc>> },
443 { "pctosnes", fixed_arity<fn_snes_pc<pctosnes>> },
444 { "realbase", { fixed_arity<fn_pc_realbase<realsnespos>>, 3 } },
445 { "pc", { fixed_arity<fn_pc_realbase<snespos>>, 3 } },
446
447 { "max", fixed_arity<fn_max> },
448 { "min", fixed_arity<fn_min> },
449 { "clamp", fixed_arity<fn_clamp> },
450
451 { "safediv", fixed_arity<fn_safediv> },
452
453 { "select", fixed_arity<fn_select> },
454 { "bank", { fixed_arity<fn_bank>, 0, true } }, // hack: 3rd initializer member is "is this the bank function?", needed for get_len
455 { "not", fixed_arity<fn_not> },
456 { "equal", math_binop_function<math_binop_type::comp_eq> },
457 { "notequal", math_binop_function<math_binop_type::comp_ne> },
458 { "less", math_binop_function<math_binop_type::comp_lt> },
459 { "lessequal", math_binop_function<math_binop_type::comp_le> },
460 { "greater", math_binop_function<math_binop_type::comp_gt> },
461 { "greaterequal", math_binop_function<math_binop_type::comp_ge> },
462
463 { "and", math_bool_binop_function<fn_and> },
464 { "or", math_bool_binop_function<fn_or> },
465 { "nand", math_bool_binop_function<fn_nand> },
466 { "nor", math_bool_binop_function<fn_nor> },
467 { "xor", math_bool_binop_function<fn_xor> },
468
469 { "round", fixed_arity<fn_round> },
470
471 { "sizeof", fixed_arity<fn_sizeof> },
472 { "objectsize", fixed_arity<fn_objectsize> },
473 { "datasize", { fixed_arity<fn_datasize>, 3 } },
474
475 { "stringsequal", fixed_arity<fn_str_eq<strcmp>> },
476 { "stringsequalnocase", fixed_arity<fn_str_eq<stricmp>> },
477 { "char", fixed_arity<fn_char> },
478 { "stringlength", fixed_arity<fn_strlen> },
479 };
480