Gwion coverage report


Directory: src/
File: src/parse/operator.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 303 327 92.7%
Functions: 29 29 100.0%
Branches: 219 272 80.5%

Line Branch Exec Source
1 #include <stdlib.h>
2 #include <string.h>
3 #include "gwion_util.h"
4 #include "gwion_ast.h"
5 #include "gwion_env.h"
6 #include "vm.h"
7 #include "gwion.h"
8 #include "instr.h"
9 #include "emit.h"
10 #include "operator.h"
11 #include "object.h"
12 #include "array.h"
13 #include "import.h"
14 #include "traverse.h"
15 #include "clean.h"
16
17 typedef Type (*f_type)(const Env env, const Exp exp);
18
19 typedef struct M_Operator_ {
20 Type lhs, rhs, ret;
21 f_instr instr;
22 Func func;
23 opck ck;
24 opem em;
25 struct Vector_ effect;
26 } M_Operator;
27
28 683 ANN void free_op_map(Map map, struct Gwion_ *gwion) {
29 LOOP_OPTIM
30
2/2
✓ Branch 1 taken 39705 times.
✓ Branch 2 taken 683 times.
40388 for (m_uint i = map_size(map) + 1; --i;) {
31 39705 const restrict Vector v = (Vector)&VVAL(map, (vtype)i - 1);
32 LOOP_OPTIM
33
2/2
✓ Branch 1 taken 164949 times.
✓ Branch 2 taken 39705 times.
204654 for (m_uint j = vector_size(v) + 1; --j;) {
34 164949 M_Operator *const mop = (M_Operator *)vector_at(v, j - 1);
35
2/2
✓ Branch 0 taken 1914 times.
✓ Branch 1 taken 163035 times.
164949 if (mop->effect.ptr) vector_release(&mop->effect);
36 164949 mp_free(gwion->mp, M_Operator, mop);
37 }
38 39705 vector_release(v);
39 }
40 683 map_release(map);
41 683 }
42
43 1 ANN void free_op_tmpl(Vector v, struct Gwion_ *gwion) {
44 LOOP_OPTIM
45
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 for (m_uint i = vector_size(v) + 1; --i;) {
46 1 const Func_Def fdef = (Func_Def)vector_at(v, i - 1);
47 1 free_func_def(gwion->mp, fdef);
48 }
49 1 vector_release(v);
50 1 }
51
52 40 static m_str type_name(const Type t) {
53
3/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
40 return t ? t == OP_ANY_TYPE ? "any" : t->name : "";
54 }
55
56 22953 static m_bool op_match(const restrict Type t, const restrict Type mo) {
57
3/4
✓ Branch 0 taken 22953 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1811 times.
✓ Branch 3 taken 21142 times.
22953 if (t == OP_ANY_TYPE || mo == OP_ANY_TYPE) return GW_OK;
58 21142 return t == mo;
59 }
60
61 ANN2(1)
62 5844 static M_Operator *operator_find(const Vector v, const restrict Type lhs,
63 const restrict Type rhs) {
64
2/2
✓ Branch 1 taken 18050 times.
✓ Branch 2 taken 4685 times.
22735 for (m_uint i = vector_size(v) + 1; --i;) {
65 18050 M_Operator *mo = (M_Operator *)vector_at(v, i - 1);
66
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18045 times.
18050 if (!mo) continue;
67
4/4
✓ Branch 1 taken 4908 times.
✓ Branch 2 taken 13137 times.
✓ Branch 4 taken 1159 times.
✓ Branch 5 taken 3749 times.
18045 if (op_match(lhs, mo->lhs) && op_match(rhs, mo->rhs)) return mo;
68 }
69 4685 return NULL;
70 }
71
72 ANN2(1)
73 147955 static M_Operator *operator_find2(const Vector v, const restrict Type lhs,
74 const restrict Type rhs) {
75
2/2
✓ Branch 1 taken 624625 times.
✓ Branch 2 taken 141706 times.
766331 for (m_uint i = vector_size(v) + 1; --i;) {
76 624625 M_Operator *mo = (M_Operator *)vector_at(v, i - 1);
77
6/6
✓ Branch 0 taken 624620 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 102790 times.
✓ Branch 3 taken 521830 times.
✓ Branch 4 taken 6249 times.
✓ Branch 5 taken 96541 times.
624625 if (mo && lhs == mo->lhs && rhs == mo->rhs) return mo;
78 }
79 141706 return NULL;
80 }
81
82 18 ANN void operator_suspend(const Nspc n, struct Op_Import *opi) {
83 18 const m_int idx = map_index(&n->operators->map, (vtype)opi->op);
84 18 const Vector v = (Vector)&VVAL(&n->operators->map, idx);
85
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
23 for (m_uint i = vector_size(v) + 1; --i;) {
86 23 M_Operator *mo = (M_Operator *)vector_at(v, i - 1);
87
4/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 3 times.
23 if (opi->lhs == mo->lhs && opi->rhs == mo->rhs) {
88 18 opi->data = (uintptr_t)mo;
89 18 opi->ret = (Type)&VPTR(v, i - 1);
90 18 VPTR(v, i - 1) = 0;
91 18 break;
92 }
93 }
94 18 }
95
96 164758 ANN static M_Operator *new_mo(MemPool p, const struct Op_Import *opi) {
97 164758 M_Operator *mo = mp_calloc(p, M_Operator);
98 164758 mo->lhs = opi->lhs;
99 164758 mo->rhs = opi->rhs;
100 164758 mo->ret = opi->ret;
101 164758 mo->instr = (f_instr)opi->data;
102
2/2
✓ Branch 0 taken 160918 times.
✓ Branch 1 taken 3840 times.
164758 if (opi->func) {
103 160918 mo->ck = opi->func->ck;
104 160918 mo->em = opi->func->em;
105 160918 mo->effect.ptr = opi->func->effect.ptr;
106 }
107 164758 return mo;
108 }
109
110 struct OpChecker {
111 const Env env;
112 const Map map;
113 const struct Op_Import *opi;
114 struct Vector_ effect;
115 };
116
117 __attribute__((returns_nonnull)) ANN static Vector
118 164758 op_vector(const struct OpChecker *ock) {
119 164758 const m_int idx = map_index(ock->map, (vtype)ock->opi->op);
120
2/2
✓ Branch 0 taken 125118 times.
✓ Branch 1 taken 39640 times.
164758 if (idx > -1) return (Vector)&VVAL(ock->map, idx);
121 39640 map_set(ock->map, (vtype)ock->opi->op, 0);
122 39640 const Vector create = (Vector)&VVAL(ock->map, VLEN(ock->map) - 1);
123 39640 vector_init(create);
124 39640 return create;
125 }
126
127 164207 ANN static m_bool _op_exist(const struct OpChecker *ock, const Nspc n) {
128 164207 const m_int idx = map_index(&n->operators->map, (vtype)ock->opi->op);
129
3/4
✓ Branch 0 taken 125249 times.
✓ Branch 1 taken 38958 times.
✓ Branch 2 taken 125249 times.
✗ Branch 3 not taken.
289456 if (idx == -1 || !operator_find2((Vector)&VVAL(ock->map, idx), ock->opi->lhs,
130 125249 ock->opi->rhs))
131 164207 return GW_OK;
132 env_err(ock->env, ock->opi->pos,
133 _("operator '%s', for type '%s' and '%s' already imported"),
134 s_name(ock->opi->op), type_name(ock->opi->lhs),
135 type_name(ock->opi->rhs));
136 return GW_ERROR;
137 }
138
139 164208 ANN static m_bool op_exist(const struct OpChecker *ock, const Nspc n) {
140
2/2
✓ Branch 0 taken 164207 times.
✓ Branch 1 taken 1 times.
164208 return n->operators->map.ptr ? _op_exist(ock, n) : GW_OK;
141 }
142
143 164758 ANN m_bool add_op(const Gwion gwion, const struct Op_Import *opi) {
144 164758 Nspc n = gwion->env->curr;
145 do {
146
2/2
✓ Branch 0 taken 164208 times.
✓ Branch 1 taken 985 times.
165193 if (n->operators) {
147 164208 struct OpChecker ock = {
148 164208 .env = gwion->env, .map = &n->operators->map, .opi = opi};
149
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 164208 times.
164208 CHECK_BB(op_exist(&ock, n));
150 }
151
2/2
✓ Branch 0 taken 435 times.
✓ Branch 1 taken 164758 times.
165193 } while ((n = n->parent));
152
2/2
✓ Branch 0 taken 693 times.
✓ Branch 1 taken 164065 times.
164758 if (!gwion->env->curr->operators)
153 693 gwion->env->curr->operators = mp_calloc(gwion->mp, NspcOp);
154
2/2
✓ Branch 0 taken 694 times.
✓ Branch 1 taken 164064 times.
164758 if (!gwion->env->curr->operators->map.ptr)
155 694 map_init(&gwion->env->curr->operators->map);
156 164758 struct OpChecker ock = {
157 164758 .env = gwion->env, .map = &gwion->env->curr->operators->map, .opi = opi};
158 164758 const Vector v = op_vector(&ock);
159 164758 const M_Operator *mo = new_mo(gwion->mp, opi);
160 164758 vector_add(v, (vtype)mo);
161 164758 return GW_OK;
162 }
163
164 25761 ANN static inline Type op_parent(const Env env, const Type t) {
165 25761 const size_t depth = t->array_depth;
166
2/2
✓ Branch 0 taken 25536 times.
✓ Branch 1 taken 225 times.
25761 if (!depth)
167 25536 return t->info->parent;
168 225 const Type base = array_base_simple(t);
169 225 return !base->info->parent
170 182 ? t->info->parent
171
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 43 times.
225 : array_type(env, base->info->parent, depth);
172 }
173
174 17888 ANN static Type op_check_inner(const Env env, struct OpChecker *ock,
175 const uint i) {
176 17888 Type t, r = ock->opi->rhs;
177 do {
178 const M_Operator *mo;
179 19462 const m_int idx = map_index(ock->map, (vtype)ock->opi->op);
180
6/6
✓ Branch 0 taken 18814 times.
✓ Branch 1 taken 648 times.
✓ Branch 2 taken 16872 times.
✓ Branch 3 taken 1942 times.
✓ Branch 4 taken 6220 times.
✓ Branch 5 taken 12594 times.
38276 if (idx > -1 && (mo = !i ? operator_find2((Vector)&VVAL(ock->map, idx),
181 16872 ock->opi->lhs, r)
182 1942 : operator_find((Vector)&VVAL(ock->map, idx),
183 1942 ock->opi->lhs, r))) {
184
4/4
✓ Branch 0 taken 6080 times.
✓ Branch 1 taken 140 times.
✓ Branch 3 taken 6071 times.
✓ Branch 4 taken 9 times.
6220 if ((mo->ck && (t = mo->ck(ock->env, (void *)ock->opi->data)))) {
185 6071 ock->effect.ptr = mo->effect.ptr;
186 6071 return t;
187 } else
188 149 return mo->ret;
189 }
190
4/4
✓ Branch 0 taken 2234 times.
✓ Branch 1 taken 11008 times.
✓ Branch 3 taken 1574 times.
✓ Branch 4 taken 660 times.
13242 } while (r && (r = op_parent(env, r)));
191 11668 return NULL;
192 }
193 /*
194 //! check if type matches for template operator
195 ANN bool _tmpl_match(const Env env, const Type t, Type_Decl *const td,
196 Specialized_List *slp) {
197 const Specialized_List sl = *slp;
198 if (sl && !td->next && !td->types && td->xid == sl->xid) {
199 *slp = sl->next;
200 return true;
201 }
202 const Type base = known_type(env, td);
203 return base ? isa(t, base) > 0 : false;
204 }
205 */
206 //! check if type matches for template operator
207 2 ANN2(1,2,3) bool _tmpl_match(const Env env, const Type t, Type_Decl *const td,
208 Specialized *spec, uint32_t *idx) {
209
4/8
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2 times.
✗ Branch 7 not taken.
2 if (spec && !td->next && !td->types && td->xid == spec->xid) {
210 2 (*idx)++;
211 2 return true;
212 }
213 const Type base = known_type(env, td);
214 return base ? isa(t, base) > 0 : false;
215 }
216
217 //! check Func_Base matches for template operator
218 1 ANN bool tmpl_match(const Env env, const struct Op_Import *opi,
219 Func_Base *const base) {
220 1 Specialized_List sl = base->tmpl->list;
221 1 const Arg_List args = base->args;
222 1 Arg *arg0 = mp_vector_at(args, Arg, 0);
223
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 Arg *arg1 = args->len > 1 ? mp_vector_at(args, Arg, 1) : NULL;
224 1 uint32_t idx = 0;
225
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (opi->lhs) {
226
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!_tmpl_match(env, opi->lhs, arg0->td, mp_vector_at(sl, Specialized, idx), &idx)) return false;
227
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (fbflag(base, fbflag_postfix)) return !!opi->rhs;
228
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (!fbflag(base, fbflag_unary)) {
229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!opi->rhs) return false;
230
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!_tmpl_match(env, opi->rhs, arg1->td, mp_vector_at(sl, Specialized, idx), &idx)) return false;
231 } else if (opi->rhs)
232 return false;
233 } else {
234 if (!fbflag(base, fbflag_unary) ||
235 !_tmpl_match(env, opi->rhs, arg0->td, mp_vector_at(sl, Specialized, idx), &idx))
236 return false;
237 }
238 1 return true;
239 }
240
241 //! make template operator Func_def
242 1 ANN static Type op_def(const Env env, struct Op_Import *const opi,
243 const Func_Def fdef) {
244 1 const Func_Def tmpl_fdef = cpy_func_def(env->gwion->mp, fdef);
245 1 tmpl_fdef->base->tmpl->call = new_mp_vector(env->gwion->mp,
246 Type_Decl*, fdef->base->tmpl->list->len);
247
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (opi->lhs) {
248 1 uint32_t idx = 0;
249 1 const Type lhs = find_type(env, mp_vector_at(fdef->base->args, Arg, 0)->td);
250
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!lhs)
251 1 mp_vector_set(tmpl_fdef->base->tmpl->call, Type_Decl*, idx++, type2td(env->gwion, opi->lhs, opi->pos));
252 1 const Type rhs = find_type(env, mp_vector_at(fdef->base->args, Arg, 1)->td);
253
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if(!rhs)
254 1 mp_vector_set(tmpl_fdef->base->tmpl->call, Type_Decl*, idx, type2td(env->gwion, opi->rhs, opi->pos));
255 } else
256 mp_vector_set(tmpl_fdef->base->tmpl->call, Type_Decl*, 0, type2td(env->gwion, opi->rhs, opi->pos));
257
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (traverse_func_def(env, tmpl_fdef) < 0) {
258 if (!tmpl_fdef->base->func) func_def_cleaner(env->gwion, tmpl_fdef);
259 return NULL;
260 }
261 1 return op_check(env, opi);
262 }
263
264 //! find template operator
265 95 ANN static Type op_check_tmpl(const Env env, struct Op_Import *opi) {
266 95 Nspc nspc = env->curr;
267 do {
268
4/4
✓ Branch 0 taken 101 times.
✓ Branch 1 taken 329 times.
✓ Branch 2 taken 100 times.
✓ Branch 3 taken 1 times.
430 if (!nspc->operators || !nspc->operators->tmpl.ptr) continue;
269 1 const Vector v = &nspc->operators->tmpl;
270
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 for (m_uint i = vector_size(v) + 1; --i;) {
271 1 const Func_Def fdef = (Func_Def)vector_at(v, i - 1);
272
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (opi->op != fdef->base->xid) continue;
273
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if (!tmpl_match(env, opi, fdef->base)) continue;
274 1 return op_def(env, opi, fdef);
275 }
276
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 94 times.
429 } while ((nspc = nspc->parent));
277 94 return NULL;
278 }
279
280 476 ANN void* op_get(const Env env, struct Op_Import *opi) {
281
2/2
✓ Branch 0 taken 931 times.
✓ Branch 1 taken 455 times.
1386 for (int i = 0; i < 2; ++i) {
282 931 Nspc nspc = env->curr;
283 do {
284 3823 Type l = opi->lhs;
285
2/2
✓ Branch 0 taken 2787 times.
✓ Branch 1 taken 1036 times.
3823 if (!nspc->operators) continue;
286
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1036 times.
1036 if (!nspc->operators->map.ptr) continue;
287 1036 const Map map = &nspc->operators->map;
288 do {
289 1074 Type r = opi->rhs;
290 do {
291 3194 const m_int idx = map_index(map, (vtype)opi->op);
292
2/2
✓ Branch 0 taken 2879 times.
✓ Branch 1 taken 315 times.
3194 if(idx != -1) {
293 2879 M_Operator *const mo = !i
294 1450 ? operator_find2((Vector)&VVAL(map, idx), l, r)
295
2/2
✓ Branch 0 taken 1450 times.
✓ Branch 1 taken 1429 times.
2879 : operator_find((Vector)&VVAL(map, idx), l, r);
296
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2858 times.
2879 if (mo)
297 21 return mo;
298 }
299
4/4
✓ Branch 0 taken 3149 times.
✓ Branch 1 taken 24 times.
✓ Branch 3 taken 2120 times.
✓ Branch 4 taken 1029 times.
3173 } while (r && (r = op_parent(env, r)));
300
4/4
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 976 times.
✓ Branch 3 taken 38 times.
✓ Branch 4 taken 39 times.
1053 } while (l && (l = op_parent(env, l)));
301
2/2
✓ Branch 0 taken 2892 times.
✓ Branch 1 taken 910 times.
3802 } while ((nspc = nspc->parent));
302 }
303 455 return NULL;
304 }
305
306 3 ANN static Type chuck_rewrite(const Env env, const struct Op_Import *opi, const m_str op, const size_t len) {
307 3 Exp_Binary *base = (Exp_Binary*)opi->data;
308 3 const Exp lhs = cpy_exp(env->gwion->mp, base->lhs); // no need to copy
309 3 const Exp call = new_exp_call(env->gwion->mp, cpy_exp(env->gwion->mp, base->rhs), NULL, lhs->pos);
310 3 char c[len - 1];
311 3 strncpy(c, op, len - 2);
312 3 c[len - 2] = '\0';
313 // are there other expressions that would need such a test?
314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if(!strcmp(c, "$")) {
315 env_err(env, opi->pos, "can't rewrite cast operations");
316 env_set_error(env, true);
317 return NULL;
318 }
319 3 const Exp bin = new_exp_binary(env->gwion->mp, lhs, insert_symbol(env->gwion->st, c), call, exp_self(base)->pos);
320 3 base->lhs = bin;
321 3 base->op = insert_symbol(env->gwion->st, "=>");
322 3 const Type ret = check_exp(env, exp_self(base));
323
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if(ret) return ret;
324 2 env_set_error(env, false);
325 2 env_warn(env, opi->pos, _("during rewriting operation"));
326 2 env_set_error(env, true);
327 2 return NULL;
328 }
329
330 6298 ANN Type op_check(const Env env, struct Op_Import *opi) {
331
2/2
✓ Branch 0 taken 7023 times.
✓ Branch 1 taken 95 times.
7118 for (int i = 0; i < 2; ++i) {
332 7023 Nspc nspc = env->curr;
333 do {
334
2/2
✓ Branch 0 taken 14185 times.
✓ Branch 1 taken 7274 times.
21459 if (!nspc->operators) continue;
335
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7272 times.
7274 if (!nspc->operators->map.ptr) continue;
336 7272 Type l = opi->lhs;
337 do {
338 17888 struct Op_Import opi2 = {
339 17888 .op = opi->op, .lhs = l, .rhs = opi->rhs, .data = opi->data};
340 17888 struct OpChecker ock = {
341 17888 .env = env, .map = &nspc->operators->map, .opi = &opi2};
342 17888 const Type ret = op_check_inner(env, &ock, i);
343
2/2
✓ Branch 0 taken 6203 times.
✓ Branch 1 taken 11685 times.
17888 if (ret) {
344
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 6118 times.
12321 if (ret == env->gwion->type[et_error]) return NULL;
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6118 times.
6118 if (ock.effect.ptr) {
346 const Vector base = &ock.effect;
347 for (m_uint i = 0; i < vector_size(base); i++)
348 env_add_effect(env, (Symbol)vector_at(base, i), opi->pos);
349 }
350 6118 opi->nspc = nspc;
351 6118 return ret;
352 }
353
4/4
✓ Branch 0 taken 11573 times.
✓ Branch 1 taken 112 times.
✓ Branch 3 taken 10616 times.
✓ Branch 4 taken 957 times.
11685 } while (l && (l = op_parent(env, l)));
354
2/2
✓ Branch 0 taken 14436 times.
✓ Branch 1 taken 820 times.
15256 } while ((nspc = nspc->parent));
355 }
356 95 const Type try_tmpl = op_check_tmpl(env, opi);
357
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 94 times.
95 if (try_tmpl) return try_tmpl;
358 94 const m_str op = s_name(opi->op);
359
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 93 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
94 if (!strcmp(op, "$") && opi->rhs == opi->lhs)
360 1 return opi->rhs;
361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
93 if (!strcmp(op, "@func_check")) return NULL;
362
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 89 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
93 if(!strcmp(op, "=>") && !strcmp(opi->rhs->name, "@now")) {
363 gwerr_basic(_("no match found for operator"), "expected duration", "did you try converting to `dur`?", env->name, opi->pos, 0);
364 env_set_error(env, true);
365
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 70 times.
93 } else if (strcmp(op, "@implicit")) {
366
6/6
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 2 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 16 times.
23 if (opi->rhs && opi->lhs && is_func(env->gwion, opi->rhs)) { // is_callable
367 3 const size_t len = strlen(op);
368
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 if (len > 2 && !strcmp(op + len - 2, "=>"))
369 3 return chuck_rewrite(env, opi, op, len);
370 }
371 20 env_err(env, opi->pos, _("%s %s %s: no match found for operator"),
372 type_name(opi->lhs), s_name(opi->op), type_name(opi->rhs));
373 }
374 90 return NULL;
375 }
376
377 22 ANN m_bool operator_set_func(const struct Op_Import *opi) {
378 22 const Nspc nspc = ((Func)opi->data)->value_ref->from->owner;
379 22 const m_int idx = map_index(&nspc->operators->map, (vtype)opi->op);
380 22 const Vector v = (Vector)&VVAL(&nspc->operators->map, idx);
381
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 22 times.
22 DECL_OB(M_Operator *, mo, = operator_find(v, opi->lhs, opi->rhs));
382 22 mo->func = (Func)opi->data;
383 22 return GW_OK;
384 }
385
386 475 ANN static m_bool handle_instr(const Emitter emit, const M_Operator *mo) {
387
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 466 times.
475 if (mo->func) {
388 9 emit_pushfunc(emit, mo->func);
389
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 CHECK_BB(emit_exp_call1(emit, mo->func, true));
390 9 if (mo->func->def->base->xid ==
391
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 insert_symbol(emit->gwion->st, "@conditional"))
392 1 emit_add_instr(emit, BranchEqInt);
393 8 else if (mo->func->def->base->xid ==
394
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
8 insert_symbol(emit->gwion->st, "@unconditional"))
395 1 emit_add_instr(emit, BranchNeqInt);
396 9 return GW_OK;
397 }
398 466 (void)emit_add_instr(emit, mo->instr);
399 466 return GW_OK;
400 }
401
402 1129 ANN m_bool op_emit(const Emitter emit, const struct Op_Import *opi) {
403
2/2
✓ Branch 0 taken 1616 times.
✓ Branch 1 taken 7 times.
1623 for (int i = 0; i < 2; ++i) {
404 1616 Nspc nspc = emit->env->curr;
405 do {
406
2/2
✓ Branch 0 taken 4966 times.
✓ Branch 1 taken 1810 times.
6776 if (!nspc->operators) continue;
407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1810 times.
1810 if (!nspc->operators->map.ptr) continue;
408 1810 Type l = opi->lhs;
409 do {
410 3773 Type r = opi->rhs;
411 do {
412 7442 const m_int idx = map_index(&nspc->operators->map, (vtype)opi->op);
413
2/2
✓ Branch 0 taken 607 times.
✓ Branch 1 taken 6835 times.
7442 if (idx == -1) continue;
414 6835 const Vector v = (Vector)&VVAL(&nspc->operators->map, idx);
415
2/2
✓ Branch 0 taken 4384 times.
✓ Branch 1 taken 2451 times.
6835 const M_Operator *mo =
416 6835 !i ? operator_find2(v, l, r) : operator_find(v, l, r);
417
2/2
✓ Branch 0 taken 1145 times.
✓ Branch 1 taken 5690 times.
6835 if (mo) {
418
2/2
✓ Branch 0 taken 647 times.
✓ Branch 1 taken 498 times.
1145 if (mo->em) {
419 647 const m_bool ret = mo->em(emit, (void *)opi->data);
420
1/2
✓ Branch 0 taken 647 times.
✗ Branch 1 not taken.
647 if (ret) return ret;
421
4/4
✓ Branch 0 taken 489 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 466 times.
✓ Branch 3 taken 23 times.
498 } else if (mo->func || mo->instr)
422 475 return handle_instr(emit, mo);
423 }
424
4/4
✓ Branch 0 taken 6149 times.
✓ Branch 1 taken 171 times.
✓ Branch 3 taken 3669 times.
✓ Branch 4 taken 2480 times.
6320 } while (r && (r = op_parent(emit->env, r)));
425
4/4
✓ Branch 0 taken 2579 times.
✓ Branch 1 taken 72 times.
✓ Branch 3 taken 1963 times.
✓ Branch 4 taken 616 times.
2651 } while (l && (l = op_parent(emit->env, l)));
426
2/2
✓ Branch 0 taken 5160 times.
✓ Branch 1 taken 494 times.
5654 } while ((nspc = nspc->parent));
427 }
428 7 return GW_ERROR;
429 }
430
431 #define CONVERT(t) t != from ? t : to
432 340 ANN static M_Operator *cpy_mo(MemPool p, M_Operator *const base,
433 const Type from, const Type to) {
434 340 M_Operator *mo = mp_calloc(p, M_Operator);
435
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 210 times.
340 mo->lhs = CONVERT(base->lhs);
436
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 205 times.
340 mo->rhs = CONVERT(base->rhs);
437
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 162 times.
340 mo->ret = CONVERT(base->ret);
438 340 mo->instr = base->instr;
439 340 mo->func = base->func;
440 340 mo->ck = base->ck;
441 340 mo->em = base->em;
442
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
340 if (base->effect.ptr) {
443 vector_init(&mo->effect);
444 vector_copy2(&base->effect, &mo->effect);
445 }
446 340 return mo;
447 }
448 #undef CONVERT
449
450 4 ANN static inline Map ensure_map(MemPool mp, const Nspc nspc) {
451
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!nspc->operators) nspc->operators = mp_calloc(mp, NspcOp);
452 4 const Map map = &nspc->operators->map;
453
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!map->ptr) map_init(map);
454 4 return map;
455 }
456
457 340 ANN static inline Vector ensure_vec(const Map map, const m_uint key) {
458 340 const m_int idx = map_index(map, key);
459
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 130 times.
340 if (idx > -1) return (Vector)&VVAL(map, idx);
460 130 map_set(map, key, 0);
461 130 const Vector v = (Vector)&VVAL(map, VLEN(map) - 1);
462 130 vector_init(v);
463 130 return v;
464 }
465
466 22 ANN static void op_visit(const MemPool mp, const Nspc nspc,
467 const struct Op_Import *opi, const Vector visited) {
468
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 14 times.
22 if (vector_find(visited, (m_uint)nspc) != -1) return;
469 14 vector_add(visited, (m_uint)nspc);
470
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
14 if (nspc->operators && nspc->operators->map.ptr) {
471 4 const Map map = &nspc->operators->map;
472 4 const Map base_map = ensure_map(mp, opi->rhs->info->value->from->owner);
473
2/2
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 4 times.
252 for (m_uint i = 0; i < map_size(map); i++) {
474 248 const Vector v = (Vector)&VVAL(map, i);
475 248 const m_uint sz = vector_size(v);
476
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 248 times.
1280 for (m_uint j = 0; j < sz; j++) {
477 1032 M_Operator *const mo = (M_Operator *)vector_at(v, j);
478
6/6
✓ Branch 0 taken 822 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 704 times.
✓ Branch 3 taken 118 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 692 times.
1032 if (opi->lhs == mo->lhs || opi->lhs == mo->rhs || opi->lhs == mo->ret) {
479 340 const M_Operator *tmp = cpy_mo(mp, mo, opi->lhs, opi->rhs);
480 340 const Vector target = ensure_vec(base_map, VKEY(map, i));
481 340 vector_add(target, (vtype)tmp);
482 }
483 }
484 }
485 }
486
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 4 times.
14 if (nspc->parent) op_visit(mp, nspc->parent, opi, visited);
487 }
488
489 4 ANN void op_cpy(const Env env, const struct Op_Import *opi) {
490 struct Vector_ visited;
491 4 vector_init(&visited);
492 4 op_visit(env->gwion->mp, opi->rhs->info->value->from->owner, opi, &visited);
493 4 op_visit(env->gwion->mp, opi->lhs->info->value->from->owner, opi, &visited);
494 4 op_visit(env->gwion->mp, env->curr, opi, &visited);
495 4 vector_release(&visited);
496 4 }
497