Line | Branch | Exec | Source |
---|---|---|---|
1 | #include "gwion_util.h" | ||
2 | #include "gwion_ast.h" | ||
3 | #include "gwion_env.h" | ||
4 | #include "vm.h" | ||
5 | #include "gwion.h" | ||
6 | #include "instr.h" | ||
7 | #include "emit.h" | ||
8 | #include "object.h" | ||
9 | #include "operator.h" | ||
10 | #include "import.h" | ||
11 | #include "traverse.h" | ||
12 | #include "template.h" | ||
13 | #include "parse.h" | ||
14 | #include "partial.h" | ||
15 | #include "gack.h" | ||
16 | #include "tmp_resolve.h" | ||
17 | |||
18 | 3 | ANN static Exp uncurry(const Env env, const Exp_Binary *bin) { | |
19 | 3 | const Stmt stmt = mp_vector_at(bin->rhs->type->info->func->def->d.code, struct Stmt_, 0); | |
20 | 3 | const Exp ecall = stmt->d.stmt_exp.val; | |
21 | 3 | const Exp_Call *call = &ecall->d.exp_call; | |
22 | 3 | Exp args = call->args; | |
23 | 3 | Exp lhs = bin->lhs; | |
24 | 3 | Exp base = NULL, tmp = NULL; | |
25 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
|
10 | while(args) { |
26 |
4/6✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
|
7 | if(args->exp_type != ae_exp_primary || args->d.prim.prim_type != ae_prim_id || *s_name(args->d.prim.d.var) != '@') { |
27 | 3 | const Exp next = args->next; | |
28 | 3 | args->next = NULL; | |
29 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if(tmp) tmp = (tmp->next = cpy_exp(env->gwion->mp, args)); |
30 | 1 | else base = (tmp = cpy_exp(env->gwion->mp, args)); | |
31 | 3 | args->next = next; | |
32 | } else { | ||
33 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if(!lhs) { |
34 | ✗ | free_exp(env->gwion->mp, base); | |
35 | ✗ | return NULL; | |
36 | } | ||
37 | 4 | const Exp next = lhs->next; | |
38 | 4 | lhs->next = NULL; | |
39 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if(tmp) tmp = (tmp->next = cpy_exp(env->gwion->mp, lhs)); |
40 | 2 | else base = (tmp = cpy_exp(env->gwion->mp, lhs)); | |
41 | 4 | lhs = lhs->next = next; | |
42 | } | ||
43 | 7 | args = args->next; | |
44 | } | ||
45 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if(traverse_exp(env, base) > 0) { |
46 | 3 | free_exp(env->gwion->mp, bin->lhs); | |
47 | 3 | return base; | |
48 | } | ||
49 | ✗ | free_exp(env->gwion->mp, base); | |
50 | ✗ | return NULL; | |
51 | } | ||
52 | |||
53 | 54 | ANN static Type mk_call(const Env env, const Exp e, const Exp func, const Exp args) { | |
54 | 54 | Exp_Call call = {.func = func, .args = args }; | |
55 | 54 | e->exp_type = ae_exp_call; | |
56 | 54 | e->d.exp_call = call; | |
57 |
2/2✓ Branch 1 taken 50 times.
✓ Branch 2 taken 4 times.
|
54 | return check_exp_call1(env, &e->d.exp_call) ?: env->gwion->type[et_error]; |
58 | } | ||
59 | |||
60 | 53 | static OP_CHECK(opck_func_call) { | |
61 | 53 | Exp_Binary *bin = (Exp_Binary *)data; | |
62 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 50 times.
|
53 | if(!strncmp(bin->rhs->type->name, "partial:", 8)) { |
63 | 3 | const Stmt stmt = mp_vector_at(bin->rhs->type->info->func->def->d.code, struct Stmt_, 0); | |
64 | 3 | const Exp_Call *call = &stmt->d.stmt_exp.val->d.exp_call; | |
65 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | DECL_ON(const Exp, args, = uncurry(env, bin)); |
66 | 3 | return mk_call(env, exp_self(bin), call->func, args); | |
67 | } | ||
68 | 50 | return mk_call(env, exp_self(bin), bin->rhs, bin->lhs); | |
69 | } | ||
70 | |||
71 | 1 | static OP_CHECK(opck_fptr_call) { | |
72 | 1 | Exp_Binary *bin = (Exp_Binary *)data; | |
73 | 1 | const Type t = mk_call(env, exp_self(bin), bin->rhs, bin->lhs); | |
74 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (t == env->gwion->type[et_error]) |
75 | ✗ | gw_err("{-}did you mean to use {0}{+}:=>{0}{-}?{0}\n"); | |
76 | 1 | return t; | |
77 | } | ||
78 | |||
79 | 3 | ANN Type upvalue_type(const Env env, Capture *cap) { | |
80 | 3 | const Value v = nspc_lookup_value1(env->curr, cap->xid); | |
81 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if(!v) ERR_O(cap->pos, _("non existing value")); // did_you_mean |
82 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
|
3 | if(cap->is_ref && not_upvalue(env, v)) |
83 | 1 | ERR_O(cap->pos, _("can't take ref of a scoped value")); | |
84 | 2 | cap->orig = v; | |
85 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
|
2 | const Type base_type = !tflag(v->type, tflag_ref) ? v->type : (Type)vector_front(&v->type->info->tuple->contains); |
86 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | return !cap->is_ref ? base_type : ref_type(env->gwion, base_type, cap->pos); |
87 | } | ||
88 | |||
89 | ✗ | ANN void free_captures(const VM_Shred shred, m_bit *const caps) { | |
90 | ✗ | uint32_t sz = SZ_INT; | |
91 | ✗ | const Capture_List captures = (*(Func_Def*)caps)->captures; | |
92 | ✗ | for(m_uint i = 0; i < captures->len; i++) { | |
93 | ✗ | Capture *const cap = mp_vector_at(captures, Capture, i); | |
94 | ✗ | if(tflag(cap->temp->type, tflag_compound)) | |
95 | ✗ | compound_release(shred, cap->temp->type, caps + sz); | |
96 | ✗ | sz += cap->temp->type->size; | |
97 | } | ||
98 | ✗ | mp_free2(shred->info->mp, sz, caps); | |
99 | } | ||
100 | |||
101 | ✗ | static INSTR(fptr_capture) { | |
102 | ✗ | POP_REG(shred, instr->m_val); | |
103 | ✗ | const M_Object o = *(M_Object*)REG(-SZ_INT); | |
104 | ✗ | m_bit *caps = mp_malloc2(shred->info->mp, SZ_INT + instr->m_val); | |
105 | ✗ | memcpy(caps + SZ_INT, REG(0), instr->m_val); | |
106 | ✗ | *(Func_Def*)caps = (Func_Def)instr->m_val2; | |
107 | ✗ | *(m_bit**)(o->data + SZ_INT) = caps; | |
108 | } | ||
109 | |||
110 | 36 | static INSTR(fptr_assign) { | |
111 | 36 | POP_REG(shred, SZ_INT); | |
112 | 36 | const M_Object o = *(M_Object*)REG(0); | |
113 | 36 | *(VM_Code*)(o->data + instr->m_val) = *(VM_Code*)REG(-SZ_INT); | |
114 | 36 | m_bit *old_caps = *(m_bit**)(o->data + SZ_INT); | |
115 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
|
36 | if(old_caps) free_captures(shred, old_caps); |
116 | 36 | *(VM_Code*)(o->data + instr->m_val + SZ_INT) = NULL; | |
117 | 36 | *(M_Object*)REG(-SZ_INT) = o; | |
118 | 36 | } | |
119 | |||
120 | 37 | ANN static m_bool emit_fptr_assign(const Emitter emit, const Type lhs, const Type rhs) { | |
121 | 37 | const Instr instr = emit_add_instr(emit, fptr_assign); | |
122 |
3/4✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 35 times.
|
37 | if(rhs->info->cdef && rhs->info->cdef->base.tmpl) |
123 | ✗ | instr->m_val = SZ_INT * 2; | |
124 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if(!lhs->info->func) { |
125 | ✗ | const Func_Def fdef = lhs->info->func->def; | |
126 | ✗ | const Capture_List captures = fdef->captures; | |
127 | ✗ | if(captures) { | |
128 | ✗ | uint32_t offset = 0; | |
129 | ✗ | Exp e = new_prim_id(emit->gwion->mp, fdef->base->xid, fdef->base->pos); // free me | |
130 | ✗ | for(uint32_t i = 0; i < captures->len; i++) { | |
131 | ✗ | Capture *const cap = mp_vector_at(captures, Capture, i); | |
132 | ✗ | e->d.prim.d.var = cap->xid; | |
133 | ✗ | e->d.prim.value = cap->orig; | |
134 | ✗ | e->type = cap->orig->type; | |
135 | ✗ | exp_setvar(e, cap->is_ref); | |
136 | ✗ | CHECK_BB(emit_exp(emit, e)); | |
137 | ✗ | if(!cap->is_ref && tflag(cap->temp->type, tflag_compound)) | |
138 | ✗ | emit_compound_addref(emit, cap->temp->type, cap->temp->type->size, 0); | |
139 | ✗ | offset += cap->temp->type->size; | |
140 | } | ||
141 | ✗ | free_exp(emit->gwion->mp, e); | |
142 | ✗ | const Instr instr = emit_add_instr(emit, fptr_capture); | |
143 | ✗ | instr->m_val = offset; | |
144 | ✗ | instr->m_val2 = (m_uint)fdef; | |
145 | } | ||
146 | } | ||
147 | 37 | return GW_OK; | |
148 | } | ||
149 | |||
150 | 31 | static OP_EMIT(opem_fptr_assign) { | |
151 | 31 | Exp_Binary *bin = (Exp_Binary*)data; | |
152 | 31 | return emit_fptr_assign(emit, bin->lhs->type, bin->rhs->type); | |
153 | } | ||
154 | |||
155 | |||
156 | struct FptrInfo { | ||
157 | Func lhs; | ||
158 | const Func rhs; | ||
159 | const Exp exp; | ||
160 | }; | ||
161 | |||
162 | 11 | ANN static void _fptr_tmpl_push(const Env env, const Func f) { | |
163 | 11 | const Tmpl *tmpl = f->def->base->tmpl; | |
164 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (!tmpl) return; |
165 | 11 | Type_List tl = tmpl->call; | |
166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (!tl) return; |
167 | 11 | Specialized_List sl = tmpl->list; | |
168 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 11 times.
|
22 | for(uint32_t i = 0; i < sl->len; i++) { |
169 | 11 | Specialized *spec = mp_vector_at(sl, Specialized, i); | |
170 | 11 | Type_Decl *td = *mp_vector_at(tl, Type_Decl*, i); | |
171 | 11 | const Type t = known_type(env, td); | |
172 | 11 | nspc_add_type(env->curr, spec->xid, t); | |
173 | } | ||
174 | } | ||
175 | |||
176 | 52 | ANN static m_bool fptr_tmpl_push(const Env env, struct FptrInfo *info) { | |
177 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 11 times.
|
52 | if (!info->rhs->def->base->tmpl) return GW_OK; |
178 | 11 | nspc_push_type(env->gwion->mp, env->curr); | |
179 | 11 | _fptr_tmpl_push(env, info->rhs); | |
180 | 11 | return GW_OK; | |
181 | } | ||
182 | |||
183 | 52 | static m_bool td_match(const Env env, Type_Decl *id[2]) { | |
184 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
|
52 | DECL_OB(const Type, t0, = known_type(env, id[0])); |
185 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
|
52 | DECL_OB(const Type, t1, = known_type(env, id[1])); |
186 |
1/2✓ Branch 0 taken 52 times.
✗ Branch 1 not taken.
|
52 | if (isa(t0, t1) > 0) return GW_OK; |
187 | ✗ | return t1 == env->gwion->type[et_auto] ? GW_OK : GW_ERROR; | |
188 | } | ||
189 | |||
190 | 52 | ANN static m_bool fptr_args(const Env env, Func_Base *base[2]) { | |
191 | 52 | Arg_List args0 = base[0]->args, args1 = base[1]->args; | |
192 | 52 | const bool member = vflag(base[0]->func->value_ref, vflag_member); | |
193 | 52 | const uint32_t len0 = mp_vector_len(args0) + member; | |
194 | 52 | const uint32_t len1 = mp_vector_len(args1); | |
195 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 40 times.
|
52 | if(len0 != len1) return GW_ERROR; |
196 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 22 times.
|
40 | if(member) { |
197 | 18 | const Arg *arg = mp_vector_at(args1, Arg, 0); | |
198 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | CHECK_BB(isa(base[0]->func->value_ref->from->owner_class, arg->type)); |
199 | } | ||
200 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 40 times.
|
58 | for(uint32_t i = member; i < len0; i++) { |
201 | 18 | const Arg *arg0 = mp_vector_at(args0, Arg, (i - member)); | |
202 | 18 | const Arg *arg1 = mp_vector_at(args1, Arg, i); | |
203 |
2/4✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | if (arg0->type && arg1->type) |
204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
|
18 | CHECK_BB(isa(arg0->type, arg1->type)); |
205 | ✗ | else if(!tmpl_base(base[0]->tmpl) && !tmpl_base(base[1]->tmpl)){ | |
206 | ✗ | Type_Decl *td[2] = {arg0->td, arg1->td}; | |
207 | ✗ | CHECK_BB(td_match(env, td)); | |
208 | } | ||
209 | } | ||
210 | 40 | return GW_OK; | |
211 | } | ||
212 | |||
213 | 40 | ANN static bool fptr_effects(const Env env, struct FptrInfo *info) { | |
214 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1 times.
|
40 | if (!info->lhs->def->base->effects.ptr) return true; |
215 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!info->rhs->def->base->effects.ptr) { |
216 | 1 | gwerr_secondary("too many effects", env->name, info->exp->pos); | |
217 | 1 | return false; | |
218 | } | ||
219 | ✗ | const Vector lhs = &info->lhs->def->base->effects; | |
220 | ✗ | const Vector rhs = &info->rhs->def->base->effects; | |
221 | ✗ | for (m_uint i = 0; i < vector_size(lhs); i++) { | |
222 | ✗ | if (vector_find(rhs, vector_at(lhs, 0)) == -1) { | |
223 | ✗ | gwerr_secondary("effect not handled", env->name, info->exp->pos); | |
224 | ✗ | return false; | |
225 | } | ||
226 | } | ||
227 | ✗ | return true; | |
228 | } | ||
229 | |||
230 | 47 | ANN static m_bool fptr_check(const Env env, struct FptrInfo *info) { | |
231 | // if(!info->lhs->def->base->tmpl != !info->rhs->def->base->tmpl) | ||
232 | // return GW_ERROR; | ||
233 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
|
47 | if(!info->lhs) |
234 | ✗ | ERR_B(info->exp->pos, | |
235 | _("can't resolve operator")) | ||
236 | 47 | return GW_OK; | |
237 | } | ||
238 | |||
239 | 52 | ANN static inline m_bool fptr_rettype(const Env env, struct FptrInfo *info) { | |
240 | 52 | Type_Decl *td[2] = {info->lhs->def->base->td, info->rhs->def->base->td}; | |
241 | 52 | return td_match(env, td); | |
242 | } | ||
243 | |||
244 | 47 | ANN static Type fptr_type(const Env env, struct FptrInfo *info) { | |
245 | 47 | const Value v = info->lhs->value_ref; | |
246 | 47 | const Nspc nspc = v->from->owner; | |
247 | 47 | const m_str c = s_name(info->lhs->def->base->xid), | |
248 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 36 times.
|
47 | stmpl = !info->rhs->def->base->tmpl ? NULL : "template"; |
249 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 8 times.
|
60 | for (m_uint i = 0; i <= v->from->offset; ++i) { |
250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | const Symbol sym = (!info->lhs->def->base->tmpl || i != 0) |
251 | 43 | ? func_symbol(env, nspc->name, c, stmpl, i) | |
252 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 43 times.
|
61 | : info->lhs->def->base->xid; |
253 |
1/2✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
|
52 | if (!is_class(env->gwion, info->lhs->value_ref->type)) { |
254 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 41 times.
|
52 | if (!(info->lhs = nspc_lookup_func1(nspc, sym))) { |
255 | 11 | const Value v = nspc_lookup_value1(nspc, insert_symbol(c)); | |
256 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
|
50 | if (!is_func(env->gwion, v->type)) return NULL; // is_callable |
257 | 11 | info->lhs = v->type->info->func; | |
258 | } | ||
259 | } else { | ||
260 | ✗ | DECL_OO(const Type, t, | |
261 | = nspc_lookup_type1(nspc, info->lhs->def->base->xid)); | ||
262 | ✗ | info->lhs = actual_type(env->gwion, t)->info->func; | |
263 | } | ||
264 | 52 | Type type = NULL; | |
265 | 52 | Func_Base *base[2] = {info->lhs->def->base, info->rhs->def->base}; | |
266 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
|
52 | CHECK_BO(fptr_tmpl_push(env, info)); |
267 |
3/4✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 40 times.
✓ Branch 4 taken 12 times.
|
104 | if (fptr_rettype(env, info) > 0 && |
268 |
2/2✓ Branch 2 taken 39 times.
✓ Branch 3 taken 1 times.
|
92 | fptr_args(env, base) > 0 && fptr_effects(env, info)) |
269 | 78 | type = actual_type(env->gwion, info->lhs->value_ref->type) | |
270 |
1/2✓ Branch 0 taken 39 times.
✗ Branch 1 not taken.
|
39 | ?: info->lhs->value_ref->type; |
271 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 41 times.
|
52 | if (info->rhs->def->base->tmpl) nspc_pop_type(env->gwion->mp, env->curr); |
272 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 13 times.
|
52 | if (type) return type; |
273 | } | ||
274 | 8 | return NULL; | |
275 | } | ||
276 | |||
277 | 9 | ANN static m_bool _check_lambda(const Env env, Exp_Lambda *l, | |
278 | const Func_Def fdef) { | ||
279 | 9 | Arg_List bases = fdef->base->args; | |
280 | 9 | Arg_List args = l->def->base->args; | |
281 |
2/2✓ Branch 2 taken 5 times.
✓ Branch 3 taken 4 times.
|
9 | if (mp_vector_len(bases) != mp_vector_len(args)) |
282 | 5 | ERR_B(exp_self(l)->pos, _("argument number does not match for lambda")) | |
283 | |||
284 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if(l->def->captures) { |
285 | // here move to arguments | ||
286 | ✗ | for(uint32_t i = 0; i < l->def->captures->len; i++) { | |
287 | ✗ | Capture *cap = mp_vector_at(l->def->captures, Capture, i); | |
288 | ✗ | const Value v = nspc_lookup_value1(env->curr, cap->xid); | |
289 | ✗ | if(!v) ERR_B(cap->pos, _("unknown value in capture")); | |
290 | ✗ | DECL_OB(const Type, t, = upvalue_type(env, cap)); | |
291 | ✗ | cap->temp = new_value(env, t, s_name(cap->xid), cap->pos); | |
292 | ✗ | cap->orig = v; | |
293 | } | ||
294 | } | ||
295 | |||
296 | 4 | Type owner = fdef->base->func->value_ref->from->owner_class; | |
297 | 4 | struct EnvSet es = {.env = env, | |
298 | .data = env, | ||
299 | .func = (_exp_func)traverse_cdef, | ||
300 | 4 | .scope = env->scope->depth, | |
301 | .flag = tflag_scan0}; | ||
302 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | CHECK_BB(envset_pushv(&es, owner->info->value)); |
303 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
|
11 | while(owner) { |
304 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if(owner->info->cdef->base.tmpl) |
305 | 1 | template_push_types(env, owner->info->cdef->base.tmpl); | |
306 | 7 | owner = owner->info->value->from->owner_class; | |
307 | } | ||
308 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if(bases) { |
309 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
|
11 | for(uint32_t i = 0; i < bases->len; i++) { |
310 | 7 | Arg *base = mp_vector_at(bases, Arg, i); | |
311 | 7 | Arg *arg = mp_vector_at(args, Arg, i); | |
312 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | DECL_OB(const Type, arg_type, = known_type(env, base->td)); |
313 | 7 | arg->td = type2td(env->gwion, arg_type, exp_self(l)->pos); | |
314 | } | ||
315 | } | ||
316 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | DECL_OB(const Type, ret_type, = known_type(env, fdef->base->td)); |
317 | 4 | l->def->base->td = type2td(env->gwion, ret_type, exp_self(l)->pos); | |
318 | 4 | /*Type*/ owner = fdef->base->func->value_ref->from->owner_class; | |
319 | |||
320 | 4 | Upvalues upvalues = { | |
321 | 4 | .values = env->curr->info->value | |
322 | }; | ||
323 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if(env->class_def) env->class_def->info->values = env->curr->info->value; |
324 | 4 | l->def->base->values = &upvalues; | |
325 | 4 | const m_uint scope = env->scope->depth; | |
326 | 4 | env->scope->depth = 0; | |
327 | 4 | const bool shadowing = env->scope->shadowing; | |
328 | 4 | env->scope->shadowing = true; | |
329 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if(env->class_def)SET_FLAG(l->def->base, static); |
330 | 4 | const m_bool ret = traverse_func_def(env, l->def); | |
331 | 4 | env->scope->shadowing = shadowing; | |
332 | 4 | env->scope->depth = scope; | |
333 | |||
334 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (l->def->base->func) { |
335 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (env->curr->info->value != l->def->base->values->values) { |
336 | 4 | free_scope(env->gwion->mp, env->curr->info->value); | |
337 | 4 | env->curr->info->value = l->def->base->values->values; | |
338 | } | ||
339 | } | ||
340 | 4 | /*Type*/ owner = fdef->base->func->value_ref->from->owner_class->info->value->from->owner_class; | |
341 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
|
7 | while(owner) { |
342 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if(owner->info->cdef->base.tmpl) |
343 | 1 | nspc_pop_type(env->gwion->mp, env->curr); | |
344 | 3 | owner = owner->info->value->from->owner_class; | |
345 | } | ||
346 | 4 | envset_pop(&es, owner); | |
347 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if(ret < 0) { |
348 | ✗ | if(args) { | |
349 | ✗ | for(uint32_t i = 0; i < bases->len; i++) { | |
350 | ✗ | Arg *arg = mp_vector_at(args, Arg, i); | |
351 | ✗ | free_value(arg->var_decl.value, env->gwion); | |
352 | ✗ | arg->var_decl.value = NULL; | |
353 | } | ||
354 | } | ||
355 | } | ||
356 | 4 | return ret; | |
357 | } | ||
358 | |||
359 | 9 | ANN m_bool check_lambda(const Env env, const Type t, Exp_Lambda *l) { | |
360 | 9 | const Func_Def fdef = t->info->func->def; | |
361 |
2/2✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
|
9 | CHECK_BB(_check_lambda(env, l, fdef)); |
362 | 4 | exp_self(l)->type = l->def->base->func->value_ref->type; | |
363 | 4 | return GW_OK; | |
364 | } | ||
365 | |||
366 | 56 | ANN static m_bool fptr_do(const Env env, struct FptrInfo *info) { | |
367 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 9 times.
|
56 | if(info->exp->type->info->func) { |
368 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
|
47 | CHECK_BB(fptr_check(env, info)); |
369 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 39 times.
|
47 | if (!(info->exp->type = fptr_type(env, info))) |
370 | 8 | ERR_B(info->exp->pos, _("no match found")) | |
371 | 39 | return GW_OK; | |
372 | } | ||
373 | 9 | Exp_Lambda *l = &info->exp->d.exp_lambda; | |
374 | 9 | return check_lambda(env, actual_type(env->gwion, info->rhs->value_ref->type), l); | |
375 | } | ||
376 | |||
377 | ✗ | ANN static Type partial2auto(const Env env, const Exp_Binary *bin) { | |
378 | ✗ | const Func_Def fdef = bin->lhs->d.exp_lambda.def; | |
379 | ✗ | unset_fbflag(fdef->base, fbflag_lambda); | |
380 | ✗ | CHECK_BN(traverse_func_def(env, fdef)); | |
381 | ✗ | set_fbflag(fdef->base, fbflag_lambda); | |
382 | ✗ | const Type actual = fdef->base->func->value_ref->type; | |
383 | ✗ | set_fbflag(fdef->base, fbflag_lambda); | |
384 | ✗ | Var_Decl vd = bin->rhs->d.exp_decl.vd; | |
385 | ✗ | return vd.value->type = bin->rhs->type = bin->rhs->d.exp_decl.type = actual; | |
386 | } | ||
387 | |||
388 | 1 | static OP_CHECK(opck_auto_fptr) { | |
389 | 1 | const Exp_Binary *bin = (Exp_Binary *)data; | |
390 | // we'll only deal with auto fptr declaration | ||
391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (bin->rhs->exp_type != ae_exp_decl && |
392 | ✗ | bin->rhs->d.exp_decl.td->xid != insert_symbol("auto")) | |
393 | ✗ | ERR_N(bin->lhs->pos, "invalid {G+}function{0} {+}:=>{0} {+G}function{0} assignment"); | |
394 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (bin->lhs->exp_type == ae_exp_td) |
395 | ✗ | ERR_N(bin->lhs->pos, "can't use {/}type decl expressions{0} in auto function pointer declarations"); | |
396 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if(!bin->lhs->type->info->func) |
397 | ✗ | return partial2auto(env, bin); | |
398 | // create a matching signature | ||
399 | // TODO: we could check first if there a matching existing one | ||
400 | Func_Base *const fbase = | ||
401 | 1 | cpy_func_base(env->gwion->mp, bin->lhs->type->info->func->def->base); | |
402 | 1 | const Fptr_Def fptr_def = new_fptr_def(env->gwion->mp, fbase); | |
403 | 1 | char name[13 + strlen(env->curr->name) + num_digit(bin->rhs->pos.first.line) + | |
404 | 1 | num_digit(bin->rhs->pos.first.column)]; | |
405 | 1 | sprintf(name, "generated@%s@%u:%u", env->curr->name, bin->rhs->pos.first.line, | |
406 | 1 | bin->rhs->pos.first.column); | |
407 | 1 | fptr_def->base->xid = insert_symbol(name); | |
408 | 1 | const m_bool ret = traverse_fptr_def(env, fptr_def); | |
409 | 1 | const Type t = fptr_def->cdef->base.type; | |
410 | 1 | free_fptr_def(env->gwion->mp, fptr_def); | |
411 | 1 | Var_Decl vd = bin->rhs->d.exp_decl.vd; | |
412 | 1 | vd.value->type = bin->rhs->type = | |
413 | 1 | bin->rhs->d.exp_decl.type = t; | |
414 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | return ret > 0 ? t : env->gwion->type[et_error]; |
415 | } | ||
416 | |||
417 | 43 | static OP_CHECK(opck_fptr_assign) { | |
418 | 43 | Exp_Binary *bin = (Exp_Binary *)data; | |
419 | 43 | const Func_Def rhs = closure_def(bin->rhs->type); | |
420 | 43 | struct FptrInfo info = {.lhs = bin->lhs->type->info->func, | |
421 | 43 | .rhs = rhs->base->func, | |
422 | 43 | .exp = bin->lhs}; | |
423 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 35 times.
|
43 | CHECK_BN(fptr_do(env, &info)); |
424 | 35 | return bin->rhs->type; | |
425 | } | ||
426 | |||
427 | 9 | static OP_CHECK(opck_fptr_impl) { | |
428 | 9 | struct Implicit *impl = (struct Implicit *)data; | |
429 | 9 | const Func f = closure_def(impl->t)->base->func; | |
430 | 9 | struct FptrInfo info = {.lhs = impl->e->type->info->func, | |
431 | .rhs = f, | ||
432 | 9 | .exp = impl->e}; | |
433 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 5 times.
|
9 | CHECK_BN(fptr_do(env, &info)); |
434 | 5 | return impl->t; | |
435 | } | ||
436 | |||
437 | 3 | static OP_EMIT(opem_fptr_impl) { | |
438 | 3 | struct Implicit *impl = (struct Implicit *)data; | |
439 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 | if(!impl->e->type->info->func->def->base->tmpl && impl->t->info->cdef->base.tmpl) { |
440 | ✗ | const Instr instr = (Instr)vector_back(&emit->code->instr); | |
441 | ✗ | instr->opcode = eRegPushImm; | |
442 | ✗ | instr->m_val = (m_uint)impl->e->type->info->func; | |
443 | } | ||
444 | 3 | const Instr instr = emit_add_instr(emit, ObjectInstantiate); | |
445 | 3 | instr->m_val2 = (m_uint)impl->t; | |
446 | 3 | return emit_fptr_assign(emit, impl->e->type, impl->t); | |
447 | } | ||
448 | |||
449 | 4 | static OP_CHECK(opck_fptr_cast) { | |
450 | 4 | Exp_Cast *cast = (Exp_Cast *)data; | |
451 | 4 | const Type t = known_type(env, cast->td); | |
452 | 4 | const Func f = closure_def(t)->base->func; | |
453 | 4 | struct FptrInfo info = {.lhs = cast->exp->type->info->func, | |
454 | .rhs = f, | ||
455 | 4 | .exp = cast->exp}; | |
456 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
|
4 | CHECK_BN(fptr_do(env, &info)); |
457 | 3 | return t; | |
458 | } | ||
459 | |||
460 | ✗ | static void op_narg_err(const Env env, const Func_Def fdef, const loc_t loc) { | |
461 | ✗ | if (!env->context->error) { | |
462 | ✗ | gwerr_basic(_("invalid operator decay"), | |
463 | ✗ | _("Decayed operators take two arguments"), NULL, env->name, loc, | |
464 | 0); | ||
465 | ✗ | if (fdef) defined_here(fdef->base->func->value_ref); | |
466 | ✗ | env_set_error(env, true); | |
467 | } | ||
468 | } | ||
469 | 2 | static m_bool op_call_narg(const Env env, Exp arg, const loc_t loc) { | |
470 | 2 | m_uint narg = 0; | |
471 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | while (arg) { |
472 | 4 | narg++; | |
473 | 4 | arg = arg->next; | |
474 | } | ||
475 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (narg == 2) return GW_OK; |
476 | ✗ | op_narg_err(env, NULL, loc); | |
477 | ✗ | return GW_ERROR; | |
478 | } | ||
479 | |||
480 | 2 | ANN Type check_op_call(const Env env, Exp_Call *const exp) { | |
481 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | CHECK_BO(op_call_narg(env, exp->args, exp->func->pos)); |
482 | 2 | const Exp base = exp_self(exp); | |
483 | 2 | const Exp op_exp = exp->func; | |
484 | 2 | base->exp_type = ae_exp_binary; | |
485 | 2 | Exp_Binary *bin = &base->d.exp_binary; | |
486 | 2 | bin->lhs = exp->args; | |
487 | 2 | bin->lhs = exp->args->next; | |
488 | 2 | exp->args->next = NULL; | |
489 | 2 | bin->op = op_exp->d.prim.d.var; | |
490 | 2 | free_exp(env->gwion->mp, op_exp); | |
491 | 2 | return check_exp(env, base); | |
492 | } | ||
493 | |||
494 | 3 | static m_bool op_impl_narg(const Env env, const Func_Def fdef, | |
495 | const loc_t loc) { | ||
496 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if (mp_vector_len(fdef->base->args) == 2) return GW_OK; |
497 | ✗ | op_narg_err(env, fdef, loc); | |
498 | ✗ | return GW_ERROR; | |
499 | } | ||
500 | |||
501 | 3 | static inline void op_impl_ensure_types(const Env env, const Func func) { | |
502 | 3 | const bool owner_tmpl = | |
503 | 3 | safe_tflag(func->value_ref->from->owner_class, tflag_tmpl); | |
504 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (owner_tmpl) |
505 | ✗ | template_push_types( | |
506 | ✗ | env, func->value_ref->from->owner_class->info->cdef->base.tmpl); | |
507 | 3 | const bool func_tmpl = fflag(func, fflag_tmpl); | |
508 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (func_tmpl) template_push_types(env, func->def->base->tmpl); |
509 | |||
510 | 3 | Arg_List args = func->def->base->args; | |
511 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
9 | for(uint32_t i = 0; i < args->len; i++) { |
512 | 6 | Arg *arg = mp_vector_at(args, Arg, i); | |
513 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | if (!arg->type) arg->type = known_type(env, arg->td); |
514 | } | ||
515 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!func->def->base->ret_type) |
516 | ✗ | func->def->base->ret_type = known_type(env, func->def->base->td); | |
517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (owner_tmpl) nspc_pop_type(env->gwion->mp, env->curr); |
518 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (func_tmpl) nspc_pop_type(env->gwion->mp, env->curr); |
519 | 3 | } | |
520 | |||
521 | 3 | static OP_EMIT(opem_op_impl) { | |
522 | 3 | struct Implicit *impl = (struct Implicit *)data; | |
523 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
|
3 | if(!impl->e->type->info->func->code) |
524 | 1 | emit_ensure_func(emit, impl->e->type->info->func); | |
525 | 3 | emit_pushimm(emit, (m_uint)impl->e->type->info->func->code); | |
526 | 3 | return emit_fptr_assign(emit, impl->e->type, impl->t); | |
527 | } | ||
528 | |||
529 | 3 | static OP_CHECK(opck_op_impl) { | |
530 | 3 | struct Implicit *impl = (struct Implicit *)data; | |
531 | 3 | const Func func = closure_def(impl->t)->base->func; | |
532 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BN(op_impl_narg(env, func->def, impl->e->pos)); |
533 | 3 | op_impl_ensure_types(env, func); | |
534 | 3 | const Symbol lhs_sym = insert_symbol("@lhs"); | |
535 | 3 | const Symbol rhs_sym = insert_symbol("@rhs"); | |
536 | 3 | const Arg *arg0 = (Arg*)(func->def->base->args->ptr); | |
537 | 3 | const Arg *arg1 = (Arg*)(func->def->base->args->ptr + sizeof(Arg)); | |
538 | 3 | struct Exp_ _lhs = { | |
539 | .d = {.prim = {.d = {.var = lhs_sym}, .prim_type = ae_prim_id}}, | ||
540 | .exp_type = ae_exp_primary, | ||
541 | 3 | .type = arg0->type, | |
542 | 3 | .pos = arg0->td->pos}; | |
543 | 3 | struct Exp_ _rhs = { | |
544 | .d = {.prim = {.d = {.var = rhs_sym}, .prim_type = ae_prim_id}}, | ||
545 | .exp_type = ae_exp_primary, | ||
546 | 3 | .type = arg1->type, | |
547 | 3 | .pos = arg1->td->pos}; | |
548 | 3 | struct Exp_ self = {.pos = impl->e->pos}; | |
549 | 3 | self.d.exp_binary.lhs = &_lhs; | |
550 | 3 | self.d.exp_binary.rhs = &_rhs; | |
551 | 3 | self.d.exp_binary.op = impl->e->d.prim.d.var; | |
552 | 3 | struct Op_Import opi = {.op = impl->e->d.prim.d.var, | |
553 | 3 | .lhs = arg0->type, | |
554 | 3 | .rhs = arg1->type, | |
555 | 3 | .data = (uintptr_t)&self.d.exp_binary, | |
556 | 3 | .pos = impl->e->pos}; | |
557 | 3 | vector_add(&env->scope->effects, 0); | |
558 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | DECL_ON(const Type, t, = op_check(env, &opi)); |
559 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | CHECK_BN(isa(t, func->def->base->ret_type)); // error message? |
560 | 3 | MP_Vector *const eff = (MP_Vector*)vector_back(&env->scope->effects); | |
561 | // if (eff && !check_effect_overload(eff, func)) | ||
562 | // ERR_N(impl->pos, _("`{+Y}%s{0}` has effects not present in `{+G}%s{0}`\n"), | ||
563 | // s_name(impl->e->d.prim.d.var), func->name); | ||
564 | 3 | const Value v = nspc_lookup_value0(opi.nspc, impl->e->d.prim.d.var); | |
565 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | if (v) { |
566 | 2 | const m_uint scope = env_push(env, NULL, opi.nspc); | |
567 | 2 | _lhs.next = &_rhs; | |
568 | 2 | Exp_Call call = {.args = &_lhs}; | |
569 | 2 | const Func exists = (Func)find_func_match(env, v->d.func_ref, &call); | |
570 | 2 | env_pop(env, scope); | |
571 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (exists) { // improve me |
572 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (eff) { |
573 | ✗ | free_mp_vector(env->gwion->mp, struct ScopeEffect, eff); | |
574 | 2 | ERR_N(impl->pos, | |
575 | _("`{+Y}%s{0}` has effects not present in `{+G}%s{0}`\n"), | ||
576 | s_name(impl->e->d.prim.d.var), func->name); | ||
577 | } | ||
578 | 2 | return func->value_ref->from->owner_class; | |
579 | } | ||
580 | } | ||
581 | 1 | const Arg_List args = cpy_arg_list(env->gwion->mp, func->def->base->args); | |
582 | 1 | Arg *larg0 = (Arg*)(args->ptr); | |
583 | 1 | Arg *larg1 = (Arg*)(args->ptr + sizeof(Arg)); | |
584 | 1 | larg0->var_decl.xid = lhs_sym; | |
585 | 1 | larg1->var_decl.xid = rhs_sym; | |
586 | Func_Base *base = | ||
587 | 1 | new_func_base(env->gwion->mp, type2td(env->gwion, t, impl->e->pos), | |
588 | 1 | impl->e->d.prim.d.var, args, ae_flag_none, impl->e->pos); | |
589 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (eff) { |
590 | ✗ | for (m_uint i = 0; i < eff->len; i++) { | |
591 | ✗ | struct ScopeEffect *effect = mp_vector_at(eff, struct ScopeEffect, i); | |
592 | ✗ | vector_add(&base->effects, (m_uint)effect->sym); | |
593 | } | ||
594 | ✗ | free_mp_vector(env->gwion->mp, struct ScopeEffect, eff); | |
595 | } | ||
596 | const Exp lhs = | ||
597 | 1 | new_prim_id(env->gwion->mp, larg0->var_decl.xid, impl->e->pos); | |
598 | const Exp rhs = | ||
599 | 1 | new_prim_id(env->gwion->mp, larg1->var_decl.xid, impl->e->pos); | |
600 | 1 | const Exp bin = new_exp_binary(env->gwion->mp, lhs, impl->e->d.prim.d.var, | |
601 | 1 | rhs, impl->e->pos); | |
602 | 1 | Stmt_List code = new_mp_vector(env->gwion->mp, struct Stmt_, 1); | |
603 | 1 | mp_vector_set(code, struct Stmt_, 0, | |
604 | ((struct Stmt_) { | ||
605 | .stmt_type = ae_stmt_return, .d = { .stmt_exp = { .val = bin }}, | ||
606 | .pos = impl->e->pos | ||
607 | })); | ||
608 | 1 | const Func_Def def = new_func_def(env->gwion->mp, base, code); | |
609 | 1 | def->base->xid = impl->e->d.prim.d.var; | |
610 | // use envset | ||
611 | // or better, some function with envset and traverse | ||
612 | 1 | const m_uint scope = env_push(env, NULL, opi.nspc); | |
613 | // we assume succes here | ||
614 | 1 | /*const m_bool ret = */ traverse_func_def(env, def); | |
615 | 1 | env_pop(env, scope); | |
616 | 1 | def->base->func->value_ref->type->info->parent = env->gwion->type[et_op]; | |
617 | 1 | impl->e->type = def->base->func->value_ref->type; | |
618 | 1 | impl->e->d.prim.value = def->base->func->value_ref; | |
619 | 1 | return opck_fptr_impl(env, impl); | |
620 | } | ||
621 | |||
622 | ✗ | static OP_CHECK(opck_op_cast) { | |
623 | ✗ | Exp_Cast *cast = (Exp_Cast*)data; | |
624 | ✗ | struct Implicit impl = { .e = cast->exp, .t = known_type(env, cast->td) }; | |
625 | ✗ | return opck_op_impl(env, &impl); | |
626 | } | ||
627 | |||
628 | 7 | static OP_CHECK(opck_func_partial) { | |
629 | 7 | Exp_Call *call = (Exp_Call*)data; | |
630 |
2/2✓ Branch 1 taken 4 times.
✓ Branch 2 taken 3 times.
|
7 | return partial_type(env, call) ?: env->gwion->type[et_error]; |
631 | } | ||
632 | |||
633 | ✗ | static OP_CHECK(opck_class_partial) { | |
634 | ✗ | Exp_Call *call = (Exp_Call*)data; | |
635 | ✗ | struct Op_Import opi = {.op = insert_symbol("@partial"), | |
636 | ✗ | .lhs = actual_type(env->gwion, call->func->type), | |
637 | ✗ | .pos = call->func->pos, | |
638 | ✗ | .data = (uintptr_t)data}; | |
639 | ✗ | return op_check(env, &opi); | |
640 | } | ||
641 | |||
642 | 10 | static FREEARG(freearg_gtmpl) { | |
643 | 10 | free_mstr(((Gwion)gwion)->mp, (m_str)instr->m_val2); | |
644 | 10 | } | |
645 | 20 | static FREEARG(freearg_dottmpl) { | |
646 | 20 | struct dottmpl_ *dt = (struct dottmpl_*) instr->m_val2; | |
647 | 20 | free_mstr(((Gwion)gwion)->mp, dt->tmpl_name); | |
648 | 20 | } | |
649 | |||
650 | #include "tmpl_info.h" | ||
651 | #include "parse.h" | ||
652 | #include "traverse.h" | ||
653 | #include "gwi.h" | ||
654 | |||
655 | 12 | ANN static bool is_base(const Env env, const Type_List tl) { | |
656 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
|
24 | for(uint32_t i = 0; i < tl->len; i++) { |
657 | 12 | Type_Decl *td = *mp_vector_at(tl, Type_Decl*, i); | |
658 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
|
12 | if(known_type(env, td) == env->gwion->type[et_auto]) |
659 | ✗ | return true; | |
660 | } | ||
661 | 12 | return false; | |
662 | } | ||
663 | |||
664 | 18 | static OP_CHECK(opck_closure_scan) { | |
665 | 18 | struct TemplateScan *ts = (struct TemplateScan *)data; | |
666 | 18 | struct tmpl_info info = { | |
667 | 18 | .base = ts->t, .td = ts->td, .list = ts->t->info->cdef->base.tmpl->list}; | |
668 | 18 | const Type exists = tmpl_exists(env, &info); | |
669 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
|
18 | if (exists) return exists != env->gwion->type[et_error] ? exists : NULL; |
670 | 12 | const Func_Base *base = closure_def(ts->t)->base; | |
671 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 7 times.
|
12 | const Arg_List args = base->args ? cpy_arg_list(env->gwion->mp, base->args) : NULL; |
672 | 12 | Func_Base *const fbase = new_func_base(env->gwion->mp, cpy_type_decl(env->gwion->mp, base->td), info.name, args, ae_flag_none, base->pos); | |
673 | 12 | fbase->tmpl = cpy_tmpl(env->gwion->mp, base->tmpl); | |
674 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | if(!is_base(env, ts->td->types)) |
675 | 12 | fbase->tmpl->call = cpy_type_list(env->gwion->mp, ts->td->types); | |
676 | 12 | const Fptr_Def fdef = new_fptr_def(env->gwion->mp, cpy_func_base(env->gwion->mp, fbase)); | |
677 | 12 | fdef->base->xid = info.name; | |
678 | 12 | struct EnvSet es = {.env = env, | |
679 | .data = env, | ||
680 | .func = (_exp_func)traverse_cdef, | ||
681 | 12 | .scope = env->scope->depth, | |
682 | .flag = tflag_scan0}; | ||
683 | 12 | const Type owner = ts->t; | |
684 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
|
12 | CHECK_BO(envset_pushv(&es, owner->info->value)); |
685 | 12 | const m_bool ret = traverse_fptr_def(env, fdef); | |
686 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | const Type t = ret > 0 ? fdef->cdef->base.type : NULL; |
687 | 12 | envset_pop(&es, owner->info->value->from->owner_class); | |
688 | 12 | free_fptr_def(env->gwion->mp, fdef); // clean? | |
689 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if(t) set_tflag(t, tflag_emit); |
690 | 12 | return t; | |
691 | } | ||
692 | |||
693 | 24 | static CTOR(fptr_ctor) { | |
694 | 24 | *(VM_Code*)o->data = ((Func)vector_at(&o->type_ref->nspc->vtable, 1))->code; | |
695 | 24 | } | |
696 | |||
697 | 4064 | ANN m_bool tmpl_fptr(const Env env, const Fptr_Def fptr, const Func_Def fdef) { | |
698 | 4064 | fptr->cdef->base.type->nspc->offset += SZ_INT * 3; | |
699 | 4064 | env_push_type(env, fptr->cdef->base.type); | |
700 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4064 times.
|
4064 | CHECK_BB(traverse_func_def(env, fdef)); |
701 | 4064 | builtin_func(env->gwion, fdef->base->func, fptr_ctor); | |
702 | 4064 | set_tflag(fdef->base->func->value_ref->type, tflag_ftmpl); | |
703 | 4064 | env_pop(env, 0); | |
704 | 4064 | return GW_OK; | |
705 | } | ||
706 | |||
707 | 22 | static DTOR(fptr_dtor) { | |
708 | 22 | m_bit *const caps = *(m_bit**)(o->data + SZ_INT); | |
709 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
|
22 | if(caps) free_captures(shred, caps); |
710 | 22 | } | |
711 | |||
712 | ✗ | static MFUN(fptr_default) { | |
713 | ✗ | xfun_handle(shred, "EmptyFunctionPointer"); | |
714 | } | ||
715 | |||
716 | 15 | static GACK(gack_function) { INTERP_PRINTF("%s", t->name); } | |
717 | |||
718 | 638 | GWION_IMPORT(func) { | |
719 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
|
638 | gwidoc(gwi, "the base of all functions."); |
720 | 638 | const Type t_function = gwi_mk_type(gwi, "function", SZ_INT, NULL); | |
721 | 638 | GWI_BB(gwi_gack(gwi, t_function, gack_function)) | |
722 | 638 | GWI_BB(gwi_set_global_type(gwi, t_function, et_function)) | |
723 | |||
724 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
|
638 | gwidoc(gwi, "the base of decayed operators."); |
725 | 638 | const Type t_op = gwi_mk_type(gwi, "operator", SZ_INT, "function"); | |
726 | 638 | GWI_BB(gwi_set_global_type(gwi, t_op, et_op)) | |
727 | |||
728 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
|
638 | gwidoc(gwi, "the base of function pointers."); |
729 | 638 | const Type t_closure = gwi_class_ini(gwi, "funptr", "Object"); | |
730 | 638 | t_closure->nspc->offset = SZ_INT*3; | |
731 | 638 | gwi_class_xtor(gwi, fptr_ctor, fptr_dtor); | |
732 | 638 | GWI_BB(gwi_set_global_type(gwi, t_closure, et_closure)) | |
733 | 638 | GWI_BB(gwi_func_ini(gwi, "void", "default")); | |
734 | 638 | GWI_BB(gwi_func_end(gwi, fptr_default, ae_flag_none)); | |
735 | 638 | gwi_class_end(gwi); | |
736 | |||
737 | 638 | GWI_BB(gwi_oper_ini(gwi, "funptr", NULL, NULL)) | |
738 | 638 | GWI_BB(gwi_oper_add(gwi, opck_closure_scan)) | |
739 | 638 | GWI_BB(gwi_oper_end(gwi, "class", NULL)) | |
740 | |||
741 | 638 | GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "function", NULL)) | |
742 | 638 | GWI_BB(gwi_oper_add(gwi, opck_func_call)) | |
743 | 638 | GWI_BB(gwi_oper_end(gwi, "=>", NULL)) | |
744 | 638 | GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "funptr", NULL)) | |
745 | 638 | GWI_BB(gwi_oper_add(gwi, opck_fptr_call)) | |
746 | 638 | GWI_BB(gwi_oper_end(gwi, "=>", NULL)) | |
747 | 638 | GWI_BB(gwi_oper_ini(gwi, "function", "funptr", NULL)) | |
748 | 638 | GWI_BB(gwi_oper_add(gwi, opck_fptr_assign)) | |
749 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_fptr_assign)) | |
750 | 638 | GWI_BB(gwi_oper_end(gwi, ":=>", NULL)) | |
751 | 638 | GWI_BB(gwi_oper_add(gwi, opck_fptr_impl)) | |
752 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_fptr_impl)) | |
753 | 638 | GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) | |
754 | 638 | GWI_BB(gwi_oper_add(gwi, opck_fptr_cast)) | |
755 | 638 | GWI_BB(gwi_oper_end(gwi, "$", NULL)) | |
756 | 638 | GWI_BB(gwi_oper_ini(gwi, "operator", "funptr", NULL)) | |
757 | 638 | GWI_BB(gwi_oper_add(gwi, opck_op_impl)) | |
758 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_op_impl)) | |
759 | 638 | GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) | |
760 | 638 | GWI_BB(gwi_oper_add(gwi, opck_op_cast)) | |
761 | 638 | GWI_BB(gwi_oper_end(gwi, "$", NULL)) | |
762 | 638 | GWI_BB(gwi_oper_ini(gwi, "function", "function", NULL)) | |
763 | 638 | GWI_BB(gwi_oper_add(gwi, opck_auto_fptr)) | |
764 | 638 | GWI_BB(gwi_oper_end(gwi, ":=>", int_r_assign)) | |
765 | 638 | GWI_BB(gwi_oper_ini(gwi, "function", NULL, NULL)) | |
766 | 638 | GWI_BB(gwi_oper_add(gwi, opck_func_partial)) | |
767 | 638 | GWI_BB(gwi_oper_end(gwi, "@partial", NULL)) | |
768 | 638 | GWI_BB(gwi_oper_ini(gwi, "Class", NULL, NULL)) | |
769 | 638 | GWI_BB(gwi_oper_add(gwi, opck_class_partial)) | |
770 | 638 | GWI_BB(gwi_oper_end(gwi, "@partial", NULL)) | |
771 | |||
772 | 638 | gwi_register_freearg(gwi, GTmpl, freearg_gtmpl); | |
773 | 638 | gwi_register_freearg(gwi, DotTmpl, freearg_dottmpl); | |
774 | 638 | return GW_OK; | |
775 | } | ||
776 |