Gwion coverage report


Directory: src/
File: src/lib/array.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 479 807 59.4%
Functions: 46 84 54.8%
Branches: 111 250 44.4%

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 "array.h"
9 #include "emit.h"
10 #include "operator.h"
11 #include "import.h"
12 #include "traverse.h"
13 #include "parse.h"
14 #include "gwi.h"
15 #include "emit.h"
16 #include "looper.h"
17
18 26 static DTOR(array_dtor) {
19
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
26 if (*(void **)(o->data + SZ_INT)) xfree(*(void **)(o->data + SZ_INT));
20 26 struct M_Vector_ *a = ARRAY(o);
21 26 m_vector_release(a);
22 26 }
23
24 8 static DTOR(array_dtor_obj) {
25 8 struct M_Vector_ *a = ARRAY(o);
26
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 8 times.
21 for (m_uint i = 0; i < ARRAY_LEN(a); ++i)
27 13 release(*(M_Object *)(ARRAY_PTR(a) + i * SZ_INT), shred);
28 8 }
29
30 static DTOR(array_dtor_struct) {
31 struct M_Vector_ *a = ARRAY(o);
32 for (m_uint i = 0; i < ARRAY_LEN(a); ++i)
33 struct_release(shred, array_base(o->type_ref),
34 &*(m_bit *)(ARRAY_PTR(a) + i * SZ_INT));
35 }
36
37 29 ANN M_Object new_array(MemPool p, const Type t, const m_uint length) {
38 29 const M_Object a = new_object(p, t);
39 29 const m_uint depth =
40
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 5 times.
29 !tflag(t, tflag_typedef) ? t->array_depth : t->info->parent->array_depth;
41 // const m_uint size = depth > 1 ? SZ_INT : array_base(t)->size;
42
3/4
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
29 const m_uint size = depth > 1 ? SZ_INT : array_base(t)->actual_size ?: array_base(t)->size;
43 //ARRAY(a) = new_m_vector(p, size, length);
44 29 m_vector_init(ARRAY(a), size, length);
45 29 return a;
46 }
47
48 static MFUN(vm_vector_rem) {
49 const m_int index = *(m_int *)(shred->mem + SZ_INT);
50 const M_Vector v = ARRAY(o);
51 if (index < 0 || (m_uint)index >= ARRAY_LEN(v)) return;
52 m_vector_rem(v, (vtype)index);
53 }
54
55 static MFUN(vm_vector_rem_obj) {
56 const m_int index = *(m_int *)(shred->mem + SZ_INT);
57 const M_Vector v = ARRAY(o);
58 if (index < 0 || (m_uint)index >= ARRAY_LEN(v)) return;
59 release(*(M_Object *)(ARRAY_PTR(v) + index * ARRAY_SIZE(v)), shred);
60 m_vector_rem(v, (vtype)index);
61 }
62
63 static MFUN(vm_vector_rem_struct) {
64 const m_int index = *(m_int *)(shred->mem + SZ_INT);
65 const M_Vector v = ARRAY(o);
66 if (index < 0 || (m_uint)index >= ARRAY_LEN(v)) return;
67 const Type t = o->type_ref;
68 struct_release(shred, array_base(t), ARRAY_PTR(v) + index * ARRAY_SIZE(v));
69 m_vector_rem(v, (vtype)index);
70 }
71
72 static MFUN(vm_vector_insert) {
73 const m_int index = *(m_int *)(shred->mem + SZ_INT);
74 const M_Vector v = ARRAY(o);
75 if (index < 0 || (m_uint)index > ARRAY_LEN(v)) return;
76 m_vector_insert(v, index, shred->mem + SZ_INT * 2);
77 }
78
79 static MFUN(vm_vector_insert_obj) {
80 const m_int index = *(m_int *)(shred->mem + SZ_INT);
81 const M_Vector v = ARRAY(o);
82 if (index < 0 || (m_uint)index > ARRAY_LEN(v)) return;
83 m_vector_insert(v, index, shred->mem + SZ_INT * 2);
84 ++(*(M_Object *)(shred->mem + SZ_INT * 2))->ref;
85 }
86
87 static MFUN(vm_vector_insert_struct) {
88 const m_int index = *(m_int *)(shred->mem + SZ_INT);
89 const M_Vector v = ARRAY(o);
90 if (index < 0 || (m_uint)index > ARRAY_LEN(v)) return;
91 m_vector_insert(v, index, shred->mem + SZ_INT * 2);
92 struct_addref(shred->info->vm->gwion, array_base(o->type_ref),
93 shred->mem + SZ_INT * 2);
94 }
95
96 4 static MFUN(vm_vector_size) { *(m_uint *)RETURN = ARRAY_LEN(ARRAY(o)); }
97
98 static MFUN(vm_vector_depth) { *(m_uint *)RETURN = o->type_ref->array_depth; }
99
100 static MFUN(vm_vector_cap) { *(m_uint *)RETURN = ARRAY_CAP(ARRAY(o)); }
101
102 static MFUN(vm_vector_random) {
103 const M_Vector array = ARRAY(o);
104 const m_uint sz = ARRAY_LEN(array);
105 const m_uint idx =
106 (m_int)(sz) * (gw_rand(shred->info->vm->rand) / (UINT32_MAX + 1.0));
107 m_vector_get(array, idx, (void *)RETURN);
108 }
109
110 #define ARRAY_OPCK(a, b, pos) \
111 const Type l = array_base(a->type); \
112 const Type r = array_base(b->type); \
113 if (isa(r, l) < 0) ERR_N(pos, _("array types do not match."));
114
115 5 static OP_CHECK(opck_array_at) {
116 5 const Exp_Binary *bin = (Exp_Binary *)data;
117
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 4 times.
5 CHECK_NN(opck_const_rhs(env, data));
118
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (bin->lhs->type != env->gwion->type[et_error]) {
119
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 ARRAY_OPCK(bin->lhs, bin->rhs, exp_self(bin)->pos)
120
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (bin->lhs->type->array_depth != bin->rhs->type->array_depth)
121 1 ERR_N(exp_self(bin)->pos, _("array depths do not match."));
122 }
123
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (bin->rhs->exp_type == ae_exp_decl) {
124 2 Type_Decl *td = bin->rhs->d.exp_decl.td;
125
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
2 if (td->array && td->array->exp)
126 1 ERR_N(exp_self(bin)->pos,
127 _("do not provide array for 'xxx => declaration'."));
128 1 SET_FLAG(bin->rhs->d.exp_decl.vd.value, late);
129 }
130 1 bin->rhs->ref = bin->lhs;
131 // bin->rhs->data = bin->lhs;
132 1 exp_setvar(bin->rhs, 1);
133 1 return bin->rhs->type;
134 }
135
136 ANN static inline bool shift_match(const Type base, const Type more) {
137 return get_depth(base) == get_depth(more);
138 }
139
140 1 ANN static Type check_array_shift(const Env env, const Exp a, const Exp b,
141 const m_str str, const loc_t pos) {
142 /* if(a->type == env->gwion->type[et_error] &&
143 b->type->array_depth > 1)
144 return a->type;*/
145
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 ARRAY_OPCK(a, b, pos)
146 1 const m_int diff = get_depth(a->type) - get_depth(b->type);
147
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (diff >= 0 && diff <= 1)
148 return a->type;
149 1 ERR_N(pos, "array depths do not match for '%s'.", str);
150 }
151
152 1 static OP_CHECK(opck_array_sl) {
153 1 const Exp_Binary *bin = (Exp_Binary *)data;
154 1 return check_array_shift(env, bin->lhs, bin->rhs, "<<", exp_self(bin)->pos);
155 }
156
157 static OP_CHECK(opck_array_sr) {
158 const Exp_Binary *bin = (Exp_Binary *)data;
159 return check_array_shift(env, bin->rhs, bin->lhs, ">>", exp_self(bin)->pos);
160 }
161
162 ANN static inline m_bool emit_array_shift(const Emitter emit,
163 const f_instr exec) {
164 emit_regmove(emit, -SZ_INT);
165 (void)emit_add_instr(emit, exec);
166 return GW_OK;
167 }
168
169 static INSTR(ArrayAppendFront) {
170 const M_Object o = *(M_Object *)(shred->reg);
171 const M_Vector a = ARRAY(o);
172 m_vector_add_front(a, shred->reg - ARRAY_SIZE(a));
173 }
174
175 static INSTR(ArrayConcatLeft) {
176 const M_Object obase = *(M_Object *)(shred->reg - SZ_INT);
177 const M_Object omore = *(M_Object *)(shred->reg);
178 const M_Vector base = ARRAY(obase);
179 const M_Vector more = ARRAY(omore);
180 const m_uint len = ARRAY_LEN(base);
181 const m_uint sz = ARRAY_SIZE(base);
182 if ((ARRAY_LEN(base) += ARRAY_LEN(more)) >= ARRAY_CAP(base)) {
183 ARRAY_CAP(base) += ARRAY_CAP(more);
184 m_bit *ptr =
185 (m_bit *)xrealloc(base->ptr, ARRAY_OFFSET + ARRAY_CAP(base) * sz);
186 base->ptr = ptr;
187 }
188 m_bit *data = more->ptr + ARRAY_OFFSET;
189 memmove(ARRAY_PTR(base) + len * sz, data, sz);
190 }
191
192 static INSTR(ArrayConcatRight) {
193 const M_Object obase = *(M_Object *)(shred->reg);
194 const M_Object omore = *(M_Object *)(shred->reg - SZ_INT);
195 const M_Vector base = ARRAY(obase);
196 const M_Vector more = ARRAY(omore);
197 const m_uint len = ARRAY_LEN(base);
198 const m_uint sz = ARRAY_SIZE(base);
199 if ((ARRAY_LEN(base) += ARRAY_LEN(more)) >= ARRAY_CAP(base)) {
200 ARRAY_CAP(base) += ARRAY_CAP(more);
201 m_bit *ptr =
202 (m_bit *)xrealloc(base->ptr, ARRAY_OFFSET + ARRAY_CAP(base) * sz);
203 base->ptr = ptr;
204 }
205 memmove(ARRAY_PTR(base) + (ARRAY_LEN(more) + len - 1) * sz, ARRAY_PTR(base),
206 len * sz);
207 memmove(ARRAY_PTR(base), ARRAY_PTR(more), ARRAY_LEN(more) * sz);
208 }
209
210 static OP_EMIT(opem_array_sr) {
211 const Exp_Binary *bin = (Exp_Binary *)data;
212 if (shift_match(bin->lhs->type, bin->rhs->type))
213 return emit_array_shift(emit, ArrayConcatRight);
214 emit_regmove(emit, -SZ_INT);
215 if (tflag(bin->lhs->type, tflag_compound))
216 emit_compound_addref(emit, bin->lhs->type, -SZ_INT - bin->lhs->type->size, false);
217 (void)emit_add_instr(emit, ArrayAppendFront);
218 return GW_OK;
219 }
220
221 static OP_EMIT(opem_array_sl) {
222 const Exp_Binary *bin = (Exp_Binary *)data;
223 if (shift_match(bin->rhs->type, bin->lhs->type))
224 return emit_array_shift(emit, ArrayConcatLeft);
225 if (tflag(bin->rhs->type, tflag_compound))
226 emit_compound_addref(emit, bin->rhs->type, -bin->rhs->type->size, false);
227 emit_regmove(emit, -bin->rhs->type->size);
228 emit_add_instr(emit, ArrayAppend);
229 return GW_OK;
230 }
231
232 // check me. use common ancestor maybe
233 1 static OP_CHECK(opck_array_cast) {
234 1 const Exp_Cast *cast = (Exp_Cast *)data;
235 1 const Type l = array_base(cast->exp->type);
236 1 const Type r = array_base(exp_self(cast)->type);
237
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
1 if (get_depth(cast->exp->type) == get_depth(exp_self(cast)->type) &&
238 isa(l->info->base_type, r->info->base_type) > 0)
239 return l;
240 1 return NULL;
241 }
242
243 4 static OP_CHECK(opck_array_slice) {
244 4 const Exp e = (Exp)data;
245 4 exp_setmeta(exp_self(e), 1);
246 4 return e->d.exp_slice.base->type;
247 }
248
249 7 static inline m_bool bounds(const M_Vector v, const m_int i) {
250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 CHECK_BB(i);
251
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
7 return (m_uint)i < ARRAY_LEN(v) ? GW_OK : GW_ERROR;
252 }
253
254 4 static INSTR(ArraySlice) {
255 4 shred->reg -= SZ_INT * 2;
256 4 const M_Object array = *(M_Object *)REG(-SZ_INT);
257 4 const M_Vector in = ARRAY(array);
258 4 const m_int start = *(m_uint *)REG(0);
259 4 m_int end = *(m_uint *)REG(SZ_INT);
260
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (end < 0) end = ARRAY_LEN(in) + end;
261
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 const m_int op = start < end ? 1 : -1;
262
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 const m_uint sz = op > 0 ? end - start : start - end;
263
3/4
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3 times.
4 if (bounds(in, start) < 0 || bounds(in, end) < 0) {
264 1 handle(shred, "OutOfBoundsArraySliceException");
265 1 return;
266 }
267 3 const M_Object out = new_array(shred->info->mp, array->type_ref, sz);
268
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 for (m_int i = start, j = 0; i != end; i += op, ++j) {
269 3 m_bit buf[ARRAY_SIZE(in)];
270 3 m_vector_get(in, i, &buf);
271 3 m_vector_set(ARRAY(out), j, buf);
272 }
273 3 *(M_Object *)REG(-SZ_INT) = out;
274 }
275
276 4 static OP_EMIT(opem_array_slice) {
277 4 emit_add_instr(emit, ArraySlice);
278 4 return GW_OK;
279 }
280
281 13 static FREEARG(freearg_array) {
282 13 ArrayInfo *info = (ArrayInfo *)instr->m_val;
283 13 vector_release(&info->type);
284 13 mp_free(((Gwion)gwion)->mp, ArrayInfo, info);
285 13 }
286
287 ANN Type check_array_access(const Env env, const Array_Sub array);
288
289 5 ANN static inline Type get_array_type(const Type type) {
290
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 const Type t = !tflag(type, tflag_ref) ? type : (Type)vector_front(&type->info->tuple->contains);
291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 return t->array_depth ? t : typedef_base(t);
292 }
293
294 5 static OP_CHECK(opck_array) {
295 5 const Array_Sub array = (Array_Sub)data;
296 5 const Type t_int = env->gwion->type[et_int];
297 5 Exp e = array->exp;
298
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 do CHECK_BN(check_implicit(env, e, t_int));
299
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
7 while ((e = e->next));
300 5 const Type t = get_array_type(array->type);
301
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (t->array_depth >= array->depth)
302 5 return array_type(env, array_base(t), t->array_depth - array->depth);
303 const Exp curr = take_exp(array->exp, t->array_depth);
304 struct Array_Sub_ next = {curr->next, array_base(t),
305 array->depth - t->array_depth};
306 return check_array_access(env, &next) ?: env->gwion->type[et_error];
307 }
308
309 4 ANN static void array_loop(const Emitter emit, const m_uint depth) {
310 4 emit_regmove(emit, -depth * SZ_INT);
311
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
6 for (m_uint i = 0; i < depth - 1; ++i) {
312 2 const Instr access = emit_add_instr(emit, ArrayAccess);
313 2 access->m_val = i * SZ_INT;
314
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 access->m_val2 = !i ? SZ_INT : 0;
315 2 const Instr get = emit_add_instr(emit, ArrayGet);
316 2 get->m_val = i * SZ_INT;
317 2 get->m_val2 = -SZ_INT;
318 2 const Instr ex = emit_add_instr(emit, GWOP_EXCEPT);
319 2 ex->m_val = -SZ_INT;
320 }
321 4 emit_regmove(emit, -SZ_INT);
322 4 const Instr access = emit_add_instr(emit, ArrayAccess);
323 4 access->m_val = depth * SZ_INT;
324 4 }
325
326 4 ANN static void array_finish(const Emitter emit, const Array_Sub array, const m_bool is_var) {
327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 const Instr get = emit_add_instr(emit, is_var ? ArrayAddr : ArrayGet);
328 4 const Type t = array->type;
329
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if(!is_var) {
330
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 1 times.
4 if(array->depth < get_depth(t) || isa(array_base(t), emit->gwion->type[et_object]) > 0)
331 3 emit_add_instr(emit, GWOP_EXCEPT);
332 }
333 4 get->m_val = array->depth * SZ_INT;
334
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 emit_regmove(emit, is_var ? SZ_INT : t->size);
335 4 }
336
337 4 ANN static inline m_bool array_do(const Emitter emit, const Array_Sub array,
338 const m_bool is_var) {
339
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 CHECK_BB(emit_exp(emit, array->exp));
340 4 array_loop(emit, array->depth);
341 4 array_finish(emit, array, is_var);
342 4 return GW_OK;
343 }
344
345 16 ANN m_bool get_emit_var(const Emitter emit, const Type t, bool is_var) {
346 16 const Env env = emit->env;
347 16 bool vars[2] = { is_var };
348 16 struct Op_Import opi = {.op = insert_symbol("@array_init"),
349 .lhs = t,
350 16 .data = (uintptr_t)vars};
351
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 CHECK_BB(op_emit(emit, &opi));
352 16 return vars[1];
353 }
354
355 ANN static inline Exp emit_n_exp(const Emitter emit,
356 struct ArrayAccessInfo *const info) {
357 const Exp e = take_exp(info->array.exp, info->array.depth);
358 const Exp next = e->next;
359 e->next = NULL;
360 struct Array_Sub_ partial = {info->array.exp, info->array.type,
361 info->array.depth};
362 const bool is_var = get_emit_var(emit, array_base(info->array.type), info->is_var);
363 const m_bool ret = array_do(emit, &partial, is_var);
364 e->next = next;
365 return ret > 0 ? next : NULL;
366 }
367
368 4 ANN static Type emit_get_array_type(const Emitter emit, const Type t) {
369
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if(!tflag(t, tflag_ref)) return t;
370 const Instr instr = emit_add_instr(emit, Reg2RegDeref);
371 instr->m_val = -SZ_INT;
372 instr->m_val2 = -SZ_INT;
373 return (Type)vector_front(&t->info->tuple->contains);
374
375 }
376
377 4 static OP_EMIT(opem_array_access) {
378 4 struct ArrayAccessInfo *const info = (struct ArrayAccessInfo *)data;
379 4 const Type t = emit_get_array_type(emit, info->array.type);
380
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (t->array_depth >= info->array.depth) {
381 4 struct Array_Sub_ next = {
382 4 .exp = info->array.exp, .type = info->type, .depth = info->array.depth};
383 4 return array_do(emit, &next, info->is_var);
384 }
385 struct Array_Sub_ partial = {info->array.exp, t,
386 t->array_depth};
387 struct Array_Sub_ next = {info->array.exp, array_base(t),
388 info->array.depth - t->array_depth};
389 info->array = partial;
390 const Exp exp = emit_n_exp(emit, info);
391 next.exp = exp;
392 info->array = next;
393 return exp ? emit_array_access(emit, info) : GW_ERROR;
394 }
395
396 static m_bit map_byte[BYTECODE_SZ * 5];
397 static const struct VM_Code_ map_run_code = {.name = "map_run_code",
398 .bytecode = map_byte};
399
400 static m_bit compactmap_byte[BYTECODE_SZ * 5];
401 static const struct VM_Code_ compactmap_run_code = {
402 .name = "compactmap_run_code", .bytecode = compactmap_byte};
403
404 static m_bit filter_byte[BYTECODE_SZ * 5];
405 static const struct VM_Code_ filter_run_code = {.name = "filter_run_code",
406 .bytecode = filter_byte};
407
408 static m_bit count_byte[BYTECODE_SZ * 5];
409 static const struct VM_Code_ count_run_code = {.name = "count_run_code",
410 .bytecode = count_byte};
411
412 static m_bit foldl_byte[BYTECODE_SZ * 5];
413 static const struct VM_Code_ foldl_run_code = {.name = "foldl_run_code",
414 .bytecode = foldl_byte};
415
416 static m_bit foldr_byte[BYTECODE_SZ * 5];
417 static const struct VM_Code_ foldr_run_code = {.name = "foldr_run_code",
418 .bytecode = foldr_byte};
419
420 static m_bit new_byte[BYTECODE_SZ * 5];
421 static const struct VM_Code_ new_run_code = {.name = "new_run_code",
422 .bytecode = new_byte};
423
424 typedef struct FunctionalFrame {
425 VM_Code code;
426 M_Object o;
427 uint16_t pc;
428 uint16_t offset;
429 uint16_t index;
430 uint16_t ret_size;
431 } FunctionalFrame;
432
433 2 ANN static inline void _init(const VM_Shred shred, const struct VM_Code_ *code, const M_Object o,
434 const m_uint offset, const m_uint start) {
435 2 FunctionalFrame *frame = &*(FunctionalFrame *)MEM(SZ_INT * 2 + start);
436 2 frame->pc = shred->pc;
437 2 frame->code = shred->code;
438 2 frame->offset = offset;
439 2 frame->index = 0;
440 2 *(m_uint *)REG(SZ_INT) = offset;
441 2 shred->code = (VM_Code)code;
442 2 shred->pc = 0;
443 2 shredule(shred->tick->shreduler, shred, 0);
444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(!(*(VM_Code *)REG(0) = *(VM_Code*)o->data))
445 handle(shred, "MissingCodeException");
446 2 }
447
448 ANN static inline void _next(const VM_Shred shred, const m_uint offset) {
449 shred->pc = 0;
450 *(m_uint *)REG(0) = offset;
451 POP_REG(shred, SZ_INT);
452 }
453
454 2 ANN static inline void _return(const VM_Shred shred,
455 const FunctionalFrame *frame) {
456 2 shred->pc = frame->pc;
457 2 shred->code = frame->code;
458 2 }
459
460 2 ANN static inline void _finish(const VM_Shred shred,
461 const FunctionalFrame *frame) {
462 2 POP_MEM(shred, frame->offset);
463 2 shredule(shred->tick->shreduler, shred, 0);
464 2 }
465
466 #define MAP_CODE_OFFSET (sizeof(FunctionalFrame) + sizeof(struct frame_t))
467 2 static INSTR(map_run_ini) {
468 2 const VM_Code code = *(VM_Code*)REG(0);
469 2 const m_uint offset = *(m_uint *)REG(SZ_INT);
470
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (offset) PUSH_MEM(shred, offset);
471 2 PUSH_REG(shred, SZ_INT);
472 2 const M_Object self = *(M_Object *)MEM(0);
473 2 const M_Vector array = ARRAY(self);
474 2 FunctionalFrame *frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
475 2 frame->ret_size = code->ret_type->size;
476 2 shred->pc++;
477 2 shred->mem += MAP_CODE_OFFSET + SZ_INT; // work in a safe memory space
478 2 m_vector_get(array, frame->index, &*(m_bit **)(shred->mem + SZ_INT * 2 + frame->offset + frame->code->stack_depth));
479 2 }
480
481 static INSTR(map_run_end) {
482 shred->mem -= MAP_CODE_OFFSET + SZ_INT;
483 const M_Object ret_obj = *(M_Object *)MEM(SZ_INT * 2);
484 const M_Vector array = ARRAY(*(M_Object *)MEM(0));
485 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
486 POP_REG(shred, frame->ret_size);
487 m_vector_set(ARRAY(ret_obj), frame->index, shred->reg);
488 if (++frame->index == ARRAY_LEN(array)) {
489 _return(shred, frame);
490 *(M_Object *)(REG(-SZ_INT)) = ret_obj;
491 } else
492 _next(shred, frame->offset);
493 _finish(shred, frame);
494 }
495
496 static INSTR(compactmap_run_end) {
497 shred->mem -= MAP_CODE_OFFSET + SZ_INT;
498 const M_Object self = *(M_Object *)MEM(0);
499 const M_Vector self_array = ARRAY(self);
500 const M_Object ret_obj = *(M_Object *)MEM(SZ_INT * 2);
501 const M_Vector ret_array = ARRAY(ret_obj);
502 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
503 POP_REG(shred, frame->ret_size);
504 const m_uint size = m_vector_size(self_array);
505 const M_Object obj = *(M_Object *)REG(0);
506 if (*(m_uint *)obj->data)
507 m_vector_add(ret_array, &*(m_bit *)(obj->data + SZ_INT));
508 if (++frame->index == size) {
509 _return(shred, frame);
510 *(M_Object *)(REG(-SZ_INT)) = ret_obj;
511 } else
512 _next(shred, frame->offset);
513 _finish(shred, frame);
514 }
515
516 2 static INSTR(filter_run_end) {
517 2 shred->mem -= MAP_CODE_OFFSET + SZ_INT;
518 2 POP_REG(shred, SZ_INT);
519 2 const M_Object self = *(M_Object *)MEM(0);
520 2 const M_Object ret_obj = *(M_Object *)MEM(SZ_INT * 2);
521 2 const M_Vector array = ARRAY(ret_obj);
522 2 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
523
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (*(m_uint *)(shred->reg))
524 1 m_vector_add(array,
525 1 ARRAY_PTR(ARRAY(self)) + frame->index * ARRAY_SIZE(array));
526
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (++frame->index == ARRAY_LEN(ARRAY(self))) {
527 2 _return(shred, frame);
528 2 *(M_Object *)(REG(-SZ_INT)) = ret_obj;
529 } else
530 _next(shred, frame->offset);
531 2 _finish(shred, frame);
532 2 }
533
534 static INSTR(count_run_end) {
535 shred->mem -= MAP_CODE_OFFSET + SZ_INT;
536 const M_Object self = *(M_Object *)MEM(0);
537 POP_REG(shred, SZ_INT);
538 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
539 if (*(m_uint *)(shred->reg)) (*(m_uint *)MEM(SZ_INT * 2))++;
540 if (++frame->index == ARRAY_LEN(ARRAY(self))) {
541 _return(shred, frame);
542 *(m_uint *)(REG(-SZ_INT)) = *(m_uint *)MEM(SZ_INT * 2);
543 } else
544 _next(shred, frame->offset);
545 _finish(shred, frame);
546 }
547
548 static MFUN(vm_vector_map) {
549 const m_uint offset = *(m_uint *)REG(SZ_INT * 3);
550 const M_Object ret =
551 new_array(shred->info->mp, o->type_ref, ARRAY_LEN(ARRAY(o)));
552 if (ARRAY_LEN(ARRAY(o))) {
553 *(M_Object *)MEM(SZ_INT * 2) = ret;
554 _init(shred, &map_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
555 } else
556 *(M_Object *)RETURN = ret;
557 }
558
559 static MFUN(vm_vector_compactmap) {
560 const VM_Code code = *(VM_Code *)REG(SZ_INT * 2);
561 const m_uint offset = *(m_uint *)REG(SZ_INT * 3);
562 const M_Object ret = new_array(shred->info->mp, code->ret_type, 0);
563 if (ARRAY_LEN(ARRAY(o))) {
564 _init(shred, &compactmap_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
565 *(M_Object *)MEM(SZ_INT * 2) = ret;
566 } else
567 *(M_Object *)RETURN = ret;
568 }
569
570 2 static MFUN(vm_vector_filter) {
571 2 const m_uint offset = *(m_uint *)REG(SZ_INT * 3);
572 2 const M_Object ret = new_array(shred->info->mp, o->type_ref, 0);
573
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (ARRAY_LEN(ARRAY(o))) {
574 2 _init(shred, &filter_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
575 2 *(M_Object *)MEM(SZ_INT * 2) = ret;
576 } else
577 *(M_Object *)RETURN = ret;
578 2 }
579
580 static MFUN(vm_vector_count) {
581 const m_uint offset = *(m_uint *)REG(SZ_INT * 3);
582 if (ARRAY_LEN(ARRAY(o))) {
583 _init(shred, &count_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
584 *(m_uint *)MEM(SZ_INT * 2) = 0;
585 } else
586 *(m_uint *)RETURN = 0;
587 }
588
589 static INSTR(foldl_run_ini) {
590 const VM_Code code = *(VM_Code*)REG(0);
591 const m_uint offset = *(m_uint *)REG(SZ_INT);
592 if (offset) PUSH_MEM(shred, offset);
593 const M_Object self = *(M_Object *)MEM(0);
594 *(m_uint *)(shred->reg + SZ_INT) = 0;
595 PUSH_REG(shred, SZ_INT);
596 shred->pc++;
597 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
598 frame->ret_size = code->ret_type->size;
599 shred->mem += MAP_CODE_OFFSET + SZ_INT; // work in a safe memory space
600 m_vector_get(ARRAY(self), frame->index,
601 &*(m_bit **)(shred->mem + SZ_INT * 2 + frame->code->stack_depth));
602 }
603
604 static INSTR(foldr_run_ini) {
605 const VM_Code code = *(VM_Code*)REG(0);
606 const m_uint offset = *(m_uint *)REG(SZ_INT);
607 if (offset) PUSH_MEM(shred, offset);
608 const M_Object self = *(M_Object *)MEM(0);
609 *(m_uint *)(shred->reg + SZ_INT) = 0;
610 PUSH_REG(shred, SZ_INT);
611 shred->pc++;
612 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
613 frame->ret_size = code->ret_type->size;
614 shred->mem += MAP_CODE_OFFSET + SZ_INT; // work in a safe memory space
615 const M_Vector array = ARRAY(self);
616 m_vector_get(array, ARRAY_LEN(array) - frame->index - 1,
617 &*(m_bit **)(shred->mem + SZ_INT * 2 + frame->code->stack_depth));
618 }
619
620 static INSTR(fold_run_end) {
621 shred->mem -= MAP_CODE_OFFSET + SZ_INT;
622 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
623 const M_Object self = *(M_Object *)MEM(0);
624 const VM_Code code = *(VM_Code *)(*(M_Object*)MEM(SZ_INT))->data;
625 const m_uint sz = code->stack_depth - ARRAY_SIZE(ARRAY(self));
626 const m_uint base_sz = code->stack_depth - sz;
627 POP_REG(shred, base_sz); // ret_sz?
628 if (++frame->index == ARRAY_LEN(ARRAY(self))) {
629 POP_REG(shred, SZ_INT - base_sz);
630 shred->pc = frame->pc;
631 shred->code = frame->code;
632 memcpy(REG(-sz), REG(0), base_sz);
633 } else {
634 memcpy(shred->mem + MAP_CODE_OFFSET + SZ_INT * 3 + sz, shred->reg, base_sz);
635 _next(shred, frame->offset);
636 }
637 _finish(shred, frame);
638 }
639
640 static INSTR(new_run_ini) {
641 const m_uint offset = *(m_uint *)REG(SZ_INT);
642 if (offset) PUSH_MEM(shred, offset);
643 const M_Object arg = *(M_Object *)MEM(SZ_INT);
644 const VM_Code code = *(VM_Code*)arg->data;
645 *(VM_Code*)REG(0) = code;
646 PUSH_REG(shred, SZ_INT);
647 FunctionalFrame *frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
648 shred->pc++;
649 shred->mem += MAP_CODE_OFFSET + SZ_INT; // work in a safe memory space
650 *(m_uint*)MEM(SZ_INT*2+offset) = frame->index;
651 }
652
653 static INSTR(new_run_end) {
654 shred->mem -= MAP_CODE_OFFSET + SZ_INT;
655 FunctionalFrame *const frame = &*(FunctionalFrame *)MEM(SZ_INT * 3);
656 const M_Object self = *(M_Object *)MEM(0);
657 const M_Vector array = ARRAY(self);
658 const m_uint base_sz = ARRAY_SIZE(array);
659 m_vector_set(array, frame->index, REG(-base_sz));
660 POP_REG(shred, base_sz);
661 if (++frame->index == ARRAY_LEN(ARRAY(self))) {
662 shred->pc = frame->pc;
663 shred->code = frame->code;
664 *(M_Object*)REG(-SZ_INT) = self;
665 } else _next(shred, frame->offset);
666 _finish(shred, frame);
667 }
668
669 static MFUN(vm_vector_foldl) {
670 const m_bit *byte = shred->code->bytecode + (shred->pc - 1) * BYTECODE_SZ;
671 const m_uint acc_sz = *(m_uint *)(byte + SZ_INT);
672 const m_uint offset = *(m_uint *)REG(SZ_INT * 3 + acc_sz);
673 if (ARRAY_LEN(ARRAY(o))) {
674 _init(shred, &foldl_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
675 memcpy(shred->mem + MAP_CODE_OFFSET + SZ_INT * 3 + acc_sz, MEM(SZ_INT * 2),
676 acc_sz);
677 } else
678 memcpy((m_bit *)RETURN, MEM(SZ_INT * 2), acc_sz);
679 }
680
681 static MFUN(vm_vector_foldr) {
682 const m_bit *byte = shred->code->bytecode + (shred->pc - 1) * BYTECODE_SZ;
683 const m_uint acc_sz = *(m_uint *)(byte + SZ_INT);
684 const m_uint offset = *(m_uint *)REG(SZ_INT * 3 + acc_sz);
685 if (ARRAY_LEN(ARRAY(o))) {
686 _init(shred, &foldr_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
687 memcpy(shred->mem + MAP_CODE_OFFSET + SZ_INT * 3 + acc_sz, MEM(SZ_INT * 2),
688 acc_sz);
689 } else
690 memcpy((m_bit *)RETURN, MEM(SZ_INT * 2), acc_sz);
691 }
692
693 static MFUN(vm_vector_new) {
694 if (ARRAY_LEN(ARRAY(o))) {
695 const m_uint offset = *(m_uint *)REG(SZ_INT * 3);
696 _init(shred, &new_run_code, *(M_Object*)MEM(SZ_INT*1), offset, SZ_INT);
697 }
698 *(M_Object *)RETURN = o;
699 }
700
701 14872 static void array_func(const Env env, const Type t, const m_str name, f_xfun fun) {
702 14872 const Value v = nspc_lookup_value0(t->nspc, insert_symbol(name));
703 14872 builtin_func(env->gwion, v->d.func_ref, fun);
704 14872 }
705
706 1352 static OP_CHECK(opck_array_scan) {
707 1352 struct TemplateScan *ts = (struct TemplateScan *)data;
708 1352 const Type t_array = env->gwion->type[et_array];
709 1352 const Class_Def c = t_array->info->cdef;
710
2/4
✓ Branch 0 taken 1352 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 1352 times.
1352 DECL_ON(const Type, base,
711 = ts->t != t_array ? ts->t : known_type(env, *mp_vector_at(ts->td->types, Type_Decl*, 0)));
712
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1352 times.
1352 if (base->size == 0) {
713 gwerr_basic("Can't use type of size 0 as array base", NULL, NULL,
714 "/dev/null", (loc_t) {}, 0);
715 env_set_error(env, true);
716 return env->gwion->type[et_error];
717 }
718
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1352 times.
1352 if (tflag(base, tflag_ref)) {
719 gwerr_basic("Can't use ref types as array base", NULL, NULL, "/dev/null",
720 (loc_t) {}, 0);
721 env_set_error(env, true);
722 return env->gwion->type[et_error];
723 }
724 /*
725 if (!strncmp(base->name, "Option:[", 5)) {
726 gwerr_basic("Can't use option types as array base", NULL, NULL, "/dev/null",
727 (loc_t) {}, 0);
728 env_set_error(env, true);
729 return env->gwion->type[et_error];
730 }
731 */
732 1352 const Symbol sym = array_sym(env, array_base_simple(base), base->array_depth + 1);
733 1352 const Type type = nspc_lookup_type1(base->info->value->from->owner, sym);
734
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1352 times.
1352 if (type) return type;
735 1352 const Class_Def cdef = cpy_class_def(env->gwion->mp, c);
736 1352 cdef->base.ext = type2td(env->gwion, t_array, (loc_t) {});
737 1352 cdef->base.xid = sym;
738 1352 cdef->base.tmpl->call = new_mp_vector(env->gwion->mp, Type_Decl*, 1);
739 1352 mp_vector_set(cdef->base.tmpl->call, Type_Decl*, 0, type2td(env->gwion, base, (loc_t) {}));
740 1352 const Context ctx = env->context;
741 1352 env->context = base->info->value->from->ctx;
742 1352 const m_uint scope = env_push(env, base->info->value->from->owner_class,
743 1352 base->info->value->from->owner);
744
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1352 times.
1352 CHECK_BN(scan0_class_def(env, cdef));
745 1352 const Type t = cdef->base.type;
746
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1348 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
1352 if (GET_FLAG(base, abstract) && !tflag(base, tflag_union))
747 4 SET_FLAG(t, abstract);
748 else
749 1348 UNSET_FLAG(t, abstract);
750 1352 const m_bool ret = traverse_cdef(env, t);
751 1352 UNSET_FLAG(t, abstract);
752 1352 env_pop(env, scope);
753 1352 env->context = ctx;
754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1352 times.
1352 if (ret == GW_ERROR) return NULL;
755 1352 set_tflag(t, tflag_emit);
756 1352 t->array_depth = base->array_depth + 1;
757 1352 t->info->base_type = array_base(base);
758 1352 set_tflag(t, tflag_cdef | tflag_tmpl);
759
3/4
✓ Branch 1 taken 666 times.
✓ Branch 2 taken 686 times.
✓ Branch 3 taken 666 times.
✗ Branch 4 not taken.
2018 void *rem = tflag(base, tflag_compound)
760 666 ? !tflag(base, tflag_struct) ? vm_vector_rem_obj
761 : vm_vector_rem_struct
762 : vm_vector_rem;
763 1352 builtin_func(env->gwion, (Func)vector_at(&t->nspc->vtable, 0), rem);
764
3/4
✓ Branch 1 taken 666 times.
✓ Branch 2 taken 686 times.
✓ Branch 3 taken 666 times.
✗ Branch 4 not taken.
2018 void *insert = tflag(base, tflag_compound)
765 666 ? !tflag(base, tflag_struct) ? vm_vector_insert_obj
766 : vm_vector_insert_struct
767 : vm_vector_insert;
768 1352 array_func(env, t, "insert", insert);
769 1352 array_func(env, t, "size", vm_vector_size);
770 1352 array_func(env, t, "depth", vm_vector_depth);
771 1352 array_func(env, t, "cap", vm_vector_cap);
772 1352 array_func(env, t, "random", vm_vector_random);
773
774 1352 array_func(env, t, "map", vm_vector_map);
775 1352 array_func(env, t, "compactMap", vm_vector_compactmap);
776 1352 array_func(env, t, "filter", vm_vector_filter);
777 1352 array_func(env, t, "count", vm_vector_count);
778 1352 array_func(env, t, "foldl", vm_vector_foldl);
779 1352 array_func(env, t, "foldr", vm_vector_foldr);
780 // array_func(env, t, "new", vm_vector_new);
781
782
2/2
✓ Branch 1 taken 666 times.
✓ Branch 2 taken 686 times.
1352 if (tflag(base, tflag_compound)) {
783 666 t->nspc->dtor = new_vmcode(env->gwion->mp, NULL, NULL,
784 "array component dtor", SZ_INT, true, false);
785 666 set_tflag(t, tflag_dtor);
786
1/2
✓ Branch 0 taken 666 times.
✗ Branch 1 not taken.
666 t->nspc->dtor->native_func = (m_uint)(
787 666 !tflag(base, tflag_struct) ? array_dtor_obj : array_dtor_struct);
788 }
789 1352 return t;
790 }
791
792 static OP_CHECK(opck_array_implicit) {
793 const struct Implicit *imp = (struct Implicit *)data;
794 if (imp->t->array_depth != imp->e->type->array_depth)
795 return env->gwion->type[et_error];
796 if (isa(array_base(imp->e->type), array_base(imp->t)) < 0)
797 return env->gwion->type[et_error];
798 return imp->t;
799 }
800
801 1 static OP_EMIT(opem_array_each_init) {
802 1 Looper *loop = (Looper *)data;
803 1 const Instr instr = emit_add_instr(emit, AutoUnrollInit);
804 1 instr->m_val = loop->offset;
805 1 return GW_OK;
806 }
807
808
809 7 ANN static inline Type foreach_type(const Env env, const Exp exp) {
810 7 const Type et = exp->type;
811
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 DECL_OO(Type, base, = typedef_base(et));
812
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 DECL_OO(const Type, t, = array_base_simple(base));
813
1/2
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
7 if(!tflag(base, tflag_ref)) {
814 7 const m_uint depth = base->array_depth - 1;
815
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 return depth ? array_type(env, t, depth) : t;
816 }
817 const Type inner = (Type)vector_front(&base->info->tuple->contains);
818 const Type refbase = array_base_simple(inner);
819 const m_uint depth = inner->array_depth - 1;
820 return depth ? array_type(env, refbase, depth) : refbase;
821 }
822
823 // rewrite me
824 7 static OP_CHECK(opck_array_each_val) {
825 7 const Exp exp = (const Exp) data;
826
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 DECL_ON(const Type, base, = foreach_type(env, exp));
827
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 CHECK_BN(ensure_traverse(env, base));
828 7 return ref_type(env->gwion, base, exp->pos);
829 }
830
831 7 static OP_EMIT(opem_array_each) {
832 7 Looper *loop = (Looper *)data;
833 7 const Instr instr = emit_add_instr(emit, AutoLoop);
834
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if(!loop->n) {
835 5 instr->m_val2 = loop->offset + SZ_INT;
836 5 loop->instr = instr;
837 } else {
838 2 instr->m_val2 = loop->offset + SZ_INT*2;
839 2 vector_add(&loop->unroll_v, (m_uint)instr);
840 }
841 7 return GW_OK;
842 }
843
844 4466 ANN static void prepare_run(m_bit *const byte, const f_instr ini,
845 const f_instr end) {
846 4466 *(unsigned *)(byte) = eOP_MAX;
847 4466 *(f_instr *)(byte+ SZ_INT * 2) = ini;
848 4466 *(unsigned *)(byte + BYTECODE_SZ) = eSetCode;
849 4466 *(uint16_t *)(byte + BYTECODE_SZ + SZ_INT * 2) = 3;
850 4466 *(unsigned *)(byte + BYTECODE_SZ * 2) = eOverflow;
851 4466 *(unsigned *)(byte + BYTECODE_SZ * 3) = eOP_MAX;
852 4466 *(f_instr *)(byte + BYTECODE_SZ * 3 + SZ_INT * 2) = end;
853 4466 *(unsigned *)(byte + BYTECODE_SZ * 4) = eEOC;
854 4466 }
855
856 2552 ANN static void prepare_map_run(m_bit *const byte, const f_instr end) {
857 2552 prepare_run(byte, map_run_ini, end);
858 2552 vm_prepare(NULL, byte);
859 2552 }
860
861 1276 ANN static void prepare_fold_run(m_bit *const byte, const f_instr ini) {
862 1276 prepare_run(byte, ini, fold_run_end);
863 1276 vm_prepare(NULL, byte);
864 1276 }
865
866 638 GWION_IMPORT(array) {
867 638 prepare_map_run(map_byte, map_run_end);
868 638 prepare_map_run(compactmap_byte, compactmap_run_end);
869 638 prepare_map_run(filter_byte, filter_run_end);
870 638 prepare_map_run(count_byte, count_run_end);
871 638 prepare_fold_run(foldl_byte, foldl_run_ini);
872 638 prepare_fold_run(foldr_byte, foldr_run_ini);
873 638 prepare_run(new_byte, new_run_ini, new_run_end);
874 638 vm_prepare(NULL, new_byte);
875 638 const Type t_array = gwi_class_ini(gwi, "Array:[T]", "Object");
876 638 set_tflag(t_array, tflag_infer);
877 638 gwi->gwion->type[et_array] = t_array;
878 638 gwi_class_xtor(gwi, NULL, array_dtor);
879 638 t_array->nspc->offset += SZ_INT*2;
880
881 638 GWI_BB(gwi_fptr_ini(gwi, "A", "map_t:[A]"))
882 638 GWI_BB(gwi_func_arg(gwi, "T", "elem"))
883 638 GWI_BB(gwi_fptr_end(gwi, ae_flag_static))
884
885 638 GWI_BB(gwi_fptr_ini(gwi, "Option:[A]", "compactmap_t:[A]"))
886 638 GWI_BB(gwi_func_arg(gwi, "T", "elem"))
887 638 GWI_BB(gwi_fptr_end(gwi, ae_flag_static))
888
889 638 GWI_BB(gwi_fptr_ini(gwi, "A", "fold_t:[A]"))
890 638 GWI_BB(gwi_func_arg(gwi, "T", "elem"))
891 638 GWI_BB(gwi_func_arg(gwi, "A", "acc"))
892 638 GWI_BB(gwi_fptr_end(gwi, ae_flag_static))
893
894 638 GWI_BB(gwi_fptr_ini(gwi, "bool", "filter_t"))
895 638 GWI_BB(gwi_func_arg(gwi, "T", "elem"))
896 638 GWI_BB(gwi_fptr_end(gwi, ae_flag_static))
897
898 638 GWI_BB(gwi_fptr_ini(gwi, "T", "new_t"))
899 638 GWI_BB(gwi_func_arg(gwi, "int", "idx"))
900 638 GWI_BB(gwi_fptr_end(gwi, ae_flag_static))
901
902 // put functions using T first
903 638 GWI_BB(gwi_func_ini(gwi, "bool", "remove"))
904 638 GWI_BB(gwi_func_arg(gwi, "int", "index"))
905 638 GWI_BB(gwi_func_end(gwi, vm_vector_rem, ae_flag_none))
906
907 638 GWI_BB(gwi_func_ini(gwi, "bool", "insert"))
908 638 GWI_BB(gwi_func_arg(gwi, "int", "index"))
909 638 GWI_BB(gwi_func_arg(gwi, "T", "data"))
910 638 GWI_BB(gwi_func_end(gwi, vm_vector_insert, ae_flag_none))
911
912 638 GWI_BB(gwi_func_ini(gwi, "int", "size"))
913 638 GWI_BB(gwi_func_end(gwi, vm_vector_size, ae_flag_none))
914 638 GWI_BB(gwi_func_ini(gwi, "int", "depth"))
915 638 GWI_BB(gwi_func_end(gwi, vm_vector_depth, ae_flag_none))
916
917 638 GWI_BB(gwi_func_ini(gwi, "int", "cap"))
918 638 GWI_BB(gwi_func_end(gwi, vm_vector_cap, ae_flag_none))
919
920 638 GWI_BB(gwi_func_ini(gwi, "T", "random"))
921 638 GWI_BB(gwi_func_end(gwi, vm_vector_random, ae_flag_none))
922
923 638 GWI_BB(gwi_func_ini(gwi, "A[]", "map:[A]"))
924 638 GWI_BB(gwi_func_arg(gwi, "map_t:[A]", "data"))
925 638 GWI_BB(gwi_func_end(gwi, vm_vector_map, ae_flag_none))
926
927 638 GWI_BB(gwi_func_ini(gwi, "A[]", "compactMap:[A]"))
928 638 GWI_BB(gwi_func_arg(gwi, "compactmap_t:[A]", "data"))
929 638 GWI_BB(gwi_func_end(gwi, vm_vector_compactmap, ae_flag_none))
930
931 638 GWI_BB(gwi_func_ini(gwi, "T[]", "filter"))
932 638 GWI_BB(gwi_func_arg(gwi, "filter_t", "data"))
933 638 GWI_BB(gwi_func_end(gwi, vm_vector_filter, ae_flag_none))
934
935 638 GWI_BB(gwi_func_ini(gwi, "int", "count"))
936 638 GWI_BB(gwi_func_arg(gwi, "filter_t", "data"))
937 638 GWI_BB(gwi_func_end(gwi, vm_vector_count, ae_flag_none))
938
939 638 GWI_BB(gwi_func_ini(gwi, "A", "foldl:[A]"))
940 638 GWI_BB(gwi_func_arg(gwi, "fold_t:[A]", "data"))
941 638 GWI_BB(gwi_func_arg(gwi, "A", "initial"))
942 638 GWI_BB(gwi_func_end(gwi, vm_vector_foldl, ae_flag_none))
943
944 638 GWI_BB(gwi_func_ini(gwi, "A", "foldr:[A]"))
945 638 GWI_BB(gwi_func_arg(gwi, "fold_t:[A]", "data"))
946 638 GWI_BB(gwi_func_arg(gwi, "A", "initial"))
947 638 GWI_BB(gwi_func_end(gwi, vm_vector_foldr, ae_flag_none))
948
949 638 GWI_BB(gwi_func_ini(gwi, "auto", "new"))
950 638 GWI_BB(gwi_func_arg(gwi, "new_t", "init"))
951 638 GWI_BB(gwi_func_end(gwi, vm_vector_new, ae_flag_none))
952
953 638 GWI_BB(gwi_class_end(gwi))
954
955 638 GWI_BB(gwi_oper_ini(gwi, "Array", "Array", NULL))
956 638 GWI_BB(gwi_oper_add(gwi, opck_array_at))
957 638 GWI_BB(gwi_oper_end(gwi, ":=>", NULL))
958 638 GWI_BB(gwi_oper_add(gwi, opck_array_implicit))
959 // GWI_BB(gwi_oper_end(gwi, "@implicit", NULL))
960 638 GWI_BB(gwi_oper_end(gwi, "@implicit", NoOp))
961 638 GWI_BB(gwi_oper_ini(gwi, "Array", (m_str)OP_ANY_TYPE, NULL))
962 638 GWI_BB(gwi_oper_add(gwi, opck_array_sl))
963 638 GWI_BB(gwi_oper_emi(gwi, opem_array_sl))
964 638 GWI_BB(gwi_oper_end(gwi, "<<", NULL))
965 638 GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, "Array", NULL))
966 638 GWI_BB(gwi_oper_add(gwi, opck_array_sr))
967 638 GWI_BB(gwi_oper_emi(gwi, opem_array_sr))
968 638 GWI_BB(gwi_oper_end(gwi, ">>", NULL))
969 638 GWI_BB(gwi_oper_ini(gwi, "Array", "Array", NULL))
970 638 GWI_BB(gwi_oper_add(gwi, opck_array_cast))
971 638 GWI_BB(gwi_oper_end(gwi, "$", NULL))
972 638 GWI_BB(gwi_oper_ini(gwi, "int", "Array", "int"))
973 638 GWI_BB(gwi_oper_add(gwi, opck_array_slice))
974 638 GWI_BB(gwi_oper_emi(gwi, opem_array_slice))
975 638 GWI_BB(gwi_oper_end(gwi, "[:]", NULL))
976 638 GWI_BB(gwi_oper_ini(gwi, "int", "Array", NULL))
977 638 GWI_BB(gwi_oper_add(gwi, opck_array))
978 638 GWI_BB(gwi_oper_emi(gwi, opem_array_access))
979 638 GWI_BB(gwi_oper_end(gwi, "[]", NULL))
980 638 GWI_BB(gwi_oper_ini(gwi, "Array", NULL, "void"))
981 638 GWI_BB(gwi_oper_emi(gwi, opem_array_each_init))
982 638 GWI_BB(gwi_oper_end(gwi, "@each_init", NULL))
983 638 GWI_BB(gwi_oper_ini(gwi, "Array", NULL, "int"))
984 638 GWI_BB(gwi_oper_emi(gwi, opem_array_each))
985 638 GWI_BB(gwi_oper_end(gwi, "@each", NULL))
986 638 GWI_BB(gwi_oper_ini(gwi, "Array", NULL, NULL))
987 638 GWI_BB(gwi_oper_add(gwi, opck_array_each_val))
988 638 GWI_BB(gwi_oper_end(gwi, "@each_val", NULL))
989 638 GWI_BB(gwi_oper_ini(gwi, "Array", NULL, "int"))
990 638 GWI_BB(gwi_oper_end(gwi, "@each_idx", NULL))
991 638 GWI_BB(gwi_oper_ini(gwi, "Array", NULL, NULL))
992 638 GWI_BB(gwi_oper_add(gwi, opck_array_scan))
993 638 GWI_BB(gwi_oper_end(gwi, "class", NULL))
994
995 638 GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, NULL, "bool"))
996 638 GWI_BB(gwi_oper_end(gwi, "@array_init", NoOp))
997
998 638 gwi_register_freearg(gwi, ArrayAlloc, freearg_array);
999 638 return GW_OK;
1000 }
1001
1002 INSTR(ArrayStruct) {
1003 const M_Object ref = *(M_Object *)(REG(-SZ_INT * 5));
1004 const m_int idx = (*(m_int *)((shred->reg - SZ_INT * 3)))++;
1005 *(m_bit **)(shred->reg) = m_vector_addr(ARRAY(ref), idx);
1006 shred->reg += SZ_INT; // regpush
1007 }
1008
1009 7 INSTR(ArrayBottom) {
1010 7 *(M_Object *)(*(m_uint **)REG(-SZ_INT * 4))[(*(m_int *)REG(-SZ_INT * 3))++] =
1011 7 *(M_Object *)REG(-SZ_INT);
1012 7 }
1013
1014 4 INSTR(ArrayPost) {
1015 4 xfree(*(m_uint **)REG(0));
1016 4 const M_Object o = *(M_Object *)(REG(-SZ_INT));
1017 4 *(m_uint *)(o->data + SZ_INT) = 0;
1018 4 }
1019
1020 6 INSTR(ArrayInit) { // for litteral array
1021 6 const Type t = (Type)instr->m_val;
1022 6 const m_uint sz = *(m_uint *)REG(0);
1023 6 const m_uint off = instr->m_val2 * sz;
1024 6 POP_REG(shred, off - SZ_INT);
1025 6 const M_Object obj = new_array(shred->info->mp, t, sz);
1026 6 memcpy(ARRAY(obj)->ptr + ARRAY_OFFSET, REG(-SZ_INT), off);
1027 6 *(M_Object *)REG(-SZ_INT) = obj;
1028 6 }
1029
1030 #define TOP -1
1031
1032 ANN static inline M_Object
1033 16 do_alloc_array_object(MemPool p, const ArrayInfo *info, const m_int cap) {
1034 16 struct Vector_ v = info->type;
1035 16 const Type t = (Type)vector_at(&v, (vtype)(-info->depth - 1));
1036 16 return new_array(p, t, (m_uint)cap);
1037 }
1038
1039 ANN static inline M_Object
1040 4 do_alloc_array_init(ArrayInfo *info, const m_uint cap, const M_Object base) {
1041
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
11 for (m_uint i = 0; i < cap; ++i)
1042 7 info->data[(*info->d.idx)++] = (M_Object)m_vector_addr(ARRAY(base), i);
1043 4 return base;
1044 }
1045
1046 ANN static M_Object do_alloc_array(const VM_Shred shred, ArrayInfo *info);
1047 4 ANN static M_Object do_alloc_array_loop(const VM_Shred shred, ArrayInfo *info,
1048 const m_uint cap, const M_Object base) {
1049
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 for (m_uint i = 0; i < cap; ++i) {
1050 5 struct ArrayInfo_ aai = {info->depth + 1, info->type, info->base,
1051 5 info->data, {info->d.idx}, info->is_obj};
1052 5 const M_Object next = do_alloc_array(shred, &aai);
1053
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (!next) {
1054 1 _release(base, shred);
1055 1 return NULL;
1056 }
1057 4 m_vector_set(ARRAY(base), i, &next);
1058 }
1059 3 return base;
1060 }
1061
1062 18 ANN static M_Object do_alloc_array(const VM_Shred shred, ArrayInfo *info) {
1063 18 const m_int cap = *(m_int *)REG(info->depth * SZ_INT);
1064
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if (cap < 0) {
1065 2 gw_err("{-}[{0}{+}Gwion{0}{-}](VM):{0} NegativeArraySize: while allocating arrays...\n");
1066 2 return NULL;
1067 }
1068 16 const M_Object base = do_alloc_array_object(shred->info->mp, info, cap);
1069 4 return info->depth < TOP ? do_alloc_array_loop(shred, info, (m_uint)cap, base)
1070
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 12 times.
32 : info->data ? do_alloc_array_init(info, (m_uint)cap, base)
1071
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8 times.
12 : base;
1072 }
1073
1074 4 ANN static M_Object *init_array(const VM_Shred shred, const ArrayInfo *info,
1075 m_uint *num_obj) {
1076 4 m_int curr = -info->depth;
1077
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 while (curr <= TOP) {
1078 6 *num_obj *= *(m_uint *)REG(SZ_INT * curr);
1079 6 ++curr;
1080 }
1081
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 return *num_obj > 0 ? (M_Object *)xcalloc(*num_obj, info->base->size) : NULL;
1082 }
1083
1084 13 INSTR(ArrayAlloc) {
1085 13 const ArrayInfo * info = (ArrayInfo *)instr->m_val;
1086 13 m_uint num_obj = 1;
1087 13 m_int idx = 0;
1088 13 struct ArrayInfo_ aai = {-info->depth, info->type, .base = info->base,
1089 13 NULL, {&idx}, info->is_obj};
1090
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (info->is_obj) aai.data = init_array(shred, info, &num_obj);
1091 13 const M_Object ref = do_alloc_array(shred, &aai);
1092
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
13 if (!ref) {
1093 2 gw_err("{-}[{0}{+}Gwion{0}{-}](VM):{0} (note: in shred[id=%" UINT_F ":%s])\n",
1094 shred->tick->xid, shred->code->name);
1095
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (info->is_obj) xfree(aai.data);
1096 2 handle(shred, "ArrayAllocException");
1097 2 return; // TODO make exception vararg
1098 }
1099 11 *(void **)(ref->data + SZ_INT) = aai.data;
1100
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 4 times.
11 if (!info->is_obj) {
1101 7 POP_REG(shred, SZ_INT * (info->depth - 1));
1102 7 *(M_Object *)REG(-SZ_INT) = ref;
1103 } else {
1104 4 POP_REG(shred, SZ_INT * (info->depth - 4));
1105 4 *(M_Object *)REG(-SZ_INT * 4) = ref;
1106 4 *(M_Object **)REG(-SZ_INT * 3) = aai.data;
1107 4 *(m_uint *)REG(-SZ_INT * 2) = 0;
1108 4 *(m_uint *)REG(-SZ_INT) = num_obj;
1109 }
1110 }
1111
1112 ANN static bool last_is_zero(Exp e) {
1113 while(e->next) e = e->next;
1114 return exp_is_zero(e);
1115 }
1116
1117 ANN2(1,2) m_bool check_array_instance(const Env env, Type_Decl *td, const Exp args) {
1118 if (!last_is_zero(td->array->exp)) {
1119 if (!args)
1120 ERR_B(td->pos, "declaration of abstract type arrays needs lambda");
1121 } else {
1122 if(args)
1123 gwerr_warn("array is empty", "no need to provide a lambda",
1124 NULL, env->name, td->array->exp->pos);
1125 }
1126 return GW_OK;
1127 }
1128