GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/object_op.c Lines: 297 315 94.3 %
Date: 2020-07-24 14:14:26 Branches: 153 186 82.3 %

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
1
describe_logical(Eq,  ==)
33
1
describe_logical(Neq, !=)
34
48
static inline m_bool nonnull_check(const Type l, const Type r) {
35

48
  return !GET_FLAG(l, nonnull) && GET_FLAG(r, nonnull);
36
}
37
38
62
static inline Type check_nonnull(const Env env, const Type l, const Type r,
39
      const m_str action, const loc_t pos) {
40
62
  if(GET_FLAG(r, nonnull)) {
41
20
    if(isa(l, env->gwion->type[et_null]) > 0)
42
4
      ERR_N(pos, _("can't %s '%s' to '%s'"), action, l->name, r->name);
43
16
    if(isa(l, r) < 0)
44
1
      ERR_N(pos, _("can't %s '%s' to '%s'"), action, l->name, r->name);
45
15
    return r->e->parent;
46
  }
47

42
  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
38
  return r;
50
}
51
52
31
static OP_CHECK(at_object) {
53
31
  const Exp_Binary* bin = (Exp_Binary*)data;
54
31
  const Type l = bin->lhs->info->type;
55
31
  const Type r = bin->rhs->info->type;
56
31
  if(opck_rassign(env, data, mut) == env->gwion->type[et_null])
57
    return env->gwion->type[et_null];
58
31
  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
29
  if(bin->rhs->exp_type == ae_exp_decl) {
61
21
    SET_FLAG(bin->rhs->d.exp_decl.td, ref);
62
21
    SET_FLAG(bin->rhs->d.exp_decl.list->self->value, ref);
63
  }
64
29
  exp_setvar(bin->rhs, 1);
65
29
  return r;
66
}
67
68
29
static OP_EMIT(opem_at_object) {
69
29
  const Exp_Binary* bin = (Exp_Binary*)data;
70
29
  const Type l = bin->lhs->info->type;
71
29
  const Type r = bin->rhs->info->type;
72
29
  if(nonnull_check(l, r)) {
73
5
    const Instr instr = emit_add_instr(emit, GWOP_EXCEPT);
74
5
    instr->m_val = SZ_INT;
75
  }
76
29
  return emit_add_instr(emit, ObjectAssign);
77
}
78
79
12
static OP_CHECK(opck_object_cast) {
80
12
  const Exp_Cast* cast = (Exp_Cast*)data;
81
12
  const Type l = cast->exp->info->type;
82
12
  const Type r = exp_self(cast)->info->type;
83
12
  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
8
  return force_type(env, r);
86
}
87
88
8
static OP_EMIT(opem_object_cast) {
89
8
  const Exp_Cast* cast = (Exp_Cast*)data;
90
8
  const Type l = cast->exp->info->type;
91
8
  const Type r = exp_self(cast)->info->type;
92
8
  if(nonnull_check(l, r))
93
4
    emit_add_instr(emit, GWOP_EXCEPT);
94
8
  return (Instr)GW_OK;
95
}
96
97
19
static OP_CHECK(opck_implicit_null2obj) {
98
19
  const struct Implicit* imp = (struct Implicit*)data;
99
19
  const Type l = imp->e->info->type;
100
19
  const Type r = imp->t;
101
19
  if(check_nonnull(env, l, r, "implicitly cast", imp->e->pos) == env->gwion->type[et_null])
102
3
    return env->gwion->type[et_null];
103
16
  imp->e->info->cast_to = r;
104
16
  return imp->t;
105
}
106
107
11
static OP_EMIT(opem_implicit_null2obj) {
108
11
  const struct Implicit* imp = (struct Implicit*)data;
109
11
  const Type l = imp->e->info->type;
110
11
  const Type r = imp->t;
111
11
  if(nonnull_check(l, r))
112
3
    emit_add_instr(emit, GWOP_EXCEPT);
113
11
  return (Instr)GW_OK;
114
}
115
116
ANN /*static*/ Type scan_class(const Env env, const Type t, const Type_Decl* td);
117
118
43
static Type opck_object_scan(const Env env, const struct TemplateScan *ts) {
119
43
  if(ts->td->types)
120
42
    return scan_class(env, ts->t, ts->td) ?: env->gwion->type[et_null];
121
1
  ERR_N(td_pos(ts->td), _("you must provide template types for type '%s'"), ts->t->name)
122
}
123
124
43
static OP_CHECK(opck_struct_scan) {
125
43
  struct TemplateScan *ts = (struct TemplateScan*)data;
126
43
  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
39
ANN static void emit_dot_static_data(const Emitter emit, const Value v, const uint emit_var) {
134
39
  const m_uint size = v->type->size;
135
39
  const Instr instr = emit_kind(emit, size, emit_var, dotstatic);
136
39
  instr->m_val = (m_uint)(v->from->owner->info->class_data + v->from->offset);
137
39
  instr->m_val2 = size;
138
39
}
139
140
static const f_instr regpushimm[] = { RegPushImm, RegPushImm2, RegPushImm3, RegPushImm4 };
141
59
ANN static void emit_dot_static_import_data(const Emitter emit, const Value v, const uint emit_addr) {
142

79
  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
39
    emit_dot_static_data(emit, v, emit_addr);
149
59
}
150
static const f_instr dotmember[]  = { DotMember, DotMember2, DotMember3, DotMember4 };
151
152
290
ANN static void emit_member_func(const Emitter emit, const Exp_Dot* member) {
153
290
  const Func f = exp_self(member)->info->type->e->d.func;
154
290
  if(f->def->base->tmpl)
155
36
    emit_add_instr(emit, DotTmplVal);
156
else
157

254
  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
221
    if(GET_FLAG(member->t_base, struct)) {
166
4
      if(!GET_FLAG(f->def, 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
217
    const Instr instr = emit_add_instr(emit, GET_FLAG(f, member) ? DotFunc : DotStaticFunc);
175
217
    instr->m_val = f->vt_index;
176
  }
177
253
  return;
178
}
179
180
163
ANN static inline void emit_member(const Emitter emit, const Value v, const uint emit_addr) {
181
163
  const m_uint size = v->type->size;
182
163
  const Instr instr = emit_kind(emit, size, emit_addr, dotmember);
183
163
  instr->m_val = v->from->offset;
184
163
  instr->m_val2 = size;
185
163
}
186
187
ANN static inline void emit_struct_addr(const Emitter emit, const Value v) {
188
  const Instr set = emit_add_instr(emit, StructMemberAddr);
189
  set->m_val = v->from->offset;
190
}
191
192
ANN static inline void emit_struct_var(const Emitter emit, const Value v) {
193
  for(m_uint i = 0; i < v->type->size; i += SZ_INT) {
194
    const Instr set = emit_add_instr(emit, Reg2Reg);
195
    set->m_val2 = -v->type->size + i;
196
    set->m_val = -v->type->size + v->from->offset + i;
197
  }
198
}
199
200
14
ANN static inline void emit_struct_data(const Emitter emit, const Value v, const uint emit_addr) {
201
14
  const Instr instr = emit_kind(emit, v->type->size, emit_addr, structmember);
202
14
  instr->m_val = v->from->offset;
203
14
  if(!emit_addr) {
204
10
    const Instr instr = emit_add_instr(emit, RegPush);
205
10
    instr->m_val = v->type->size -SZ_INT;
206
  }
207
14
}
208
209
ANN m_bool not_from_owner_class(const Env env, const Type t, const Value v, const loc_t pos);
210
717
OP_CHECK(opck_object_dot) {
211
717
  const Exp_Dot *member = (Exp_Dot*)data;
212
717
  const m_str str = s_name(member->xid);
213
717
  const m_bool base_static = is_class(env->gwion, member->t_base);
214
717
  const Type the_base = base_static ? member->t_base->e->d.base_type : member->t_base;
215
717
  if(!the_base->nspc)
216
1
    ERR_O(member->base->pos,
217
          _("type '%s' does not have members - invalid use in dot expression of %s"),
218
          the_base->name, str)
219

716
  if(member->xid ==  insert_symbol(env->gwion->st, "this") && base_static)
220
2
    ERR_O(exp_self(member)->pos,
221
          _("keyword 'this' must be associated with object instance..."))
222
714
  const Value value = find_value(the_base, member->xid);
223
714
  if(!value) {
224
31
    env_err(env, exp_self(member)->pos,
225
          _("class '%s' has no member '%s'"), the_base->name, str);
226
31
    if(member->t_base->nspc)
227
30
      did_you_mean_type(the_base, str);
228
31
    return NULL;
229
  }
230
683
  CHECK_BO(not_from_owner_class(env, the_base, value, exp_self(member)->pos))
231

683
  if(!env->class_def || isa(env->class_def, value->from->owner_class) < 0) {
232
499
    if(GET_FLAG(value, private))
233
12
      ERR_O(exp_self(member)->pos,
234
          _("can't access private '%s' outside of class..."), value->name)
235
487
    else if(GET_FLAG(value, protect))
236
2
      exp_setprot(exp_self(member), 1);
237
  }
238

671
  if(base_static && GET_FLAG(value, member))
239
2
    ERR_O(exp_self(member)->pos,
240
          _("cannot access member '%s.%s' without object instance..."),
241
          the_base->name, str)
242
669
  if(GET_FLAG(value, const))
243
440
    exp_setmeta(exp_self(member), 1);
244
669
  return value->type;
245
}
246
247
526
OP_EMIT(opem_object_dot) {
248
526
  const Exp_Dot *member = (Exp_Dot*)data;
249
526
  const Type t_base = actual_type(emit->gwion, member->t_base);
250
526
  const Value value = find_value(t_base, member->xid);
251

537
  if(!is_class(emit->gwion, member->t_base) && (GET_FLAG(value, member) ||
252
18
       (isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0 &&
253
7
       !is_fptr(emit->gwion, exp_self(member)->info->type)))) {
254
432
    if(!GET_FLAG(t_base, struct))
255
414
      CHECK_BO(emit_exp(emit, member->base))
256
432
    if(isa(member->t_base, emit->env->gwion->type[et_object]) > 0)
257
414
      emit_except(emit, member->t_base);
258
  }
259

526
  if(isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0 && !is_fptr(emit->gwion, exp_self(member)->info->type))
260
290
	  emit_member_func(emit, member);
261
236
  else if(GET_FLAG(value, member)) {
262
177
    if(!GET_FLAG(t_base, struct))
263
163
      emit_member(emit, value, exp_getvar(exp_self(member)));
264
    else {
265
//      exp_setvar(member->base, exp_getvar(exp_self(member)));
266
14
      exp_setvar(member->base, 1);
267
14
      CHECK_BO(emit_exp(emit, member->base))
268
14
      emit_struct_data(emit, value, exp_getvar(exp_self(member)));
269
    }
270
59
  } else if(GET_FLAG(value, static))
271
59
    emit_dot_static_import_data(emit, value, exp_getvar(exp_self(member)));
272
  else { // member type
273
    const Instr instr = emit_add_instr(emit, RegPushImm);
274
    instr->m_val = (m_uint)value->type;
275
  }
276
526
  return (Instr)GW_OK;
277
}
278
279
struct tmpl_info {
280
  const  Class_Def cdef;
281
  Type_List        call;
282
  struct Vector_   type;
283
  struct Vector_   size;
284
  uint8_t index;
285
};
286
287
144
ANN static inline size_t tmpl_set(struct tmpl_info* info, const Type t) {
288
144
  vector_add(&info->type, (vtype)t);
289
144
  const size_t len = strlen(t->name);
290
144
  vector_add(&info->size, len);
291
144
  return len;
292
}
293
294
67
ANN static ssize_t template_size(const Env env, struct tmpl_info* info) {
295
67
  ID_List base = info->cdef->base.tmpl->list;
296
67
  Type_List call = info->call;
297
67
  size_t size = 0;
298
  do {
299
77
    DECL_OB(const Type, t, = known_type(env, call->td))
300
77
    size += tmpl_set(info, t);
301

77
  } while((call = call->next) && (base = base->next) && ++size);
302
67
  size += tmpl_set(info, info->cdef->base.type);
303
67
  return size + 16 + 3;
304
}
305
306
144
ANN static inline m_str tmpl_get(struct tmpl_info* info, m_str str) {
307
144
  const Type t = (Type)vector_at(&info->type, info->index);
308
144
  strcpy(str, t->name);
309
144
  return str += vector_at(&info->size, info->index);
310
}
311
312
67
ANN static void template_name(struct tmpl_info* info, m_str s) {
313
67
  m_str str = s;
314
67
  *str++ = '<';
315
67
  *str++ = '~';
316
67
  const m_uint size = vector_size(&info->type) -1;
317
144
  for(info->index = 0; info->index < size; ++info->index) {
318
77
    str = tmpl_get(info, str);
319
77
    if(info->index < size - 1)
320
10
      *str++ = ',';
321
    else {
322
67
      *str++ = '~';
323
67
      *str++ = '>';
324
    }
325
  }
326
67
  str = tmpl_get(info, str);
327
67
  *str = '\0';
328
67
}
329
330
67
ANEW ANN static Symbol template_id(const Env env, const Class_Def c, const Type_List call) {
331
67
  struct tmpl_info info = { .cdef=c, .call=call };
332
67
  vector_init(&info.type);
333
67
  vector_init(&info.size);
334
67
  ssize_t sz = template_size(env, &info);
335
67
  char name[sz];
336
67
  if(sz > GW_ERROR)
337
67
    template_name(&info, name);
338
67
  vector_release(&info.type);
339
67
  vector_release(&info.size);
340
67
  return sz > GW_ERROR ? insert_symbol(env->gwion->st, name) : NULL;
341
}
342
343
69
ANN static m_bool template_match(ID_List base, Type_List call) {
344

69
  while((call = call->next) && (base = base->next));
345
69
  return !call ? GW_OK : GW_ERROR;
346
}
347
348
67
ANN static Class_Def template_class(const Env env, const Class_Def def, const Type_List call) {
349
67
  DECL_OO(const Symbol, name, = template_id(env, def, call))
350

67
  if(env->class_def && name == insert_symbol(env->gwion->st, env->class_def->name))
351
1
     return env->class_def->e->def;
352
66
  const Type t = nspc_lookup_type1(env->curr, name);
353
66
  if(t)
354
22
    return t->e->def;
355
44
  const Class_Def c = cpy_class_def(env->gwion->mp, def);
356
44
  c->base.xid = name;
357
44
  SET_FLAG(c, template | ae_flag_ref);
358
44
  UNSET_FLAG(c, scan0 | ae_flag_scan1 | ae_flag_scan2 |
359
    ae_flag_check | ae_flag_emit | ae_flag_valid);
360
44
  return c;
361
}
362
363
3
ANN static m_bool class2udef(const Env env, const Class_Def a, const Type t) {
364
6
  a->union_def = new_union_def(env->gwion->mp, cpy_decl_list(env->gwion->mp, a->list),
365
6
    loc_cpy(env->gwion->mp, t->e->def->pos));
366
3
  a->union_def->type_xid = a->base.xid;
367
3
  if(GET_FLAG(t, global))
368
    SET_FLAG(a->union_def, global);
369
3
  CHECK_BB(scan0_union_def(env, a->union_def))
370
3
  a->base.type = a->union_def->type;
371
3
  a->base.type->e->def = a;
372
3
  a->union_def->tmpl = cpy_tmpl(env->gwion->mp, a->base.tmpl);
373
3
  return GW_OK;
374
}
375
376
44
ANN static m_bool _scan_class(const Env env, const Type t, const Class_Def a) {
377
44
  if(t->e->parent !=  env->gwion->type[et_union])
378
41
    CHECK_BB(scan0_class_def(env, a))
379
  else
380
3
    CHECK_BB(class2udef(env, a, t))
381
44
  SET_FLAG(a->base.type, template);
382
44
  if(GET_FLAG(t, builtin))
383
18
    SET_FLAG(a->base.type, builtin);
384
44
  return GW_OK;
385
}
386
387
69
ANN Type scan_class(const Env env, const Type t, const Type_Decl* td) {
388
69
  if(template_match(t->e->def->base.tmpl->list, td->types) < 0)
389
2
   ERR_O(td->pos, _("invalid template types number"))
390
67
  DECL_OO(const Class_Def, a, = template_class(env, t->e->def, td->types))
391
67
  if(a->base.type)
392
23
    return a->base.type;
393
88
  struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)scan0_cdef,
394
44
    .scope=env->scope->depth, .flag=ae_flag_scan0 };
395
//  CHECK_BO(envset_push(&es, t->e->owner_class, env->context ? env->context->nspc : env->curr))
396

44
  CHECK_BO(envset_push(&es, t->e->owner_class, t->e->ctx ? t->e->ctx->nspc : env->curr))
397
44
  a->base.tmpl = mk_tmpl(env, t->e->def->base.tmpl, td->types);
398
44
  const m_bool ret = _scan_class(env, t, a);
399
44
  if(es.run)
400
1
    envset_pop(&es, t->e->owner_class);
401
44
  if(ret > 0)
402
44
    return a->base.type;
403
  if(!a->base.type)
404
    free_class_def(env->gwion->mp, a);
405
  return NULL;
406
}
407
408
322
ANN static inline Symbol dot_symbol(SymTable *st, const Value v) {
409
322
  const m_str name = !GET_FLAG(v, static) ? "this" : v->from->owner_class->name;
410
322
  return insert_symbol(st, name);
411
}
412
413
322
ANN Exp symbol_owned_exp(const Gwion gwion, const Symbol *data) {
414
322
  const Value v = prim_self(data)->value;
415
322
  const Exp base = new_prim_id(gwion->mp, dot_symbol(gwion->st, v), loc_cpy(gwion->mp, prim_pos(data)));
416
322
  const Exp dot = new_exp_dot(gwion->mp, base, *data);
417
322
  const Type owner = v->from->owner_class;
418
644
  dot->d.exp_dot.t_base = dot->d.exp_dot.base->info->type = !GET_FLAG(v, static) ?
419
322
    owner : type_class(gwion, owner);
420
322
  dot->info->type = prim_exp(data)->info->type;
421
322
  exp_setvar(dot, exp_getvar(prim_exp(data)));
422
322
  return dot;
423
}
424
425
ANN void struct_release(const VM_Shred shred, const Type base, const m_bit *ptr) {
426
  const Vector types   = &base->e->tuple->types;
427
  const Vector offsets = &base->e->tuple->offset;
428
  for(m_uint i = 0; i < vector_size(types); ++i) {
429
    const Type t = (Type)vector_at(types, i);
430
    if(isa(t, shred->info->vm->gwion->type[et_compound]) < 0)
431
      continue;
432
    const m_uint offset = vector_at(offsets, i);
433
    if(!GET_FLAG(t, struct))
434
      release(*(M_Object*)(ptr + offset), shred);
435
    else
436
      struct_release(shred, t, *(m_bit**)(ptr + offset));
437
  }
438
}
439
440
730
GWION_IMPORT(object_op) {
441
730
  const Type t_null  = gwi_mk_type(gwi, "@null",  SZ_INT, "Object");
442
730
  gwi->gwion->type[et_null] = t_null;
443
730
  GWI_BB(gwi_set_global_type(gwi, t_null, et_null))
444
730
  GWI_BB(gwi_oper_cond(gwi, "Object", BranchEqInt, BranchNeqInt))
445
730
  GWI_BB(gwi_oper_ini(gwi, "Object", "Object", NULL))
446
730
  GWI_BB(gwi_oper_add(gwi, at_object))
447
730
  GWI_BB(gwi_oper_emi(gwi, opem_at_object))
448
730
  GWI_BB(gwi_oper_end(gwi, "@=>", ObjectAssign))
449
730
  GWI_BB(gwi_oper_ini(gwi, "Object", "Object", "int"))
450
730
  GWI_BB(gwi_oper_end(gwi, "==",  EqObject))
451
730
  GWI_BB(gwi_oper_end(gwi, "!=", NeqObject))
452
730
  GWI_BB(gwi_oper_add(gwi, opck_object_cast))
453
730
  GWI_BB(gwi_oper_emi(gwi, opem_object_cast))
454
730
  GWI_BB(gwi_oper_end(gwi, "$", NULL))
455
730
  GWI_BB(gwi_oper_add(gwi, opck_implicit_null2obj))
456
730
  GWI_BB(gwi_oper_emi(gwi, opem_implicit_null2obj))
457
730
  GWI_BB(gwi_oper_end(gwi, "@implicit", NULL))
458
730
  GWI_BB(gwi_oper_ini(gwi, "@null", "Object", "int"))
459
730
  GWI_BB(gwi_oper_add(gwi, opck_implicit_null2obj))
460
730
  GWI_BB(gwi_oper_end(gwi, "@implicit", NULL))
461
730
  GWI_BB(gwi_oper_ini(gwi, NULL, "Object", "bool"))
462
730
  GWI_BB(gwi_oper_add(gwi, opck_unary_meta2))
463
730
  GWI_BB(gwi_oper_end(gwi, "!", IntNot))
464
730
  GWI_BB(gwi_oper_ini(gwi, "@Compound", NULL, NULL))
465
730
  GWI_BB(gwi_oper_add(gwi, opck_struct_scan))
466
730
  GWI_BB(gwi_oper_end(gwi, "@scan", NULL))
467
730
  gwi_item_ini(gwi, "@null", "null");
468
730
  gwi_item_end(gwi, 0, NULL);
469
730
  return GW_OK;
470
}