asar coverage - build #272


src/asar/
File: src/asar/math_functions.cpp
Date: 2025-03-03 19:47:10
Lines:
229/238
96.2%
Functions:
92/100
92.0%
Branches:
370/579
63.9%

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