Gwion coverage report


Directory: src/
File: src/lib/union.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 126 143 88.1%
Functions: 7 10 70.0%
Branches: 33 52 63.5%

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 "instr.h"
6 #include "emit.h"
7 #include "gwion.h"
8 #include "object.h"
9 #include "operator.h"
10 #include "import.h"
11 #include "gwi.h"
12 #include "specialid.h"
13 #include "gack.h"
14 #include "traverse.h"
15
16 static GACK(gack_none) { INTERP_PRINTF("None") }
17
18 1 static OP_CHECK(opck_none) {
19 1 Exp_Binary *bin = (Exp_Binary *)data;
20
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 CHECK_NN(opck_rassign(env, data));
21 exp_setvar(bin->rhs, 1);
22 return bin->rhs->type;
23 }
24
25 static OP_EMIT(opem_none) {
26 emit_regmove(emit, -SZ_INT);
27 return GW_OK;
28 }
29
30 10 static OP_EMIT(opem_union_dot) {
31 10 const Exp_Dot *member = (Exp_Dot *)data;
32 10 const Map map = &member->base->type->nspc->info->value->map;
33
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 CHECK_BB(emit_exp(emit, member->base));
34
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 9 times.
10 if (is_func(emit->gwion, exp_self(member)->type)) { // is_callable? can only be a func
35 1 emit_pushimm(emit, (m_uint)exp_self(member)->type->info->func->code);
36 1 return GW_OK;
37 }
38
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
9 if (!strcmp(s_name(member->xid), "index")) {
39 1 emit_add_instr(emit, DotMember);
40 1 return GW_OK;
41 }
42
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
23 for (m_uint i = 0; i < map_size(map); ++i) {
43
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 15 times.
23 if (VKEY(map, i) == (m_uint)member->xid) {
44 8 const Value v = (Value)VVAL(map, i);
45 8 const uint emit_addr = exp_getvar(exp_self(member));
46 8 emit_unionmember(emit, i, v->type->size, emit_addr);
47 8 return GW_OK;
48 }
49 }
50 return GW_ERROR;
51 }
52
53 3 static DTOR(UnionDtor) {
54 3 const m_uint idx = *(m_uint *)o->data;
55
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (idx) {
56 2 const Map map = &o->type_ref->nspc->info->value->map;
57 2 const Value v = (Value)map_at(map, idx - 1);
58
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (tflag(v->type, tflag_compound))
59 compound_release(shred, v->type, (o->data + SZ_INT));
60 }
61 3 }
62
63 1 static OP_CHECK(opck_union_is) {
64 1 const Exp e = (Exp)data;
65 1 const Exp_Call *call = &e->d.exp_call;
66 1 const Exp exp = call->args;
67
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if(!exp)
68 ERR_N(e->pos, "Union.is() takes one argument of form id");
69
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (exp->exp_type != ae_exp_primary || exp->d.prim.prim_type != ae_prim_id)
70 ERR_N(exp->pos, "Union.is() argument must be of form id");
71 1 const Type t = call->func->d.exp_dot.base->type;
72 1 const Value v = find_value(t, exp->d.prim.d.var);
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!v)
74 ERR_N(exp->pos, "'%s' has no member '%s'", t->name,
75 s_name(exp->d.prim.d.var));
76 1 const Map map = &t->nspc->info->value->map;
77
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 for (m_uint i = 0; i < map_size(map); ++i) {
78 3 const Value v = (Value)VVAL(map, i);
79
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (!strcmp(s_name(exp->d.prim.d.var), v->name)) {
80 1 const Exp exp_func = call->func;
81 1 const Exp exp_args = call->args;
82 1 e->exp_type = ae_exp_binary;
83 1 e->d.exp_binary.lhs = cpy_exp(env->gwion->mp, exp_func);
84 1 e->d.exp_binary.lhs->d.exp_dot.xid =
85 1 insert_symbol(env->gwion->st, "index");
86 // e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i+1, e->pos);
87 1 e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i, e->pos);
88 1 free_exp(env->gwion->mp, exp_func);
89 1 free_exp(env->gwion->mp, exp_args);
90 1 e->d.exp_binary.op = insert_symbol(env->gwion->st, "==");
91
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 CHECK_ON(check_exp(env, e));
92 1 return e->type;
93 }
94 }
95 return env->gwion->type[et_error];
96 }
97
98 static MFUN(union_is) {
99 *(m_uint *)RETURN = *(m_uint *)MEM(SZ_INT) == *(m_uint *)o->data;
100 }
101
102 1 static MFUN(union_new) {
103 1 memcpy(o->data, MEM(SZ_INT*2), *(m_uint*)MEM(SZ_INT));
104 1 *(M_Object *)RETURN = o;
105 1 }
106
107 2 static OP_CHECK(opck_union_new) {
108 2 Exp_Call *call = (Exp_Call *)data;
109 2 const Exp name = call->args;
110
4/6
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
2 if (!name || !name->next || name->next->next)
111 1 ERR_N(call->func->pos, "Union constructor takes two arguments, "
112 "'id' and 'value'");
113
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (name->exp_type != ae_exp_primary || name->d.prim.prim_type != ae_prim_id)
114 return env->gwion->type[et_error];
115 1 const Exp val = name->next;
116 1 const Type base = call->func->d.exp_dot.base->type;
117 1 const Map map = &base->nspc->info->value->map;
118
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 for (m_uint i = 0; i < map_size(map); ++i) {
119
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (VKEY(map, i) == (m_uint)name->d.prim.d.var) {
120 1 const Value v = (Value)VVAL(map, i);
121 1 name->d.prim.prim_type = ae_prim_num;
122 1 name->d.prim.d.num = i;
123 1 name->type = env->gwion->type[et_int];
124
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 DECL_ON(const Type, t, = check_exp(env, val));
125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (isa(t, v->type) < 0) {
126 ERR_N(val->pos, "Invalid type '%s' for '%s', should be '%s'", t->name,
127 v->name, v->type->name);
128 }
129 1 const Exp e = new_prim_int(env->gwion->mp, t->size + SZ_INT, val->pos);
130 1 e->next = name;
131 1 e->type = env->gwion->type[et_int];
132 1 call->args = e;
133 1 return base;
134 }
135 }
136 return env->gwion->type[et_error];
137 }
138
139 638 ANN GWION_IMPORT(union) {
140 638 const Type t_none = gwi_mk_type(gwi, "None", 0, NULL);
141 638 GWI_BB(gwi_set_global_type(gwi, t_none, et_none))
142 638 GWI_BB(gwi_gack(gwi, t_none, gack_none))
143 638 gwi_add_type(gwi, t_none);
144 638 struct SpecialId_ spid = {
145 638 .type = gwi->gwion->type[et_none], .exec = NoOp, .is_const = 1};
146 638 gwi_specialid(gwi, "None", &spid);
147
148 638 GWI_BB(gwi_oper_ini(gwi, "None", "None", "None"))
149 638 GWI_BB(gwi_oper_add(gwi, opck_none))
150 638 GWI_BB(gwi_oper_emi(gwi, opem_none))
151 638 GWI_BB(gwi_oper_end(gwi, ":=>", NoOp))
152
153 638 const Type t_union = gwi_class_ini(gwi, "union", "Object");
154 638 gwi_class_xtor(gwi, NULL, UnionDtor);
155 638 gwi->gwion->type[et_union] = t_union;
156
157 638 GWI_BB(gwi_item_ini(gwi, "int", "index"))
158 638 GWI_BB(gwi_item_end(gwi, ae_flag_const, num, 0))
159 638 GWI_BB(gwi_func_ini(gwi, "bool", "is"))
160 638 GWI_BB(gwi_func_arg(gwi, "int", "member"))
161 638 GWI_BB(gwi_func_end(gwi, union_is, ae_flag_none))
162 638 GWI_BB(gwi_func_ini(gwi, "auto", "new:[T]"))
163 638 GWI_BB(gwi_func_arg(gwi, "int", "size"))
164 638 GWI_BB(gwi_func_arg(gwi, "int", "id"))
165 638 GWI_BB(gwi_func_arg(gwi, "T", "value"))
166 638 GWI_BB(gwi_func_end(gwi, union_new, ae_flag_none))
167 638 GWI_BB(gwi_class_end(gwi))
168
169 638 const Func f = (Func)vector_front(&t_union->nspc->vtable);
170 638 const struct Op_Func opfunc = {.ck = opck_union_is};
171 638 const struct Op_Import opi = {
172 638 .rhs = f->value_ref->type,
173 .func = &opfunc,
174 638 .data = (uintptr_t)f,
175 .pos = gwi->loc,
176 638 .op = insert_symbol(gwi->gwion->st, "@func_check")};
177
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 638 times.
638 CHECK_BB(add_op(gwi->gwion, &opi));
178
179 638 const Func f1 = (Func)vector_at(&t_union->nspc->vtable, 1);
180 638 const struct Op_Func opfunc1 = {.ck = opck_union_new};
181 638 const struct Op_Import opi1 = {
182 638 .rhs = f1->value_ref->type,
183 .func = &opfunc1,
184 638 .data = (uintptr_t)f1,
185 .pos = gwi->loc,
186 638 .op = insert_symbol(gwi->gwion->st, "@func_check")};
187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 638 times.
638 CHECK_BB(add_op(gwi->gwion, &opi1));
188
189 638 gwi->gwion->type[et_union] = t_union;
190
191 638 GWI_BB(gwi_oper_ini(gwi, "union", (m_str)OP_ANY_TYPE, NULL))
192 638 GWI_BB(gwi_oper_emi(gwi, opem_union_dot))
193 638 GWI_BB(gwi_oper_end(gwi, ".", NULL))
194
195 638 GWI_BB(gwi_union_ini(gwi, "Option:[A]"))
196 638 GWI_BB(gwi_union_add(gwi, "None", "none"))
197 638 GWI_BB(gwi_union_add(gwi, "A", "val"))
198 638 GWI_BB(gwi_union_end(gwi, ae_flag_none))
199
200 638 return GW_OK;
201 }
202