asar coverage - build #325


src/asar/
File: src/asar/assembleblock.cpp
Date: 2025-11-04 16:32:25
Lines:
1303/1417
92.0%
Functions:
130/135
96.3%
Branches:
1988/3301
60.2%

Line Branch Exec Source
1 #include "addr2line.h"
2 #include "asar.h"
3 #include "assembleblock.h"
4 #include "asar_math.h"
5 #include "macro.h"
6 #include "table.h"
7 #include "unicode.h"
8 #include "frozen/string.h"
9 #include "frozen/unordered_map.h"
10
11 #include "interface-shared.h"
12 #include "arch-shared.h"
13
14 int arch=arch_65816;
15
16 bool snespos_valid = false;
17 int snespos;
18 int realsnespos;
19 int startpos;
20 int realstartpos;
21
22 static bool mapper_set = false;
23 int label_counter = 0;
24
25 static int old_snespos;
26 static int old_startpos;
27 static int old_optimizeforbank;
28 static bool old_snespos_valid;
29 static int struct_base;
30 static string struct_name;
31 static string struct_parent;
32 static bool in_struct = false;
33 static bool in_sub_struct = false;
34 static bool static_struct = false;
35 static bool in_spcblock = false;
36
37 assocarr<snes_struct> structs;
38
39 static bool movinglabelspossible = false;
40
41 static bool disable_bank_cross_errors = false;
42 static bool check_half_banks_crossed = false;
43
44 int bytes;
45 static int freespaceuse=0;
46
47 static enum {
48 ratsmeta_ban,
49 ratsmeta_allow,
50 ratsmeta_used,
51 } ratsmetastate=ratsmeta_ban;
52
53 enum spcblock_type{
54 spcblock_nspc,
55 spcblock_custom
56 };
57
58 static struct spcblock_data{
59 unsigned int destination;
60 spcblock_type type;
61 string macro_name;
62
63 unsigned int size_address;
64 mapper_t old_mapper;
65 }spcblock;
66
67 438115 static inline void verifysnespos()
68 {
69
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 438115 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 219152 times.
438115 if (!snespos_valid)
70 {
71 throw_err_block(0, err_missing_org);
72 snespos=0x008000;
73 realsnespos=0x008000;
74 startpos=0x008000;
75 realstartpos=0x008000;
76 snespos_valid = true;
77 }
78 438115 }
79
80 552 static int fixsnespos(int inaddr, int step)
81 {
82 // randomdude999: turns out it wasn't very reliable at all.
83 /* // RPG Hacker: No idea how reliable this is.
84 // Might not work with some of the more exotic mappers.
85 return pctosnes(snestopc(inaddr) + step); */
86
4/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 504 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 228 times.
552 if (mapper == lorom) {
87
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 84 times.
96 if ((inaddr&0xFFFF)+step > 0xFFFF) {
88 // bank crossed
89 12 return inaddr+step+0x8000;
90 }
91 84 return inaddr+step;
92
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == hirom) {
93 if ((inaddr&0x400000) == 0 && freespaceid == 0) {
94 // we shouldn't get here in pass 2 inside a freespace anyways i think
95 // system pages, need to account for low pages and stuff
96 if ((inaddr&0xFFFF)+step > 0xFFFF) {
97 return inaddr+step+0x8000;
98 }
99 }
100 return inaddr+step;
101
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == exlorom) {
102 // exlorom has no mirroring so this should work fine
103 return pctosnes(snestopc(inaddr)+step);
104
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == exhirom) {
105 // apparently exhirom is pretty similar to hirom after all
106 if ((inaddr&0x400000) == 0) {
107 // system pages, need to account for low pages and stuff
108 if ((inaddr&0xFFFF)+step > 0xFFFF) {
109 return inaddr+step+0x8000;
110 }
111 }
112 return inaddr+step;
113
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == sa1rom) {
114 if((inaddr&0x400000) == 0) {
115 // lorom area
116 if ((inaddr&0xFFFF)+step > 0xFFFF) {
117 return inaddr+step+0x8000;
118 }
119 return inaddr+step;
120 } else {
121 // hirom area
122 return inaddr+step;
123 }
124
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == sfxrom) {
125 if ((inaddr&0x400000) == 0) {
126 // lorom area
127 if ((inaddr&0xFFFF)+step > 0xFFFF) {
128 return inaddr+step+0x8000;
129 }
130 } else {
131 // hirom area
132 return inaddr+step;
133 }
134
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 228 times.
456 } else if (mapper == bigsa1rom) {
135 // no mirrors here, so this should work
136 return pctosnes(snestopc(inaddr)+step);
137
3/4
✓ Branch 0 taken 228 times.
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 228 times.
✗ Branch 3 not taken.
456 } else if (mapper == norom) {
138 456 return inaddr+step;
139 }
140 return -1;
141 }
142
143 437620 static inline void step(int num)
144 {
145
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 437482 times.
✓ Branch 2 taken 138 times.
✓ Branch 3 taken 218756 times.
437620 if (disable_bank_cross_errors)
146 {
147 276 snespos = fixsnespos(snespos, num);
148 276 realsnespos = fixsnespos(realsnespos, num);
149
150 // RPG Hacker: Not adjusting startpos here will eventually throw
151 // an error in checkbankcross() if we set warn bankcross on again.
152 // As far as I can tell, those are pretty much just used for
153 // checking bank crossing, anyways, so it's hopefully save to just
154 // adjust them here.
155 276 startpos = snespos;
156 276 realstartpos = realsnespos;
157 }
158 else
159 {
160 437344 snespos += num;
161 437344 realsnespos += num;
162 }
163 437620 bytes+=num;
164 437620 }
165
166 437002 void write1(unsigned int num)
167 {
168 437002 verifysnespos();
169
2/2
✓ Branch 0 taken 145638 times.
✓ Branch 1 taken 291364 times.
437002 if (pass==2)
170 {
171 145638 int pcpos=snestopc(realsnespos&0xFFFFFF);
172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 145638 times.
145638 if (pcpos<0)
173 {
174 movinglabelspossible=true;
175 throw_err_block(2, err_snes_address_doesnt_map_to_rom, hex((unsigned int)realsnespos, 6).data());
176 }
177 145638 writeromdata_byte(pcpos, (unsigned char)num, freespaceid != 0);
178
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 145636 times.
145638 if (pcpos>=romlen) {
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(pcpos - romlen > 0) writeromdata_bytes(romlen, freespacebyte, pcpos - romlen, false);
180 2 romlen=pcpos+1;
181 }
182 }
183
4/4
✓ Branch 0 taken 145680 times.
✓ Branch 1 taken 291322 times.
✓ Branch 2 taken 9178 times.
✓ Branch 3 taken 136502 times.
437002 if(pass == 1 && freespaceid == 0) {
184 9178 int pcpos = snestopc(realsnespos & 0xFFFFFF);
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9178 times.
9178 if(pcpos < 0)
186 {
187 movinglabelspossible=true;
188 throw_err_block(2, err_snes_address_doesnt_map_to_rom, hex((unsigned int)realsnespos, 6).data());
189 }
190 9178 addromwrite(pcpos, 1);
191
2/2
✓ Branch 0 taken 8761 times.
✓ Branch 1 taken 417 times.
9178 if (pcpos>=romlen) {
192
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 8672 times.
8761 if(pcpos - romlen > 0) writeromdata_bytes(romlen, freespacebyte, pcpos - romlen, false);
193 8761 romlen=pcpos+1;
194 }
195 }
196 437002 step(1);
197 437002 ratsmetastate=ratsmeta_ban;
198 437002 }
199
200 32039 static bool asblock_pick(const string& firstword, const char* par)
201 {
202
6/6
✓ Branch 0 taken 29693 times.
✓ Branch 1 taken 2346 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 29678 times.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 14953 times.
32039 if (arch==arch_spc700 || in_spcblock) {
203 // TODO
204
2/3
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 1188 times.
✗ Branch 2 not taken.
2376 string dup(firstword);
205
2/3
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 1188 times.
✗ Branch 2 not taken.
2376 string duppar(par);
206 2376 char* words[] = { dup.raw(), duppar.raw() };
207
4/6
✓ Branch 0 taken 1128 times.
✓ Branch 1 taken 1188 times.
✓ Branch 2 taken 1248 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1188 times.
✗ Branch 5 not taken.
2376 return asblock_spc700(words, *par ? 2 : 1);
208 2376 }
209
2/2
✓ Branch 0 taken 26009 times.
✓ Branch 1 taken 3654 times.
29663 if (arch==arch_65816) {
210 26009 return asblock_65816(firstword, par);
211 }
212
1/2
✓ Branch 0 taken 3654 times.
✗ Branch 1 not taken.
3654 if (arch==arch_superfx) {
213
2/3
✓ Branch 0 taken 1827 times.
✓ Branch 1 taken 1827 times.
✗ Branch 2 not taken.
3654 string dup(firstword);
214
2/3
✓ Branch 0 taken 1827 times.
✓ Branch 1 taken 1827 times.
✗ Branch 2 not taken.
3654 string duppar(par);
215 3654 char* words[] = { dup.raw(), duppar.raw() };
216
4/6
✓ Branch 0 taken 1722 times.
✓ Branch 1 taken 1827 times.
✓ Branch 2 taken 1932 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1827 times.
✗ Branch 5 not taken.
3654 return asblock_superfx(words, *par ? 2 : 1);
217 3654 }
218 return true;
219 }
220
221 11527 const char * safedequote(char * str)
222 {
223 11527 const char * tmp=dequote(str);
224
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11527 times.
11527 if (!tmp) throw_err_block(0, err_garbage_near_quoted_string);
225 11527 return tmp;
226 }
227
228 1877 void write2(unsigned int num)
229 {
230 1877 write1(num);
231 1877 write1(num/256);
232 1877 }
233
234 1236 void write3(unsigned int num)
235 {
236 1236 write1(num);
237 1236 write1(num/256);
238 1236 write1(num/65536);
239 1236 }
240
241 114 void write4(unsigned int num)
242 {
243 114 write1(num);
244 114 write1(num/256);
245 114 write1(num/65536);
246 114 write1(num/16777216);
247 114 }
248
249 //these are NOT used by the math parser - see asar_math.cpp for that
250 22 static int read2(int insnespos)
251 {
252 22 int addr=snestopc(insnespos);
253
2/4
✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
22 if (addr<0 || addr+2>romlen_r) return -1;
254 return
255 22 romdata_r[addr ] |
256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
33 (romdata_r[addr+1]<< 8);
257 }
258
259 54 static int read3(int insnespos)
260 {
261 54 int addr=snestopc(insnespos);
262
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if (addr<0 || addr+3>romlen_r) return -1;
263 return
264 54 romdata_r[addr ] |
265 81 (romdata_r[addr+1]<< 8)|
266
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
81 (romdata_r[addr+2]<<16);
267 }
268
269 1452 int getlenfromchar(char c)
270 {
271 1452 c=(char)to_lower(c);
272
2/2
✓ Branch 0 taken 660 times.
✓ Branch 1 taken 792 times.
1452 if (c=='b') return 1;
273
2/2
✓ Branch 0 taken 690 times.
✓ Branch 1 taken 102 times.
792 if (c=='w') return 2;
274
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 6 times.
102 if (c=='l') return 3;
275 6 throw_err_block(0, err_invalid_opcode_length);
276 }
277
278 assocarr<snes_label> labels;
279 static autoarray<int> poslabels;
280 static autoarray<int> neglabels;
281
282 autoarray<int>* macroposlabels;
283 autoarray<int>* macroneglabels;
284
285 autoarray<string> sublabels;
286 autoarray<string>* macrosublabels;
287
288 // randomdude999: ns is still the string to prefix to all labels, it's calculated whenever namespace_list is changed
289 string ns;
290 static string ns_backup;
291 autoarray<string> namespace_list;
292
293 autoarray<string> includeonce;
294
295 autoarray<freespace_data> freespaces;
296
297 // id of the next unused freespace.
298 static int freespaceidnext;
299 // id of the current freespace, or 0 if not in freespace.
300 int freespaceid;
301 // start address of the current freespace, used for computing the length of the
302 // current freespace.
303 static int freespacestart;
304 static freespace_data default_freespace_settings;
305
306 1222 bool confirmname(const char * name)
307 {
308
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 608 times.
✓ Branch 2 taken 614 times.
1222 if (!name[0]) return false;
309
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 608 times.
✓ Branch 2 taken 614 times.
1222 if (is_digit(name[0])) return false;
310
4/4
✓ Branch 0 taken 6030 times.
✓ Branch 1 taken 608 times.
✓ Branch 2 taken 6048 times.
✓ Branch 3 taken 614 times.
13300 for (int i=0;name[i];i++)
311 {
312
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6030 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6048 times.
12078 if (!is_ualnum(name[i])) return false;
313 }
314 1222 return true;
315 }
316
317 53370 string posneglabelname(const char ** input, bool define)
318 {
319 53370 const char* label = *input;
320
321 53370 string output;
322
323 53370 int depth = 0;
324 53370 bool ismacro = false;
325
326
3/3
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 26481 times.
✓ Branch 2 taken 26862 times.
53370 if (label[0] == '?')
327 {
328 54 ismacro = true;
329 54 label++;
330 }
331
6/6
✓ Branch 0 taken 26456 times.
✓ Branch 1 taken 26883 times.
✓ Branch 2 taken 97 times.
✓ Branch 3 taken 26390 times.
✓ Branch 4 taken 72 times.
✓ Branch 5 taken 26786 times.
53370 if (label[0] == '-' || label[0] == '+')
332 {
333 194 char first = label[0];
334
6/6
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 223 times.
✓ Branch 3 taken 103 times.
✓ Branch 4 taken 103 times.
✓ Branch 5 taken 29 times.
388 for (depth = 0; label[0] && label[0] == first; depth++) label++;
335
336
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 16 times.
194 if (!ismacro)
337 {
338
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 48 times.
178 if (first == '+')
339 {
340 130 *input = label;
341
12/22
✓ Branch 0 taken 62 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 62 times.
✓ Branch 5 taken 68 times.
✓ Branch 6 taken 62 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 62 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 130 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 62 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 68 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 68 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 68 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 68 times.
✗ Branch 21 not taken.
130 output = STR":pos_" + dec(depth) + "_" + dec(poslabels[depth]);
342
3/4
✓ Branch 0 taken 105 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 105 times.
✗ Branch 3 not taken.
130 if (define) poslabels[depth]++;
343 }
344 else
345 {
346 48 *input = label;
347
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
48 if (define) neglabels[depth]++;
348
12/22
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 21 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 21 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 48 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 21 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 27 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 27 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 27 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 27 times.
✗ Branch 21 not taken.
48 output = STR":neg_" + dec(depth) + "_" + dec(neglabels[depth]);
349 }
350 }
351 else
352 {
353
3/6
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 16 times.
16 if (macrorecursion == 0 || macroposlabels == nullptr || macroneglabels == nullptr)
354 {
355 if (!macrorecursion) throw_err_block(0, err_macro_label_outside_of_macro);
356 }
357 else
358 {
359
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (first == '+')
360 {
361 8 *input = label;
362
16/32
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 4 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 4 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 4 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 4 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 4 times.
✗ Branch 31 not taken.
8 output = STR":macro_" + dec(calledmacros) + "_pos_" + dec(depth) + "_" + dec((*macroposlabels)[depth]);
363
4/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
8 if (define) (*macroposlabels)[depth]++;
364 }
365 else
366 {
367 8 *input = label;
368
4/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
8 if (define) (*macroneglabels)[depth]++;
369
16/32
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 4 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 8 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 4 times.
✓ Branch 19 taken 4 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✓ Branch 22 taken 4 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 4 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 4 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 4 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 4 times.
✗ Branch 31 not taken.
8 output = STR":macro_" + dec(calledmacros) + "_neg_" + dec(depth) + "_" + dec((*macroneglabels)[depth]);
370 }
371 }
372 }
373 }
374
375 53370 return output;
376 }
377
378 2425 string labelname(const char ** rawname, bool define, bool is_addlabel)
379 {
380 #define deref_rawname (*rawname)
381 2425 autoarray<string>* sublabellist = &sublabels;
382
383 2425 bool ismacro = (deref_rawname[0] == '?');
384 2425 bool issublabel = false;
385
386
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2401 times.
2425 if (ismacro)
387 {
388 24 deref_rawname++;
389 24 sublabellist = macrosublabels;
390 }
391
392 2425 string name;
393 2425 int i=-1;
394
395
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1203 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1222 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2425 if (is_digit(*deref_rawname)) throw_err_block(2, err_invalid_label_name);
396
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1203 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1222 times.
2425 if (*deref_rawname ==':')
397 {
398 deref_rawname++;
399 name=":";
400 }
401
7/8
✓ Branch 0 taken 1086 times.
✓ Branch 1 taken 1339 times.
✓ Branch 2 taken 2179 times.
✓ Branch 3 taken 129 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1105 times.
✓ Branch 6 taken 1093 times.
✓ Branch 7 taken 12 times.
2425 else if (!in_struct && !in_sub_struct)
402 {
403
4/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1074 times.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 1093 times.
2267 for (i=0;(*deref_rawname =='.');i++) deref_rawname++;
404
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1074 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1093 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2167 if (!is_ualnum(*deref_rawname)) throw_err_block(2, err_invalid_label_name);
405
2/2
✓ Branch 0 taken 94 times.
✓ Branch 1 taken 2073 times.
2167 if (i)
406 {
407
7/14
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
✓ Branch 3 taken 50 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 44 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 44 times.
✓ Branch 8 taken 50 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 50 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
94 if (!sublabellist || !(*sublabellist)[i - 1]) throw_err_block(2, err_label_missing_parent);
408
7/12
✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 94 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 50 times.
✓ Branch 6 taken 44 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 50 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 50 times.
✗ Branch 11 not taken.
94 name+=STR(*sublabellist)[i-1]+"_";
409 94 issublabel = true;
410 }
411 }
412
413
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 2401 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 8 times.
2425 if (ismacro && !issublabel)
414 {
415 // RPG Hacker: Don't add the prefix for sublabels, because they already inherit it from
416 // their parents' names.
417
4/6
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
16 if (!macrorecursion || macrosublabels == nullptr) throw_err_block(2, err_macro_label_outside_of_macro);
418
7/14
✓ 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 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 10 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 5 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 5 times.
✗ Branch 13 not taken.
10 name = STR":macro_" + dec(calledmacros) + "_" + name;
419 }
420
421
422
7/8
✓ Branch 0 taken 1083 times.
✓ Branch 1 taken 1336 times.
✓ Branch 2 taken 1114 times.
✓ Branch 3 taken 1188 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1102 times.
✓ Branch 6 taken 12 times.
✓ Branch 7 taken 1090 times.
2419 if (in_struct || in_sub_struct)
423 {
424
7/9
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 114 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 114 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
258 if(is_addlabel && *deref_rawname != '.') throw_err_block(2, err_invalid_label_name); //probably should be a better error. TODO!!!
425
4/4
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 3 times.
246 if(*deref_rawname == '.') {
426 240 deref_rawname++;
427
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 228 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 108 times.
240 if(in_sub_struct)
428 {
429
4/7
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
24 name += struct_parent + ".";
430 }
431
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 name += struct_name;
432
1/2
✓ Branch 0 taken 240 times.
✗ Branch 1 not taken.
240 name += '.';
433 }
434 }
435
436
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1194 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1213 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2407 if (!is_ualnum(*deref_rawname)) throw_err_block(2, err_invalid_label_name);
437
438
10/10
✓ Branch 0 taken 1290 times.
✓ Branch 1 taken 8084 times.
✓ Branch 2 taken 1405 times.
✓ Branch 3 taken 9353 times.
✓ Branch 4 taken 8180 times.
✓ Branch 5 taken 1194 times.
✓ Branch 6 taken 96 times.
✓ Branch 7 taken 1213 times.
✓ Branch 8 taken 8255 times.
✓ Branch 9 taken 1213 times.
18842 while (is_ualnum(*deref_rawname) || *deref_rawname == '.')
439 {
440
2/4
✓ Branch 0 taken 8180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8255 times.
✗ Branch 3 not taken.
16435 name+=*(deref_rawname++);
441 }
442
443
4/4
✓ Branch 0 taken 987 times.
✓ Branch 1 taken 1420 times.
✓ Branch 2 taken 759 times.
✓ Branch 3 taken 228 times.
2407 if (define && i>=0)
444 {
445 759 (*sublabellist).reset(i);
446
4/7
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 387 times.
✓ Branch 2 taken 372 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 387 times.
✗ Branch 6 not taken.
759 (*sublabellist)[i]=name;
447 }
448 2407 return name;
449 #undef deref_rawname
450 18 }
451
452 196 static inline bool labelvalcore(const char ** rawname, snes_label * rval, bool define, bool shouldthrow)
453 {
454
2/3
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 99 times.
✗ Branch 2 not taken.
196 string name=labelname(rawname, define);
455
11/30
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 194 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 97 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 99 times.
✓ Branch 12 taken 97 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 97 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✓ Branch 18 taken 99 times.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
196 if (ns && labels.exists(ns+name)) {*rval = labels.find(ns+name);}
456
4/6
✓ Branch 0 taken 196 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 173 times.
✗ Branch 5 not taken.
196 else if (labels.exists(name)) {*rval = labels.find(name);}
457 else
458 {
459
3/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 22 times.
23 if (shouldthrow && pass)
460 {
461
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 throw_err_block(2, err_label_not_found, name.data());
462 }
463 22 rval->pos = (unsigned int)-1;
464 22 rval->freespace_id = 0;
465 22 rval->is_static = false;
466 22 return false;
467 }
468 173 return true;
469 196 }
470
471 170 snes_label labelval(const char ** rawname, bool define)
472 {
473 170 snes_label rval;
474
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 1 times.
170 labelvalcore(rawname, &rval, define, true);
475 169 return rval;
476 }
477
478 26 snes_label labelval(string name, bool define)
479 {
480 26 const char * rawname=name;
481 26 snes_label rval;
482
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 labelvalcore(&rawname, &rval, define, true);
483 52 return rval;
484 }
485
486 bool labelval(const char ** rawname, snes_label * rval, bool define)
487 {
488 return labelvalcore(rawname, rval, define, false);
489 }
490
491 bool labelval(string name, snes_label * rval, bool define)
492 {
493 const char * str=name;
494 return labelvalcore(&str, rval, define, false);
495 }
496
497 1366 static void setlabel(string name, int loc=-1, bool is_static=false)
498 {
499 1366 int lbl_fs_id = 0;
500
2/2
✓ Branch 0 taken 1107 times.
✓ Branch 1 taken 259 times.
1366 if (loc==-1)
501 {
502
1/2
✓ Branch 0 taken 1107 times.
✗ Branch 1 not taken.
1107 verifysnespos();
503 1107 loc = snespos;
504 // if base is not active:
505
2/2
✓ Branch 0 taken 855 times.
✓ Branch 1 taken 252 times.
1107 if(snespos == realsnespos) lbl_fs_id = freespaceid;
506 // if base is active, always treat the label as freespace 0, i.e. not freespace.
507 }
508
509 1366 snes_label label_data;
510 1366 label_data.pos = (unsigned int)loc;
511 1366 label_data.is_static = is_static;
512 1366 label_data.freespace_id = lbl_fs_id;
513
514 unsigned int labelpos;
515
2/2
✓ Branch 0 taken 454 times.
✓ Branch 1 taken 912 times.
1366 if (pass==0)
516 {
517
3/4
✓ Branch 0 taken 454 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 452 times.
454 if (labels.exists(name))
518 {
519 2 movinglabelspossible=true;
520
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 throw_err_block(0, err_label_redefined, name.data());
521 }
522
1/2
✓ Branch 0 taken 452 times.
✗ Branch 1 not taken.
452 labels.create(name) = label_data;
523 }
524
2/2
✓ Branch 0 taken 456 times.
✓ Branch 1 taken 456 times.
912 else if (pass==1)
525 {
526
1/2
✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
456 labels.create(name) = label_data;
527 }
528
1/2
✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
456 else if (pass==2)
529 {
530 //all label locations are known at this point, add a sanity check
531
2/6
✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 456 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
456 if (!labels.exists(name)) throw_err_block(2, err_internal_error, "label created on 3rd pass");
532
1/2
✓ Branch 0 taken 456 times.
✗ Branch 1 not taken.
456 labelpos = labels.find(name).pos;
533
5/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 450 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
456 if ((int)labelpos != loc && !movinglabelspossible)
534 {
535
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 if((unsigned int)loc>>16 != labelpos>>16) throw_err_block(2, err_label_ambiguous, name.data());
536
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
6 else if(labelpos == (dp_base + 0xFFu)) throw_err_block(2, err_label_ambiguous, name.data());
537
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
4 else if(errored) return;
538 else throw_err_block(2, err_internal_error, "moving label");
539 }
540 }
541 }
542
543 table thetable;
544 static autoarray<table> tablestack;
545
546 853 static void cleartable()
547 {
548
4/7
✓ Branch 0 taken 380 times.
✓ Branch 1 taken 473 times.
✓ Branch 2 taken 380 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 473 times.
✗ Branch 6 not taken.
853 thetable = table();
549 853 }
550
551 struct pushable {
552 int arch;
553 int snespos;
554 int snesstart;
555 int snesposreal;
556 int snesstartreal;
557 int freeid;
558 int freest;
559 int arch1;
560 int arch2;
561 int arch3;
562 int arch4;
563 };
564 static autoarray<pushable> pushpc;
565 static int pushpcnum;
566
567 static autoarray<int> basestack;
568 static int basestacknum;
569
570 struct ns_pushable {
571 string ns;
572 autoarray<string> namespace_list;
573 bool nested_namespaces;
574 };
575
576 static autoarray<ns_pushable> pushns;
577 static int pushnsnum;
578
579
580 static unsigned char fillbyte[12];
581 static unsigned char padbyte[12];
582
583 static bool nested_namespaces = false;
584
585 48692 void checkbankcross()
586 {
587
4/4
✓ Branch 0 taken 4599 times.
✓ Branch 1 taken 44093 times.
✓ Branch 2 taken 4671 times.
✓ Branch 3 taken 19828 times.
48692 if (!snespos_valid) return;
588
4/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 39233 times.
✓ Branch 2 taken 189 times.
✓ Branch 3 taken 19639 times.
39422 if (disable_bank_cross_errors) return;
589
4/4
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 38898 times.
✓ Branch 2 taken 146 times.
✓ Branch 3 taken 19493 times.
39044 unsigned int mask = 0x7FFF0000 | (check_half_banks_crossed ? 0x8000 : 0);
590
4/4
✓ Branch 0 taken 588 times.
✓ Branch 1 taken 38456 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 584 times.
39044 if (((snespos^startpos) & mask) && (((snespos - 1) ^ startpos) & mask))
591 {
592 4 throw_err_fatal(pass, err_bank_border_crossed, snespos);
593 }
594 // don't verify realsnespos when using norom. this allows making custom mappers where the file layout doesn't follow bank borders
595
7/8
✓ Branch 0 taken 19262 times.
✓ Branch 1 taken 19778 times.
✓ Branch 2 taken 19743 times.
✓ Branch 3 taken 19156 times.
✓ Branch 4 taken 298 times.
✓ Branch 5 taken 19445 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 298 times.
39040 else if (mapper != norom && ((realsnespos^realstartpos) & mask) && (((realsnespos - 1) ^ realstartpos) & mask))
596 {
597 throw_err_fatal(pass, err_bank_border_crossed, realsnespos);
598 }
599 }
600
601 3351 static void freespaceend()
602 {
603
2/2
✓ Branch 0 taken 1608 times.
✓ Branch 1 taken 1743 times.
3351 if (freespaceid > 0)
604 {
605 1608 freespaces[freespaceid].len = realsnespos-freespacestart;
606 1608 snespos=(int)0xFFFFFFFF;
607 1608 snespos_valid = false;
608 }
609 3351 freespaceid = 0;
610 3351 }
611
612 2568 static void adddefine(const string & key, string & value)
613 {
614
2/4
✓ Branch 0 taken 1131 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1437 times.
✗ Branch 3 not taken.
2568 if (!defines.exists(key)) defines.create(key) = value;
615 2568 }
616
617 847 void initstuff()
618 {
619
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 558 times.
847 if (pass==0)
620 {
621 289 freespaces.reset();
622 289 movinglabelspossible = false;
623 289 found_rats_tags_initialized = false;
624 289 found_rats_tags.clear();
625 }
626 847 arch=arch_65816;
627 847 mapper=lorom;
628 847 mapper_set = false;
629 847 calledmacros = 0;
630 847 reallycalledmacros = 0;
631 847 macrorecursion = 0;
632 847 defines.reset();
633 847 builtindefines.each(adddefine);
634 847 clidefines.each(adddefine);
635 847 ns="";
636 847 namespace_list.reset();
637 847 sublabels.reset();
638 847 poslabels.reset();
639 847 neglabels.reset();
640 847 macroposlabels = nullptr;
641 847 macroneglabels = nullptr;
642 847 macrosublabels = nullptr;
643 847 cleartable();
644 847 pushpc.reset();
645 847 pushpcnum=0;
646 847 pushns.reset();
647 847 pushnsnum = 0;
648 847 bytes=0;
649 847 freespaceuse=0;
650
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 470 times.
847 memset(fillbyte, 0, sizeof(fillbyte));
651
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 470 times.
847 memset(padbyte, 0, sizeof(padbyte));
652 847 snespos_valid = false;
653 847 snespos=(int)0xFFFFFFFF;
654 847 realsnespos= (int)0xFFFFFFFF;
655 847 startpos= (int)0xFFFFFFFF;
656 847 realstartpos= (int)0xFFFFFFFF;
657 847 freespaceidnext=1;
658 847 freespaceid=0;
659 847 freespacebyte=0x00;
660 847 incsrcdepth = 0;
661
662 847 optimizeforbank = -1;
663 847 optimize_dp = optimize_dp_flag::ALWAYS;
664 847 dp_base = 0;
665 847 optimize_address = optimize_address_flag::MIRRORS;
666
667 847 in_struct = false;
668 847 in_sub_struct = false;
669 847 in_spcblock = false;
670
671 847 disable_bank_cross_errors = false;
672 847 check_half_banks_crossed = false;
673 847 nested_namespaces = false;
674
675 847 includeonce.reset();
676
677 extern AddressToLineMapping addressToLineMapping;
678 847 addressToLineMapping.reset();
679
680 847 push_warnings(false);
681
682 847 initmathcore();
683
684 1317 default_freespace_settings = {};
685 847 default_freespace_settings.bank = -3;
686 847 default_freespace_settings.search_start = -1;
687 847 default_freespace_settings.write_rats = true;
688 // rest are initialized to false/0/empty string
689
690 847 callstack.clear();
691 #if defined(_WIN32) || !defined(NO_USE_THREADS)
692 847 init_stack_use_check();
693 #endif
694 847 }
695
696 1608 static void parse_freespace_arguments(freespace_data& thisfs, string& arguments) {
697
3/3
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 804 times.
✓ Branch 2 taken 693 times.
1608 if(arguments == "") return;
698
2/4
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 693 times.
✗ Branch 3 not taken.
1386 autoptr<char**> pars=qpsplit(arguments.temp_raw(), ',');
699
700
4/4
✓ Branch 0 taken 702 times.
✓ Branch 1 taken 693 times.
✓ Branch 2 taken 702 times.
✓ Branch 3 taken 693 times.
2790 for (int i=0;pars[i];i++)
701 {
702
3/6
✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1404 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 702 times.
1404 if (!stricmp(pars[i], "ram")) { thisfs.bank = -2; }
703
5/6
✓ Branch 0 taken 702 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1401 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 699 times.
1404 else if (!stricmp(pars[i], "noram")) { thisfs.bank = -1; }
704
5/6
✓ Branch 0 taken 699 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1392 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 693 times.
1398 else if (!stricmp(pars[i], "static")) { thisfs.is_static = true; }
705
3/6
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1386 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 693 times.
1386 else if (!stricmp(pars[i], "nostatic")) { thisfs.is_static = false; }
706
5/6
✓ Branch 0 taken 693 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 1380 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 687 times.
1386 else if (!stricmp(pars[i], "align")) { thisfs.flag_align = true; }
707
3/6
✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1374 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 687 times.
1374 else if (!stricmp(pars[i], "noalign")) { thisfs.flag_align = false; }
708
5/6
✓ Branch 0 taken 687 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 636 times.
✓ Branch 3 taken 738 times.
✓ Branch 4 taken 636 times.
✓ Branch 5 taken 51 times.
1374 else if (!stricmp(pars[i], "cleaned")) { thisfs.flag_cleaned = true; }
709
3/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
102 else if (!stricmp(pars[i], "nocleaned")) { thisfs.flag_cleaned = false; }
710
3/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
102 else if (!stricmp(pars[i], "rats")) { thisfs.write_rats = true; }
711
3/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
102 else if (!stricmp(pars[i], "norats")) { thisfs.write_rats = false; }
712
3/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
102 else if (!stricmp(pars[i], "bankcross")) { thisfs.allow_bankcross = true; }
713
3/6
✓ Branch 0 taken 51 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 51 times.
102 else if (!stricmp(pars[i], "nobankcross")) { thisfs.allow_bankcross = false; }
714
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 27 times.
102 else if (stribegin(pars[i], "bank="))
715 {
716
6/11
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 24 times.
✗ Branch 10 not taken.
48 thisfs.bank = parse_math_expr(pars[i] + 5)->evaluate_static().get_integer();
717 }
718
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 15 times.
54 else if (stribegin(pars[i], "start="))
719 {
720
6/11
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
24 thisfs.search_start = parse_math_expr(pars[i] + 6)->evaluate_static().get_integer();
721 }
722
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 else if (stribegin(pars[i], "pin="))
723 {
724 // TODO: should we handle posneg labels here too?
725
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 string pin_to = pars[i] + 4;
726 30 const char* pin_to_c = pin_to.data();
727
2/3
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
30 thisfs.pin_target = labelname(&pin_to_c);
728
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
30 if(*pin_to_c) throw_err_block(0, err_invalid_label_name);
729 // this is to throw an "undefined label" error with the proper callstack
730
6/8
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 10 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 10 times.
✗ Branch 7 not taken.
30 if(pass) labelval(pin_to);
731
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 thisfs.pin_target_ns = ns;
732 30 }
733 else throw_err_block(0, err_invalid_freespace_request);
734 }
735 1386 }
736
737 544 static int get_freespace_pin_target(int target_id) {
738 // union-find algorithm
739
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 272 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 272 times.
548 while(freespaces[target_id].pin_target_id != target_id) {
740 // i love programming
741 6 freespaces[target_id].pin_target_id =
742 4 freespaces[freespaces[target_id].pin_target_id].pin_target_id;
743 4 target_id = freespaces[target_id].pin_target_id;
744 }
745 544 return target_id;
746 }
747
748 279 static void resolve_pinned_freespaces() {
749
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 279 times.
813 for(int i = 1; i < freespaces.count; i++)
750 // default to everyone being in a separate component
751 534 freespaces[i].pin_target_id = i;
752
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 279 times.
813 for(int i = 1; i < freespaces.count; i++) {
753
1/2
✓ Branch 0 taken 534 times.
✗ Branch 1 not taken.
534 freespace_data& fs = freespaces[i];
754
4/4
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 262 times.
✓ Branch 3 taken 5 times.
534 if(fs.pin_target == "") continue;
755 10 snes_label value;
756
7/29
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 5 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 5 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✓ Branch 20 taken 5 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 5 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 5 times.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 27 not taken.
✗ Branch 28 not taken.
10 if(fs.pin_target_ns && labels.exists(fs.pin_target_ns + fs.pin_target))
757 value = labels.find(fs.pin_target_ns + fs.pin_target);
758
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 else if(labels.exists(fs.pin_target))
759
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
10 value = labels.find(fs.pin_target);
760 else continue; // the error for this is thrown in the freespace command during pass 2
761
1/2
✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
10 fs.pin_target_id = get_freespace_pin_target(value.freespace_id);
762 10 fs.len = 0;
763 }
764
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 279 times.
813 for(int i = 1; i < freespaces.count; i++) {
765 534 freespace_data& fs = freespaces[i];
766 // just in case the pin target changed again or something
767 534 fs.pin_target_id = get_freespace_pin_target(fs.pin_target_id);
768 }
769 279 }
770
771 279 static void allocate_freespaces() {
772 // compute real size of all pinned freespace blocks
773
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 279 times.
813 for(int i = 1; i < freespaces.count; i++) {
774 534 freespace_data& fs = freespaces[i];
775 534 freespace_data& target = freespaces[fs.pin_target_id];
776 534 target.total_len += fs.len;
777 534 target.search_start = std::max(fs.search_start, target.search_start);
778 }
779
780
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 279 times.
813 for(int i = 1; i < freespaces.count; i++) {
781 534 freespace_data& fs = freespaces[i];
782
7/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 268 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 265 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 1 times.
534 if(fs.is_static && fs.orgpos > 0) {
783 2 fs.pos = fs.orgpos;
784 2 continue;
785 }
786 // if this freespace is pinned to another one, set it later
787
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 262 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 262 times.
532 if(fs.pin_target_id != i) continue;
788 // TODO: possibly fancier align
789
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 262 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 262 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 262 times.
524 fs.pos = getsnesfreespace(fs.total_len, fs.bank, true, !fs.allow_bankcross, fs.flag_align, fs.write_rats, fs.search_start);
790 524 fs.used_len = fs.len;
791 }
792 // set pos for all pinned freespaces
793
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 279 times.
813 for(int i = 1; i < freespaces.count; i++) {
794 534 freespace_data& fs = freespaces[i];
795
4/4
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 263 times.
✓ Branch 3 taken 4 times.
534 if(fs.pin_target_id == i) continue;
796 8 freespace_data& tgt = freespaces[fs.pin_target_id];
797 8 fs.pos = tgt.pos + tgt.used_len;
798 8 tgt.used_len += fs.len;
799 }
800
801 // relocate all labels that were in freespace to point them to their real location
802 279 labels.each([](const char * key, snes_label & val) {
803
4/4
✓ Branch 0 taken 49 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 182 times.
454 if(val.freespace_id != 0) {
804 98 val.pos += freespaces[val.freespace_id].pos;
805 }
806 454 });
807 279 }
808
809 837 void finishpass()
810 {
811 837 verify_warnings();
812 837 pull_warnings(false);
813
814
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 837 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 465 times.
837 if(in_spcblock) throw_err_block(0, err_missing_endspcblock);
815
6/8
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 465 times.
✓ Branch 2 taken 465 times.
✓ Branch 3 taken 372 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 465 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 465 times.
837 if (in_struct || in_sub_struct) throw_err_null(0, err_struct_without_endstruct);
816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 837 times.
837 else if (pushpcnum) throw_err_null(0, err_pushpc_without_pullpc);
817
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 837 times.
837 else if (pushnsnum) throw_err_null(0, err_pushns_without_pullns);
818 837 freespaceend();
819
820 837 deinitmathcore();
821
2/2
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 558 times.
837 if(pass == 0) {
822 279 resolve_pinned_freespaces();
823
2/2
✓ Branch 0 taken 279 times.
✓ Branch 1 taken 279 times.
558 } else if(pass == 1) {
824 279 allocate_freespaces();
825 279 handle_cleared_rats_tags();
826 }
827 #if defined(_WIN32) || !defined(NO_USE_THREADS)
828 837 deinit_stack_use_check();
829 #endif
830 837 }
831
832 32651 static bool addlabel(const char * label, int pos=-1, bool global_label = false)
833 {
834
4/6
✓ Branch 0 taken 16195 times.
✓ Branch 1 taken 16456 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 16195 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 16456 times.
32651 if (!label[0] || label[0]==':') return false;//colons are reserved for special labels
835
836 32651 const char* posneglabel = label;
837
2/3
✓ Branch 0 taken 16195 times.
✓ Branch 1 taken 16456 times.
✗ Branch 2 not taken.
32651 string posnegname = posneglabelname(&posneglabel, true);
838
839
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 32525 times.
32651 if (posnegname.length() > 0)
840 {
841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (global_label) return false;
842
5/9
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
126 if (*posneglabel != '\0' && *posneglabel != ':') throw_err_block(0, err_broken_label_definition);
843
4/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 66 times.
✗ Branch 5 not taken.
126 setlabel(posnegname, pos);
844 126 return true;
845 }
846
11/13
✓ Branch 0 taken 15652 times.
✓ Branch 1 taken 16873 times.
✓ Branch 2 taken 15622 times.
✓ Branch 3 taken 30 times.
✓ Branch 4 taken 31514 times.
✓ Branch 5 taken 498 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 31481 times.
✓ Branch 8 taken 33 times.
✓ Branch 9 taken 15859 times.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15859 times.
32525 if (label[strlen(label)-1]==':' || label[0]=='.' || label[0]=='?' || label[0] == '#')
847 {
848
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 525 times.
1047 if (!label[1]) return false;
849
10/12
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 993 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 39 times.
✓ Branch 8 taken 21 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✓ Branch 11 taken 18 times.
1035 if(global_label && (in_struct || in_sub_struct || label[0]=='?')) return false;
850
851 1029 bool define = true;
852
853
3/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 507 times.
✓ Branch 2 taken 510 times.
1029 if (label[0] == '#')
854 {
855 24 define = false;
856 24 label++;
857 }
858
859 // RPG Hacker: Also checking label[1] now, since it might be a macro sublabel.
860 // Also, apparently this here doesn't account for main labels. I guess because
861 // we don't even get here in the first place if they don't include a colon?
862
13/15
✓ Branch 0 taken 354 times.
✓ Branch 1 taken 516 times.
✓ Branch 2 taken 510 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 345 times.
✓ Branch 5 taken 366 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 345 times.
✓ Branch 8 taken 360 times.
✓ Branch 9 taken 354 times.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 354 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 354 times.
1029 bool requirecolon = (label[0] != '.' && label[1] != '.') && (in_struct || in_sub_struct);
863
3/3
✓ Branch 0 taken 498 times.
✓ Branch 1 taken 522 times.
✓ Branch 2 taken 9 times.
1029 string name=labelname(&label, define, true);
864
3/3
✓ Branch 0 taken 465 times.
✓ Branch 1 taken 510 times.
✓ Branch 2 taken 36 times.
1011 if (label[0]==':') label++;
865
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
69 else if (requirecolon) throw_err_block(0, err_broken_label_definition);
866
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 63 times.
69 else if (global_label) return false;
867
4/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 495 times.
✓ Branch 2 taken 510 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
1005 if (label[0]) throw_err_block(0, err_broken_label_definition);
868
8/9
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 870 times.
✓ Branch 2 taken 99 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 99 times.
✓ Branch 5 taken 882 times.
✓ Branch 6 taken 48 times.
✓ Branch 7 taken 51 times.
✗ Branch 8 not taken.
981 if (ns && !global_label) name=ns+name;
869
15/16
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 597 times.
✓ Branch 2 taken 411 times.
✓ Branch 3 taken 471 times.
✓ Branch 4 taken 81 times.
✓ Branch 5 taken 429 times.
✓ Branch 6 taken 495 times.
✓ Branch 7 taken 387 times.
✓ Branch 8 taken 481 times.
✓ Branch 9 taken 113 times.
✓ Branch 10 taken 81 times.
✓ Branch 11 taken 30 times.
✓ Branch 12 taken 498 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 496 times.
✓ Branch 15 taken 2 times.
985 setlabel(name, pos, ((in_struct || in_sub_struct) && static_struct));
870 977 return true;
871 1011 }
872 31478 return false;
873 32651 }
874
875 15646 static void add_addr_to_line(int pos)
876 {
877
2/2
✓ Branch 0 taken 5520 times.
✓ Branch 1 taken 10126 times.
15646 if (pass == 2)
878 5520 addressToLineMapping.includeMapping(get_current_file_name(), get_current_line() + 1, pos);
879 15646 }
880
881 static autoarray<bool> elsestatus;
882 int numtrue=0;//if 1 -> increase both
883 int numif = 0; //if 0 or inside if 0 -> increase only numif
884
885 autoarray<whiletracker> whilestatus;
886
887
888 112 static void push_pc()
889 {
890 112 pushpc[pushpcnum].arch=arch;
891 112 pushpc[pushpcnum].snespos=snespos;
892 112 pushpc[pushpcnum].snesstart=startpos;
893 112 pushpc[pushpcnum].snesposreal=realsnespos;
894 112 pushpc[pushpcnum].snesstartreal=realstartpos;
895 112 pushpc[pushpcnum].freeid=freespaceid;
896 112 pushpc[pushpcnum].freest=freespacestart;
897 112 pushpcnum++;
898 112 }
899
900 112 static void pop_pc()
901 {
902 112 pushpcnum--;
903 112 snespos=pushpc[pushpcnum].snespos;
904 112 startpos=pushpc[pushpcnum].snesstart;
905 112 realsnespos=pushpc[pushpcnum].snesposreal;
906 112 realstartpos=pushpc[pushpcnum].snesstartreal;
907 112 freespaceid=pushpc[pushpcnum].freeid;
908 112 freespacestart=pushpc[pushpcnum].freest;
909 112 }
910
911
912 372 static string handle_print(const char* input)
913 {
914 // evaluating this math can be unsafe in pass 0
915
3/4
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 244 times.
✗ Branch 3 not taken.
372 if(pass != 2) return "";
916 128 string out;
917
2/3
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
128 string buf = input;
918
2/3
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
128 autoptr<char**> pars = qpsplit(buf.raw(), ',');
919
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 verify_paren(pars);
920
4/4
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 108 times.
✓ Branch 3 taken 62 times.
329 for (int i = 0; pars[i]; i++)
921 {
922 if (0);
923 // leaving these here is kinda hacky, but whatever...
924
8/12
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 207 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 106 times.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2 times.
✗ Branch 11 not taken.
209 else if (!stricmp(pars[i], "bytes")) out += dec(bytes);
925
8/12
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 204 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 105 times.
✓ Branch 6 taken 1 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
205 else if (!stricmp(pars[i], "freespaceuse")) out += dec(freespaceuse);
926
3/12
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 203 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 105 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
203 else if (!stricmp(pars[i], "pc")) out += hex((unsigned int)(snespos & 0xFFFFFF), 6);
927 else {
928
5/6
✓ Branch 0 taken 98 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 199 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 101 times.
✓ Branch 5 taken 4 times.
426 math_val value = parse_math_expr(pars[i])->evaluate();
929
2/4
✓ Branch 0 taken 195 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 195 times.
✗ Branch 3 not taken.
195 out += value.get_str();
930 195 }
931 }
932 120 return out;
933 347 }
934
935 114 void handle_autoclean(string& arg, int checkbyte, int write_pos)
936 {
937
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
114 if(freespaceid > 0) throw_err_block(0, err_autoclean_in_freespace);
938
939 114 const char* labeltest = arg.data();
940
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 snes_label lblval = labelval(&labeltest);
941
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
114 if (*labeltest) throw_err_block(0, err_label_not_found, arg.data());
942 114 int num = lblval.pos;
943
1/2
✓ Branch 0 taken 114 times.
✗ Branch 1 not taken.
114 auto& targetfs = freespaces[lblval.freespace_id];
944
945
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 60 times.
114 if (pass == 1) {
946 54 targetfs.leaked = false;
947
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 6 times.
54 int orig_pos = read3(checkbyte != -1 ? write_pos+1 : write_pos);
948 54 int write_pos_pc = snestopc(write_pos);
949 54 targetfs.orgpos = targetfs.orglen = -1;
950
8/10
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 48 times.
✓ Branch 5 taken 6 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 13 times.
✓ Branch 8 taken 11 times.
✓ Branch 9 taken 13 times.
54 if(write_pos_pc >= 0 && write_pos_pc < romlen_r && (checkbyte == -1 || romdata_r[write_pos_pc] == checkbyte)) {
951
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 int rats_loc = ratsstart(orig_pos);
952
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6 times.
28 if(rats_loc != -1) {
953 22 targetfs.orgpos = rats_loc + 8;
954 22 targetfs.orglen = read2(rats_loc + 4) + 1;
955
6/7
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 10 times.
✗ Branch 6 not taken.
22 if(!targetfs.is_static) removerats(rats_loc + 8, freespacebyte);
956 }
957 }
958
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 6 times.
60 } else if(pass == 2) {
959
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 27 times.
54 if(targetfs.pos < 0) {
960 // this freespace failed to allocate.
961 // ratsstart is obviously not going to find a nonexistent freespace,
962 // and would error too, we don't need 2 errors about the same thing.
963 // especially if one of them is as weird as this one.
964 return;
965 }
966
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 int start = ratsstart(num);
967
2/6
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
54 if(start >= num || start < 0) throw_err_block(2, err_autoclean_label_at_freespace_end);
968 }
969 }
970
971 namespace {
972
973 template<void (*do_write)(unsigned int)>
974 9654 void cmd_write_data(const char* par) {
975 9654 int addrToLinePos = realsnespos & 0xFFFFFF;
976
2/3
✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 2451 times.
✗ Branch 2 not taken.
9654 string line = par;
977
2/3
✓ Branch 0 taken 2376 times.
✓ Branch 1 taken 2451 times.
✗ Branch 2 not taken.
9654 autoptr<char**> pars=qpsplit(line.temp_raw(), ',');
978
1/2
✓ Branch 0 taken 4827 times.
✗ Branch 1 not taken.
9654 verify_paren(pars);
979
980
4/4
✓ Branch 0 taken 2782 times.
✓ Branch 1 taken 2363 times.
✓ Branch 2 taken 2896 times.
✓ Branch 3 taken 2438 times.
20958 for (int i=0;pars[i];i++)
981 {
982
4/4
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 2671 times.
✓ Branch 2 taken 114 times.
✓ Branch 3 taken 2782 times.
11356 if (pars[i][0]=='"') {
983
2/4
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 114 times.
✗ Branch 3 not taken.
450 const char * str = safedequote(pars[i]);
984 450 int codepoint = 0u;
985
1/2
✓ Branch 0 taken 225 times.
✗ Branch 1 not taken.
450 str += utf8_val(&codepoint, str);
986
3/4
✓ Branch 0 taken 918 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 918 times.
✗ Branch 3 not taken.
2286 while ( codepoint != 0 && codepoint != -1 )
987 {
988
1/2
✓ Branch 0 taken 918 times.
✗ Branch 1 not taken.
1836 do_write(thetable.get_val(codepoint));
989
1/2
✓ Branch 0 taken 918 times.
✗ Branch 1 not taken.
1836 str += utf8_val(&codepoint, str);
990 }
991
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
450 if (codepoint == -1) throw_err_block(0, err_invalid_utf8);
992 } else {
993
36/40
✓ Branch 0 taken 880 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1792 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 875 times.
✓ Branch 5 taken 1783 times.
✓ Branch 6 taken 875 times.
✓ Branch 7 taken 1783 times.
✓ Branch 8 taken 875 times.
✓ Branch 9 taken 2695 times.
✓ Branch 10 taken 5 times.
✓ Branch 11 taken 13 times.
✓ Branch 12 taken 5 times.
✓ Branch 13 taken 920 times.
✓ Branch 14 taken 5 times.
✓ Branch 15 taken 920 times.
✓ Branch 16 taken 1857 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 912 times.
✓ Branch 19 taken 1857 times.
✓ Branch 20 taken 912 times.
✓ Branch 21 taken 1857 times.
✓ Branch 22 taken 912 times.
✓ Branch 23 taken 1857 times.
✓ Branch 24 taken 912 times.
✓ Branch 25 taken 1857 times.
✓ Branch 26 taken 1857 times.
✓ Branch 27 taken 912 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 13 times.
✓ Branch 30 taken 13 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 5 times.
✓ Branch 33 taken 8 times.
✓ Branch 34 taken 5 times.
✓ Branch 35 taken 8 times.
✓ Branch 36 taken 5 times.
✓ Branch 37 taken 8 times.
✗ Branch 38 not taken.
✓ Branch 39 taken 13 times.
20132 do_write((pass==2) ? parse_math_expr(pars[i])->evaluate().get_integer() : 0);
994 }
995 }
996
1/2
✓ Branch 0 taken 4801 times.
✗ Branch 1 not taken.
9602 add_addr_to_line(addrToLinePos);
997 18176 }
998
999 366 void cmd_assert(const char* par) {
1000
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
✓ Branch 2 taken 186 times.
366 if(!*par) {
1001 throw_err_block(0, err_broken_command, "assert", "Missing condition.");
1002 }
1003 // todo optimize after adding some math helpers
1004
1/2
✓ Branch 0 taken 366 times.
✗ Branch 1 not taken.
366 const char* message_start = strqpchr(par, ',');
1005
1006 366 string cond_str;
1007
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 336 times.
366 if(message_start) {
1008
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 cond_str.assign(par, message_start - par);
1009 30 message_start++; // eat the comma
1010 } else {
1011
1/2
✓ Branch 0 taken 336 times.
✗ Branch 1 not taken.
336 cond_str = par;
1012 }
1013
1014
2/2
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 122 times.
366 if(pass != 2) return;
1015
1016
7/12
✓ Branch 0 taken 60 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 13 times.
✓ Branch 4 taken 47 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 49 times.
✓ Branch 9 taken 13 times.
✓ Branch 10 taken 49 times.
✗ Branch 11 not taken.
322 bool cond = parse_math_expr(cond_str)->evaluate().get_bool();
1017
1018
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 84 times.
96 if(!cond) {
1019
9/15
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 3 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
36 if (message_start) throw_err_block(2, err_assertion_failed, (string(": ") + handle_print(message_start)).data());
1020
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 else throw_err_block(2, err_assertion_failed, ".");
1021 }
1022
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 244 times.
488 }
1023
1024 120 void cmd_undef(const char* par) {
1025
2/3
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
120 string temp = par;
1026
4/6
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 60 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 60 times.
✗ Branch 5 not taken.
120 string def = safedequote(temp.raw());
1027
4/5
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 60 times.
120 if (builtindefines.exists(def)) {
1028 throw_err_line(0, err_overriding_builtin_define, def.data());
1029 }
1030
1031
5/5
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 60 times.
✓ Branch 4 taken 3 times.
120 if (defines.exists(def)) {
1032
2/3
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 57 times.
✗ Branch 2 not taken.
114 defines.remove(def);
1033 } else {
1034
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_define_not_found, def.data());
1035 }
1036 183 }
1037
1038 21 void cmd_error(const char* par) {
1039
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 9 times.
21 if(!*par)
1040
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_error_command, ".");
1041
2/3
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
15 string out = handle_print(par);
1042
5/11
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 9 times.
✗ Branch 10 not taken.
54 throw_err_block(2, err_error_command, (string(": ") + out).data());
1043 15 }
1044
1045 33 void cmd_warn(const char* par) {
1046
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
33 if(!*par) {
1047
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_warning(0, warn_warn_command, ".");
1048 6 return;
1049 }
1050
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
27 string out = handle_print(par);
1051
5/11
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
27 throw_warning(2, warn_warn_command, (string(": ") + out).data());
1052 27 }
1053
1054 132 void cmd_warnings(char** words, int numwords) {
1055
7/7
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 24 times.
✓ Branch 5 taken 66 times.
✓ Branch 6 taken 54 times.
132 if(numwords == 1 && !stricmpwithlower(words[0], "push")) {
1056 24 push_warnings();
1057
7/7
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 54 times.
✓ Branch 6 taken 42 times.
108 } else if(numwords == 1 && !stricmpwithlower(words[0], "pull")) {
1058 24 pull_warnings();
1059
6/7
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 42 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 33 times.
84 } else if(numwords == 2 && !stricmpwithlower(words[0], "enable")) {
1060 18 asar_warning_id warnid = parse_warning_id_from_string(words[1]);
1061
1062
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
18 if (warnid != warning_id_end) {
1063 12 set_warning_enabled(warnid, true);
1064 } else {
1065 6 throw_warning(0, warn_invalid_warning_id, words[1], "warnings enable");
1066 }
1067
5/7
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 33 times.
✗ Branch 6 not taken.
66 } else if(numwords == 2 && !stricmpwithlower(words[0], "disable")) {
1068 66 asar_warning_id warnid = parse_warning_id_from_string(words[1]);
1069
1070
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 12 times.
66 if (warnid != warning_id_end) {
1071 54 set_warning_enabled(warnid, false);
1072 } else {
1073 12 throw_warning(0, warn_invalid_warning_id, words[1], "warnings disable");
1074 }
1075 } else {
1076 throw_err_block(0, err_broken_command, "warnings", "Unknown parameter");
1077 }
1078 126 }
1079
1080 42 void cmd_global(const char* par) {
1081
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 30 times.
42 if(!addlabel(par, -1, true)) {
1082 12 throw_err_block(1, err_invalid_global_label, par);
1083 }
1084 30 }
1085
1086 70 void cmd_check(char** words, int numwords) {
1087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if(numwords != 2) throw_err_block(0, err_invalid_check);
1088
1089
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 32 times.
70 if(!stricmpwithlower(words[0], "title")) {
1090 // RPG Hacker: Removed trimming for now - I think requiring an exact match is probably
1091 // better here (not sure, though, it's worth discussing)
1092
3/6
✓ 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 not taken.
6 string expected_title = safedequote(words[1]);
1093 // in hirom the rom needs to be an entire bank for it to have a title, other modes only need 0x8000 bytes
1094
7/10
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3 times.
6 if (romlen < ((mapper == hirom || mapper == exhirom) ? 0x10000 : 0x8000)) // too short
1095 {
1096 if (!ignoretitleerrors) // title errors shouldn't be ignored
1097 throw_err_block(0, err_rom_too_short, expected_title.data());
1098 else // title errors should be ignored, throw a warning anyways
1099 throw_warning(0, warn_rom_too_short, expected_title.data());
1100 } else {
1101 6 string actual_title;
1102 6 string actual_display_title;
1103
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 6 times.
132 for (int i = 0;i < 21;i++)
1104 {
1105 126 unsigned char c = romdata[snestopc(0x00FFC0 + i)];
1106
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 actual_title += (char)c;
1107 // the replacements are from interface-cli.cpp
1108
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == 7) c = 14;
1109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == 8) c = 27;
1110
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == 9) c = 26;
1111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == '\r') c = 17;
1112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == '\n') c = 25;
1113
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 126 times.
126 if (c == '\0') c = 155;
1114
1/2
✓ Branch 0 taken 126 times.
✗ Branch 1 not taken.
126 actual_display_title += (char)c;
1115 }
1116
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
6 if (strncmp(expected_title, actual_title, 21) != 0)
1117 {
1118 if (!ignoretitleerrors) // title errors shouldn't be ignored
1119 throw_err_block(0, err_rom_title_incorrect, expected_title.data(), actual_display_title.data());
1120 else // title errors should be ignored, throw a warning anyways
1121 throw_warning(0, warn_rom_title_incorrect, expected_title.data(), actual_display_title.data());
1122 }
1123 6 }
1124
2/3
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
70 } else if(!stricmpwithlower(words[0], "bankcross")) {
1125
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 17 times.
64 if(!stricmpwithlower(words[1], "off")) {
1126 30 disable_bank_cross_errors = true;
1127
4/4
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1 times.
34 } else if(!stricmpwithlower(words[1], "half")) {
1128 32 disable_bank_cross_errors = false;
1129 32 check_half_banks_crossed = true;
1130
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 } else if(!stricmpwithlower(words[1], "full")) {
1131 2 disable_bank_cross_errors = false;
1132 2 check_half_banks_crossed = false;
1133 } else {
1134 throw_err_block(0, err_invalid_check);
1135 }
1136 } else {
1137 throw_err_block(0, err_invalid_check);
1138 }
1139 70 }
1140
1141 36 void cmd_asar(const char* par) {
1142
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
36 if(!asarverallowed) throw_err_block(0, err_start_of_file);
1143
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 18 times.
51 if(!*par) return;
1144 36 int dots = 0;
1145 36 int dig = 0;
1146
4/4
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 18 times.
186 for (int i=0;par[i];i++)
1147 {
1148
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 54 times.
150 if (par[i]=='.')
1149 {
1150
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
42 if (!dig) throw_err_block(0, err_invalid_version_number);
1151 42 dig=0;
1152 42 dots++;
1153 }
1154
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
108 else if (is_digit(par[i])) dig++;
1155 else throw_err_block(0, err_invalid_version_number);
1156 }
1157
3/8
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
36 if (!dig || !dots || dots>2) throw_err_block(0, err_invalid_version_number);
1158
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 string vers_buf = par;
1159
2/3
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
36 autoptr<char**> vers = split(vers_buf.raw(), '.');
1160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
36 int vermaj=atoi(vers[0]);
1161
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
36 if (vermaj > asarver_maj) throw_err_fatal(pass, err_asar_too_old);
1162
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
36 if (vermaj < asarver_maj) return;
1163
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (dots==1) {
1164 // todo: probably want to allow some more stuff here (it bans "asar 2.0" right now)
1165 if (strlen(vers[1])!=2) throw_err_block(0, err_invalid_version_number);
1166 int verminbug=atoi(vers[1]);
1167 int tmpver=asarver_bug;
1168 if (tmpver>9) tmpver=9;
1169 if (asarver_min*10+tmpver<verminbug) throw_err_fatal(pass, err_asar_too_old);
1170 } else {
1171
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 int vermin = atoi(vers[1]);
1172
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
6 if (vermin > asarver_min) throw_err_fatal(pass, err_asar_too_old);
1173
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
6 int verbug = atoi(vers[2]);
1174
2/6
✓ 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.
6 if (vermin == asarver_min && verbug > asarver_bug) throw_err_fatal(pass, err_asar_too_old);
1175 }
1176
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 30 times.
66 }
1177
1178 2 void cmd_include(const char* par) {
1179
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 if(!asarverallowed) throw_err_block(0, err_start_of_file);
1180
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if(*par) throw_err_block(0, err_broken_command, "include", "");
1181
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if(in_top_level_file()) throw_err_fatal(pass, err_cant_be_main_file, "");
1182 }
1183
1184 6 void cmd_includefrom(const char* par) {
1185
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 if(!asarverallowed) throw_err_block(0, err_start_of_file);
1186 if(!*par) throw_err_block(0, err_broken_command, "include", "");
1187 if(in_top_level_file()) throw_err_fatal(pass, err_cant_be_main_file, (string(" The main file is '") + par + "'.").data());
1188 }
1189
1190 30 void cmd_includeonce(const char* par) {
1191
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
30 if(*par) throw_err_block(0, err_broken_command, "includeonce", "");
1192
1193 30 const char* current_file = get_current_file_name();
1194
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 if (!file_included_once(current_file))
1195 {
1196
4/7
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 includeonce.append(current_file);
1197 }
1198 30 }
1199
1200 906 void cmd_org(const char* par) {
1201
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 906 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 489 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
906 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1202
1/2
✓ Branch 0 taken 906 times.
✗ Branch 1 not taken.
906 freespaceend();
1203
2/3
✓ Branch 0 taken 417 times.
✓ Branch 1 taken 489 times.
✗ Branch 2 not taken.
906 auto math_expr = parse_math_expr(par);
1204
4/7
✓ Branch 0 taken 416 times.
✓ Branch 1 taken 489 times.
✓ Branch 2 taken 417 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 488 times.
✗ Branch 6 not taken.
906 int64_t num = math_expr->evaluate_non_forward().get_integer();
1205
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 904 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.
904 if (num&~0xFFFFFF) throw_err_block(1, err_snes_address_out_of_bounds, hex(num, 6).data());
1206
8/14
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 766 times.
✓ Branch 2 taken 153 times.
✓ Branch 3 taken 473 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 431 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 147 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 341 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
904 if ((mapper==lorom || mapper==exlorom) && (num&0x408000)==0x400000 && (num&0x700000)!=0x700000) throw_warning(0, warn_set_middle_byte);
1207 904 snespos=(int)num;
1208 904 realsnespos=(int)num;
1209 904 startpos=(int)num;
1210 904 realstartpos=(int)num;
1211 904 snespos_valid = true;
1212 1394 }
1213
1214 114 void cmd_struct(char** words, int numwords) {
1215 //verifysnespos();
1216
6/8
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 57 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 57 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 57 times.
114 if (in_struct || in_sub_struct) throw_err_block(0, err_nested_struct);
1217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (numwords < 1) throw_err_block(0, err_missing_struct_params);
1218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 114 times.
114 if (numwords > 3) throw_err_block(0, err_too_many_struct_params);
1219
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 57 times.
114 if (!confirmname(words[0])) throw_err_block(0, err_invalid_struct_name);
1220
1221
7/7
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 27 times.
✓ Branch 5 taken 57 times.
✓ Branch 6 taken 57 times.
114 if (structs.exists(words[0]) && pass == 0) throw_err_block(0, err_struct_redefined, words[0]);
1222
1223 114 static_struct = false;
1224 114 old_snespos = snespos;
1225 114 old_startpos = startpos;
1226 114 old_optimizeforbank = optimizeforbank;
1227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
114 old_snespos_valid = snespos_valid;
1228 114 unsigned int base = 0;
1229
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 66 times.
114 if (numwords == 2)
1230 {
1231 48 static_struct = true;
1232
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
48 auto base_expr = parse_math_expr(words[1]);
1233
4/7
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 23 times.
✗ Branch 6 not taken.
48 base = base_expr->evaluate_non_forward().get_integer();
1234
1235
4/8
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 23 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 23 times.
46 if (base_expr->has_label() > 1) static_struct = false;
1236
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 14 times.
46 if (pass > 0) {
1237 // foundlabel_static isn't accurate anymore
1238
8/13
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 16 times.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 15 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 15 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 15 times.
32 if(structs.exists(words[0])) static_struct &= structs.find(words[0]).is_static;
1239 }
1240 48 }
1241
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 bool old_in_struct = in_struct;
1243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 bool old_in_sub_struct = in_sub_struct;
1244
4/4
✓ Branch 0 taken 76 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 30 times.
112 in_struct = numwords == 1 || numwords == 2;
1245 112 in_sub_struct = numwords == 3;
1246
1247 #define cleanup() (in_struct = old_in_struct, in_sub_struct = old_in_sub_struct)
1248
1249
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 66 times.
112 if (numwords == 2)
1250 {
1251
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 46 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.
46 if (base&~0xFFFFFF) cleanup(), throw_err_block(0, err_snes_address_out_of_bounds, hex((unsigned int)base, 6).data());
1252 46 snespos = (int)base;
1253 46 startpos = (int)base;
1254 }
1255
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 36 times.
66 else if (numwords == 3)
1256 {
1257
3/8
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
30 if (strcasecmp(words[1], "extends")) cleanup(), throw_err_block(0, err_missing_extends);
1258
3/9
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
30 if (!confirmname(words[2])) cleanup(), throw_err_block(0, err_struct_invalid_parent_name);
1259
2/4
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 string tmp_struct_parent = words[2];
1260
1261
2/6
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
30 if (!structs.exists(tmp_struct_parent)) cleanup(), throw_err_block(0, err_struct_not_found, tmp_struct_parent.data());
1262
4/7
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 snes_struct structure = structs.find(tmp_struct_parent);
1263
1264
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
30 static_struct = structure.is_static;
1265
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 struct_parent = tmp_struct_parent;
1266 30 snespos = structure.base_end;
1267 30 startpos = structure.base_end;
1268 30 }
1269
1270 112 push_pc();
1271
1272 112 optimizeforbank = -1;
1273
1274 112 struct_name = words[0];
1275 112 struct_base = snespos;
1276 112 realsnespos = 0;
1277 112 realstartpos = 0;
1278 112 snespos_valid = true;
1279
1280
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 41 times.
112 if(in_sub_struct) {
1281
3/7
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 15 times.
✗ Branch 6 not taken.
30 string labelname = struct_parent + "." + struct_name;
1282
5/8
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
30 setlabel(ns + labelname, snespos, static_struct);
1283 30 } else {
1284
5/8
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 41 times.
✓ Branch 2 taken 41 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 41 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 41 times.
✗ Branch 7 not taken.
82 setlabel(ns + struct_name, snespos, static_struct);
1285 }
1286
1287 #undef cleanup
1288 112 }
1289
1290 114 void cmd_endstruct(char** words, int numwords) {
1291
3/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
114 if (numwords != 0 && numwords != 2) throw_err_block(0, err_invalid_endstruct_count);
1292
6/10
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 57 times.
✓ Branch 6 taken 57 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
114 if (numwords == 2 && stricmpwithlower(words[0], "align")) throw_err_block(0, err_expected_align);
1293
9/10
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 16 times.
✓ Branch 6 taken 1 times.
✓ Branch 7 taken 15 times.
✓ Branch 8 taken 1 times.
✗ Branch 9 not taken.
114 if (!in_struct && !in_sub_struct) throw_err_block(0, err_endstruct_without_struct);
1294
1295
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
112 int alignment = numwords == 2 ? (int)getnum(words[1]) : 1;
1296
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 112 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
112 if (alignment < 1) throw_err_block(0, err_alignment_too_small);
1297
1298 112 snes_struct structure;
1299 112 structure.base_end = snespos;
1300
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 structure.struct_size = alignment * ((snespos - struct_base + alignment - 1) / alignment);
1301 112 structure.object_size = structure.struct_size;
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 structure.is_static = static_struct;
1303
1304
4/4
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 15 times.
112 if (in_struct)
1305 {
1306
3/5
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 41 times.
✗ Branch 4 not taken.
82 structs.create(struct_name) = structure;
1307 }
1308
3/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 15 times.
✗ Branch 3 not taken.
30 else if (in_sub_struct)
1309 {
1310 30 snes_struct parent;
1311
3/5
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
30 parent = structs.find(struct_parent);
1312
1313
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 6 times.
30 if (parent.object_size < parent.struct_size + structure.struct_size) {
1314 24 parent.object_size = parent.struct_size + structure.struct_size;
1315 }
1316
1317
7/13
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 15 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 15 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 15 times.
✗ Branch 12 not taken.
30 structs.create(struct_parent + "." + struct_name) = structure;
1318
3/5
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 15 times.
✗ Branch 4 not taken.
30 structs.create(struct_parent) = parent;
1319 30 }
1320
1321
1/2
✓ Branch 0 taken 112 times.
✗ Branch 1 not taken.
112 pop_pc();
1322 112 in_struct = false;
1323 112 in_sub_struct = false;
1324 112 snespos = old_snespos;
1325 112 startpos = old_startpos;
1326 112 optimizeforbank = old_optimizeforbank;
1327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
112 snespos_valid = old_snespos_valid;
1328 112 static_struct = false;
1329 168 }
1330
1331 12 void cmd_spcblock(char** words, int num_words) {
1332 12 int addrToLinePos = realsnespos & 0xFFFFFF;
1333 //banned features when active: org, freespace(and variants), arch, mapper,namespace,pushns
1334
6/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
12 if(in_struct || in_sub_struct) throw_err_block(0, err_spcblock_inside_struct);
1335
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(num_words < 1) throw_err_block(0, err_spcblock_too_few_args);
1336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(num_words > 3) throw_err_block(0, err_spcblock_too_many_args);
1337
1338 12 spcblock.destination = getnum(words[0]);
1339 12 spcblock.type = spcblock_nspc;
1340 12 spcblock.macro_name = "";
1341
1342
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 12 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.
12 if (spcblock.destination&~0xFFFF) throw_err_block(0, err_snes_address_out_of_bounds, hex(spcblock.destination, 6).data());
1343
1344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if(num_words == 2)
1345 {
1346 if(!stricmp(words[1], "nspc")) spcblock.type = spcblock_nspc;
1347 else if(!stricmp(words[1], "custom")) throw_err_block(0, err_custom_spcblock_missing_macro);
1348 else throw_err_block(0, err_unknown_spcblock_type);
1349 }
1350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 else if(num_words == 3)
1351 {
1352 if(!stricmp(words[1], "custom")) spcblock.type = spcblock_custom;
1353 else throw_err_block(0, err_extra_spcblock_arg_for_type);
1354
1355 if(macros.exists(words[2]))
1356 {
1357 macrodata *macro = macros.find(words[2]);
1358 if(!macro->variadic) throw_err_block(0, err_spcblock_macro_must_be_varadic);
1359 if(macro->numargs != 3) throw_err_block(0, err_spcblock_macro_invalid_static_args);
1360 spcblock.macro_name = words[2];
1361 }
1362 else throw_err_block(0, err_spcblock_macro_doesnt_exist);
1363 }
1364
1365
3/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 switch(spcblock.type)
1366 {
1367 12 case spcblock_nspc:
1368 12 spcblock.size_address=realsnespos;
1369 12 write2(0x0000);
1370 12 write2(spcblock.destination);
1371 12 snespos=(int)spcblock.destination;
1372 12 startpos=(int)spcblock.destination;
1373 12 add_addr_to_line(addrToLinePos);
1374 12 break;
1375 case spcblock_custom:
1376 //this is a todo that probably won't be ready for 1.9
1377 //mostly so we can leverage some cleanups we make in 2.0 for practicality
1378 throw_err_block(0, err_spcblock_custom_types_incomplete);
1379 push_pc();
1380 spcblock.old_mapper = mapper;
1381 mapper = norom;
1382 break;
1383 default:
1384 throw_err_fatal(0, err_internal_error, "invalid spcblock type");
1385 }
1386
1387 12 ns_backup = ns;
1388
3/7
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
12 ns = STR":SPCBLOCK:_" + ns_backup;
1389 12 in_spcblock = true;
1390 12 }
1391
1392 12 void cmd_endspcblock(char** words, int num_words) {
1393
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 if(!in_spcblock) throw_err_block(0, err_endspcblock_without_spcblock);
1394
1395
3/5
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
12 switch(spcblock.type)
1396 {
1397 12 case spcblock_nspc:
1398
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 if (pass==2)
1399 {
1400 4 int pcpos=snestopc(spcblock.size_address&0xFFFFFF);
1401
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 4 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.
4 if (pcpos<0) throw_err_block(2, err_snes_address_doesnt_map_to_rom, hex((unsigned int)realsnespos, 6).data());
1402 // compute number of bytes written;
1403 // offset by 4 for the spcblock header itself
1404 4 int num = realsnespos - ((int)spcblock.size_address + 4);
1405 4 writeromdata_byte(pcpos, (unsigned char)num);
1406 4 writeromdata_byte(pcpos+1, (unsigned char)(num >> 8));
1407 }
1408
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 6 times.
12 if (num_words == 2)
1409 {
1410 // todo allow spaces here
1411
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
6 if (strcmp(words[0], "execute")) throw_err_null(0, err_invalid_endspcblock_arg, words[0]);
1412 else
1413 {
1414 6 write2(0x0000);
1415
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 write2(pass == 2 ? (unsigned int)getnum(words[1]) : 0);
1416 }
1417 }
1418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 else if (num_words != 0)
1419 {
1420 throw_err_null(0, err_unknown_endspcblock_format);
1421 }
1422 12 break;
1423 case spcblock_custom:
1424 mapper = spcblock.old_mapper;
1425 pop_pc();
1426 break;
1427 default:
1428 throw_err_fatal(0, err_internal_error, "invalid spcblock type");
1429 }
1430 12 ns = ns_backup;
1431 12 in_spcblock = false;
1432 12 snespos=realsnespos;
1433 12 startpos=realstartpos;
1434 12 }
1435
1436 102 void cmd_base(const char* par) {
1437
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 36 times.
102 if (!stricmp(par, "off"))
1438 {
1439 30 snespos=realsnespos;
1440 30 startpos=realstartpos;
1441 30 snespos_valid = realsnespos >= 0;
1442 30 return;
1443 }
1444
5/10
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 36 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 36 times.
✗ Branch 9 not taken.
72 unsigned int num=parse_math_expr(par)->evaluate_non_forward().get_integer();
1445
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 72 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.
72 if (num&~0xFFFFFF) throw_err_block(1, err_snes_address_out_of_bounds, hex((unsigned int)num).data());
1446 72 snespos=(int)num;
1447 72 startpos=(int)num;
1448 72 optimizeforbank=-1;
1449 72 snespos_valid = realsnespos >= 0;
1450 }
1451
1452 12 void cmd_dpbase(const char* par) {
1453
5/10
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
12 unsigned int num=parse_math_expr(par)->evaluate_non_forward().get_integer();
1454
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 12 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.
12 if (num&~0xFF00) throw_err_block(1, err_bad_dp_base, hex((unsigned int)num, 6).data());
1455 12 dp_base = (int)num;
1456 12 }
1457
1458 108 void cmd_optimize(char** words, int num_words) {
1459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if(num_words != 2) throw_err_block(1, err_bad_optimize, "");
1460
1461
5/5
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 54 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 33 times.
108 if (!stricmp(words[0], "dp"))
1462 {
1463
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 9 times.
42 if (!stricmp(words[1], "none"))
1464 {
1465 24 optimize_dp = optimize_dp_flag::NONE;
1466 24 return;
1467 }
1468
5/6
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6 times.
18 if (!stricmp(words[1], "ram"))
1469 {
1470 6 optimize_dp = optimize_dp_flag::RAM;
1471 6 return;
1472 }
1473
3/6
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
12 if (!stricmp(words[1], "always"))
1474 {
1475 12 optimize_dp = optimize_dp_flag::ALWAYS;
1476 12 return;
1477 }
1478 throw_err_block(1, err_bad_dp_optimize, words[1]);
1479 }
1480
3/5
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 33 times.
✗ Branch 4 not taken.
66 if (!stricmp(words[0], "address"))
1481 {
1482
5/6
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 21 times.
66 if (!stricmp(words[1], "default"))
1483 {
1484 24 optimize_address = optimize_address_flag::DEFAULT;
1485 24 return;
1486 }
1487
5/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 12 times.
42 if (!stricmp(words[1], "ram"))
1488 {
1489 18 optimize_address = optimize_address_flag::RAM;
1490 18 return;
1491 }
1492
3/6
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
24 if (!stricmp(words[1], "mirrors"))
1493 {
1494 24 optimize_address = optimize_address_flag::MIRRORS;
1495 24 return;
1496 }
1497 throw_err_block(1, err_bad_address_optimize, words[1]);
1498 }
1499 throw_err_block(1, err_bad_optimize, words[0]);
1500 }
1501
1502 18 void cmd_bank(const char* par) {
1503
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
18 if (!stricmp(par, "auto"))
1504 {
1505 6 optimizeforbank=-1;
1506 6 return;
1507 }
1508
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
12 if (!stricmp(par, "noassume"))
1509 {
1510 6 optimizeforbank=0x140;
1511 6 return;
1512 }
1513 6 unsigned int num=getnum(par);
1514 //if (forwardlabel) error(0, "bank Label is not valid");
1515 //if (foundlabel) num>>=16;
1516
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 6 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.
6 if (num&~0x0000FF) throw_err_block(1, err_snes_address_out_of_bounds, hex((unsigned int)num, 6).data());
1517 6 optimizeforbank=(int)num;
1518 }
1519
1520 enum class freespace_cmds {
1521 freespace,
1522 freecode,
1523 freedata,
1524 segment,
1525 };
1526
1527 template<freespace_cmds the_cmd>
1528 3204 void cmd_freespace(const char* par) {
1529
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 1602 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 801 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
3204 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1530
1531
2/3
✓ Branch 0 taken 801 times.
✓ Branch 1 taken 801 times.
✗ Branch 2 not taken.
3204 freespace_data this_fs_settings = default_freespace_settings;
1532 2244 if (the_cmd == freespace_cmds::freecode) this_fs_settings.bank = -2;
1533 672 if (the_cmd == freespace_cmds::freedata) this_fs_settings.bank = -1;
1534 276 if (the_cmd == freespace_cmds::segment) this_fs_settings.write_rats = false;
1535
1536
2/3
✓ Branch 0 taken 801 times.
✓ Branch 1 taken 801 times.
✗ Branch 2 not taken.
3204 string parstr = par;
1537
1/2
✓ Branch 0 taken 1602 times.
✗ Branch 1 not taken.
3204 parse_freespace_arguments(this_fs_settings, parstr);
1538
1539
5/6
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 1518 times.
✓ Branch 2 taken 42 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
3204 if(this_fs_settings.bank == -3 && !this_fs_settings.write_rats) this_fs_settings.bank = -1;
1540
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1602 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
3204 if(this_fs_settings.bank == -3) throw_err_block(0, err_invalid_freespace_request);
1541 // no point specifying anything about cleaning when not writing a rats tag
1542
4/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 1533 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 732 times.
3204 if(!this_fs_settings.write_rats &&
1543
6/8
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 69 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 69 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 69 times.
276 (this_fs_settings.flag_cleaned || this_fs_settings.is_static))
1544 throw_err_block(0, err_invalid_freespace_request);
1545
4/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 1533 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 732 times.
3204 if(!this_fs_settings.write_rats) this_fs_settings.flag_cleaned = true;
1546
1/2
✓ Branch 0 taken 1602 times.
✗ Branch 1 not taken.
3204 freespaceend();
1547 3204 freespaceid = freespaceidnext++;
1548
1/2
✓ Branch 0 taken 1602 times.
✗ Branch 1 not taken.
3204 freespace_data& thisfs = freespaces[freespaceid];
1549
1550
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 1068 times.
3204 if (pass==0) {
1551
2/3
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
1068 thisfs = this_fs_settings;
1552 1068 thisfs.pos = -1;
1553 1068 thisfs.leaked = true;
1554 1068 thisfs.orgpos = -2;
1555 1068 thisfs.orglen = -1;
1556 1068 snespos=0;
1557 }
1558
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 1068 times.
3204 if (pass==1)
1559 {
1560
6/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
1068 if (thisfs.is_static && thisfs.orgpos == -2)
1561 {
1562 thisfs.pos = 0;
1563 thisfs.leaked = false;//mute some other errors
1564 throw_err_block(1, err_static_freespace_autoclean);
1565 }
1566 1068 snespos = 0;
1567 }
1568
2/2
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 1068 times.
3204 if (pass==2)
1569 {
1570
6/7
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
1068 if (thisfs.is_static && thisfs.orgpos == -2) return;//to kill some errors (supposedly????)
1571 1068 snespos=thisfs.pos;
1572
7/12
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 468 times.
✓ Branch 4 taken 33 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 234 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 234 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1068 if (thisfs.leaked && !thisfs.flag_cleaned) throw_warning(2, warn_freespace_leaked);
1573
5/5
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 244 times.
✓ Branch 4 taken 23 times.
1068 freespaceuse += (thisfs.write_rats ? 8 : 0) + thisfs.len;
1574
1575 // add a mapping for the start of the rats tag
1576
6/7
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 511 times.
✓ Branch 3 taken 244 times.
✓ Branch 4 taken 23 times.
✓ Branch 5 taken 244 times.
✗ Branch 6 not taken.
1068 if (thisfs.write_rats) add_addr_to_line(snespos-8);
1577 }
1578
1/12
✗ Branch 0 not taken.
✓ Branch 1 taken 1602 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.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
3204 if (snespos < 0 && mapper == sa1rom) throw_err_fatal(pass, err_no_freespace_in_mapped_banks, dec(thisfs.len).data());
1579
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 1602 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.
3204 if (snespos < 0) throw_err_fatal(pass, err_no_freespace, dec(thisfs.len).data());
1580
5/5
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 801 times.
✓ Branch 3 taken 732 times.
✓ Branch 4 taken 69 times.
3204 bytes+=thisfs.write_rats ? 8 : 0;
1581 3204 freespacestart=snespos;
1582 3204 startpos=snespos;
1583 3204 realstartpos=snespos;
1584 3204 realsnespos=snespos;
1585 3204 optimizeforbank=-1;
1586
5/5
✓ Branch 0 taken 732 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 801 times.
✓ Branch 3 taken 732 times.
✓ Branch 4 taken 69 times.
3204 ratsmetastate=thisfs.write_rats ? ratsmeta_allow : ratsmeta_ban;
1587 3204 snespos_valid = true;
1588 // check this at the very end so that snespos gets set properly, to
1589 // prevent spurious errors later
1590 //...i guess this can still cause bankcross errors if the old freespace
1591 //happened to be very close to the end of a bank or something, but
1592 //whatever
1593
10/12
✓ Branch 0 taken 534 times.
✓ Branch 1 taken 1068 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 265 times.
✓ Branch 4 taken 268 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 266 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 1 times.
✗ Branch 11 not taken.
3204 if (pass == 2 && thisfs.is_static && thisfs.orgpos > 0 && thisfs.len > thisfs.orglen)
1594
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
4 throw_err_block(2, err_static_freespace_growing);
1595
2/4
✓ Branch 0 taken 1600 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1600 times.
✗ Branch 3 not taken.
3208 }
1596
1597 6 void cmd_freespace_settings(const char* par) {
1598
2/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
6 string arg = par;
1599
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 parse_freespace_arguments(default_freespace_settings, arg);
1600 9 }
1601
1602 42 void cmd_prot(const char* par) {
1603 42 int addrToLinePos = realsnespos & 0xFFFFFF;
1604
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
42 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1605
2/7
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
42 if (!ratsmetastate) throw_err_block(2, err_prot_not_at_freespace_start);
1606
4/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 15 times.
42 if (ratsmetastate==ratsmeta_used) step(-5);
1607 21 int num;
1608
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 string parbuf = par;
1609
2/3
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
42 autoptr<char**> pars=qpsplit(parbuf.raw(), ',', &num);
1610
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 verify_paren(pars);
1611
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('P');
1612
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('R');
1613
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('O');
1614
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('T');
1615
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
42 if (num * 3 > 255) throw_err_block(0, err_prot_too_many_entries);
1616
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1((unsigned int)(num*3));
1617
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 42 times.
96 for (int i=0;i<num;i++)
1618 {
1619 54 const char * labeltest=pars[i];
1620
2/3
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
54 string testlabel = labeltest;
1621
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 snes_label lblval = labelval(&labeltest);
1622
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
54 if (*labeltest) throw_err_block(0, err_label_not_found, testlabel.data());
1623
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 write3(lblval.pos);
1624
3/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
54 if (pass==1) freespaces[lblval.freespace_id].leaked = false;
1625 54 }
1626
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('S');
1627
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('T');
1628
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('O');
1629
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1('P');
1630
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 write1(0);
1631 42 ratsmetastate=ratsmeta_used;
1632
1633
1/2
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
42 add_addr_to_line(addrToLinePos);
1634 63 }
1635
1636 18 void cmd_autoclean(char** words, int num_words) {
1637
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
18 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1638
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 if (num_words==2)
1639 {
1640 18 const char * labeltest = words[1];
1641
2/3
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 string testlabel = labeltest;
1642
2/3
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
18 if(!stricmpwithlower(words[0], "dl")) {
1643
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 handle_autoclean(testlabel, -1, snespos);
1644
1645
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 add_addr_to_line(realsnespos & 0xFFFFFF);
1646
12/20
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 15 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 3 times.
✓ Branch 12 taken 6 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 3 times.
✓ Branch 15 taken 6 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
18 write3(pass==2 ? labelval(testlabel).pos : 0);
1647 } else {
1648 // other ones are handled in arch-65816
1649 throw_err_block(0, err_broken_autoclean);
1650 }
1651 18 }
1652 else if (num_words == 1) {
1653 if(pass==0) removerats(parse_math_expr(words[0])->evaluate_static().get_integer(), freespacebyte);
1654 } else {
1655 throw_err_block(0, err_broken_autoclean);
1656 }
1657 18 }
1658
1659 6 void cmd_freespacebyte(const char* par) {
1660
5/10
✓ 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 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
6 freespacebyte = parse_math_expr(par)->evaluate_static().get_integer();
1661 6 }
1662
1663 6 void cmd_pushpc(const char* par) {
1664
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pushpc", "");
1665 6 verifysnespos();
1666 6 pushpc[pushpcnum].arch=arch;
1667 6 pushpc[pushpcnum].snespos=snespos;
1668 6 pushpc[pushpcnum].snesstart=startpos;
1669 6 pushpc[pushpcnum].snesposreal=realsnespos;
1670 6 pushpc[pushpcnum].snesstartreal=realstartpos;
1671 6 pushpc[pushpcnum].freeid=freespaceid;
1672 6 pushpc[pushpcnum].freest=freespacestart;
1673 6 pushpcnum++;
1674 6 snespos=(int)0xFFFFFFFF;
1675 6 startpos= (int)0xFFFFFFFF;
1676 6 realsnespos= (int)0xFFFFFFFF;
1677 6 realstartpos= (int)0xFFFFFFFF;
1678 6 snespos_valid = false;
1679 6 }
1680
1681 6 void cmd_pullpc(const char* par) {
1682
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pullpc", "");
1683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!pushpcnum) throw_err_block(0, err_pullpc_without_pushpc);
1684 6 pushpcnum--;
1685 6 freespaceend();
1686
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if (arch != pushpc[pushpcnum].arch) throw_err_block(0, err_pullpc_different_arch);
1687 6 snespos=pushpc[pushpcnum].snespos;
1688 6 startpos=pushpc[pushpcnum].snesstart;
1689 6 realsnespos=pushpc[pushpcnum].snesposreal;
1690 6 realstartpos=pushpc[pushpcnum].snesstartreal;
1691 6 freespaceid=pushpc[pushpcnum].freeid;
1692 6 freespacestart=pushpc[pushpcnum].freest;
1693 6 snespos_valid = true;
1694 6 }
1695
1696 6 void cmd_pushbase(const char* par) {
1697
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pushbase", "");
1698 6 basestack[basestacknum] = snespos;
1699 6 basestacknum++;
1700 6 }
1701
1702 6 void cmd_pullbase(const char* par) {
1703
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pullbase", "");
1704
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!basestacknum) throw_err_block(0, err_pullbase_without_pushbase);
1705 6 basestacknum--;
1706 6 snespos = basestack[basestacknum];
1707 6 startpos = basestack[basestacknum];
1708
1709
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (snespos != realstartpos)
1710 {
1711 6 optimizeforbank = -1;
1712 }
1713 6 }
1714
1715 12 void cmd_pushns(const char* par) {
1716
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
12 if(*par) throw_err_block(0, err_broken_command, "pushns", "");
1717
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1718 12 pushns[pushnsnum].ns = ns;
1719
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for(int i = 0; i < namespace_list.count; i++)
1720 {
1721 12 pushns[pushnsnum].namespace_list.append(namespace_list[i]);
1722 }
1723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 pushns[pushnsnum].nested_namespaces = nested_namespaces;
1724 12 pushnsnum++;
1725
1726 12 namespace_list.reset();
1727 12 ns = "";
1728 12 nested_namespaces = false;
1729 12 }
1730
1731 12 void cmd_pullns(const char* par) {
1732
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 6 times.
12 if(*par) throw_err_block(0, err_broken_command, "pullns", "");
1733
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
12 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!pushnsnum) throw_err_block(0, err_pullns_without_pushns);
1735 12 pushnsnum--;
1736 12 ns = pushns[pushnsnum].ns;
1737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 nested_namespaces = pushns[pushnsnum].nested_namespaces;
1738 12 namespace_list.reset();
1739
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
36 for(int i = 0; i < pushns[pushnsnum].namespace_list.count; i++)
1740 {
1741 24 namespace_list.append(pushns[pushnsnum].namespace_list[i]);
1742 }
1743 12 }
1744
1745 165 void cmd_namespace(char** words, int num_words) {
1746
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
165 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1747 165 bool leave = false;
1748
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 if (num_words >= 1)
1749 {
1750
5/5
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 84 times.
✓ Branch 3 taken 24 times.
✓ Branch 4 taken 60 times.
165 if (!stricmp(words[0], "off"))
1751 {
1752
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (num_words != 1) throw_err_block(0, err_invalid_namespace_use);
1753 48 leave = true;
1754 }
1755
5/5
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 42 times.
117 else if (!stricmp(words[0], "nested"))
1756 {
1757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (num_words != 2) throw_err_block(0, err_invalid_namespace_use);
1758
5/6
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 9 times.
✓ Branch 5 taken 9 times.
36 else if (!stricmp(words[1], "on")) nested_namespaces = true;
1759
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 else if (!stricmp(words[1], "off")) nested_namespaces = false;
1760 }
1761 else
1762 {
1763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (num_words != 1) throw_err_block(0, err_invalid_namespace_use);
1764 81 const char * tmpstr= safedequote(words[0]);
1765
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 if (!confirmname(tmpstr)) throw_err_block(0, err_invalid_namespace_name);
1766
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 24 times.
81 if (!nested_namespaces)
1767 {
1768 33 namespace_list.reset();
1769 }
1770
4/7
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 39 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
81 namespace_list.append(tmpstr);
1771 }
1772 }
1773 else
1774 {
1775 throw_err_block(0, err_invalid_namespace_use);
1776 //leave = true;
1777 }
1778
1779
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 117 times.
165 if (leave)
1780 {
1781
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 6 times.
48 if (nested_namespaces)
1782 {
1783 36 namespace_list.remove(namespace_list.count - 1);
1784 }
1785 else
1786 {
1787 12 namespace_list.reset();
1788 }
1789 }
1790
1791 // recompute ns
1792 165 ns = "";
1793
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 165 times.
360 for (int i = 0; i < namespace_list.count; i++)
1794 {
1795 195 ns += namespace_list[i];
1796 195 ns += "_";
1797 }
1798 165 }
1799
1800 10171 void cmd_incsrc(const char* par) {
1801 // RPG Hacker: Should this also throw on absolute paths?
1802 // E.g., on something starting with C:/ or whatever.
1803
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10168 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 5093 times.
10171 if (strchr(par, '\\'))
1804 {
1805
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_platform_paths);
1806 }
1807
2/3
✓ Branch 0 taken 5072 times.
✓ Branch 1 taken 5093 times.
✗ Branch 2 not taken.
10165 string temp = par;
1808
1/2
✓ Branch 0 taken 10165 times.
✗ Branch 1 not taken.
10165 const char* name = safedequote(temp.raw());
1809
2/2
✓ Branch 0 taken 159 times.
✓ Branch 1 taken 10006 times.
10165 assemblefile(name);
1810 10255 }
1811
1812 60 void cmd_incbin(const char* par) {
1813 60 int addrToLinePos = realsnespos & 0xFFFFFF;
1814 30 int len;
1815 60 int start=0;
1816 60 int end=0;
1817
2/3
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
60 string temp = par;
1818 60 const char* lengths = strqchr(temp, ':');
1819
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 30 times.
60 if (lengths)
1820 {
1821 30 lengths++;
1822
1823
1/2
✓ Branch 0 taken 30 times.
✗ Branch 1 not taken.
30 const char* split = strqpstr(lengths, "..");
1824
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
30 if(!split) throw_err_block(0, err_broken_incbin);
1825
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 string start_str(lengths, split-lengths);
1826
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if(start_str == "") throw_err_block(0, err_broken_incbin);
1827
5/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
24 start = parse_math_expr(start_str)->evaluate_non_forward().get_integer();
1828
2/4
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 string end_str(split+2);
1829
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
24 if(end_str == "") throw_err_block(0, err_broken_incbin);
1830
5/10
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
24 end = parse_math_expr(end_str)->evaluate_non_forward().get_integer();
1831 // make temp just the filename without the lengths
1832
2/3
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
24 temp.truncate(lengths-1 - temp.data());
1833 24 }
1834
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
54 const char* current_file = get_current_file_name();
1835 // RPG Hacker: Should this also throw on absolute paths?
1836 // E.g., on something starting with C:/ or whatever.
1837
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 24 times.
54 if (strchr(par, '\\'))
1838 {
1839
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 throw_err_block(0, err_platform_paths);
1840 }
1841
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 const char* name = safedequote(temp.raw());
1842
1843 24 char * data;//I couldn't find a way to get this into an autoptr
1844
5/8
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 36 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 12 times.
48 if (!readfile(name, current_file, &data, &len)) throw_vfile_error(0, asar_get_last_io_error(), name);
1845 36 autoptr<char*> datacopy=data;
1846
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
36 if (!end) end=len;
1847
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 36 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.
36 if(start < 0) throw_err_block(1, err_file_offset_out_of_bounds, dec(start).data(), name);
1848
3/13
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 36 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
36 if (end < start || end > len || end < 0) throw_err_block(1, err_file_offset_out_of_bounds, dec(end).data(), name);
1849
1850
5/6
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 18 times.
102 for (int i=start;i<end;i++) write1((unsigned int)data[i]);
1851
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 add_addr_to_line(addrToLinePos);
1852 78 }
1853
1854 template<bool is_fill>
1855 1344 void cmd_skip_fill(char** words, int num_words) {
1856 1344 const char* cmdname = is_fill ? "fill" : "skip";
1857
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
1344 if(num_words != 1 && num_words != 2 && num_words != 4) throw_err_block(0, err_broken_command, cmdname, "");
1858
6/7
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 336 times.
✓ Branch 6 taken 3 times.
1344 if(num_words > 1 && stricmp(words[0], "align")) throw_err_block(0, err_broken_command, cmdname, "expected \"align\"");
1859
5/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 339 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 3 times.
1344 if(num_words == 4 && stricmp(words[2], "offset")) throw_err_block(0, err_broken_command, cmdname, "expected \"offset\"");
1860 int amount;
1861
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 666 times.
1344 if(num_words > 1)
1862 {
1863
5/10
✓ 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 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
12 int alignment = parse_math_expr(words[1])->evaluate_static().get_integer();
1864 12 int offset = 0;
1865
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
12 if(num_words==4)
1866 {
1867
5/10
✓ 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 not taken.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
12 offset = parse_math_expr(words[3])->evaluate_static().get_integer();
1868 }
1869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if(alignment > 0x800000) throw_err_block(0, err_alignment_too_big);
1870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if(alignment < 1) throw_err_block(0, err_alignment_too_small);
1871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
12 if(alignment & (alignment-1)) throw_err_block(0, err_invalid_alignment);
1872 // i just guessed this formula but it seems to work
1873 12 amount = (alignment - ((snespos - offset) & (alignment-1))) & (alignment-1);
1874 // TODO: set current freespace align to at least alignment
1875 }
1876 else
1877 {
1878
5/10
✓ Branch 0 taken 333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 666 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 333 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 333 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 333 times.
✗ Branch 9 not taken.
1332 amount = parse_math_expr(words[0])->evaluate_non_forward().get_integer();
1879 }
1880 1212 if(!is_fill) step(amount);
1881 else
1882 {
1883 132 add_addr_to_line(realsnespos & 0xFFFFFF);
1884
4/4
✓ Branch 0 taken 203535 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 203535 times.
✓ Branch 3 taken 33 times.
814272 for(int i=0; i < amount; i++) write1(fillbyte[i%12]);
1885 }
1886 1344 }
1887
1888 6 void cmd_cleartable(const char* par) {
1889
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "cleartable", "");
1890 6 cleartable();
1891 6 }
1892
1893 6 void cmd_pushtable(const char* par) {
1894
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pushtable", "");
1895 6 tablestack.append(thetable);
1896 6 }
1897
1898 6 void cmd_pulltable(const char* par) {
1899
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if(*par) throw_err_block(0, err_broken_command, "pulltable", "");
1900
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (tablestack.count <= 0) throw_err_block(0, err_pulltable_without_table);
1901 6 thetable=tablestack[tablestack.count-1];
1902 6 tablestack.remove(tablestack.count-1);
1903 6 }
1904
1905 48 void cmd_function(const char* par) {
1906
2/3
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
48 string parbuf = par;
1907
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 parbuf.qnormalize(); // todo what's the point of doing this here in particular???
1908 48 char* name_and_args = parbuf.raw();
1909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
48 char* fn_body = strchr(name_and_args, '=');
1910
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 if(!fn_body) throw_err_block(0, err_broken_function_declaration);
1911 48 *fn_body = 0;
1912 48 fn_body++;
1913
2/6
✓ 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.
48 if(!confirmqpar(name_and_args)) throw_err_block(0, err_broken_function_declaration);
1914 48 char* startpar = strqchr(name_and_args, '(');
1915
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 if (!startpar) throw_err_block(0, err_broken_function_declaration);
1916 48 *startpar = 0;
1917 48 startpar++;
1918
3/7
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
48 if(!confirmname(name_and_args)) throw_err_block(0, err_invalid_function_name);
1919 48 char* endpar = strqchr(startpar, ')');
1920 48 *endpar = 0;
1921 48 endpar++;
1922 // it's legal for there to be spaces between ) and =
1923
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 24 times.
96 while(*endpar == ' ') endpar++;
1924
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 24 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
48 if(*endpar) throw_err_block(0, err_broken_function_declaration);
1925
1926
1/2
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
48 createuserfunc(name_and_args, startpar, fn_body);
1927 72 }
1928
1929 324 void cmd_print(const char* par) {
1930
3/3
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 4 times.
324 string out = handle_print(par);
1931
3/4
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 100 times.
✗ Branch 3 not taken.
316 if(pass == 2) print(out);
1932 477 }
1933
1934 6 void cmd_reset(const char* par) {
1935 if(0);
1936
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
6 else if (!stricmp(par, "bytes")) bytes=0;
1937 else if (!stricmp(par, "freespaceuse")) freespaceuse=0;
1938 else throw_err_block(2, err_unknown_variable);
1939 6 }
1940
1941 template<int width, bool is_fill>
1942 108 void cmd_padbytes(const char* par) {
1943
5/10
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 27 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 27 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
108 unsigned int val = parse_math_expr(par)->evaluate_static().get_integer();
1944
2/2
✓ Branch 0 taken 510 times.
✓ Branch 1 taken 54 times.
1128 for (int i=0;i<12;i+=width)
1945 {
1946 1020 unsigned int tmpval=val;
1947
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 510 times.
2316 for (int j=0;j<width;j++)
1948 {
1949 1296 (is_fill ? fillbyte : padbyte)[i+j] = (unsigned char)tmpval;
1950 1296 tmpval>>=8;
1951 }
1952 }
1953 108 }
1954
1955 12 void cmd_pad(const char* par) {
1956
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (freespaceid > 0) throw_err_block(0, err_pad_in_freespace);
1957
5/10
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
12 int num = parse_math_expr(par)->evaluate_non_forward().get_integer();
1958
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 12 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.
12 if ((unsigned int)num & 0xFF000000) throw_err_block(0, err_snes_address_doesnt_map_to_rom, hex((unsigned int)num, 6).data());
1959
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (num>realsnespos)
1960 {
1961 12 int end=snestopc(num);
1962 12 int start=snestopc(realsnespos);
1963 12 int len=end-start;
1964 12 add_addr_to_line(realsnespos & 0xFFFFFF);
1965
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 6 times.
72 for (int i=0;i<len;i++) write1(padbyte[i%12]);
1966 }
1967 12 }
1968
1969 90 void cmd_arch(const char* par) {
1970
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 45 times.
90 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1971
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 33 times.
90 if (!stricmp(par, "65816")) { arch=arch_65816; return; }
1972
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 21 times.
✓ Branch 3 taken 12 times.
66 if (!stricmp(par, "spc700")) { arch=arch_spc700; return; }
1973
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
24 if (!stricmp(par, "superfx")) { arch=arch_superfx; return; }
1974 throw_err_block(0, err_broken_command, "arch", "Invalid architecture, expected one of 65816, spc700, superfx");
1975 }
1976
1977 72 void cmd_braces(const char* par) {
1978
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 36 times.
72 if(*par) throw_err_block(0, err_broken_command, "{ / }", "");
1979 72 }
1980
1981 template<void (*F)(const char*)>
1982 530 void wrap_mapper(const char* par) {
1983
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 149 times.
530 if(in_spcblock) throw_err_block(0, err_feature_unavaliable_in_spcblock);
1984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 149 times.
530 mapper_t previous_mapper = mapper;
1985 F(par);
1986
4/4
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 194 times.
✓ Branch 2 taken 104 times.
✓ Branch 3 taken 45 times.
530 if(!mapper_set){
1987 350 mapper_set = true;
1988
4/4
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 39 times.
✓ Branch 3 taken 6 times.
180 }else if(previous_mapper != mapper){
1989 156 throw_warning(1, warn_mapper_already_set);
1990 }
1991 530 }
1992
1993 template<mapper_t the_mapper>
1994 386 void mapper_simple(const char* par) {
1995
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 86 times.
✓ Branch 2 taken 107 times.
386 if(*par) throw_err_block(0, err_invalid_mapper);
1996 386 mapper = the_mapper;
1997 386 }
1998
1999 45 void mapper_norom(const char* par) {
2000
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 27 times.
45 if(*par) throw_err_block(0, err_invalid_mapper);
2001 //$000000 would be the best snespos for this, but I don't care
2002 45 mapper = norom;
2003
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 21 times.
45 if(!force_checksum_fix)
2004 6 checksum_fix_enabled = false;//we don't know where the header is, so don't set the checksum
2005 45 }
2006
2007 27 void mapper_sa1rom(const char* par) {
2008
3/3
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 3 times.
27 if (*par) {
2009 // todo why doesn't this allow math?
2010
2/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
42 if (!is_digit(par[0]) || par[1]!=',' ||
2011
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
21 !is_digit(par[2]) || par[3]!=',' ||
2012
3/6
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
21 !is_digit(par[4]) || par[5]!=',' ||
2013
7/12
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 9 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 9 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 12 times.
42 !is_digit(par[6]) || par[7]) throw_err_block(0, err_invalid_mapper);
2014 /*
2015 // this part is just useless ???
2016 int len;
2017 string parbuf = par;
2018 autoptr<char**> pars=qpsplit(parbuf.raw(), ',', &len);
2019 verify_paren(pars);
2020 if (len!=4) throw_err_block(0, err_invalid_mapper); */
2021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[0]=(par[0]-'0')<<20;
2022
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[1]=(par[2]-'0')<<20;
2023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[4]=(par[4]-'0')<<20;
2024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
21 sa1banks[5]=(par[6]-'0')<<20;
2025 }
2026 else
2027 {
2028 6 sa1banks[0]=0<<20;
2029 6 sa1banks[1]=1<<20;
2030 6 sa1banks[4]=2<<20;
2031 6 sa1banks[5]=3<<20;
2032 }
2033 27 mapper=sa1rom;
2034 27 }
2035
2036 using command_fn_t = void(*)(const char*);
2037
2038 template<void (*F)(char**, int)>
2039 2834 void wrap_split(const char* par) {
2040
2/3
✓ Branch 0 taken 707 times.
✓ Branch 1 taken 710 times.
✗ Branch 2 not taken.
2834 string temp(par);
2041 1420 int num_words;
2042
2/3
✓ Branch 0 taken 707 times.
✓ Branch 1 taken 710 times.
✗ Branch 2 not taken.
2834 autoptr<char**> word = qsplit(temp.raw(), ' ', &num_words);
2043
8/8
✓ Branch 0 taken 1005 times.
✓ Branch 1 taken 412 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 444 times.
✓ Branch 4 taken 114 times.
✓ Branch 5 taken 1097 times.
✓ Branch 6 taken 57 times.
✓ Branch 7 taken 653 times.
2834 if(num_words == 1 && word[0][0] == 0) num_words--;
2044 F(word, num_words);
2045 4264 }
2046
2047 }
2048
2049
39/59
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 606 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 165 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 18 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 108 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 112 times.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 112 times.
✓ Branch 17 taken 2 times.
✓ Branch 18 taken 70 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 126 times.
✓ Branch 21 taken 6 times.
✓ Branch 22 taken 48 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 22 times.
✓ Branch 25 taken 44 times.
✓ Branch 26 taken 44 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 45 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 111 times.
✓ Branch 31 taken 198 times.
✓ Branch 32 taken 99 times.
✓ Branch 33 taken 494 times.
✓ Branch 34 taken 98 times.
✓ Branch 35 taken 12 times.
✓ Branch 36 taken 296 times.
✓ Branch 37 taken 8 times.
✓ Branch 38 taken 31 times.
✗ Branch 39 not taken.
✓ Branch 40 taken 35 times.
✓ Branch 41 taken 19 times.
✓ Branch 42 taken 8 times.
✓ Branch 43 taken 420 times.
✓ Branch 44 taken 27 times.
✓ Branch 45 taken 807 times.
✓ Branch 46 taken 2020 times.
✗ Branch 47 not taken.
✓ Branch 48 taken 3183 times.
✓ Branch 49 taken 1544 times.
✓ Branch 50 taken 758 times.
✗ Branch 51 not taken.
✓ Branch 52 taken 2302 times.
✗ Branch 53 not taken.
✗ Branch 54 not taken.
✗ Branch 55 not taken.
✗ Branch 56 not taken.
✗ Branch 57 not taken.
✗ Branch 58 not taken.
9840 static constexpr auto normal_commands = frozen::make_unordered_map<frozen::string, command_fn_t>({
2050 { "db", cmd_write_data<write1> },
2051 { "dw", cmd_write_data<write2> },
2052 { "dl", cmd_write_data<write3> },
2053 { "dd", cmd_write_data<write4> },
2054 { "assert", cmd_assert },
2055 { "undef", cmd_undef },
2056 { "error", cmd_error },
2057 { "warn", cmd_warn },
2058 { "warnings", wrap_split<cmd_warnings> },
2059 { "global", cmd_global },
2060 { "check", wrap_split<cmd_check> },
2061 { "asar", cmd_asar },
2062 { "include", cmd_include },
2063 { "includefrom", cmd_includefrom },
2064 { "includeonce", cmd_includeonce },
2065 { "org", cmd_org },
2066 { "struct", wrap_split<cmd_struct> },
2067 { "endstruct", wrap_split<cmd_endstruct> },
2068 { "spcblock", wrap_split<cmd_spcblock> },
2069 { "endspcblock", wrap_split<cmd_endspcblock> },
2070 { "base", cmd_base },
2071 { "dpbase", cmd_dpbase },
2072 { "optimize", wrap_split<cmd_optimize> },
2073 { "bank", cmd_bank },
2074 { "freespace", cmd_freespace<freespace_cmds::freespace> },
2075 { "freecode", cmd_freespace<freespace_cmds::freecode> },
2076 { "freedata", cmd_freespace<freespace_cmds::freedata> },
2077 { "segment", cmd_freespace<freespace_cmds::segment> },
2078 { "freespace_settings", cmd_freespace_settings },
2079 { "prot", cmd_prot },
2080 { "autoclean", wrap_split<cmd_autoclean> },
2081 { "freespacebyte", cmd_freespacebyte },
2082 { "pushpc", cmd_pushpc },
2083 { "pullpc", cmd_pullpc },
2084 { "pushbase", cmd_pushbase },
2085 { "pullbase", cmd_pullbase },
2086 { "pushns", cmd_pushns },
2087 { "pullns", cmd_pullns },
2088 { "namespace", wrap_split<cmd_namespace> },
2089 { "incsrc", cmd_incsrc },
2090 { "incbin", cmd_incbin },
2091 { "skip", wrap_split<cmd_skip_fill<false>> },
2092 { "fill", wrap_split<cmd_skip_fill<true>> },
2093 { "cleartable", cmd_cleartable },
2094 { "pushtable", cmd_pushtable },
2095 { "pulltable", cmd_pulltable },
2096 { "function", cmd_function },
2097 { "print", cmd_print },
2098 { "reset", cmd_reset },
2099 { "padbyte", cmd_padbytes<1, false> },
2100 { "padword", cmd_padbytes<2, false> },
2101 { "padlong", cmd_padbytes<3, false> },
2102 { "paddword", cmd_padbytes<4, false> },
2103 { "fillbyte", cmd_padbytes<1, true> },
2104 { "fillword", cmd_padbytes<2, true> },
2105 { "filllong", cmd_padbytes<3, true> },
2106 { "filldword", cmd_padbytes<4, true> },
2107 { "pad", cmd_pad },
2108 { "arch", cmd_arch },
2109 { "{", cmd_braces },
2110 { "}", cmd_braces },
2111
2112 { "lorom", wrap_mapper<mapper_simple<lorom>> },
2113 { "hirom", wrap_mapper<mapper_simple<hirom>> },
2114 { "exlorom", wrap_mapper<mapper_simple<exlorom>> },
2115 { "exhirom", wrap_mapper<mapper_simple<exhirom>> },
2116 { "sfxrom", wrap_mapper<mapper_simple<sfxrom>> },
2117 { "norom", wrap_mapper<mapper_norom> },
2118 { "sa1rom", wrap_mapper<mapper_sa1rom> },
2119 { "fullsa1rom", wrap_mapper<mapper_simple<bigsa1rom>> },
2120 });
2121
2122 namespace control_flow {
2123
2124 enum cf_cmds {
2125 c_if,
2126 c_elseif,
2127 c_while,
2128 c_for,
2129 };
2130
2131 // todo possibly this would be cleaner if `for` was refactored out entirely?
2132 template<cf_cmds type>
2133 6264 void cf_start(const char* par, int& single_line_for_tracker) {
2134 6264 const char* typ_name =
2135 type == c_if ? "if" :
2136 type == c_elseif ? "elseif" :
2137 type == c_while ? "while" : "for";
2138 6264 whiletracker wstatus;
2139
1/2
✓ Branch 0 taken 3132 times.
✗ Branch 1 not taken.
6264 wstatus.startline = get_current_line();
2140 6264 wstatus.iswhile = type == c_while;
2141 6264 wstatus.cond = false;
2142 6264 wstatus.is_for = false;
2143 6264 wstatus.for_start = wstatus.for_end = wstatus.for_cur = 0;
2144 6264 wstatus.for_has_var_backup = false;
2145 696 if(type == c_for) wstatus.is_for = true;
2146
2147 6264 bool is_for_cont = false;
2148 // if this is a for loop and a whilestatus entry already exists at this level,
2149 // and the for loop isn't finished, this is a continuation of the for loop
2150 696 if ((type == c_for)
2151
6/7
✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 166 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 174 times.
✓ Branch 5 taken 166 times.
✓ Branch 6 taken 8 times.
696 && whilestatus.count > numif && whilestatus[numif].is_for
2152
11/14
✓ Branch 0 taken 348 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 332 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 166 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 289 times.
✓ Branch 7 taken 43 times.
✓ Branch 8 taken 123 times.
✓ Branch 9 taken 51 times.
✓ Branch 10 taken 123 times.
✓ Branch 11 taken 43 times.
✓ Branch 12 taken 123 times.
✓ Branch 13 taken 51 times.
1392 && whilestatus[numif].for_cur < whilestatus[numif].for_end) {
2153 492 is_for_cont = true;
2154 }
2155
6/9
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 2886 times.
✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2886 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1443 times.
✓ Branch 7 taken 1443 times.
✗ Branch 8 not taken.
6264 whiletracker& addedwstatus = is_for_cont ? whilestatus[numif] : (whilestatus[numif] = wstatus);
2156 //handle nested if statements
2157
4/4
✓ Branch 0 taken 336 times.
✓ Branch 1 taken 2796 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 174 times.
6264 if (numtrue!=numif && !(type == c_elseif && numtrue+1==numif))
2158 {
2159 228 if (type != c_elseif) numif++;
2160 324 return;
2161 }
2162 5376 if (type != c_elseif) numif++;
2163
2164 bool cond;
2165 if(type != c_for)
2166 {
2167
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
✓ Branch 2 taken 1320 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
5280 if(!*par) throw_err_block(0, err_broken_command, typ_name, "Missing condition.");
2168
7/10
✓ Branch 0 taken 1320 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2619 times.
✓ Branch 3 taken 21 times.
✓ Branch 4 taken 1299 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 1299 times.
✓ Branch 7 taken 21 times.
✓ Branch 8 taken 1299 times.
✗ Branch 9 not taken.
5406 cond = parse_math_expr(par)->evaluate_static().get_bool();
2169 }
2170
2171 if (type == c_for)
2172 {
2173
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 165 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
660 if(!*par) throw_err_block(0, err_broken_for_loop, "missing loop range");
2174
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
✓ Branch 2 taken 165 times.
660 if(single_line_for_tracker != 1)
2175 {
2176 numif--;
2177 throw_err_line(0, err_bad_single_line_for);
2178 }
2179
2180
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 246 times.
660 if(!is_for_cont)
2181 {
2182
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
168 const char* past_eq = strchr(par, '=');
2183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
168 if(!past_eq)
2184 throw_err_block(0, err_broken_for_loop, "missing loop range");
2185
2186
2/3
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
168 string varname(par, past_eq - par);
2187 168 past_eq += 1;
2188
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 strip_whitespace(varname);
2189
2/4
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
168 if(!validatedefinename(varname))
2190 throw_err_block(0, err_broken_for_loop, "invalid define name");
2191
2192
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 const char* range_sep = strqpstr(past_eq, "..");
2193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
168 if(!range_sep)
2194 throw_err_block(0, err_broken_for_loop, "invalid loop range");
2195
2196
2/3
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
168 string for_start(past_eq, range_sep - past_eq);
2197
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 strip_whitespace(for_start);
2198
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
168 string for_end(range_sep+2);
2199
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
168 strip_whitespace(for_end);
2200
2201
5/10
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
168 addedwstatus.for_start = parse_math_expr(for_start)->evaluate_static().get_integer();
2202
5/10
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 42 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 42 times.
✗ Branch 9 not taken.
168 addedwstatus.for_end = parse_math_expr(for_end)->evaluate_static().get_integer();
2203
2204
2/4
✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
168 addedwstatus.for_variable = varname;
2205 168 addedwstatus.for_cur = addedwstatus.for_start;
2206 168 }
2207 492 else addedwstatus.for_cur++;
2208
2209 660 addedwstatus.cond = addedwstatus.for_cur < addedwstatus.for_end;
2210 660 single_line_for_tracker = 2;
2211
5/5
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 165 times.
✓ Branch 3 taken 123 times.
✓ Branch 4 taken 42 times.
660 if(addedwstatus.cond)
2212 {
2213 492 numtrue++;
2214
6/8
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 123 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 96 times.
✓ Branch 7 taken 27 times.
492 if(defines.exists(addedwstatus.for_variable))
2215 {
2216 384 addedwstatus.for_has_var_backup = true;
2217
4/7
✓ Branch 0 taken 96 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 96 times.
✓ Branch 3 taken 96 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 96 times.
✗ Branch 6 not taken.
384 addedwstatus.for_var_backup = defines.find(addedwstatus.for_variable);
2218 }
2219
3/7
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 246 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 123 times.
✗ Branch 6 not taken.
492 defines.create(addedwstatus.for_variable) = ftostr(addedwstatus.for_cur);
2220 }
2221 }
2222 else if (type == c_if || type == c_while)
2223 {
2224 if(0);
2225
2/2
✓ Branch 0 taken 1884 times.
✓ Branch 1 taken 432 times.
4632 else if (cond)
2226 {
2227 3768 numtrue++;
2228
1/2
✓ Branch 0 taken 1884 times.
✗ Branch 1 not taken.
3768 elsestatus[numif]=true;
2229 }
2230
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
864 else if (!cond)
2231 {
2232
1/2
✓ Branch 0 taken 432 times.
✗ Branch 1 not taken.
864 elsestatus[numif]=false;
2233 }
2234 4632 addedwstatus.cond = cond;
2235 }
2236 else if (type == c_elseif)
2237 {
2238
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 282 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
564 if (!numif) throw_err_block(1, err_misplaced_elseif);
2239
4/9
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 141 times.
✓ Branch 4 taken 141 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 141 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
564 if (whilestatus[numif - 1].iswhile) throw_err_block(1, err_elseif_in_while);
2240
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 174 times.
564 if (numif==numtrue) numtrue--;
2241
10/11
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 39 times.
✓ Branch 5 taken 15 times.
✓ Branch 6 taken 93 times.
✓ Branch 7 taken 141 times.
✓ Branch 8 taken 15 times.
✓ Branch 9 taken 39 times.
✓ Branch 10 taken 102 times.
564 if (cond && !elsestatus[numif])
2242 {
2243 156 numtrue++;
2244
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
156 elsestatus[numif]=true;
2245 }
2246 }
2247
2/2
✓ Branch 0 taken 2928 times.
✓ Branch 1 taken 162 times.
6264 }
2248
2249 template<cf_cmds type>
2250 5604 void cf_end(const char* par, int& single_line_for_tracker) {
2251
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1401 times.
✓ Branch 2 taken 1401 times.
5604 if(*par) throw_err_block(0, err_broken_command, "end<...>", "");
2252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2802 times.
5604 if (!numif)
2253 throw_err_block(1, err_misplaced_endif);
2254 5604 whiletracker& thisws = whilestatus[numif - 1];
2255
2256
7/9
✓ Branch 0 taken 963 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 2100 times.
✓ Branch 3 taken 963 times.
✓ Branch 4 taken 174 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 963 times.
✓ Branch 7 taken 963 times.
✗ Branch 8 not taken.
5604 if((!thisws.is_for && !thisws.iswhile && type != c_if) ||
2257
5/5
✓ Branch 0 taken 264 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 438 times.
✓ Branch 3 taken 264 times.
✓ Branch 4 taken 174 times.
5604 (thisws.iswhile && type != c_while) ||
2258
3/5
✗ Branch 0 not taken.
✓ Branch 1 taken 1227 times.
✓ Branch 2 taken 1227 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1227 times.
4908 (thisws.is_for && type != c_for))
2259 throw_err_block(1, err_misplaced_endif);
2260
2261
2/2
✓ Branch 0 taken 2088 times.
✓ Branch 1 taken 714 times.
5604 if (numif==numtrue) numtrue--;
2262 5604 numif--;
2263
2264
5/5
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 1227 times.
✓ Branch 2 taken 1401 times.
✓ Branch 3 taken 174 times.
✓ Branch 4 taken 1227 times.
5604 if(thisws.is_for)
2265 {
2266
3/3
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 144 times.
696 if(single_line_for_tracker == 2) single_line_for_tracker = 3;
2267
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 348 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 174 times.
696 if(moreonline)
2268 {
2269 // sabotage the whilestatus to prevent the loop running again
2270 // and spamming more of the same error
2271 thisws.for_cur = thisws.for_end;
2272 thisws.cond = false;
2273 throw_err_block(0, err_bad_single_line_for);
2274 }
2275
2276
5/5
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 123 times.
✓ Branch 4 taken 51 times.
696 if(thisws.cond)
2277 {
2278
5/5
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 123 times.
✓ Branch 3 taken 96 times.
✓ Branch 4 taken 27 times.
492 if(thisws.for_has_var_backup)
2279 384 defines.create(thisws.for_variable) = thisws.for_var_backup;
2280 else
2281 108 defines.remove(thisws.for_variable);
2282 }
2283 }
2284 5604 }
2285
2286 234 void cf_else(const char* par, int& single_line_for_tracker) {
2287
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
✓ Branch 2 taken 117 times.
234 if(*par) throw_err_block(0, err_broken_command, "else", "");
2288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (!numif) throw_err_block(1, err_misplaced_else);
2289
7/13
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✓ Branch 3 taken 234 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 117 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 117 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 117 times.
234 if (whilestatus[numif - 1].iswhile || whilestatus[numif - 1].is_for) throw_err_block(1, err_else_in_while_loop);
2290
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 162 times.
234 else if (numif==numtrue) numtrue--;
2291
9/9
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 45 times.
✓ Branch 4 taken 105 times.
✓ Branch 5 taken 81 times.
✓ Branch 6 taken 45 times.
✓ Branch 7 taken 30 times.
✓ Branch 8 taken 51 times.
162 else if (numif==numtrue+1 && !elsestatus[numif])
2292 {
2293 60 numtrue++;
2294 60 elsestatus[numif]=true;
2295 }
2296 234 }
2297
2298 }
2299
2300 static constexpr auto control_flow_commands = frozen::make_unordered_map<frozen::string, void(*)(const char*, int&)>({
2301 { "if", control_flow::cf_start<control_flow::c_if> },
2302 { "elseif", control_flow::cf_start<control_flow::c_elseif> },
2303 { "while", control_flow::cf_start<control_flow::c_while> },
2304 { "for", control_flow::cf_start<control_flow::c_for> },
2305 { "endif", control_flow::cf_end<control_flow::c_if> },
2306 { "endwhile", control_flow::cf_end<control_flow::c_while> },
2307 { "endfor", control_flow::cf_end<control_flow::c_for> },
2308 { "else", control_flow::cf_else },
2309 });
2310
2311 549 static void cmd_label_assign(const char* firstword, const char* params) {
2312
4/6
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 273 times.
✓ Branch 2 taken 276 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✗ Branch 5 not taken.
549 if (firstword[0] == '\'' && firstword[1]) {
2313 201 int codepoint;
2314 402 const char* char_start = firstword + 1;
2315
1/2
✓ Branch 0 taken 402 times.
✗ Branch 1 not taken.
402 const char* after = char_start + utf8_val(&codepoint, char_start);
2316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 402 times.
402 if (codepoint == -1)
2317 throw_err_block(0, err_invalid_utf8);
2318
4/6
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 201 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 201 times.
✗ Branch 5 not taken.
402 if (after[0] == '\'' && after[1] == '\0') {
2319
8/14
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 198 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 396 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 198 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 198 times.
✗ Branch 13 not taken.
405 thetable.set_val(codepoint, parse_math_expr(params + 2)->evaluate_static().get_integer());
2320 396 return;
2321 } else {
2322 throw_err_block(0, err_invalid_character);
2323 }
2324 }
2325 147 const char* newlabelname = firstword;
2326 147 bool ismacro = false;
2327
2328
3/3
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 72 times.
✓ Branch 2 taken 72 times.
147 if (newlabelname[0] == '?') {
2329 6 ismacro = true;
2330 6 newlabelname++;
2331 }
2332
2333
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 141 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
147 if (ismacro && macrorecursion == 0) {
2334 throw_err_block(0, err_macro_label_outside_of_macro);
2335 }
2336
2337
3/4
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 72 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 75 times.
147 if (!confirmname(newlabelname))
2338 throw_err_block(0, err_invalid_label_name);
2339
2340 147 string completename;
2341
2342
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 141 times.
147 if (ismacro) {
2343
9/17
✓ 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 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 3 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 3 times.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 13 taken 3 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✗ Branch 16 not taken.
6 completename += STR ":macro_" + dec(calledmacros) + "_";
2344 }
2345
2346
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
147 completename += newlabelname;
2347
2348
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
147 auto expr = parse_math_expr(params + 2);
2349
4/7
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 75 times.
✗ Branch 6 not taken.
147 int64_t num = expr->evaluate_non_forward().get_integer();
2350
2/4
✓ Branch 0 taken 72 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 75 times.
✗ Branch 3 not taken.
147 bool is_static = expr->has_label() <= 1;
2351
2352
1/9
✗ Branch 0 not taken.
✓ Branch 1 taken 147 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.
147 if (num&~0xFFFFFF) throw_err_block(1, err_snes_address_out_of_bounds, hex(num, 6).data());
2353
2354
4/6
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 72 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 75 times.
✗ Branch 5 not taken.
147 setlabel(ns + completename, num, is_static);
2355 147 }
2356
2357 // single_line_for_tracker is:
2358 // 0 if not in first block of line, not in (single-line) for loop
2359 // 1 if first block of line
2360 // 2 if in single-line for loop
2361 // 3 if after endfor (of a single-line loop)
2362 59002 void assembleblock(const char *block, int &single_line_for_tracker) {
2363 // don't do this here; assembleline already did it for us
2364 // callstack_push cs_push(callstack_entry_type::BLOCK, block);
2365
3/3
✓ Branch 0 taken 9067 times.
✓ Branch 1 taken 29399 times.
✓ Branch 2 taken 20536 times.
59002 if (!*block) return;
2366
2367 // assumption: if the first word of a line contains quotes/spaces, it's going
2368 // to be invalid anyways. well, except for character assignment......
2369 40814 string firstword;
2370 40814 const char *params = block;
2371
1/2
✓ Branch 0 taken 40814 times.
✗ Branch 1 not taken.
40814 grab_until_space(firstword, params);
2372
2373 // when writing out the data for the addrToLine mapping,
2374 // we want to write out the snespos we had before writing opcodes
2375 40814 int addrToLinePos = realsnespos & 0xFFFFFF;
2376
2377
2/3
✓ Branch 0 taken 20278 times.
✓ Branch 1 taken 20536 times.
✗ Branch 2 not taken.
40814 string firstword_lower = firstword;
2378 40814 lower(firstword_lower);
2379
2380
5/7
✓ Branch 0 taken 20278 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23620 times.
✓ Branch 3 taken 17194 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3084 times.
✓ Branch 6 taken 17452 times.
40814 if (auto it = control_flow_commands.find(frozen::string(firstword_lower.data(), firstword_lower.length())); it != control_flow_commands.end()) {
2381
4/4
✓ Branch 0 taken 3063 times.
✓ Branch 1 taken 21 times.
✓ Branch 2 taken 3063 times.
✓ Branch 3 taken 21 times.
6168 return it->second(params, single_line_for_tracker);
2382
2/2
✓ Branch 0 taken 1770 times.
✓ Branch 1 taken 32876 times.
34646 } else if (numif != numtrue) {
2383 1770 return;
2384 }
2385
2386 32876 bool addlabeled = false;
2387 // while first word is non-empty,
2388 // and rest {is empty or doesn't start with " = "},
2389 // try to run addlabel
2390 33158 while (firstword[0]
2391
8/8
✓ Branch 0 taken 14617 times.
✓ Branch 1 taken 16663 times.
✓ Branch 2 taken 15385 times.
✓ Branch 3 taken 1110 times.
✓ Branch 4 taken 26930 times.
✓ Branch 5 taken 1410 times.
✓ Branch 6 taken 13420 times.
✓ Branch 7 taken 276 times.
33158 && !(params[0] && params[1] && stribegin(params, "= "))
2392
7/8
✓ Branch 0 taken 33158 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32563 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 1073 times.
✓ Branch 5 taken 31490 times.
✓ Branch 6 taken 1073 times.
✓ Branch 7 taken 32039 times.
66316 && addlabel(firstword)) {
2393 // addlabel was ok, move to the next word
2394 1073 addlabeled = true;
2395 // if there's no next word, we're done here
2396
3/3
✓ Branch 0 taken 388 times.
✓ Branch 1 taken 541 times.
✓ Branch 2 taken 144 times.
1073 if (!*params) return;
2397 // otherwise pull next word into firstword
2398
1/2
✓ Branch 0 taken 282 times.
✗ Branch 1 not taken.
282 grab_until_space(firstword, params);
2399 }
2400
2401
1/2
✓ Branch 0 taken 32039 times.
✗ Branch 1 not taken.
32039 firstword_lower = firstword;
2402 32039 lower(firstword_lower);
2403
2404 // recheck for any of the conditionals tested above
2405
10/15
✓ Branch 0 taken 282 times.
✓ Branch 1 taken 31757 times.
✓ Branch 2 taken 138 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 144 times.
✓ Branch 5 taken 138 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 15898 times.
✓ Branch 8 taken 144 times.
✓ Branch 9 taken 144 times.
✓ Branch 10 taken 15997 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 16141 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
32039 if (addlabeled && control_flow_commands.find(frozen::string(firstword_lower.data(), firstword_lower.length())) != control_flow_commands.end()) {
2406 throw_err_block(0, err_label_before_if, firstword.data());
2407 }
2408
2409
4/4
✓ Branch 0 taken 32019 times.
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 10171 times.
✓ Branch 3 taken 21848 times.
32039 if (asblock_pick(firstword_lower, params)) {
2410
1/2
✓ Branch 0 taken 10171 times.
✗ Branch 1 not taken.
10171 add_addr_to_line(addrToLinePos);
2411 10171 return;
2412 }
2413
2414
3/3
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 10810 times.
✓ Branch 2 taken 10777 times.
21848 if (firstword[0] == '%') {
2415 // imo using strchr here is jank, but it works i guess
2416 // (labels can't contain %)
2417
4/5
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 267 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 255 times.
✓ Branch 4 taken 6 times.
522 return callmacro(strchr(block, '%') + 1);
2418 }
2419
2420
5/7
✓ Branch 0 taken 10549 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21047 times.
✓ Branch 3 taken 279 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 10492 times.
✓ Branch 6 taken 285 times.
21326 if (auto it = normal_commands.find(frozen::string(firstword_lower.data(), firstword_lower.length())); it != normal_commands.end()) {
2421
4/4
✓ Branch 0 taken 5187 times.
✓ Branch 1 taken 5083 times.
✓ Branch 2 taken 5406 times.
✓ Branch 3 taken 5086 times.
20762 return it->second(params);
2422 }
2423
2424
4/4
✓ Branch 0 taken 549 times.
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 543 times.
✓ Branch 3 taken 6 times.
564 if (stribegin(params, "= ")) return cmd_label_assign(firstword, params);
2425
2426
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 throw_err_block(1, err_unknown_command);
2427 51124 }
2428