| 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 |