1 |
|
|
#include <stdlib.h> |
2 |
|
|
#include <string.h> |
3 |
|
|
#include "gwion_util.h" |
4 |
|
|
#include "gwion_ast.h" |
5 |
|
|
#include "gwion_env.h" |
6 |
|
|
#include "vm.h" |
7 |
|
|
#include "gwion.h" |
8 |
|
|
#include "instr.h" |
9 |
|
|
#include "object.h" |
10 |
|
|
#include "operator.h" |
11 |
|
|
#include "import.h" |
12 |
|
|
#include "emit.h" |
13 |
|
|
#include "traverse.h" |
14 |
|
|
#include "template.h" |
15 |
|
|
#include "parse.h" |
16 |
|
|
#include "specialid.h" |
17 |
|
|
|
18 |
|
|
#include "gwi.h" |
19 |
|
|
|
20 |
|
|
#undef insert_symbol |
21 |
|
|
|
22 |
|
|
#define describe_logical(name, op) \ |
23 |
|
|
static INSTR(name##Object) { \ |
24 |
|
|
POP_REG(shred, SZ_INT); \ |
25 |
|
|
const M_Object lhs = *(M_Object*)REG(-SZ_INT); \ |
26 |
|
|
const M_Object rhs = *(M_Object*)REG(0); \ |
27 |
|
|
*(m_uint*)REG(-SZ_INT) = (lhs op rhs); \ |
28 |
|
|
release(lhs, shred); \ |
29 |
|
|
release(rhs, shred); \ |
30 |
|
|
} |
31 |
|
|
|
32 |
|
4 |
describe_logical(Eq, ==) |
33 |
|
4 |
describe_logical(Neq, !=) |
34 |
|
54 |
static inline m_bool nonnull_check(const Type l, const Type r) { |
35 |
✓✓✓✓
|
54 |
return !GET_FLAG(l, nonnull) && GET_FLAG(r, nonnull); |
36 |
|
|
} |
37 |
|
|
|
38 |
|
77 |
static inline Type check_nonnull(const Env env, const Type l, const Type r, |
39 |
|
|
const m_str action, const loc_t pos) { |
40 |
✓✓ |
77 |
if(GET_FLAG(r, nonnull)) { |
41 |
✓✓ |
24 |
if(isa(l, env->gwion->type[et_null]) > 0) |
42 |
|
6 |
ERR_N(pos, _("can't %s '%s' to '%s'"), action, l->name, r->name); |
43 |
✓✓ |
18 |
if(isa(l, r) < 0) |
44 |
|
1 |
ERR_N(pos, _("can't %s '%s' to '%s'"), action, l->name, r->name); |
45 |
|
17 |
return r->e->parent; |
46 |
|
|
} |
47 |
✓✓✓✓
|
53 |
if(l != env->gwion->type[et_null] && isa(l, r) < 0) |
48 |
|
4 |
ERR_N(pos, _("can't %s '%s' to '%s'"), action, l->name, r->name); |
49 |
|
49 |
return r; |
50 |
|
|
} |
51 |
|
|
|
52 |
|
34 |
static OP_CHECK(at_object) { |
53 |
|
34 |
const Exp_Binary* bin = (Exp_Binary*)data; |
54 |
|
34 |
const Type l = bin->lhs->info->type; |
55 |
|
34 |
const Type r = bin->rhs->info->type; |
56 |
✗✓ |
34 |
if(opck_rassign(env, data, mut) == env->gwion->type[et_null]) |
57 |
|
|
return env->gwion->type[et_null]; |
58 |
✓✓ |
34 |
if(check_nonnull(env, l, r, "assign", exp_self(bin)->pos) == env->gwion->type[et_null]) |
59 |
|
2 |
return env->gwion->type[et_null]; |
60 |
✓✓ |
32 |
if(bin->rhs->exp_type == ae_exp_decl) { |
61 |
|
23 |
SET_FLAG(bin->rhs->d.exp_decl.td, ref); |
62 |
|
23 |
SET_FLAG(bin->rhs->d.exp_decl.list->self->value, ref); |
63 |
|
|
} |
64 |
|
32 |
exp_setvar(bin->rhs, 1); |
65 |
|
32 |
return r; |
66 |
|
|
} |
67 |
|
|
|
68 |
|
32 |
static OP_EMIT(opem_at_object) { |
69 |
|
32 |
const Exp_Binary* bin = (Exp_Binary*)data; |
70 |
|
32 |
const Type l = bin->lhs->info->type; |
71 |
|
32 |
const Type r = bin->rhs->info->type; |
72 |
✓✓ |
32 |
if(nonnull_check(l, r)) { |
73 |
|
6 |
const Instr instr = emit_add_instr(emit, GWOP_EXCEPT); |
74 |
|
6 |
instr->m_val = SZ_INT; |
75 |
|
|
} |
76 |
|
32 |
return emit_add_instr(emit, ObjectAssign); |
77 |
|
|
} |
78 |
|
|
|
79 |
|
16 |
static OP_CHECK(opck_object_cast) { |
80 |
|
16 |
const Exp_Cast* cast = (Exp_Cast*)data; |
81 |
|
16 |
const Type l = cast->exp->info->type; |
82 |
|
16 |
const Type r = exp_self(cast)->info->type; |
83 |
✓✓ |
16 |
if(check_nonnull(env, l, r, "cast", exp_self(cast)->pos) == env->gwion->type[et_null]) |
84 |
|
4 |
return env->gwion->type[et_null]; |
85 |
|
12 |
return force_type(env, r); |
86 |
|
|
} |
87 |
|
|
|
88 |
|
10 |
static OP_EMIT(opem_object_cast) { |
89 |
|
10 |
const Exp_Cast* cast = (Exp_Cast*)data; |
90 |
|
10 |
const Type l = cast->exp->info->type; |
91 |
|
10 |
const Type r = exp_self(cast)->info->type; |
92 |
✓✓ |
10 |
if(nonnull_check(l, r)) |
93 |
|
4 |
emit_add_instr(emit, GWOP_EXCEPT); |
94 |
|
10 |
return (Instr)GW_OK; |
95 |
|
|
} |
96 |
|
|
|
97 |
|
27 |
static OP_CHECK(opck_implicit_null2obj) { |
98 |
|
27 |
const struct Implicit* imp = (struct Implicit*)data; |
99 |
|
27 |
const Type l = imp->e->info->type; |
100 |
|
27 |
const Type r = imp->t; |
101 |
✓✓ |
27 |
if(check_nonnull(env, l, r, "implicitly cast", imp->e->pos) == env->gwion->type[et_null]) |
102 |
|
5 |
return env->gwion->type[et_null]; |
103 |
|
22 |
imp->e->info->cast_to = r; |
104 |
|
22 |
return imp->t; |
105 |
|
|
} |
106 |
|
|
|
107 |
|
12 |
static OP_EMIT(opem_implicit_null2obj) { |
108 |
|
12 |
const struct Implicit* imp = (struct Implicit*)data; |
109 |
|
12 |
const Type l = imp->e->info->type; |
110 |
|
12 |
const Type r = imp->t; |
111 |
✓✓ |
12 |
if(nonnull_check(l, r)) |
112 |
|
4 |
emit_add_instr(emit, GWOP_EXCEPT); |
113 |
|
12 |
return (Instr)GW_OK; |
114 |
|
|
} |
115 |
|
|
|
116 |
|
|
ANN /*static*/ Type scan_class(const Env env, const Type t, const Type_Decl* td); |
117 |
|
|
|
118 |
|
41 |
static Type opck_object_scan(const Env env, const struct TemplateScan *ts) { |
119 |
✓✓ |
41 |
if(ts->td->types) |
120 |
✓✓ |
39 |
return scan_class(env, ts->t, ts->td) ?: env->gwion->type[et_null]; |
121 |
|
2 |
ERR_N(td_pos(ts->td), _("you must provide template types for type '%s'"), ts->t->name) |
122 |
|
|
} |
123 |
|
|
|
124 |
|
41 |
static OP_CHECK(opck_struct_scan) { |
125 |
|
41 |
struct TemplateScan *ts = (struct TemplateScan*)data; |
126 |
|
41 |
return opck_object_scan(env, ts); |
127 |
|
|
} |
128 |
|
|
|
129 |
|
|
static const f_instr dotstatic[] = { DotStatic, DotStatic2, DotStatic3, RegPushImm }; |
130 |
|
|
static const f_instr structmember[] = { StructMember, StructMemberFloat, StructMemberOther, StructMemberAddr }; |
131 |
|
|
|
132 |
|
|
ANN Instr emit_kind(Emitter emit, const m_uint size, const uint addr, const f_instr func[]); |
133 |
|
42 |
ANN static void emit_dot_static_data(const Emitter emit, const Value v, const uint emit_var) { |
134 |
|
42 |
const m_uint size = v->type->size; |
135 |
|
42 |
const Instr instr = emit_kind(emit, size, emit_var, dotstatic); |
136 |
|
42 |
instr->m_val = (m_uint)(v->from->owner->info->class_data + v->from->offset); |
137 |
|
42 |
instr->m_val2 = size; |
138 |
|
42 |
} |
139 |
|
|
|
140 |
|
|
static const f_instr regpushimm[] = { RegPushImm, RegPushImm2, RegPushImm3, RegPushImm4 }; |
141 |
|
62 |
ANN static void emit_dot_static_import_data(const Emitter emit, const Value v, const uint emit_addr) { |
142 |
✓✓✓✗ ✓✓ |
82 |
if(v->d.ptr && GET_FLAG(v, builtin) && GET_FLAG(v, const)) { |
143 |
|
20 |
const m_uint size = v->type->size; |
144 |
|
20 |
const Instr instr = emit_kind(emit, size, emit_addr, regpushimm); |
145 |
|
20 |
instr->m_val = (m_uint)v->d.ptr; |
146 |
|
20 |
instr->m_val2 = size; |
147 |
|
|
} else |
148 |
|
42 |
emit_dot_static_data(emit, v, emit_addr); |
149 |
|
62 |
} |
150 |
|
|
static const f_instr dotmember[] = { DotMember, DotMember2, DotMember3, DotMember4 }; |
151 |
|
|
|
152 |
|
305 |
ANN static void emit_member_func(const Emitter emit, const Exp_Dot* member) { |
153 |
|
305 |
const Func f = exp_self(member)->info->type->e->d.func; |
154 |
✓✓ |
305 |
if(f->def->base->tmpl) |
155 |
|
50 |
emit_add_instr(emit, DotTmplVal); |
156 |
|
|
else |
157 |
✓✓✗✓
|
255 |
if(is_class(emit->gwion, member->t_base) || GET_FLAG(member->base->info->type, force)) { |
158 |
✓✓ |
33 |
const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc); |
159 |
✓✓ |
33 |
func_i->m_val = (m_uint)f->code ?: (m_uint)f; |
160 |
|
33 |
return; |
161 |
|
|
} |
162 |
|
|
// if(f->def->base->tmpl) |
163 |
|
|
// emit_add_instr(emit, DotTmplVal); |
164 |
|
|
else { |
165 |
✓✓ |
222 |
if(GET_FLAG(member->t_base, struct)) { |
166 |
✓✓ |
4 |
if(!GET_FLAG(f->def->base, static)) { |
167 |
|
3 |
exp_setvar(member->base, 1); |
168 |
|
3 |
emit_exp(emit, member->base); |
169 |
|
|
} |
170 |
✗✓ |
4 |
const Instr func_i = emit_add_instr(emit, f->code ? RegPushImm : SetFunc); |
171 |
✓✗ |
4 |
func_i->m_val = (m_uint)f->code ?: (m_uint)f; |
172 |
|
4 |
return; |
173 |
|
|
} |
174 |
✓✓ |
218 |
const Instr instr = emit_add_instr(emit, GET_FLAG(f, member) ? DotFunc : DotStaticFunc); |
175 |
|
218 |
instr->m_val = f->vt_index; |
176 |
|
|
} |
177 |
|
268 |
return; |
178 |
|
|
} |
179 |
|
|
|
180 |
|
177 |
ANN static inline void emit_member(const Emitter emit, const Value v, const uint emit_addr) { |
181 |
|
177 |
const m_uint size = v->type->size; |
182 |
|
177 |
const Instr instr = emit_kind(emit, size, emit_addr, dotmember); |
183 |
|
177 |
instr->m_val = v->from->offset; |
184 |
|
177 |
instr->m_val2 = size; |
185 |
|
177 |
} |
186 |
|
|
|
187 |
|
12 |
ANN static inline void emit_struct_data(const Emitter emit, const Value v, const uint emit_addr) { |
188 |
|
12 |
const Instr instr = emit_kind(emit, v->type->size, emit_addr, structmember); |
189 |
|
12 |
instr->m_val = v->from->offset; |
190 |
✓✓ |
12 |
if(!emit_addr) { |
191 |
|
8 |
const Instr instr = emit_add_instr(emit, RegPush); |
192 |
|
8 |
instr->m_val = v->type->size -SZ_INT; |
193 |
|
|
} |
194 |
|
12 |
} |
195 |
|
|
|
196 |
|
|
ANN m_bool not_from_owner_class(const Env env, const Type t, const Value v, const loc_t pos); |
197 |
|
725 |
OP_CHECK(opck_object_dot) { |
198 |
|
725 |
const Exp_Dot *member = (Exp_Dot*)data; |
199 |
|
725 |
const m_str str = s_name(member->xid); |
200 |
|
725 |
const m_bool base_static = is_class(env->gwion, member->t_base); |
201 |
✓✓ |
725 |
const Type the_base = base_static ? member->t_base->e->d.base_type : member->t_base; |
202 |
✓✓ |
725 |
if(!the_base->nspc) |
203 |
|
1 |
ERR_N(member->base->pos, |
204 |
|
|
_("type '%s' does not have members - invalid use in dot expression of %s"), |
205 |
|
|
the_base->name, str) |
206 |
✓✓✓✗
|
724 |
if(member->xid == insert_symbol(env->gwion->st, "this") && base_static) |
207 |
|
1 |
ERR_N(exp_self(member)->pos, |
208 |
|
|
_("keyword 'this' must be associated with object instance...")) |
209 |
|
723 |
const Value value = find_value(the_base, member->xid); |
210 |
✓✓ |
723 |
if(!value) { |
211 |
|
5 |
env_err(env, exp_self(member)->pos, |
212 |
|
|
_("class '%s' has no member '%s'"), the_base->name, str); |
213 |
✓✓ |
5 |
if(member->t_base->nspc) |
214 |
✓✗ |
3 |
did_you_mean_type(the_base, str); |
215 |
|
5 |
return env->gwion->type[et_null]; |
216 |
|
|
} |
217 |
✗✓ |
718 |
CHECK_BN(not_from_owner_class(env, the_base, value, exp_self(member)->pos)) |
218 |
✓✓✓✓
|
718 |
if(!env->class_def || isa(env->class_def, value->from->owner_class) < 0) { |
219 |
✓✓ |
532 |
if(GET_FLAG(value, private)) |
220 |
|
4 |
ERR_N(exp_self(member)->pos, |
221 |
|
|
_("can't access private '%s' outside of class..."), value->name) |
222 |
✓✓ |
528 |
else if(GET_FLAG(value, protect)) |
223 |
|
2 |
exp_setprot(exp_self(member), 1); |
224 |
|
|
} |
225 |
✓✓✓✓
|
714 |
if(base_static && GET_FLAG(value, member)) |
226 |
|
1 |
ERR_N(exp_self(member)->pos, |
227 |
|
|
_("cannot access member '%s.%s' without object instance..."), |
228 |
|
|
the_base->name, str) |
229 |
✓✓ |
713 |
if(GET_FLAG(value, const)) |
230 |
|
471 |
exp_setmeta(exp_self(member), 1); |
231 |
|
713 |
return value->type; |
232 |
|
|
} |
233 |
|
|
|
234 |
|
556 |
OP_EMIT(opem_object_dot) { |
235 |
|
556 |
const Exp_Dot *member = (Exp_Dot*)data; |
236 |
|
556 |
const Type t_base = actual_type(emit->gwion, member->t_base); |
237 |
|
556 |
const Value value = find_value(t_base, member->xid); |
238 |
✓✓✓✓ ✓✓ |
569 |
if(!is_class(emit->gwion, member->t_base) && (GET_FLAG(value, member) || |
239 |
✓✓ |
21 |
(isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0 && |
240 |
|
8 |
!is_fptr(emit->gwion, exp_self(member)->info->type)))) { |
241 |
✓✓ |
459 |
if(!GET_FLAG(t_base, struct)) |
242 |
✗✓ |
443 |
CHECK_BO(emit_exp(emit, member->base)) |
243 |
✓✓ |
459 |
if(isa(member->t_base, emit->env->gwion->type[et_object]) > 0) |
244 |
|
443 |
emit_except(emit, member->t_base); |
245 |
|
|
} |
246 |
✓✓✓✓
|
556 |
if(isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0 && !is_fptr(emit->gwion, exp_self(member)->info->type)) |
247 |
|
305 |
emit_member_func(emit, member); |
248 |
✓✓ |
251 |
else if(GET_FLAG(value, member)) { |
249 |
✓✓ |
189 |
if(!GET_FLAG(t_base, struct)) |
250 |
|
177 |
emit_member(emit, value, exp_getvar(exp_self(member))); |
251 |
|
|
else { |
252 |
|
|
// exp_setvar(member->base, exp_getvar(exp_self(member))); |
253 |
|
12 |
exp_setvar(member->base, 1); |
254 |
✗✓ |
12 |
CHECK_BO(emit_exp(emit, member->base)) |
255 |
|
12 |
emit_struct_data(emit, value, exp_getvar(exp_self(member))); |
256 |
|
|
} |
257 |
✓✗ |
62 |
} else if(GET_FLAG(value, static)) |
258 |
|
62 |
emit_dot_static_import_data(emit, value, exp_getvar(exp_self(member))); |
259 |
|
|
else { // member type |
260 |
|
|
const Instr instr = emit_add_instr(emit, RegPushImm); |
261 |
|
|
instr->m_val = (m_uint)value->type; |
262 |
|
|
} |
263 |
|
556 |
return (Instr)GW_OK; |
264 |
|
|
} |
265 |
|
|
|
266 |
|
|
struct tmpl_info { |
267 |
|
|
const Class_Def cdef; |
268 |
|
|
Type_List call; |
269 |
|
|
struct Vector_ type; |
270 |
|
|
struct Vector_ size; |
271 |
|
|
uint8_t index; |
272 |
|
|
}; |
273 |
|
|
|
274 |
|
118 |
ANN static inline size_t tmpl_set(struct tmpl_info* info, const Type t) { |
275 |
|
118 |
vector_add(&info->type, (vtype)t); |
276 |
|
118 |
const size_t len = strlen(t->name); |
277 |
|
118 |
vector_add(&info->size, len); |
278 |
|
118 |
return len; |
279 |
|
|
} |
280 |
|
|
|
281 |
|
55 |
ANN static ssize_t template_size(const Env env, struct tmpl_info* info) { |
282 |
|
55 |
ID_List base = info->cdef->base.tmpl->list; |
283 |
|
55 |
Type_List call = info->call; |
284 |
|
55 |
size_t size = 0; |
285 |
|
|
do { |
286 |
✗✓ |
63 |
DECL_OB(const Type, t, = known_type(env, call->td)) |
287 |
|
63 |
size += tmpl_set(info, t); |
288 |
✓✓✓✗ ✓✗ |
63 |
} while((call = call->next) && (base = base->next) && ++size); |
289 |
|
55 |
size += tmpl_set(info, info->cdef->base.type); |
290 |
|
55 |
return size + 4; |
291 |
|
|
} |
292 |
|
|
|
293 |
|
118 |
ANN static inline m_str tmpl_get(struct tmpl_info* info, m_str str) { |
294 |
|
118 |
const Type t = (Type)vector_at(&info->type, info->index); |
295 |
|
118 |
strcpy(str, t->name); |
296 |
|
118 |
return str += vector_at(&info->size, info->index); |
297 |
|
|
} |
298 |
|
|
|
299 |
|
55 |
ANN static void template_name(struct tmpl_info* info, m_str s) { |
300 |
|
55 |
m_str str = s; |
301 |
|
55 |
const m_uint size = info->index = vector_size(&info->type) -1; |
302 |
|
55 |
str = tmpl_get(info, str); |
303 |
|
55 |
*str++ = ':'; |
304 |
|
55 |
*str++ = '['; |
305 |
✓✓ |
118 |
for(info->index = 0; info->index < size; ++info->index) { |
306 |
|
63 |
str = tmpl_get(info, str); |
307 |
✓✓ |
63 |
if(info->index < size - 1) |
308 |
|
8 |
*str++ = ','; |
309 |
|
|
else { |
310 |
|
55 |
*str++ = ']'; |
311 |
|
|
} |
312 |
|
|
} |
313 |
|
55 |
*str = '\0'; |
314 |
|
55 |
} |
315 |
|
|
|
316 |
|
55 |
ANEW ANN static Symbol template_id(const Env env, const Class_Def c, const Type_List call) { |
317 |
|
55 |
struct tmpl_info info = { .cdef=c, .call=call }; |
318 |
|
55 |
vector_init(&info.type); |
319 |
|
55 |
vector_init(&info.size); |
320 |
|
55 |
ssize_t sz = template_size(env, &info); |
321 |
|
55 |
char name[sz]; |
322 |
✓✗ |
55 |
if(sz > GW_ERROR) |
323 |
|
55 |
template_name(&info, name); |
324 |
|
55 |
vector_release(&info.type); |
325 |
|
55 |
vector_release(&info.size); |
326 |
✓✗ |
55 |
return sz > GW_ERROR ? insert_symbol(env->gwion->st, name) : NULL; |
327 |
|
|
} |
328 |
|
|
|
329 |
|
56 |
ANN static m_bool template_match(ID_List base, Type_List call) { |
330 |
✓✓✓✓
|
56 |
while((call = call->next) && (base = base->next)); |
331 |
✓✓ |
56 |
return !call ? GW_OK : GW_ERROR; |
332 |
|
|
} |
333 |
|
|
|
334 |
|
55 |
ANN static Class_Def template_class(const Env env, const Class_Def def, const Type_List call) { |
335 |
✗✓ |
55 |
DECL_OO(const Symbol, name, = template_id(env, def, call)) |
336 |
✓✓✓✓
|
55 |
if(env->class_def && name == insert_symbol(env->gwion->st, env->class_def->name)) |
337 |
|
1 |
return env->class_def->e->def; |
338 |
|
54 |
const Type t = nspc_lookup_type1(env->curr, name); |
339 |
✓✓ |
54 |
if(t) |
340 |
|
15 |
return t->e->def; |
341 |
|
39 |
const Class_Def c = cpy_class_def(env->gwion->mp, def); |
342 |
|
39 |
c->base.xid = name; |
343 |
|
39 |
SET_FLAG(c, template | ae_flag_ref); |
344 |
|
39 |
UNSET_FLAG(c, scan0 | ae_flag_scan1 | ae_flag_scan2 | |
345 |
|
|
ae_flag_check | ae_flag_emit | ae_flag_valid); |
346 |
|
39 |
return c; |
347 |
|
|
} |
348 |
|
|
|
349 |
|
3 |
ANN static m_bool class2udef(const Env env, const Class_Def a, const Type t) { |
350 |
|
6 |
a->union_def = new_union_def(env->gwion->mp, cpy_decl_list(env->gwion->mp, a->list), |
351 |
|
6 |
loc_cpy(env->gwion->mp, t->e->def->pos)); |
352 |
|
3 |
a->union_def->type_xid = a->base.xid; |
353 |
✗✓ |
3 |
if(GET_FLAG(t, global)) |
354 |
|
|
SET_FLAG(a->union_def, global); |
355 |
✗✓ |
3 |
CHECK_BB(scan0_union_def(env, a->union_def)) |
356 |
|
3 |
a->base.type = a->union_def->type; |
357 |
|
3 |
a->base.type->e->def = a; |
358 |
|
3 |
a->union_def->tmpl = cpy_tmpl(env->gwion->mp, a->base.tmpl); |
359 |
|
3 |
return GW_OK; |
360 |
|
|
} |
361 |
|
|
|
362 |
|
39 |
ANN static m_bool _scan_class(const Env env, const Type t, const Class_Def a) { |
363 |
✓✓ |
39 |
if(t->e->parent != env->gwion->type[et_union]) |
364 |
✗✓ |
36 |
CHECK_BB(scan0_class_def(env, a)) |
365 |
|
|
else |
366 |
✗✓ |
3 |
CHECK_BB(class2udef(env, a, t)) |
367 |
|
39 |
SET_FLAG(a->base.type, template); |
368 |
✓✓ |
39 |
if(GET_FLAG(t, builtin)) |
369 |
|
15 |
SET_FLAG(a->base.type, builtin); |
370 |
|
39 |
return GW_OK; |
371 |
|
|
} |
372 |
|
|
|
373 |
|
56 |
ANN Type scan_class(const Env env, const Type t, const Type_Decl* td) { |
374 |
✓✓ |
56 |
if(template_match(t->e->def->base.tmpl->list, td->types) < 0) |
375 |
|
1 |
ERR_O(td->pos, _("invalid template types number")) |
376 |
✗✓ |
55 |
DECL_OO(const Class_Def, a, = template_class(env, t->e->def, td->types)) |
377 |
✓✓ |
55 |
if(a->base.type) |
378 |
|
16 |
return a->base.type; |
379 |
|
78 |
struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)scan0_cdef, |
380 |
|
39 |
.scope=env->scope->depth, .flag=ae_flag_scan0 }; |
381 |
|
|
// CHECK_BO(envset_push(&es, t->e->owner_class, env->context ? env->context->nspc : env->curr)) |
382 |
✓✓✗✓
|
39 |
CHECK_BO(envset_push(&es, t->e->owner_class, t->e->ctx ? t->e->ctx->nspc : env->curr)) |
383 |
|
39 |
a->base.tmpl = mk_tmpl(env, t->e->def->base.tmpl, td->types); |
384 |
|
39 |
const m_bool ret = _scan_class(env, t, a); |
385 |
✓✓ |
39 |
if(es.run) |
386 |
|
1 |
envset_pop(&es, t->e->owner_class); |
387 |
✓✗ |
39 |
if(ret > 0) |
388 |
|
39 |
return a->base.type; |
389 |
|
|
if(!a->base.type) |
390 |
|
|
free_class_def(env->gwion->mp, a); |
391 |
|
|
return NULL; |
392 |
|
|
} |
393 |
|
|
|
394 |
|
326 |
ANN static inline Symbol dot_symbol(SymTable *st, const Value v) { |
395 |
✓✓ |
326 |
const m_str name = !GET_FLAG(v, static) ? "this" : v->from->owner_class->name; |
396 |
|
326 |
return insert_symbol(st, name); |
397 |
|
|
} |
398 |
|
|
|
399 |
|
326 |
ANN Exp symbol_owned_exp(const Gwion gwion, const Symbol *data) { |
400 |
|
326 |
const Value v = prim_self(data)->value; |
401 |
|
326 |
const Exp base = new_prim_id(gwion->mp, dot_symbol(gwion->st, v), loc_cpy(gwion->mp, prim_pos(data))); |
402 |
|
326 |
const Exp dot = new_exp_dot(gwion->mp, base, *data); |
403 |
|
326 |
const Type owner = v->from->owner_class; |
404 |
|
652 |
dot->d.exp_dot.t_base = dot->d.exp_dot.base->info->type = !GET_FLAG(v, static) ? |
405 |
✓✓ |
326 |
owner : type_class(gwion, owner); |
406 |
|
326 |
dot->info->type = prim_exp(data)->info->type; |
407 |
|
326 |
exp_setvar(dot, exp_getvar(prim_exp(data))); |
408 |
|
326 |
return dot; |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
ANN void struct_release(const VM_Shred shred, const Type base, const m_bit *ptr) { |
412 |
|
|
const Vector types = &base->e->tuple->types; |
413 |
|
|
const Vector offsets = &base->e->tuple->offset; |
414 |
|
|
for(m_uint i = 0; i < vector_size(types); ++i) { |
415 |
|
|
const Type t = (Type)vector_at(types, i); |
416 |
|
|
if(isa(t, shred->info->vm->gwion->type[et_compound]) < 0) |
417 |
|
|
continue; |
418 |
|
|
const m_uint offset = vector_at(offsets, i); |
419 |
|
|
if(!GET_FLAG(t, struct)) |
420 |
|
|
release(*(M_Object*)(ptr + offset), shred); |
421 |
|
|
else |
422 |
|
|
struct_release(shred, t, *(m_bit**)(ptr + offset)); |
423 |
|
|
} |
424 |
|
|
} |
425 |
|
|
|
426 |
|
712 |
GWION_IMPORT(object_op) { |
427 |
|
712 |
const Type t_null = gwi_mk_type(gwi, "@null", SZ_INT, NULL); |
428 |
|
712 |
gwi->gwion->type[et_null] = t_null; |
429 |
|
712 |
GWI_BB(gwi_set_global_type(gwi, t_null, et_null)) |
430 |
|
712 |
GWI_BB(gwi_oper_cond(gwi, "Object", BranchEqInt, BranchNeqInt)) |
431 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "Object", "Object", NULL)) |
432 |
|
712 |
GWI_BB(gwi_oper_add(gwi, at_object)) |
433 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_at_object)) |
434 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) |
435 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@null", "Object", NULL)) |
436 |
|
712 |
GWI_BB(gwi_oper_add(gwi, at_object)) |
437 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_at_object)) |
438 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) |
439 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "Object", "Object", "int")) |
440 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "==", EqObject)) |
441 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "!=", NeqObject)) |
442 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_object_cast)) |
443 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_object_cast)) |
444 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "$", NULL)) |
445 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_implicit_null2obj)) |
446 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_implicit_null2obj)) |
447 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) |
448 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@null", "Object", NULL)) |
449 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_implicit_null2obj)) |
450 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) |
451 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@null", "Object", NULL)) |
452 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_object_cast)) |
453 |
|
712 |
GWI_BB(gwi_oper_emi(gwi, opem_object_cast)) |
454 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "$", NULL)) |
455 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, NULL, "Object", "bool")) |
456 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_unary_meta2)) |
457 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "!", IntNot)) |
458 |
|
712 |
GWI_BB(gwi_oper_ini(gwi, "@Compound", NULL, NULL)) |
459 |
|
712 |
GWI_BB(gwi_oper_add(gwi, opck_struct_scan)) |
460 |
|
712 |
GWI_BB(gwi_oper_end(gwi, "@scan", NULL)) |
461 |
|
712 |
gwi_item_ini(gwi, "@null", "null"); |
462 |
|
712 |
gwi_item_end(gwi, 0, NULL); |
463 |
|
712 |
return GW_OK; |
464 |
|
|
} |