asar coverage - build #76


src/asar/
File: src/asar/macro.cpp
Date: 2024-01-18 11:25:05
Lines:
158/176
89.8%
Functions:
5/5
100.0%
Branches:
159/282
56.4%

Line Branch Exec Source
1 #include "libstr.h"
2 #include "asar.h"
3 #include "autoarray.h"
4 #include "assocarr.h"
5 #include "errors.h"
6 #include "assembleblock.h"
7 #include "macro.h"
8 #include "asar_math.h"
9 #include "warnings.h"
10
11 assocarr<macrodata*> macros;
12 static string thisname;
13 static macrodata * thisone;
14 static int numlines;
15
16 int calledmacros;
17 int reallycalledmacros;
18 int macrorecursion;
19 bool inmacro;
20 int numvarargs;
21
22 macrodata* current_macro;
23 const char* const* current_macro_args;
24 int current_macro_numargs;
25
26 26 void startmacro(const char * line_)
27 {
28 26 thisone= nullptr;
29
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (!confirmqpar(line_)) asar_throw_error(0, error_type_block, error_id_broken_macro_declaration);
30 26 string line=line_;
31
5/10
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 26 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 26 times.
✗ Branch 9 not taken.
26 clean_and_trim(line);
32 26 char * startpar=strqchr(line.data(), '(');
33
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26 if (!startpar) asar_throw_error(0, error_type_block, error_id_broken_macro_declaration);
34 26 *startpar=0;
35
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 startpar++;
36
2/6
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
26 if (!confirmname(line)) asar_throw_error(0, error_type_block, error_id_invalid_macro_name);
37 thisname=line;
38 26 char * endpar=strqrchr(startpar, ')');
39 //confirmqpar requires that all parentheses are matched, and a starting one exists, therefore it is harmless to not check for nullptrs
40
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26 if (endpar[1]) asar_throw_error(0, error_type_block, error_id_broken_macro_declaration);
41 26 *endpar=0;
42
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 26 times.
136 for (int i=0;startpar[i];i++)
43 {
44 char c=startpar[i];
45
5/8
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 36 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
110 if (!is_alnum(c) && c!='_' && c!=','&& c!='.') asar_throw_error(0, error_type_block, error_id_broken_macro_declaration);
46
3/6
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
110 if (c==',' && is_digit(startpar[i+1])) asar_throw_error(0, error_type_block, error_id_broken_macro_declaration);
47 }
48
4/10
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 26 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 26 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
26 if (*startpar==',' || is_digit(*startpar) || strstr(startpar, ",,") || endpar[-1]==',') asar_throw_error(0, error_type_block, error_id_broken_macro_declaration);
49
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
26 if (macros.exists(thisname)) asar_throw_error(0, error_type_block, error_id_macro_redefined, thisname.data());
50 26 thisone=(macrodata*)malloc(sizeof(macrodata));
51 new(thisone) macrodata;
52
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 10 times.
26 if (*startpar)
53 {
54
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 thisone->arguments=(const char* const*)qpsplit(duplicate_string(startpar), ",", &thisone->numargs);
55 }
56 else
57 {
58 10 const char ** noargs=(const char**)malloc(sizeof(const char**));
59 10 *noargs=nullptr;
60 10 thisone->arguments=noargs;
61 10 thisone->numargs=0;
62 }
63 26 thisone->variadic = false;
64 26 thisone->fname= duplicate_string(thisfilename);
65 26 thisone->startline=thisline;
66
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 25 times.
48 for (int i=0;thisone->arguments[i];i++)
67 {
68
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 1 times.
23 if(!strcmp(thisone->arguments[i], "...") && !thisone->arguments[i+1]) thisone->variadic = true;
69
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
12 else if(!strcmp(thisone->arguments[i], "...")) asar_throw_error(0, error_type_block, error_id_vararg_must_be_last);
70
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
11 else if(strchr(thisone->arguments[i], '.')) asar_throw_error(0, error_type_block, error_id_invalid_macro_param_name);
71
2/6
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
11 else if (!confirmname(thisone->arguments[i])) asar_throw_error(0, error_type_block, error_id_invalid_macro_param_name);
72
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 22 times.
29 for (int j=i+1;thisone->arguments[j];j++)
73 {
74
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
7 if (!strcmp(thisone->arguments[i], thisone->arguments[j])) asar_throw_error(0, error_type_block, error_id_macro_param_redefined, thisone->arguments[i]);
75 }
76 }
77 25 numlines=0;
78 26 }
79
80 64 void tomacro(const char * line)
81 {
82
1/2
✓ Branch 0 taken 64 times.
✗ Branch 1 not taken.
64 if (!thisone) return;
83 64 thisone->lines[numlines++]=line;
84 }
85
86 26 void endmacro(bool insert)
87 {
88
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (!thisone) return;
89 26 thisone->numlines=numlines;
90
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (insert) macros.create(thisname) = thisone;
91 else delete thisone;
92 }
93
94
95 108 void callmacro(const char * data)
96 {
97 108 int prev_numvarargs = numvarargs;
98 macrodata * thismacro;
99
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (!confirmqpar(data)) asar_throw_error(0, error_type_block, error_id_broken_macro_usage);
100 108 string line=data;
101
5/10
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 108 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 108 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 108 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 108 times.
✗ Branch 9 not taken.
108 clean_and_trim(line);
102 108 char * startpar=strqchr(line.data(), '(');
103
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
108 if (!startpar) asar_throw_error(0, error_type_block, error_id_broken_macro_usage);
104 108 *startpar=0;
105
1/2
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
108 startpar++;
106
2/6
✓ Branch 0 taken 108 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 108 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
108 if (!confirmname(line)) asar_throw_error(0, error_type_block, error_id_broken_macro_usage);
107
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
108 if (!macros.exists(line)) asar_throw_error(0, error_type_block, error_id_macro_not_found, line.data());
108 108 thismacro = macros.find(line);
109 108 char * endpar=strqrchr(startpar, ')');
110
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
108 if (endpar[1]) asar_throw_error(0, error_type_block, error_id_broken_macro_usage);
111
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 39 times.
108 *endpar=0;
112 autoptr<const char * const*> args;
113 108 int numargs=0;
114
3/4
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
108 if (*startpar) args=(const char* const*)qpsplit(startpar, ",", &numargs);
115
3/6
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
108 if (numargs != thismacro->numargs && !thismacro->variadic) asar_throw_error(1, error_type_block, error_id_macro_wrong_num_params);
116 // RPG Hacker: -1, because the ... is also counted as an argument, yet we want it to be entirely optional.
117
4/6
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 102 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
108 if (numargs < thismacro->numargs - 1 && thismacro->variadic) asar_throw_error(1, error_type_block, error_id_macro_wrong_min_params);
118
119 102 macrorecursion++;
120 102 inmacro=true;
121 102 int old_calledmacros = calledmacros;
122 102 calledmacros = reallycalledmacros++;
123 102 int startif=numif;
124
125 // RPG Hacker: -1 to take the ... into account, which is also being counted.
126
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 63 times.
102 if(thismacro->variadic) numvarargs = numargs-(thismacro->numargs-1);
127 63 else numvarargs = -1;
128
129 102 autoarray<int>* oldmacroposlabels = macroposlabels;
130 102 autoarray<int>* oldmacroneglabels = macroneglabels;
131 102 autoarray<string>* oldmacrosublabels = macrosublabels;
132
133 102 autoarray<int> newmacroposlabels;
134 102 autoarray<int> newmacroneglabels;
135 102 autoarray<string> newmacrosublabels;
136
137 102 macroposlabels = &newmacroposlabels;
138 102 macroneglabels = &newmacroneglabels;
139 102 macrosublabels = &newmacrosublabels;
140
141 102 macrodata* old_macro = current_macro;
142 102 const char* const* old_macro_args = current_macro_args;
143 102 int old_numargs = current_macro_numargs;
144 102 current_macro = thismacro;
145 102 current_macro_args = args;
146 102 current_macro_numargs = numargs;
147
148
2/2
✓ Branch 0 taken 516 times.
✓ Branch 1 taken 102 times.
618 for (int i=0;i<thismacro->numlines;i++)
149 {
150 try
151 {
152 516 thisfilename= thismacro->fname;
153 516 thisline= thismacro->startline+i+1;
154 516 thisblock= nullptr;
155 516 string connectedline;
156 516 int skiplines = getconnectedlines<autoarray<string> >(thismacro->lines, i, connectedline);
157 //string out = replace_macro_args(connectedline); // done in assembleline
158
1/2
✓ Branch 0 taken 516 times.
✗ Branch 1 not taken.
516 int prevnumif = numif;
159
1/2
✓ Branch 0 taken 516 times.
✗ Branch 1 not taken.
516 assembleline(thismacro->fname, thismacro->startline+i, connectedline);
160 516 i += skiplines;
161
8/10
✓ Branch 0 taken 348 times.
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 348 times.
✓ Branch 4 taken 54 times.
✓ Branch 5 taken 114 times.
✓ Branch 6 taken 54 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 66 times.
684 if ((numif != prevnumif || single_line_for_tracker == 3) && (whilestatus[numif].iswhile || whilestatus[numif].is_for) && whilestatus[numif].cond)
162 66 i = whilestatus[numif].startline - thismacro->startline - 1;
163 516 }
164 catch(errline&){}
165 }
166
167 102 current_macro = old_macro;
168 102 current_macro_args = old_macro_args;
169 102 current_macro_numargs = old_numargs;
170
171 102 macroposlabels = oldmacroposlabels;
172 102 macroneglabels = oldmacroneglabels;
173 102 macrosublabels = oldmacrosublabels;
174
175 102 macrorecursion--;
176 102 inmacro = macrorecursion;
177 102 numvarargs = prev_numvarargs;
178 102 calledmacros = old_calledmacros;
179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (repeatnext!=1)
180 {
181 thisblock= nullptr;
182 repeatnext=1;
183 asar_throw_error(0, error_type_block, error_id_rep_at_macro_end);
184 }
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
102 if (numif!=startif)
186 {
187 thisblock= nullptr;
188 numif=startif;
189 numtrue=startif;
190 asar_throw_error(0, error_type_block, error_id_unclosed_if);
191 }
192 114 }
193
194 516 string replace_macro_args(const char* line) {
195 516 string out;
196
2/2
✓ Branch 0 taken 6195 times.
✓ Branch 1 taken 495 times.
6690 for (const char * in=line;*in;)
197 {
198
3/6
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 6012 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 183 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
6195 if (*in=='<' && in[1]=='<' && in[2] != ':')
199 {
200 out+="<<";
201 in+=2;
202 }
203
2/2
✓ Branch 0 taken 183 times.
✓ Branch 1 taken 6012 times.
6195 else if (*in=='<')
204 {
205 183 const char * end=in+1;
206 // RPG Hacker: Added checking for space here, because this code would consider
207 // if a < b && a > c
208 // a macro arg expansion. In practice, this is still a sloppy solution and is
209 // likely to fail in some edge case I can't think of right now. Should parse
210 // this in a much more robust way at some point...
211
2/2
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 141 times.
183 if (*end==' ')
212 {
213 42 out += *(in++);
214 42 continue;
215 }
216
217
5/8
✓ Branch 0 taken 1104 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 963 times.
✓ Branch 3 taken 141 times.
✓ Branch 4 taken 963 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 963 times.
✗ Branch 7 not taken.
1104 while (*end && *end!='>'&& *end!='<' && *(end+1)!=':') end++; //allow for conditionals and <:
218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
141 if (*end!='>')
219 {
220 out+=*(in++);
221 continue;
222 }
223
224 bool proper_variadic = false;
225
5/8
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 63 times.
✓ Branch 2 taken 78 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 78 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 78 times.
✗ Branch 7 not taken.
141 if (in[1] == '.' && in[2] == '.' && in[3] == '.' && in[4] == '[')
226 {
227
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 75 times.
78 if (end[-1] != ']')
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 asar_throw_error(0, error_type_block, error_id_unclosed_vararg);
229
230 proper_variadic = true;
231 75 in += 4;
232 75 end--;
233 }
234
235
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
138 if(!inmacro) asar_throw_error(0, error_type_block, error_id_macro_param_outside_macro);
236 //*end=0;
237 138 in++;
238 138 string param;
239 138 string temp(in, end-in);
240
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 resolvedefines(param, temp);
241 in = param.data();
242
1/2
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
138 bool valid_named_param = confirmname(in);
243
5/6
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 75 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
138 if (!valid_named_param && !current_macro->variadic) asar_throw_error(0, error_type_block, error_id_invalid_macro_param_name);
244 bool found=false;
245
4/4
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 78 times.
✓ Branch 3 taken 75 times.
162 for (int j=0;current_macro->arguments[j]&&!proper_variadic;j++)
246 {
247
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 27 times.
78 if (!strcmp(in, current_macro->arguments[j]))
248 {
249 found=true;
250
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 15 times.
51 if (current_macro_args[j][0]=='"')
251 {
252 36 string s=current_macro_args[j];
253
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 out+=safedequote(s.temp_raw());
254 36 }
255 15 else out+=current_macro_args[j];
256 break;
257 }
258 }
259 if (!found)
260 {
261 snes_label ret;
262
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 6 times.
84 if(valid_named_param && !current_macro->variadic)
263 {
264
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (proper_variadic) asar_throw_error(0, error_type_block, error_id_invalid_vararg, in);
265 else asar_throw_error(0, error_type_block, error_id_macro_param_not_found, in);
266 }
267
8/10
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 3 times.
✓ Branch 8 taken 3 times.
✓ Branch 9 taken 78 times.
84 if(current_macro->variadic && valid_named_param && !labelval(in, &ret, false))
268 {
269
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
3 if (proper_variadic) asar_throw_error(0, error_type_block, error_id_invalid_vararg, in);
270 else asar_throw_error(0, error_type_block, error_id_macro_param_not_found, in);
271 }
272
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
78 if(!proper_variadic) asar_throw_warning(0, warning_id_feature_deprecated, "'<math>' syntax for variadic macro parameters", "Use '<...[math]>' instead.");
273
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 int arg_num = getnum(in);
274
275
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
78 if(forwardlabel) asar_throw_error(0, error_type_block, error_id_label_forward);
276
277
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 9 times.
78 if(numif<=numtrue){
278
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 66 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
69 if (arg_num < 0) asar_throw_error(1, error_type_block, error_id_vararg_out_of_bounds);
279
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
66 if (arg_num > current_macro_numargs-current_macro->numargs) asar_throw_error(1, error_type_block, error_id_vararg_out_of_bounds);
280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
60 if (current_macro_args[arg_num+current_macro->numargs-1][0]=='"')
281 {
282 string s=current_macro_args[arg_num+current_macro->numargs-1];
283 out+=safedequote(s.temp_raw());
284 }
285 60 else out+=current_macro_args[arg_num+current_macro->numargs-1];
286 }
287 }
288 120 in=end+1;
289
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 60 times.
120 if (proper_variadic) in++;
290 156 }
291 6012 else out+=*(in++);
292 }
293 495 return out;
294 21 }
295