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 |