GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
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 |
|||
14 |
typedef Type (*f_type)(const Env env, const Exp exp); |
||
15 |
|||
16 |
typedef struct M_Operator_{ |
||
17 |
Type lhs, rhs, ret; |
||
18 |
f_instr instr; |
||
19 |
Func func; |
||
20 |
opck ck; |
||
21 |
opem em; |
||
22 |
m_uint emit_var; |
||
23 |
} M_Operator; |
||
24 |
|||
25 |
747 |
ANN void free_op_map(Map map, struct Gwion_ *gwion) { |
|
26 |
LOOP_OPTIM |
||
27 |
✓✓ | 37759 |
for(m_uint i = map_size(map) + 1; --i;) { |
28 |
36265 |
const restrict Vector v = (Vector)map_at(map, (vtype)i - 1); |
|
29 |
LOOP_OPTIM |
||
30 |
✓✓ | 203970 |
for(m_uint j = vector_size(v) + 1; --j;) |
31 |
131440 |
mp_free(gwion->mp, M_Operator, (M_Operator*)vector_at(v, j - 1)); |
|
32 |
36265 |
free_vector(gwion->mp, v); |
|
33 |
} |
||
34 |
747 |
map_release(map); |
|
35 |
747 |
} |
|
36 |
|||
37 |
2003 |
ANN static Type op_parent(const Env env, const Type t) { |
|
38 |
✓✓✓✓ |
2003 |
if(GET_FLAG(t, template) && GET_FLAG(t, ref)) { |
39 |
50 |
const Type type = typedef_base(t); |
|
40 |
50 |
const m_str post = strrchr(type->name, '>') + 1; |
|
41 |
50 |
return nspc_lookup_type1(env->curr, insert_symbol(env->gwion->st, post)); |
|
42 |
} |
||
43 |
1953 |
return t->e->parent; |
|
44 |
} |
||
45 |
|||
46 |
26751 |
static m_bool op_match(const restrict Type t, const restrict Type mo) { |
|
47 |
✓✗✓✓ |
26751 |
if(t == OP_ANY_TYPE || mo == OP_ANY_TYPE) |
48 |
3897 |
return GW_OK; |
|
49 |
22854 |
Type type = t; |
|
50 |
✓✓✓✓ ✓✗✓✗ ✓✓ |
22854 |
while(SAFE_FLAG(type, template) && type->e->def && type->e->def->base.tmpl && type->e->def->base.tmpl->call) type = type->e->parent; |
51 |
✓✓✓✓ ✓✓✓✓ ✓✓ |
22854 |
if((type && mo && mo->xid == type->xid) || (!type && !mo)) |
52 |
5689 |
return GW_OK; |
|
53 |
17165 |
return 0; |
|
54 |
} |
||
55 |
|||
56 |
4700 |
ANN2(1) static M_Operator* operator_find(const Vector v, const restrict Type lhs, const restrict Type rhs) { |
|
57 |
✓✓ | 26572 |
for(m_uint i = vector_size(v) + 1; --i;) { |
58 |
20446 |
M_Operator* mo = (M_Operator*)vector_at(v, i - 1); |
|
59 |
✓✓ | 20446 |
if(!mo) |
60 |
7 |
continue; |
|
61 |
✓✓✓✓ |
20439 |
if(op_match(lhs, mo->lhs) && op_match(rhs, mo->rhs)) |
62 |
3274 |
return mo; |
|
63 |
} |
||
64 |
1426 |
return NULL; |
|
65 |
} |
||
66 |
|||
67 |
408643 |
static m_bool op_match2(const restrict Type t, const restrict Type mo) { |
|
68 |
// if(t == OP_ANY_TYPE || mo == OP_ANY_TYPE) |
||
69 |
// return GW_OK; |
||
70 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓ |
408643 |
if((t && mo && (t != OP_ANY_TYPE && mo != OP_ANY_TYPE && mo->xid == t->xid)) || (!t && !mo)) |
71 |
64199 |
return GW_OK; |
|
72 |
344444 |
return 0; |
|
73 |
} |
||
74 |
|||
75 |
95397 |
ANN2(1) static M_Operator* operator_find2(const Vector v, const restrict Type lhs, const restrict Type rhs) { |
|
76 |
✓✓ | 535227 |
for(m_uint i = vector_size(v) + 1; --i;) { |
77 |
344434 |
M_Operator* mo = (M_Operator*)vector_at(v, i - 1); |
|
78 |
✓✓✓✓ |
344434 |
if(op_match2(lhs, mo->lhs) && op_match2(rhs, mo->rhs)) |
79 |
1 |
return mo; |
|
80 |
} |
||
81 |
95396 |
return NULL; |
|
82 |
} |
||
83 |
|||
84 |
24 |
ANN void operator_suspend(const Nspc n, struct Op_Import *opi) { |
|
85 |
24 |
const Vector v = (Vector)map_get(&n->info->op_map, (vtype)opi->op); |
|
86 |
✓✗ | 59 |
for(m_uint i = vector_size(v) + 1; --i;) { |
87 |
35 |
M_Operator* mo = (M_Operator*)vector_at(v, i - 1); |
|
88 |
✓✓✓✓ |
35 |
if(op_match2(opi->lhs, mo->lhs) && op_match2(opi->rhs, mo->rhs)) { |
89 |
24 |
opi->data = (uintptr_t)mo; |
|
90 |
24 |
opi->ret = (Type)&VPTR(v, i-1); |
|
91 |
24 |
VPTR(v, i-1) = 0; |
|
92 |
24 |
break; |
|
93 |
} |
||
94 |
} |
||
95 |
24 |
} |
|
96 |
|||
97 |
131625 |
ANN static M_Operator* new_mo(MemPool p, const struct Op_Import* opi) { |
|
98 |
131625 |
M_Operator* mo = mp_calloc(p, M_Operator); |
|
99 |
131625 |
mo->lhs = opi->lhs; |
|
100 |
131625 |
mo->rhs = opi->rhs; |
|
101 |
131625 |
mo->ret = opi->ret; |
|
102 |
131625 |
mo->instr = (f_instr)opi->data; |
|
103 |
✓✗ | 131625 |
if(opi->func) { |
104 |
131625 |
mo->ck = opi->func->ck; |
|
105 |
131625 |
mo->em = opi->func->em; |
|
106 |
} |
||
107 |
131625 |
return mo; |
|
108 |
} |
||
109 |
|||
110 |
struct OpChecker { |
||
111 |
const Env env; |
||
112 |
const Map map; |
||
113 |
const struct Op_Import* opi; |
||
114 |
m_bool mut; |
||
115 |
}; |
||
116 |
|||
117 |
__attribute__((returns_nonnull)) |
||
118 |
131625 |
ANN static Vector op_vector(MemPool p, const struct OpChecker *ock) { |
|
119 |
131625 |
const Vector exist = (Vector)map_get(ock->map, (vtype)ock->opi->op); |
|
120 |
✓✓ | 131625 |
if(exist) |
121 |
95309 |
return exist; |
|
122 |
36316 |
const Vector create = new_vector(p); |
|
123 |
36316 |
map_set(ock->map, (vtype)ock->opi->op, (vtype)create); |
|
124 |
36316 |
return create; |
|
125 |
} |
||
126 |
|||
127 |
158 |
static m_str type_name(const Type t) { |
|
128 |
✓✓✓✗ |
158 |
return t ? t == OP_ANY_TYPE ? "any" : t->name : ""; |
129 |
} |
||
130 |
|||
131 |
130974 |
ANN static m_bool _op_exist(const struct OpChecker* ock, const Nspc n) { |
|
132 |
130974 |
const Vector v = (Vector)map_get(&n->info->op_map, (vtype)ock->opi->op); |
|
133 |
✓✓✓✓ |
130974 |
if(!v || !operator_find2(v, ock->opi->lhs, ock->opi->rhs)) |
134 |
130973 |
return GW_OK; |
|
135 |
3 |
env_err(ock->env, ock->opi->pos, _("operator '%s', for type '%s' and '%s' already imported"), |
|
136 |
3 |
s_name(ock->opi->op), type_name(ock->opi->lhs), type_name(ock->opi->rhs)); |
|
137 |
1 |
return GW_ERROR; |
|
138 |
} |
||
139 |
|||
140 |
131898 |
ANN static m_bool op_exist(const struct OpChecker* ock, const Nspc n) { |
|
141 |
✓✓ | 131898 |
return n->info->op_map.ptr ? _op_exist(ock, n) : GW_OK; |
142 |
} |
||
143 |
|||
144 |
131626 |
ANN m_bool add_op(const Gwion gwion, const struct Op_Import* opi) { |
|
145 |
131626 |
Nspc n = gwion->env->curr; |
|
146 |
do { |
||
147 |
131898 |
struct OpChecker ock = { gwion->env, &n->info->op_map, opi, 0 }; |
|
148 |
✓✓ | 131898 |
CHECK_BB(op_exist(&ock, n)) |
149 |
✓✓ | 131897 |
} while((n = n->parent)); |
150 |
✓✓ | 131625 |
if(!gwion->env->curr->info->op_map.ptr) |
151 |
748 |
map_init(&gwion->env->curr->info->op_map); |
|
152 |
131625 |
struct OpChecker ock = { gwion->env, &gwion->env->curr->info->op_map, opi, 0 }; |
|
153 |
131625 |
const Vector v = op_vector(gwion->mp, &ock); |
|
154 |
131625 |
const M_Operator* mo = new_mo(gwion->mp, opi); |
|
155 |
131625 |
vector_add(v, (vtype)mo); |
|
156 |
131625 |
return GW_OK; |
|
157 |
} |
||
158 |
|||
159 |
1682 |
ANN static void set_nspc(struct Op_Import *opi, const Nspc nspc) { |
|
160 |
✓✓ | 1682 |
if(opi->op_type == op_implicit) { |
161 |
44 |
struct Implicit* imp = (struct Implicit*)opi->data; |
|
162 |
44 |
imp->e->info->nspc = nspc; |
|
163 |
44 |
return; |
|
164 |
} |
||
165 |
✓✓ | 1638 |
if(opi->op_type == op_array) { |
166 |
28 |
Array_Sub array = (Array_Sub)opi->data; |
|
167 |
28 |
array->exp->info->nspc = nspc; |
|
168 |
28 |
return; |
|
169 |
} |
||
170 |
✓✓ | 1610 |
if(opi->op_type == op_exp) { |
171 |
98 |
((Exp)opi->data)->info->nspc = nspc; |
|
172 |
98 |
return; |
|
173 |
} |
||
174 |
✓✓ | 1512 |
if(opi->op_type != op_scan) |
175 |
1458 |
exp_self((union exp_data*)opi->data)->info->nspc = nspc; |
|
176 |
} |
||
177 |
|||
178 |
2437 |
ANN static inline void set_nonnull(const Type t, const Exp exp) { |
|
179 |
✓✓✓✓ |
2437 |
if(t != OP_ANY_TYPE && GET_FLAG(t, nonnull)) |
180 |
101 |
exp_setnonnull(exp, 1); |
|
181 |
2437 |
} |
|
182 |
|||
183 |
1846 |
ANN static void opi_nonnull(const M_Operator *mo, const struct Op_Import *opi) { |
|
184 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
1846 |
switch(opi->op_type) { |
185 |
56 |
case op_implicit: |
|
186 |
{ |
||
187 |
56 |
const struct Implicit *a = (struct Implicit*)opi->data; |
|
188 |
56 |
set_nonnull(mo->lhs, a->e); |
|
189 |
56 |
break; |
|
190 |
} |
||
191 |
98 |
case op_exp: |
|
192 |
{ |
||
193 |
98 |
const Exp a = (Exp)opi->data; |
|
194 |
98 |
set_nonnull(mo->rhs, a); // rhs ??? |
|
195 |
98 |
break; |
|
196 |
} |
||
197 |
742 |
case op_dot: |
|
198 |
{ |
||
199 |
742 |
const Exp_Dot *a = (Exp_Dot*)opi->data; |
|
200 |
742 |
set_nonnull(mo->lhs, a->base); |
|
201 |
742 |
break; |
|
202 |
} |
||
203 |
33 |
case op_array: |
|
204 |
{ |
||
205 |
33 |
const Array_Sub a = (Array_Sub)opi->data; |
|
206 |
33 |
set_nonnull(mo->lhs, a->exp); |
|
207 |
33 |
break; |
|
208 |
} |
||
209 |
649 |
case op_binary: |
|
210 |
{ |
||
211 |
649 |
const Exp_Binary *a = (Exp_Binary*)opi->data; |
|
212 |
649 |
set_nonnull(mo->lhs, a->lhs); |
|
213 |
649 |
set_nonnull(mo->rhs, a->rhs); |
|
214 |
649 |
break; |
|
215 |
} |
||
216 |
40 |
case op_cast: |
|
217 |
{ |
||
218 |
40 |
const Exp_Cast *a = (Exp_Cast*)opi->data; |
|
219 |
40 |
set_nonnull(mo->lhs, a->exp); |
|
220 |
40 |
break; |
|
221 |
} |
||
222 |
36 |
case op_postfix: |
|
223 |
{ |
||
224 |
36 |
const Exp_Postfix *a = (Exp_Postfix*)opi->data; |
|
225 |
36 |
set_nonnull(mo->lhs, a->exp); |
|
226 |
36 |
break; |
|
227 |
} |
||
228 |
134 |
case op_unary: |
|
229 |
{ |
||
230 |
134 |
const Exp_Unary *a = (Exp_Unary*)opi->data; |
|
231 |
134 |
set_nonnull(mo->rhs, a->exp); |
|
232 |
134 |
break; |
|
233 |
} |
||
234 |
58 |
case op_scan: |
|
235 |
58 |
break; |
|
236 |
} |
||
237 |
1846 |
} |
|
238 |
|||
239 |
2371 |
ANN static Type op_check_inner(struct OpChecker* ock) { |
|
240 |
2371 |
Type t, r = ock->opi->rhs; |
|
241 |
do { |
||
242 |
const M_Operator* mo; |
||
243 |
2989 |
const Vector v = (Vector)map_get(ock->map, (vtype)ock->opi->op); |
|
244 |
✓✓✓✓ |
2989 |
if(v && (mo = operator_find(v, ock->opi->lhs, r))) { |
245 |
1846 |
opi_nonnull(mo, ock->opi); |
|
246 |
✓✓✓✓ |
1846 |
if((mo->ck && (t = mo->ck(ock->env, (void*)ock->opi->data, &ock->mut)))) |
247 |
1496 |
return t; |
|
248 |
else |
||
249 |
350 |
return mo->ret; |
|
250 |
} |
||
251 |
✓✓✓✓ |
1143 |
} while(r && (r = op_parent(ock->env, r))); |
252 |
525 |
return NULL; |
|
253 |
} |
||
254 |
|||
255 |
1845 |
ANN Type op_check(const Env env, struct Op_Import* opi) { |
|
256 |
1845 |
Nspc nspc = env->curr; |
|
257 |
do { |
||
258 |
✓✓ | 7728 |
if(nspc->info->op_map.ptr) { |
259 |
1944 |
Type l = opi->lhs; |
|
260 |
do { |
||
261 |
2371 |
struct Op_Import opi2 = { .op=opi->op, .lhs=l, .rhs=opi->rhs, .data=opi->data, .op_type=opi->op_type }; |
|
262 |
2371 |
struct OpChecker ock = { env, &nspc->info->op_map, &opi2, 0 }; |
|
263 |
2371 |
const Type ret = op_check_inner(&ock); |
|
264 |
✓✓ | 2371 |
if(ret) { |
265 |
✓✓ | 1800 |
if(ret == env->gwion->type[et_null]) |
266 |
50 |
break; |
|
267 |
✓✓ | 1750 |
if(!ock.mut) |
268 |
1682 |
set_nspc(&opi2, nspc); |
|
269 |
1750 |
return ret; |
|
270 |
} |
||
271 |
✓✓✓✓ |
571 |
} while(l && (l = op_parent(env, l))); |
272 |
} |
||
273 |
✓✓ | 5978 |
} while((nspc = nspc->parent)); |
274 |
✓✓✗✓ |
95 |
if(opi->op == insert_symbol(env->gwion->st, "$") && opi->rhs == opi->lhs) |
275 |
return opi->rhs; |
||
276 |
✓✓ | 95 |
if(opi->op != insert_symbol(env->gwion->st, "@implicit")) |
277 |
78 |
env_err(env, opi->pos, _("%s %s %s: no match found for operator"), |
|
278 |
type_name(opi->lhs), s_name(opi->op), type_name(opi->rhs)); |
||
279 |
95 |
return NULL; |
|
280 |
} |
||
281 |
|||
282 |
24 |
ANN m_bool operator_set_func(const struct Op_Import* opi) { |
|
283 |
24 |
const Nspc nspc = ((Func)opi->data)->value_ref->from->owner; |
|
284 |
24 |
const Vector v = (Vector)map_get(&nspc->info->op_map, (vtype)opi->op); |
|
285 |
✗✓ | 24 |
DECL_OB(M_Operator*, mo, = operator_find(v, opi->lhs, opi->rhs)) |
286 |
24 |
mo->func = (Func)opi->data; |
|
287 |
24 |
return GW_OK; |
|
288 |
} |
||
289 |
|||
290 |
619 |
ANN static Instr handle_instr(const Emitter emit, const M_Operator* mo) { |
|
291 |
✓✓ | 619 |
if(mo->func) { |
292 |
✗✓ | 14 |
const Instr push = emit_add_instr(emit, mo->func->code ? RegPushImm : SetFunc); |
293 |
✓✗ | 14 |
push->m_val = ((m_uint)mo->func->code ?:(m_uint)mo->func); |
294 |
14 |
const Instr instr = emit_exp_call1(emit, mo->func); |
|
295 |
✓✓ | 14 |
if(mo->func->def->base->xid == insert_symbol(emit->gwion->st, "@conditionnal")) |
296 |
1 |
return emit_add_instr(emit, BranchEqInt); |
|
297 |
✓✓ | 13 |
if(mo->func->def->base->xid == insert_symbol(emit->gwion->st, "@unconditionnal")) |
298 |
1 |
return emit_add_instr(emit, BranchNeqInt); |
|
299 |
12 |
return instr; |
|
300 |
} |
||
301 |
605 |
return emit_add_instr(emit, mo->instr); |
|
302 |
} |
||
303 |
|||
304 |
1404 |
ANN static Nspc get_nspc(const struct Op_Import* opi) { |
|
305 |
✓✓ | 1404 |
if(opi->op_type == op_implicit) { |
306 |
39 |
struct Implicit* imp = (struct Implicit*)opi->data; |
|
307 |
39 |
return imp->e->info->nspc; |
|
308 |
} |
||
309 |
✓✓ | 1365 |
if(opi->op_type == op_array) { |
310 |
25 |
struct ArrayAccessInfo *info = (struct ArrayAccessInfo*)opi->data; |
|
311 |
25 |
return info->array.exp->info->nspc; |
|
312 |
} |
||
313 |
✓✓ | 1340 |
if(opi->op_type == op_exp) |
314 |
94 |
return ((Exp)opi->data)->info->nspc; |
|
315 |
1246 |
return exp_self((union exp_data*)opi->data)->info->nspc; |
|
316 |
} |
||
317 |
|||
318 |
1404 |
ANN static inline Nspc ensure_nspc(const struct Op_Import* opi) { |
|
319 |
✗✓ | 1404 |
DECL_OO(Nspc, nspc, = get_nspc(opi)) |
320 |
✓✓ | 2823 |
while(!nspc->info->op_map.ptr) |
321 |
15 |
nspc = nspc->parent; |
|
322 |
1404 |
return nspc; |
|
323 |
} |
||
324 |
|||
325 |
1404 |
ANN Instr op_emit(const Emitter emit, const struct Op_Import* opi) { |
|
326 |
✗✓ | 1404 |
DECL_OO(Nspc, nspc, = ensure_nspc(opi)) |
327 |
1404 |
Type l = opi->lhs; |
|
328 |
do { |
||
329 |
1527 |
Type r = opi->rhs; |
|
330 |
do { |
||
331 |
1872 |
const Vector v = (Vector)map_get(&nspc->info->op_map, (vtype)opi->op); |
|
332 |
✗✓ | 1872 |
if(!v) |
333 |
continue; |
||
334 |
1872 |
const M_Operator* mo = operator_find(v, l, r); |
|
335 |
✓✓ | 1872 |
if(mo) { |
336 |
✓✓ | 1404 |
if(mo->em) |
337 |
785 |
return mo->em(emit, (void*)opi->data); |
|
338 |
619 |
return handle_instr(emit, mo); |
|
339 |
} |
||
340 |
✓✗✓✓ |
468 |
} while(r && (r = op_parent(emit->env, r))); |
341 |
✓✗✓✗ |
123 |
} while(l && (l = op_parent(emit->env, l))); |
342 |
return NULL; |
||
343 |
} |
Generated by: GCOVR (Version 4.2) |