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