GCC Code Coverage Report
Directory: src/ Exec Total Coverage
File: src/lib/object_op.c Lines: 304 322 94.4 %
Date: 2020-09-14 09:03:05 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
38
    return scan_class(env, ts->t, ts->td) ?: env->gwion->type[et_null];
121
3
  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, 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
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
12
ANN static inline void emit_struct_data(const Emitter emit, const Value v, const uint emit_addr) {
201
12
  const Instr instr = emit_kind(emit, v->type->size, emit_addr, structmember);
202
12
  instr->m_val = v->from->offset;
203
12
  if(!emit_addr) {
204
8
    const Instr instr = emit_add_instr(emit, RegPush);
205
8
    instr->m_val = v->type->size -SZ_INT;
206
  }
207
12
}
208
209
ANN m_bool not_from_owner_class(const Env env, const Type t, const Value v, const loc_t pos);
210
742
OP_CHECK(opck_object_dot) {
211
742
  const Exp_Dot *member = (Exp_Dot*)data;
212
742
  const m_str str = s_name(member->xid);
213
742
  const m_bool base_static = is_class(env->gwion, member->t_base);
214
742
  const Type the_base = base_static ? member->t_base->e->d.base_type : member->t_base;
215
742
  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

741
  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
739
  const Value value = find_value(the_base, member->xid);
223
739
  if(!value) {
224
12
    env_err(env, exp_self(member)->pos,
225
          _("class '%s' has no member '%s'"), the_base->name, str);
226
12
    if(member->t_base->nspc)
227
10
      did_you_mean_type(the_base, str);
228
12
    return NULL;
229
  }
230
727
  CHECK_BO(not_from_owner_class(env, the_base, value, exp_self(member)->pos))
231

727
  if(!env->class_def || isa(env->class_def, value->from->owner_class) < 0) {
232
541
    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
529
    else if(GET_FLAG(value, protect))
236
2
      exp_setprot(exp_self(member), 1);
237
  }
238

715
  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
713
  if(GET_FLAG(value, const))
243
471
    exp_setmeta(exp_self(member), 1);
244
713
  return value->type;
245
}
246
247
556
OP_EMIT(opem_object_dot) {
248
556
  const Exp_Dot *member = (Exp_Dot*)data;
249
556
  const Type t_base = actual_type(emit->gwion, member->t_base);
250
556
  const Value value = find_value(t_base, member->xid);
251

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

556
  if(isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0 && !is_fptr(emit->gwion, exp_self(member)->info->type))
260
305
	  emit_member_func(emit, member);
261
251
  else if(GET_FLAG(value, member)) {
262
189
    if(!GET_FLAG(t_base, struct))
263
177
      emit_member(emit, value, exp_getvar(exp_self(member)));
264
    else {
265
//      exp_setvar(member->base, exp_getvar(exp_self(member)));
266
12
      exp_setvar(member->base, 1);
267
12
      CHECK_BO(emit_exp(emit, member->base))
268
12
      emit_struct_data(emit, value, exp_getvar(exp_self(member)));
269
    }
270
62
  } else if(GET_FLAG(value, static))
271
62
    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
556
  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
116
ANN static inline size_t tmpl_set(struct tmpl_info* info, const Type t) {
288
116
  vector_add(&info->type, (vtype)t);
289
116
  const size_t len = strlen(t->name);
290
116
  vector_add(&info->size, len);
291
116
  return len;
292
}
293
294
54
ANN static ssize_t template_size(const Env env, struct tmpl_info* info) {
295
54
  ID_List base = info->cdef->base.tmpl->list;
296
54
  Type_List call = info->call;
297
54
  size_t size = 0;
298
  do {
299
62
    DECL_OB(const Type, t, = known_type(env, call->td))
300
62
    size += tmpl_set(info, t);
301

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

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

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

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