Gwion coverage report


Directory: src/
File: src/lib/closure.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 454 569 79.8%
Functions: 40 47 85.1%
Branches: 160 278 57.6%

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