Gwion coverage report


Directory: src/
File: src/import/import_checker.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 174 247 70.4%
Functions: 24 26 92.3%
Branches: 83 158 52.5%

Line Branch Exec Source
1 /** @file: checker.c *
2 * \brief: functions to check names in import module *
3 * */
4 #include <ctype.h>
5 #include "gwion_util.h"
6 #include "gwion_ast.h"
7 #include "gwion_env.h"
8 #include "vm.h"
9 #include "traverse.h"
10 #include "instr.h"
11 #include "emit.h"
12 #include "gwion.h"
13 #include "object.h"
14 #include "operator.h"
15 #include "import.h"
16 #include "gwi.h"
17
18 struct td_checker {
19 m_str str;
20 const loc_t pos;
21 };
22
23 struct AC {
24 m_str str;
25 Exp base;
26 Exp exp;
27 loc_t pos;
28 m_uint depth;
29 };
30
31 ANN static m_bool ac_run(const Gwion gwion, struct AC *const ac);
32 17246 ANN static Array_Sub mk_array(MemPool mp, struct AC *ac) {
33 17246 const Array_Sub array = new_array_sub(mp, ac->base);
34 17246 array->depth = ac->depth;
35 17246 array->exp = ac->base;
36 17246 return array;
37 }
38
39 652118 __attribute__((returns_nonnull)) ANN static Symbol gwisym(const Gwion gwion,
40 const m_str str) {
41 652118 return insert_symbol(gwion->st, str);
42 }
43
44 652120 ANN static Symbol __str2sym(const Gwion gwion, struct td_checker *tdc) {
45 652120 char buf[strlen(tdc->str) + 1];
46 652120 m_str tmp = buf;
47
2/2
✓ Branch 0 taken 18511 times.
✓ Branch 1 taken 633609 times.
652120 if (*tdc->str == '@') *tmp++ = *tdc->str++;
48
2/2
✓ Branch 0 taken 2769250 times.
✓ Branch 1 taken 611199 times.
3380449 while (*tdc->str) {
49 2769250 const char c = *tdc->str;
50
4/4
✓ Branch 0 taken 57520 times.
✓ Branch 1 taken 2711730 times.
✓ Branch 2 taken 40921 times.
✓ Branch 3 taken 16599 times.
2769250 if (!isalnum(c) && c != '_') break;
51 2728329 *tmp++ = *tdc->str++;
52 }
53
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 652118 times.
652120 if (tmp == buf) GWION_ERR_O(tdc->pos, "empty symbol");
54 652118 *tmp = '\0';
55 652118 return gwisym(gwion, buf);
56 }
57
58 89999 ANN static inline Symbol _str2sym(const Gwion gwion, struct td_checker *tdc,
59 const m_str path) {
60 89999 const Symbol sym = __str2sym(gwion, tdc);
61
4/4
✓ Branch 0 taken 8308 times.
✓ Branch 1 taken 81691 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 8304 times.
89999 if (*tdc->str && *tdc->str != ':')
62 4 GWION_ERR_O(tdc->pos, _("illegal character '%c' in path '%s'."), *tdc->str,
63 path)
64 89995 return sym;
65 }
66
67 /** convert a string to a symbol, with error checking **/
68 14045 ANN Symbol str2sym(const Gwion gwion, const m_str path, const loc_t pos) {
69 14045 struct td_checker tdc = {.str = path, .pos = pos};
70 14045 return _str2sym(gwion, &tdc, path);
71 }
72
73 51706 ANN m_bool str2var(const Gwion gwion, Var_Decl *vd, const m_str path, const loc_t pos) {
74 51706 struct td_checker tdc = {.str = path, .pos = pos};
75
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 51706 times.
51706 DECL_OB(const Symbol, sym, = __str2sym(gwion, &tdc));
76 51706 struct AC ac = {.str = tdc.str, .pos = pos};
77
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 51706 times.
51706 CHECK_BB(ac_run(gwion, &ac));
78 51706 vd->xid = sym;
79 51706 vd->value = NULL;
80 51706 vd->pos = pos;
81 51706 return GW_OK;
82 }
83
84 #define SPEC_ERROR (Specialized_List) GW_ERROR
85 8941 ANN static bool _tmpl_list(const Gwion gwion,
86 struct td_checker *tdc, Specialized_List *sl) {
87
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8941 times.
8941 if(unlikely(!strncmp(tdc->str, "...", 3))) {
88 tdc->str += 3;
89 Specialized spec = {
90 .xid = insert_symbol(gwion->st, "..."),
91 .pos = tdc->pos
92 };
93 mp_vector_add(gwion->mp, sl, Specialized, spec);
94 return true;
95 }
96
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8941 times.
8941 DECL_OO(const Symbol, sym, = __str2sym(gwion, tdc));
97 // TODO: handle traits?
98 8941 Specialized spec = {
99 .xid = sym,
100 .pos = tdc->pos
101 };
102
1/2
✓ Branch 0 taken 8941 times.
✗ Branch 1 not taken.
8941 mp_vector_add(gwion->mp, sl, Specialized, spec);
103
2/2
✓ Branch 0 taken 639 times.
✓ Branch 1 taken 8302 times.
8941 if (*tdc->str == ',') {
104 639 ++tdc->str;
105
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 639 times.
639 if (!_tmpl_list(gwion, tdc, sl))
106 return false;
107 }
108 8941 return true;
109 }
110
111 75952 ANN static Specialized_List __tmpl_list(const Gwion gwion,
112 struct td_checker *tdc) {
113
2/2
✓ Branch 0 taken 67650 times.
✓ Branch 1 taken 8302 times.
75952 if (tdc->str[0] != ':') return NULL;
114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8302 times.
8302 if (tdc->str[1] != '[') return SPEC_ERROR;
115 8302 tdc->str += 2;
116 8302 Specialized_List sl = new_mp_vector(gwion->mp, Specialized, 0);
117
2/4
✓ Branch 1 taken 8302 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 8302 times.
8302 if(!_tmpl_list(gwion, tdc, &sl) || tdc->str[0] != ']') {
118 free_specialized_list(gwion->mp, sl);
119 }
120 8302 ++tdc->str;
121 8302 return sl;
122 }
123
124 75954 ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) {
125 75954 struct td_checker tdc = {.str = ck->name, .pos = gwi->loc};
126
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 75952 times.
75954 if (!(ck->sym = _str2sym(gwi->gwion, &tdc, tdc.str))) return GW_ERROR;
127 75952 Specialized_List sl = __tmpl_list(gwi->gwion, &tdc);
128
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75952 times.
75952 if (sl == SPEC_ERROR) return GW_ERROR;
129 75952 ck->sl = sl;
130 75952 ck->name = s_name(ck->sym);
131 75952 return GW_OK;
132 }
133
134 ANN static Type_Decl *_str2td(const Gwion gwion, struct td_checker *tdc);
135 3212 ANN bool str2tl(const Gwion gwion, struct td_checker *tdc, Type_List *tl) {
136 3212 Type_Decl *td = _str2td(gwion, tdc);
137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3212 times.
3212 if (!td) GWION_ERR_B(tdc->pos, "invalid types");
138
1/2
✓ Branch 0 taken 3212 times.
✗ Branch 1 not taken.
3212 mp_vector_add(gwion->mp, tl, Type_Decl*, td);
139
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3208 times.
3212 if (*tdc->str == ',') {
140 4 ++tdc->str;
141
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (!str2tl(gwion, tdc, tl))
142 return false;
143 }
144 3212 return true;
145 }
146
147 501474 ANN static Type_List td_tmpl(const Gwion gwion, struct td_checker *tdc) {
148
2/2
✓ Branch 0 taken 498266 times.
✓ Branch 1 taken 3208 times.
501474 if (*tdc->str != ':') return NULL; // GW_PASS
149 3208 ++tdc->str;
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3208 times.
3208 if (*tdc->str != '[') {
151 GWION_ERR(tdc->pos, "invalid character");
152 return (Type_List)GW_ERROR;
153 }
154 3208 ++tdc->str;
155 3208 Type_List tl = new_mp_vector(gwion->mp, Type_Decl*, 0);
156
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3208 times.
3208 if (!str2tl(gwion, tdc, &tl)) {
157 free_type_list(gwion->mp, tl);
158 return (Type_List)GW_ERROR;
159 }
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3208 times.
3208 if (tdc->str[0] != ']') {
161 free_type_list(gwion->mp, tl);
162 GWION_ERR(tdc->pos, "unfinished template");
163 return (Type_List)GW_ERROR;
164 }
165 3208 ++tdc->str;
166 3208 return tl;
167 }
168
169 1002948 ANN static inline uint get_n(struct td_checker *tdc, const char c) {
170 1002948 uint n = 0;
171
2/2
✓ Branch 0 taken 638 times.
✓ Branch 1 taken 1002948 times.
1003586 while (*tdc->str == c) {
172 638 n++;
173 638 ++tdc->str;
174 }
175 1002948 return n;
176 }
177
178 ANN static Arg_List fptr_args(const Gwion gwion, struct td_checker *tdc) {
179 if(tdc->str[1] == ')')
180 return NULL;
181 Arg_List args = new_mp_vector(gwion->mp, Arg, 0);
182 do {
183 Type_Decl *td = _str2td(gwion, tdc);
184 if(!td) {
185 free_arg_list(gwion->mp, args);
186 return (Arg_List)GW_ERROR;
187 }
188 mp_vector_add(gwion->mp, &args, Arg, (Arg){ .td = td });
189 } while(*tdc->str == ',' && tdc->str++);
190 return args;
191 }
192
193 ANN static Type_Decl *str2td_fptr(const Gwion gwion, struct td_checker *tdc) {
194 const m_str base = tdc->str;
195 tdc->str++;
196 Type_Decl *const ret_td = _str2td(gwion, tdc);
197 const Type_List tl = td_tmpl(gwion, tdc);
198 if (tl == (Type_List)GW_ERROR) {
199 free_type_decl(gwion->mp, ret_td);
200 return NULL;
201 }
202 const uint option = get_n(tdc, '?');
203 tdc->str++;
204 Arg_List args = fptr_args(gwion, tdc);
205 if (args == (Arg_List)GW_ERROR) {
206 if(tl) free_type_list(gwion->mp, tl);
207 free_type_decl(gwion->mp, ret_td);
208 return NULL;
209 }
210 if(tdc->str[0] != ')' || tdc->str[1] != ')') {
211 if(tl) free_type_list(gwion->mp, tl);
212 if(args) free_arg_list(gwion->mp, args);
213 return NULL;
214 }
215 tdc->str += 2;
216 struct AC ac = {.str = tdc->str, .pos = tdc->pos};
217 if(ac_run(gwion, &ac) < 0 ) {
218 if(tl) free_type_list(gwion->mp, tl);
219 if(args) free_arg_list(gwion->mp, args);
220 return NULL;
221 }
222 Func_Base *fbase = new_func_base(gwion->mp, ret_td, insert_symbol(gwion->st, base), args, ae_flag_none, tdc->pos);
223 const Fptr_Def fptr = new_fptr_def(gwion->mp, fbase);
224 Type_Decl *td = new_type_decl(gwion->mp, insert_symbol(gwion->st, base), tdc->pos);
225 td->fptr = fptr;
226 td->types = tl;
227 if (ac.depth) td->array = mk_array(gwion->mp, &ac);
228 tdc->str = ac.str;
229 td->option = option;
230 return td;
231 }
232
233 501474 ANN static Type_Decl *_str2td(const Gwion gwion, struct td_checker *tdc) {
234 501474 const uint ref = get_n(tdc, '&');
235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 501474 times.
501474 if(*tdc->str == '(') {
236 Type_Decl *const td = str2td_fptr(gwion, tdc);
237 td->ref = ref;
238 return td;
239 }
240
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 501474 times.
501474 DECL_OO(const Symbol, sym, = __str2sym(gwion, tdc));
241 501474 Type_List tl = td_tmpl(gwion, tdc);
242 501474 struct AC ac = {.str = tdc->str, .pos = tdc->pos};
243
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 501474 times.
501474 CHECK_BO(ac_run(gwion, &ac));
244 501474 tdc->str = ac.str;
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 501474 times.
501474 if (tl == (Type_List)GW_ERROR) return NULL;
246 501474 const uint option = get_n(tdc, '?');
247 501474 Type_Decl *next = NULL;
248
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 501471 times.
501474 if (*tdc->str == '.') {
249 3 ++tdc->str;
250
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if (!(next = _str2td(gwion, tdc))) {
251 if (tl) free_type_list(gwion->mp, tl);
252 if (ac.base) free_exp(gwion->mp, ac.base);
253 return NULL;
254 }
255 }
256 501474 Type_Decl *td = new_type_decl(gwion->mp, sym, tdc->pos);
257 501474 td->next = next;
258 501474 td->types = tl;
259 501474 td->option = option;
260 501474 td->ref = ref;
261
2/2
✓ Branch 0 taken 17246 times.
✓ Branch 1 taken 484228 times.
501474 if (ac.depth) td->array = mk_array(gwion->mp, &ac);
262 501474 return td;
263 }
264
265 498259 ANN Type_Decl *str2td(const Gwion gwion, const m_str str, const loc_t pos) {
266 498259 struct td_checker tdc = {.str = str, .pos = pos};
267
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 498259 times.
498259 DECL_OO(Type_Decl *, td, = _str2td(gwion, &tdc));
268
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 498258 times.
498259 if(*tdc.str) {
269 1 free_type_decl(gwion->mp, td);
270 1 GWION_ERR_O(pos, "excedental character '%c' in '%s'", *tdc.str, str);
271 }
272 498258 return td;
273 }
274
275 15 ANN Type str2type(const Gwion gwion, const m_str str, const loc_t pos) {
276
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
15 DECL_OO(Type_Decl *, td, = str2td(gwion, str, pos));
277 15 const Type t = known_type(gwion->env, td);
278 15 free_type_decl(gwion->mp, td);
279 15 return t;
280 }
281
282 struct td_info {
283 Type_List tl;
284 GwText text;
285 };
286
287 8011 ANN static void td_fullname(const Env env, GwText *text, const Type t) {
288 8011 const Type owner = t->info->value->from->owner_class;
289
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8007 times.
8011 if (owner) {
290 4 td_fullname(env, text, owner);
291 4 text_add(text, ".");
292 }
293 8011 text_add(text, t->name);
294 8011 }
295
296 3584 ANN static m_bool td_info_run(const Env env, struct td_info *info) {
297 3584 Type_List tl = info->tl;
298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3584 times.
3584 if(unlikely(!tl->len)) {
299 text_add(&info->text, "");
300 return GW_OK;
301 }
302
2/2
✓ Branch 0 taken 3608 times.
✓ Branch 1 taken 3583 times.
7191 for(uint32_t i = 0; i < tl->len; i++) {
303
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 3584 times.
3608 if (i) text_add(&info->text, ",");
304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3608 times.
3608 DECL_OB(Type_Decl *, td, = *mp_vector_at(tl, Type_Decl*, i));
305
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3607 times.
3608 DECL_OB(const Type, t, = known_type(env, td));
306 3607 td_fullname(env, &info->text, t);
307 }
308 3583 return GW_OK;
309 }
310
311 4400 ANEW ANN m_str type2str(const Gwion gwion, const Type t,
312 const loc_t pos NUSED) {
313 GwText text;
314 4400 text_init(&text, gwion->mp);
315 4400 td_fullname(gwion->env, &text, t);
316 4400 return text.str;
317 }
318
319 3584 ANEW ANN m_str tl2str(const Gwion gwion, const Type_List tl,
320 const loc_t pos NUSED) {
321 3584 struct td_info info = {.tl = tl};
322 3584 text_init(&info.text, gwion->mp);
323
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3583 times.
3584 CHECK_BO(td_info_run(gwion->env, &info));
324 3583 return info.text.str;
325 }
326
327 17251 ANN static inline m_bool ac_finish(const Gwion gwion, const struct AC *ac) {
328
1/2
✓ Branch 0 taken 17251 times.
✗ Branch 1 not taken.
17251 if (*ac->str == ']') return GW_OK;
329 GWION_ERR_B(ac->pos, "unfinished array");
330 }
331
332 1 ANN static inline m_bool ac_num(const Gwion gwion, const struct AC *ac,
333 const m_int num) {
334
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (num >= 0) return GW_OK;
335 GWION_ERR_B(ac->pos, "negative array dimension")
336 }
337
338 1 ANN static inline m_bool ac_exp(const Gwion gwion, const struct AC *ac) {
339
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!ac->depth || ac->base) return GW_OK;
340 GWION_ERR_B(ac->pos, "malformed array [][...]")
341 }
342
343 1 ANN static void ac_add_exp(struct AC *ac, const Exp exp) {
344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ac->exp)
345 ac->exp = (ac->exp->next = exp);
346 else
347 1 ac->base = ac->exp = exp;
348 1 }
349
350 17250 ANN static inline m_bool ac_noexp(const Gwion gwion, struct AC *ac) {
351
1/2
✓ Branch 0 taken 17250 times.
✗ Branch 1 not taken.
17250 if (!ac->exp) return GW_OK;
352 GWION_ERR_B(ac->pos, "malformed array [...][]")
353 }
354
355 17251 ANN static m_bool _ac_run(const Gwion gwion, struct AC *const ac) {
356 17251 const m_str str = ac->str;
357 17251 const m_int num = strtol(str, &ac->str, 10);
358
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17251 times.
17251 CHECK_BB(ac_finish(gwion, ac));
359
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 17250 times.
17251 if (str != ac->str) {
360
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 CHECK_BB(ac_num(gwion, ac, num));
361
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 CHECK_BB(ac_exp(gwion, ac));
362 1 const Exp exp = new_prim_int(gwion->mp, num, ac->pos);
363 // set type: otherwise could fail at emit time
364 1 exp->type = gwion->type[et_int];
365 1 ac_add_exp(ac, exp);
366 } else
367
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17250 times.
17250 CHECK_BB(ac_noexp(gwion, ac));
368 17251 ++ac->str;
369 17251 return GW_OK;
370 }
371
372 553180 ANN static m_bool ac_run(const Gwion gwion, struct AC *const ac) {
373
2/2
✓ Branch 0 taken 20467 times.
✓ Branch 1 taken 549964 times.
570431 while (*ac->str) {
374
2/2
✓ Branch 0 taken 3216 times.
✓ Branch 1 taken 17251 times.
20467 if (*ac->str != '[') break;
375 17251 ++ac->str;
376
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 17251 times.
17251 CHECK_BB(_ac_run(gwion, ac));
377 17251 ++ac->depth;
378 }
379 553180 return GW_OK;
380 }
381