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 |
765 |
ANN void free_op_map(Map map, struct Gwion_ *gwion) { |
|
26 |
LOOP_OPTIM |
||
27 |
✓✓ | 38763 |
for(m_uint i = map_size(map) + 1; --i;) { |
28 |
37233 |
const restrict Vector v = (Vector)map_at(map, (vtype)i - 1); |
|
29 |
LOOP_OPTIM |
||
30 |
✓✓ | 207958 |
for(m_uint j = vector_size(v) + 1; --j;) |
31 |
133492 |
mp_free(gwion->mp, M_Operator, (M_Operator*)vector_at(v, j - 1)); |
|
32 |
37233 |
free_vector(gwion->mp, v); |
|
33 |
} |
||
34 |
765 |
map_release(map); |
|
35 |
765 |
} |
|
36 |
|||
37 |
1949 |
ANN static Type op_parent(const Env env, const Type t) { |
|
38 |
✓✓✓✓ |
1949 |
if(GET_FLAG(t, template) && GET_FLAG(t, ref)) { |
39 |
40 |
const Type type = typedef_base(t); |
|
40 |
40 |
const m_str post = strrchr(type->name, '>') + 1; |
|
41 |
40 |
return nspc_lookup_type1(env->curr, insert_symbol(env->gwion->st, post)); |
|
42 |
} |
||
43 |
1909 |
return t->e->parent; |
|
44 |
} |
||
45 |
|||
46 |
25644 |
static m_bool op_match(const restrict Type t, const restrict Type mo) { |
|
47 |
✓✗✓✓ |
25644 |
if(t == OP_ANY_TYPE || mo == OP_ANY_TYPE) |
48 |
3763 |
return GW_OK; |
|
49 |
21881 |
Type type = t; |
|
50 |
✓✓✓✓ ✓✗✓✗ ✓✓ |
21881 |
while(SAFE_FLAG(type, template) && type->e->def && type->e->def->base.tmpl && type->e->def->base.tmpl->call) type = type->e->parent; |
51 |
✓✓✓✓ ✓✓✓✓ ✓✓ |
21881 |
if((type && mo && mo->xid == type->xid) || (!type && !mo)) |
52 |
5718 |
return GW_OK; |
|
53 |
16163 |
return 0; |
|
54 |
} |
||
55 |
|||
56 |
4626 |
ANN2(1) static M_Operator* operator_find(const Vector v, const restrict Type lhs, const restrict Type rhs) { |
|
57 |
✓✓ | 25417 |
for(m_uint i = vector_size(v) + 1; --i;) { |
58 |
19409 |
M_Operator* mo = (M_Operator*)vector_at(v, i - 1); |
|
59 |
✓✓ | 19409 |
if(!mo) |
60 |
2 |
continue; |
|
61 |
✓✓✓✓ |
19407 |
if(op_match(lhs, mo->lhs) && op_match(rhs, mo->rhs)) |
62 |
3244 |
return mo; |
|
63 |
} |
||
64 |
1382 |
return NULL; |
|
65 |
} |
||
66 |
|||
67 |
404056 |
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 |
✓✓✓✓ ✓✓✓✓ ✓✓✓✓ ✓✓ |
404056 |
if((t && mo && (t != OP_ANY_TYPE && mo != OP_ANY_TYPE && mo->xid == t->xid)) || (!t && !mo)) |
71 |
63699 |
return GW_OK; |
|
72 |
340357 |
return 0; |
|
73 |
} |
||
74 |
|||
75 |
96474 |
ANN2(1) static M_Operator* operator_find2(const Vector v, const restrict Type lhs, const restrict Type rhs) { |
|
76 |
✓✓ | 533304 |
for(m_uint i = vector_size(v) + 1; --i;) { |
77 |
340357 |
M_Operator* mo = (M_Operator*)vector_at(v, i - 1); |
|
78 |
✓✓✓✓ |
340357 |
if(op_match2(lhs, mo->lhs) && op_match2(rhs, mo->rhs)) |
79 |
1 |
return mo; |
|
80 |
} |
||
81 |
96473 |
return NULL; |
|
82 |
} |
||
83 |
|||
84 |
19 |
ANN void operator_suspend(const Nspc n, struct Op_Import *opi) { |
|
85 |
19 |
const Vector v = (Vector)map_get(&n->info->op_map, (vtype)opi->op); |
|
86 |
✓✗ | 39 |
for(m_uint i = vector_size(v) + 1; --i;) { |
87 |
20 |
M_Operator* mo = (M_Operator*)vector_at(v, i - 1); |
|
88 |
✓✗✓✓ |
20 |
if(op_match2(opi->lhs, mo->lhs) && op_match2(opi->rhs, mo->rhs)) { |
89 |
19 |
opi->data = (uintptr_t)mo; |
|
90 |
19 |
opi->ret = (Type)&VPTR(v, i-1); |
|
91 |
19 |
VPTR(v, i-1) = 0; |
|
92 |
19 |
break; |
|
93 |
} |
||
94 |
} |
||
95 |
19 |
} |
|
96 |
|||
97 |
133675 |
ANN static M_Operator* new_mo(MemPool p, const struct Op_Import* opi) { |
|
98 |
133675 |
M_Operator* mo = mp_calloc(p, M_Operator); |
|
99 |
133675 |
mo->lhs = opi->lhs; |
|
100 |
133675 |
mo->rhs = opi->rhs; |
|
101 |
133675 |
mo->ret = opi->ret; |
|
102 |
133675 |
mo->instr = (f_instr)opi->data; |
|
103 |
✓✗ | 133675 |
if(opi->func) { |
104 |
133675 |
mo->ck = opi->func->ck; |
|
105 |
133675 |
mo->em = opi->func->em; |
|
106 |
} |
||
107 |
133675 |
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 |
133675 |
ANN static Vector op_vector(MemPool p, const struct OpChecker *ock) { |
|
119 |
133675 |
const Vector exist = (Vector)map_get(ock->map, (vtype)ock->opi->op); |
|
120 |
✓✓ | 133675 |
if(exist) |
121 |
96391 |
return exist; |
|
122 |
37284 |
const Vector create = new_vector(p); |
|
123 |
37284 |
map_set(ock->map, (vtype)ock->opi->op, (vtype)create); |
|
124 |
37284 |
return create; |
|
125 |
} |
||
126 |
|||
127 |
154 |
static m_str type_name(const Type t) { |
|
128 |
✓✓✓✗ |
154 |
return t ? t == OP_ANY_TYPE ? "any" : t->name : ""; |
129 |
} |
||
130 |
|||
131 |
133001 |
ANN static m_bool _op_exist(const struct OpChecker* ock, const Nspc n) { |
|
132 |
133001 |
const Vector v = (Vector)map_get(&n->info->op_map, (vtype)ock->opi->op); |
|
133 |
✓✓✓✓ |
133001 |
if(!v || !operator_find2(v, ock->opi->lhs, ock->opi->rhs)) |
134 |
133000 |
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 |
133933 |
ANN static m_bool op_exist(const struct OpChecker* ock, const Nspc n) { |
|
141 |
✓✓ | 133933 |
return n->info->op_map.ptr ? _op_exist(ock, n) : GW_OK; |
142 |
} |
||
143 |
|||
144 |
133676 |
ANN m_bool add_op(const Gwion gwion, const struct Op_Import* opi) { |
|
145 |
133676 |
Nspc n = gwion->env->curr; |
|
146 |
do { |
||
147 |
133933 |
struct OpChecker ock = { gwion->env, &n->info->op_map, opi, 0 }; |
|
148 |
✓✓ | 133933 |
CHECK_BB(op_exist(&ock, n)) |
149 |
✓✓ | 133932 |
} while((n = n->parent)); |
150 |
✓✓ | 133675 |
if(!gwion->env->curr->info->op_map.ptr) |
151 |
766 |
map_init(&gwion->env->curr->info->op_map); |
|
152 |
133675 |
struct OpChecker ock = { gwion->env, &gwion->env->curr->info->op_map, opi, 0 }; |
|
153 |
133675 |
const Vector v = op_vector(gwion->mp, &ock); |
|
154 |
133675 |
const M_Operator* mo = new_mo(gwion->mp, opi); |
|
155 |
133675 |
vector_add(v, (vtype)mo); |
|
156 |
133675 |
return GW_OK; |
|
157 |
} |
||
158 |
|||
159 |
1657 |
ANN static void set_nspc(struct Op_Import *opi, const Nspc nspc) { |
|
160 |
✓✓ | 1657 |
if(opi->op_type == op_implicit) { |
161 |
39 |
struct Implicit* imp = (struct Implicit*)opi->data; |
|
162 |
39 |
imp->e->info->nspc = nspc; |
|
163 |
39 |
return; |
|
164 |
} |
||
165 |
✓✓ | 1618 |
if(opi->op_type == op_array) { |
166 |
26 |
Array_Sub array = (Array_Sub)opi->data; |
|
167 |
26 |
array->exp->info->nspc = nspc; |
|
168 |
26 |
return; |
|
169 |
} |
||
170 |
✓✓ | 1592 |
if(opi->op_type == op_exp) { |
171 |
93 |
((Exp)opi->data)->info->nspc = nspc; |
|
172 |
93 |
return; |
|
173 |
} |
||
174 |
✓✓ | 1499 |
if(opi->op_type != op_scan) |
175 |
1432 |
exp_self((union exp_data*)opi->data)->info->nspc = nspc; |
|
176 |
} |
||
177 |
|||
178 |
2433 |
ANN static inline void set_nonnull(const Type t, const Exp exp) { |
|
179 |
✓✓✓✓ |
2433 |
if(t != OP_ANY_TYPE && GET_FLAG(t, nonnull)) |
180 |
97 |
exp_setnonnull(exp, 1); |
|
181 |
2433 |
} |
|
182 |
|||
183 |
1835 |
ANN static void opi_nonnull(const M_Operator *mo, const struct Op_Import *opi) { |
|
184 |
✓✓✓✓ ✓✓✓✓ ✓✗ |
1835 |
switch(opi->op_type) { |
185 |
49 |
case op_implicit: |
|
186 |
{ |
||
187 |
49 |
const struct Implicit *a = (struct Implicit*)opi->data; |
|
188 |
49 |
set_nonnull(mo->lhs, a->e); |
|
189 |
49 |
break; |
|
190 |
} |
||
191 |
93 |
case op_exp: |
|
192 |
{ |
||
193 |
93 |
const Exp a = (Exp)opi->data; |
|
194 |
93 |
set_nonnull(mo->rhs, a); // rhs ??? |
|
195 |
93 |
break; |
|
196 |
} |
||
197 |
717 |
case op_dot: |
|
198 |
{ |
||
199 |
717 |
const Exp_Dot *a = (Exp_Dot*)opi->data; |
|
200 |
717 |
set_nonnull(mo->lhs, a->base); |
|
201 |
717 |
break; |
|
202 |
} |
||
203 |
29 |
case op_array: |
|
204 |
{ |
||
205 |
29 |
const Array_Sub a = (Array_Sub)opi->data; |
|
206 |
29 |
set_nonnull(mo->lhs, a->exp); |
|
207 |
29 |
break; |
|
208 |
} |
||
209 |
668 |
case op_binary: |
|
210 |
{ |
||
211 |
668 |
const Exp_Binary *a = (Exp_Binary*)opi->data; |
|
212 |
668 |
set_nonnull(mo->lhs, a->lhs); |
|
213 |
668 |
set_nonnull(mo->rhs, a->rhs); |
|
214 |
668 |
break; |
|
215 |
} |
||
216 |
35 |
case op_cast: |
|
217 |
{ |
||
218 |
35 |
const Exp_Cast *a = (Exp_Cast*)opi->data; |
|
219 |
35 |
set_nonnull(mo->lhs, a->exp); |
|
220 |
35 |
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 |
138 |
case op_unary: |
|
229 |
{ |
||
230 |
138 |
const Exp_Unary *a = (Exp_Unary*)opi->data; |
|
231 |
138 |
set_nonnull(mo->rhs, a->exp); |
|
232 |
138 |
break; |
|
233 |
} |
||
234 |
70 |
case op_scan: |
|
235 |
70 |
break; |
|
236 |
} |
||
237 |
1835 |
} |
|
238 |
|||
239 |
2344 |
ANN static Type op_check_inner(struct OpChecker* ock) { |
|
240 |
2344 |
Type t, r = ock->opi->rhs; |
|
241 |
do { |
||
242 |
const M_Operator* mo; |
||
243 |
2945 |
const Vector v = (Vector)map_get(ock->map, (vtype)ock->opi->op); |
|
244 |
✓✓✓✓ |
2945 |
if(v && (mo = operator_find(v, ock->opi->lhs, r))) { |
245 |
1835 |
opi_nonnull(mo, ock->opi); |
|
246 |
✓✓✓✓ |
1835 |
if((mo->ck && (t = mo->ck(ock->env, (void*)ock->opi->data, &ock->mut)))) |
247 |
1450 |
return t; |
|
248 |
else |
||
249 |
385 |
return mo->ret; |
|
250 |
} |
||
251 |
✓✓✓✓ |
1110 |
} while(r && (r = op_parent(ock->env, r))); |
252 |
509 |
return NULL; |
|
253 |
} |
||
254 |
|||
255 |
1820 |
ANN Type op_check(const Env env, struct Op_Import* opi) { |
|
256 |
1820 |
Nspc nspc = env->curr; |
|
257 |
do { |
||
258 |
✓✓ | 7604 |
if(nspc->info->op_map.ptr) { |
259 |
1906 |
Type l = opi->lhs; |
|
260 |
do { |
||
261 |
2344 |
struct Op_Import opi2 = { .op=opi->op, .lhs=l, .rhs=opi->rhs, .data=opi->data, .op_type=opi->op_type }; |
|
262 |
2344 |
struct OpChecker ock = { env, &nspc->info->op_map, &opi2, 0 }; |
|
263 |
2344 |
const Type ret = op_check_inner(&ock); |
|
264 |
✓✓ | 2344 |
if(ret) { |
265 |
✓✓ | 1772 |
if(ret == env->gwion->type[et_null]) |
266 |
45 |
break; |
|
267 |
✓✓ | 1727 |
if(!ock.mut) |
268 |
1657 |
set_nspc(&opi2, nspc); |
|
269 |
1727 |
return ret; |
|
270 |
} |
||
271 |
✓✓✓✓ |
572 |
} while(l && (l = op_parent(env, l))); |
272 |
} |
||
273 |
✓✓ | 5877 |
} while((nspc = nspc->parent)); |
274 |
✓✓✓✓ |
93 |
if(opi->op == insert_symbol(env->gwion->st, "$") && opi->rhs == opi->lhs) |
275 |
2 |
return opi->rhs; |
|
276 |
✓✓ | 91 |
if(opi->op != insert_symbol(env->gwion->st, "@implicit")) |
277 |
76 |
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 |
91 |
return NULL; |
|
280 |
} |
||
281 |
|||
282 |
19 |
ANN m_bool operator_set_func(const struct Op_Import* opi) { |
|
283 |
19 |
const Nspc nspc = ((Func)opi->data)->value_ref->from->owner; |
|
284 |
19 |
const Vector v = (Vector)map_get(&nspc->info->op_map, (vtype)opi->op); |
|
285 |
✗✓ | 19 |
DECL_OB(M_Operator*, mo, = operator_find(v, opi->lhs, opi->rhs)) |
286 |
19 |
mo->func = (Func)opi->data; |
|
287 |
19 |
return GW_OK; |
|
288 |
} |
||
289 |
|||
290 |
650 |
ANN static Instr handle_instr(const Emitter emit, const M_Operator* mo) { |
|
291 |
✓✓ | 650 |
if(mo->func) { |
292 |
✗✓ | 9 |
const Instr push = emit_add_instr(emit, mo->func->code ? RegPushImm : SetFunc); |
293 |
✓✗ | 9 |
push->m_val = ((m_uint)mo->func->code ?:(m_uint)mo->func); |
294 |
9 |
const Instr instr = emit_exp_call1(emit, mo->func); |
|
295 |
✓✓ | 9 |
if(mo->func->def->base->xid == insert_symbol(emit->gwion->st, "@conditionnal")) |
296 |
1 |
return emit_add_instr(emit, BranchEqInt); |
|
297 |
✓✓ | 8 |
if(mo->func->def->base->xid == insert_symbol(emit->gwion->st, "@unconditionnal")) |
298 |
1 |
return emit_add_instr(emit, BranchNeqInt); |
|
299 |
7 |
return instr; |
|
300 |
} |
||
301 |
641 |
return emit_add_instr(emit, mo->instr); |
|
302 |
} |
||
303 |
|||
304 |
1391 |
ANN static Nspc get_nspc(const struct Op_Import* opi) { |
|
305 |
✓✓ | 1391 |
if(opi->op_type == op_implicit) { |
306 |
34 |
struct Implicit* imp = (struct Implicit*)opi->data; |
|
307 |
34 |
return imp->e->info->nspc; |
|
308 |
} |
||
309 |
✓✓ | 1357 |
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 |
✓✓ | 1332 |
if(opi->op_type == op_exp) |
314 |
90 |
return ((Exp)opi->data)->info->nspc; |
|
315 |
1242 |
return exp_self((union exp_data*)opi->data)->info->nspc; |
|
316 |
} |
||
317 |
|||
318 |
1391 |
ANN static inline Nspc ensure_nspc(const struct Op_Import* opi) { |
|
319 |
✓✓ | 1391 |
DECL_OO(Nspc, nspc, = get_nspc(opi)) |
320 |
✓✓ | 2795 |
while(!nspc->info->op_map.ptr) |
321 |
15 |
nspc = nspc->parent; |
|
322 |
1390 |
return nspc; |
|
323 |
} |
||
324 |
|||
325 |
1391 |
ANN Instr op_emit(const Emitter emit, const struct Op_Import* opi) { |
|
326 |
✓✓ | 1391 |
DECL_OO(Nspc, nspc, = ensure_nspc(opi)) |
327 |
1390 |
Type l = opi->lhs; |
|
328 |
do { |
||
329 |
1509 |
Type r = opi->rhs; |
|
330 |
do { |
||
331 |
1831 |
const Vector v = (Vector)map_get(&nspc->info->op_map, (vtype)opi->op); |
|
332 |
✗✓ | 1831 |
if(!v) |
333 |
continue; |
||
334 |
1831 |
const M_Operator* mo = operator_find(v, l, r); |
|
335 |
✓✓ | 1831 |
if(mo) { |
336 |
✓✓ | 1390 |
if(mo->em) |
337 |
740 |
return mo->em(emit, (void*)opi->data); |
|
338 |
650 |
return handle_instr(emit, mo); |
|
339 |
} |
||
340 |
✓✗✓✓ |
441 |
} while(r && (r = op_parent(emit->env, r))); |
341 |
✓✗✓✗ |
119 |
} while(l && (l = op_parent(emit->env, l))); |
342 |
return NULL; |
||
343 |
} |
Generated by: GCOVR (Version 4.2) |