| 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 "object.h" | ||
| 8 | #include "operator.h" | ||
| 9 | #include "import.h" | ||
| 10 | #include "emit.h" | ||
| 11 | #include "traverse.h" | ||
| 12 | #include "parse.h" | ||
| 13 | #include "specialid.h" | ||
| 14 | |||
| 15 | #include "gwi.h" | ||
| 16 | #include "gack.h" | ||
| 17 | |||
| 18 | 8831 | ANN M_Object new_object(MemPool p, const Type t) { | |
| 19 | 8831 | const uint32_t offset = sizeof(struct M_Object_) + t->nspc->offset; | |
| 20 | 8831 | const M_Object a = _mp_calloc(p, offset); | |
| 21 | 8831 | a->ref = 1; | |
| 22 | 8831 | a->type_ref = t; | |
| 23 | 8831 | return a; | |
| 24 | } | ||
| 25 | |||
| 26 | 361 | ANN M_Object new_string(const struct Gwion_ *gwion, const m_str str) { | |
| 27 | 361 | const M_Object o = new_object(gwion->mp, gwion->type[et_string]); | |
| 28 | 361 | STRING(o) = mstrdup(gwion->mp, str); | |
| 29 | 361 | return o; | |
| 30 | } | ||
| 31 | |||
| 32 | 1 | ANN static void user_dtor(const M_Object o, const VM_Shred shred, const Type t) { | |
| 33 | 1 | const VM_Shred sh = new_vm_shred(shred->info->mp, t->nspc->dtor); | |
| 34 | 1 | vmcode_addref(t->nspc->dtor); | |
| 35 | 1 | sh->base = shred->base; | |
| 36 | 1 | *(M_Object *)sh->mem = o; | |
| 37 | 1 | *(Type *)(sh->mem + SZ_INT) = t; | |
| 38 | 1 | vm_add_shred(shred->info->vm, sh); | |
| 39 | 1 | ++sh->info->me->ref; | |
| 40 | 1 | } | |
| 41 | |||
| 42 | 5192 | ANN static inline void release_not_union(const m_bit *data, const VM_Shred shred, const Scope s) { | |
| 43 | 5192 | const Map m = &s->map; | |
| 44 |
2/2✓ Branch 1 taken 64034 times.
✓ Branch 2 taken 5192 times.
|
69226 | for(m_uint i = map_size(m) + 1; --i;) { |
| 45 | 64034 | const Value v = (Value) VVAL(m, i-1); | |
| 46 |
2/2✓ Branch 1 taken 25 times.
✓ Branch 2 taken 64009 times.
|
64034 | if (vflag(v, vflag_release)) |
| 47 | 25 | compound_release(shred, v->type, data + v->from->offset); | |
| 48 | } | ||
| 49 | 5192 | } | |
| 50 | |||
| 51 | 10375 | ANN static void do_release(const M_Object o, | |
| 52 | const VM_Shred shred, const Type t) { | ||
| 53 |
2/2✓ Branch 0 taken 5180 times.
✓ Branch 1 taken 5195 times.
|
10375 | if(!t->nspc->offset) { |
| 54 | 5180 | free_object(shred->info->mp, o); | |
| 55 | 5180 | return; | |
| 56 | } | ||
| 57 |
2/2✓ Branch 1 taken 5192 times.
✓ Branch 2 taken 3 times.
|
5195 | if (!tflag(t, tflag_union)) |
| 58 | 5192 | release_not_union(o->data, shred, t->nspc->info->value); | |
| 59 |
2/2✓ Branch 1 taken 5109 times.
✓ Branch 2 taken 86 times.
|
5195 | if (tflag(t, tflag_dtor)) { |
| 60 |
2/2✓ Branch 0 taken 5108 times.
✓ Branch 1 taken 1 times.
|
5109 | if (t->nspc->dtor->builtin) |
| 61 | 5108 | ((f_xtor)t->nspc->dtor->native_func)(o, NULL, shred); | |
| 62 | 1 | else return user_dtor(o, shred, t); | |
| 63 | } | ||
| 64 | 5194 | return do_release(o, shred, t->info->parent); | |
| 65 | } | ||
| 66 | |||
| 67 | 29 | ANN void struct_release(const VM_Shred shred, const Type base, | |
| 68 | const m_bit *ptr) { | ||
| 69 | 29 | const Vector types = &base->info->tuple->types; | |
| 70 | 29 | const Vector offsets = &base->info->tuple->offset; | |
| 71 |
2/2✓ Branch 1 taken 50 times.
✓ Branch 2 taken 29 times.
|
79 | for (m_uint i = 0; i < vector_size(types); ++i) { |
| 72 | 50 | const Type t = (Type)vector_at(types, i); | |
| 73 |
2/2✓ Branch 1 taken 47 times.
✓ Branch 2 taken 3 times.
|
50 | if (!tflag(t, tflag_compound)) continue; |
| 74 | 3 | const m_uint offset = vector_at(offsets, i); | |
| 75 | 3 | compound_release(shred, t, ptr + offset); | |
| 76 | } | ||
| 77 | 29 | } | |
| 78 | |||
| 79 | 1 | INSTR(DTOR_EOC) { | |
| 80 | 1 | const M_Object o = *(M_Object *)MEM(0); | |
| 81 | 1 | const Type t = *(Type *)MEM(SZ_INT); | |
| 82 | 1 | do_release(o, shred, t->info->parent); | |
| 83 | 1 | shred->info->me->ref = 1; | |
| 84 | 1 | vm_shred_exit(shred); | |
| 85 | 1 | } | |
| 86 | |||
| 87 | 5180 | ANN void __release(const M_Object o, const VM_Shred shred) { | |
| 88 | 5180 | do_release(o, shred, o->type_ref); | |
| 89 | 5180 | } | |
| 90 | |||
| 91 | 5180 | ANN void free_object(MemPool p, const M_Object o) { | |
| 92 | 5180 | mp_free2(p, sizeof(struct M_Object_) + o->type_ref->nspc->offset, o); | |
| 93 | 5180 | } | |
| 94 | |||
| 95 | 162 | static ID_CHECK(opck_this) { | |
| 96 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 161 times.
|
162 | if (!env->class_def) |
| 97 | 1 | ERR_O(exp_self(prim)->pos, | |
| 98 | _("keyword 'this' can be used only inside class definition...")) | ||
| 99 |
1/2✓ Branch 0 taken 161 times.
✗ Branch 1 not taken.
|
161 | if(env->func) { |
| 100 |
2/2✓ Branch 1 taken 1 times.
✓ Branch 2 taken 160 times.
|
161 | if (!vflag(env->func->value_ref, vflag_member)) |
| 101 | 1 | ERR_O(exp_self(prim)->pos, | |
| 102 | _("keyword 'this' cannot be used inside static functions...")) | ||
| 103 |
2/2✓ Branch 2 taken 50 times.
✓ Branch 3 taken 110 times.
|
160 | if (!exp_getuse(exp_self(prim)) && |
| 104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | !strcmp(s_name(env->func->def->base->xid), "@gack")) |
| 105 | ✗ | return get_gack(env->class_def->info->parent); // get_gack ? | |
| 106 | } | ||
| 107 | 160 | return env->class_def; | |
| 108 | } | ||
| 109 | |||
| 110 | 120 | static ID_EMIT(opem_this) { | |
| 111 |
4/4✓ Branch 2 taken 110 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 109 times.
|
230 | if (!exp_getvar(exp_self(prim)) && |
| 112 | 110 | tflag(exp_self(prim)->type, tflag_struct)) { | |
| 113 | 1 | const Instr instr = emit_add_instr(emit, RegPushMemDeref); | |
| 114 | 1 | instr->m_val2 = emit->env->class_def->size; | |
| 115 | 1 | return GW_OK; | |
| 116 | } | ||
| 117 | 119 | const Instr instr = emit_add_instr(emit, RegPushMem); | |
| 118 | 119 | instr->m_val = emit->status.this_offset; | |
| 119 | 119 | return GW_OK; | |
| 120 | } | ||
| 121 | |||
| 122 | 3 | static ID_CHECK(opck_super) { | |
| 123 | 3 | const Exp self = exp_self(prim); | |
| 124 |
3/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 2 times.
|
3 | if(!env->func || is_ctor(env->func->def)) |
| 125 | 1 | ERR_O(self->pos, "can't use 'super' outside of constructor"); | |
| 126 | 2 | const Type parent = env->class_def->info->parent; | |
| 127 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | DECL_OO(const Value, v, = find_value(parent, insert_symbol("new"))); |
| 128 | 2 | SET_FLAG(env->func, const); | |
| 129 | 2 | return v->type; | |
| 130 | } | ||
| 131 | |||
| 132 | 2 | static ID_EMIT(opem_super) { | |
| 133 | 2 | const Env env = emit->env; | |
| 134 | 2 | const Exp self = exp_self(prim); | |
| 135 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if(!self->is_call) |
| 136 | 1 | ERR_B(self->pos, "can only use 'super' as a function call"); | |
| 137 | 1 | emit_regpushmem(emit, 0, SZ_INT, false); | |
| 138 | 1 | emit_pushimm(emit, (m_uint)exp_self(prim)->type); | |
| 139 | 1 | return GW_OK; | |
| 140 | } | ||
| 141 | |||
| 142 | 638 | GWION_IMPORT(object) { | |
| 143 | 638 | const Type t_object = gwi_mk_type(gwi, "Object", SZ_INT, "@Compound"); | |
| 144 | 638 | gwi_set_global_type(gwi, t_object, et_object); | |
| 145 | 638 | set_tflag(t_object, tflag_compound); | |
| 146 | 638 | t_object->nspc = new_nspc(gwi->gwion->mp, "Object"); | |
| 147 | 638 | struct SpecialId_ spid_this = {.ck = opck_this, .em = opem_this, .is_const = 1}; | |
| 148 | 638 | gwi_specialid(gwi, "this", &spid_this); | |
| 149 | 638 | struct SpecialId_ spid_super = {.ck = opck_super, .em = opem_super, .is_const = 1}; | |
| 150 | 638 | gwi_specialid(gwi, "super", &spid_super); | |
| 151 | 638 | return GW_OK; | |
| 152 | } | ||
| 153 |