GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/object_op.c Lines: 304 322 94.4 %
Date: 2020-09-22 13:02:15 Branches: 154 186 82.8 %

Line Branch Exec Source
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
}