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 |