Gwion coverage report


Directory: src/
File: src/lib/deep_equal.c
Date: 2023-01-30 18:32:28
Exec Total Coverage
Lines: 153 154 99.4%
Functions: 18 18 100.0%
Branches: 41 50 82.0%

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 "traverse.h"
13
14 // fallbacks
15 #define deep_any(_name, _data, action, ACTION, _test, _t, _op) \
16 static OP_##ACTION(op##action##_deep_##_t##_any) { \
17 Exp_Binary *bin = data; \
18 struct Op_Import opi = { \
19 .lhs = bin->lhs->type, \
20 .rhs = bin->rhs->type, \
21 .op = insert_symbol(_data->gwion->st, #_op), \
22 .data = (m_uint)bin, \
23 .pos = exp_self(bin)->pos \
24 }; \
25 return op_##_name(_data, &opi); \
26 }
27
28 9 static OP_CHECK(opck_deep_eq_any) {
29 9 Exp_Binary *bin = data;
30 9 bin->op = insert_symbol(env->gwion->st, "==");
31
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 8 times.
9 DECL_ON(const Type, t, = check_exp(env, exp_self(bin)));
32 8 return t;
33 }
34
35 3 static OP_CHECK(opck_deep_ne_any) {
36 3 Exp_Binary *bin = data;
37 3 bin->op = insert_symbol(env->gwion->st, "!=");
38
2/2
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
3 DECL_ON(const Type, t, = check_exp(env, exp_self(bin)));
39 2 return t;
40 }
41
42 2 deep_any(emit, emit, em, EMIT, CHECK_BB, eq, ==);
43 1 deep_any(emit, emit, em, EMIT, CHECK_BB, ne, !=);
44
45 // get members of a specific type
46 36 static void type_get_member(const Gwion gwion, const Type t, const Vector v) {
47 36 const Map m = &t->nspc->info->value->map;
48
2/2
✓ Branch 1 taken 530 times.
✓ Branch 2 taken 36 times.
566 for(m_uint i = 0; i < map_size(m); i++) {
49 530 const Value value = (Value)map_at(m, i);
50
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 506 times.
530 if(!vflag(value, vflag_member)) continue;
51
2/2
✓ Branch 1 taken 492 times.
✓ Branch 2 taken 14 times.
506 if(is_func(gwion, value->type)) continue;
52 14 vector_add(v, (m_uint)value);
53 }
54 36 }
55
56 // get members of a type, starting from parents
57 36 static void compound_get_member(const Env env, const Type t, const Vector v) {
58
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
36 const Type parent = t->info->parent && t->info->parent->nspc
59
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
72 ? t->info->parent : NULL;
60
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 24 times.
36 if(parent)
61 12 compound_get_member(env, t->info->parent, v);
62 36 type_get_member(env->gwion, t, v);
63 36 }
64
65 24 ANN static inline void check_deep_equal_exp(const Env env, const Exp e, const Vector v) {
66 24 vector_init(v);
67 24 compound_get_member(env, e->type, v);
68
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
24 if(tflag(e->type, tflag_struct))
69 12 exp_setvar(e, true);
70 24 }
71
72 #define MK_DOT(_data, _exp, _value) \
73 { \
74 .d = { \
75 .exp_dot = { \
76 .base = _exp, \
77 .xid = insert_symbol(_data->gwion->st, _value->name) \
78 } \
79 }, \
80 .type = _value->type, \
81 .exp_type = ae_exp_dot, \
82 .pos = _exp->pos \
83 }
84
85 #define MK_BIN(_lhs, _rhs, _bin) \
86 { \
87 .d = { \
88 .exp_binary = { \
89 .lhs = &_lhs, \
90 .rhs = &_rhs, \
91 .op = _bin->op \
92 } \
93 }, \
94 .exp_type = ae_exp_binary, \
95 .pos = exp_self(_bin)->pos \
96 }
97
98 4 static bool deep_check(const Env env, const Exp_Binary *bin,
99 const Vector l, const Vector r) {
100 4 const m_uint lsz = vector_size(l),
101 4 rsz = vector_size(r);
102
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if(rsz >= lsz) {
103
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for(m_uint i = 0; i < lsz; i++) {
104 2 const Value lval = (Value)vector_at(l, i),
105 2 rval = (Value)vector_at(r, i);
106 2 struct Exp_ lexp = MK_DOT(env, bin->lhs, lval),
107 2 rexp = MK_DOT(env, bin->rhs, rval),
108 2 temp = MK_BIN(lexp, rexp, bin);
109
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if(!check_exp(env, &temp))
110 return false;
111 }
112 2 } else return false;
113 2 return true;
114 }
115
116 13 static OP_CHECK(opck_deep_equal) {
117 13 Exp_Binary *const bin = data;
118 26 const Symbol base_op = !strcmp(s_name(bin->op), "?=")
119
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 2 times.
13 ? insert_symbol(env->gwion->st, "==") : insert_symbol(env->gwion->st, "!=");
120 26 struct Op_Import opi = {.op = base_op,
121 13 .lhs = bin->lhs->type,
122 13 .rhs = bin->rhs->type,
123 13 .data = (uintptr_t)bin,
124 13 .pos = exp_self(bin)->pos};
125
2/2
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
13 if(op_get(env, &opi)) {
126 9 bin->op = base_op;
127 9 return op_check(env, &opi);
128 }
129 struct Vector_ l, r;
130 4 check_deep_equal_exp(env, bin->lhs, &l);
131 4 check_deep_equal_exp(env, bin->rhs, &r);
132 4 const bool ret = deep_check(env, bin, &l, &r);
133 4 vector_release(&l);
134 4 vector_release(&r);
135
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if(ret) return env->gwion->type[et_bool];
136 2 const Symbol op = bin->op;
137 2 bin->op = base_op;
138 2 env_set_error(env, true);
139 2 const Type ret_type = check_exp(env, exp_self(bin));
140 2 env_set_error(env, false);
141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if(ret_type) return env->gwion->type[et_bool];
142 2 ERR_N(exp_self(bin)->pos, "no deep operation for: {G+/}%s{0} {+}%s{0} {G+/}%s{0}",
143 bin->lhs->type->name, s_name(op), bin->rhs->type->name);
144 }
145
146 struct DeepEmit {
147 Exp exp;
148 Value val;
149 Exp tmp;
150 struct Vector_ vec;
151 };
152
153 16 ANN static inline Type deep_type(const Gwion gwion, const Type t) {
154
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 4 times.
16 if(!tflag(t, tflag_struct))
155 12 return t;
156 4 return ref_type(gwion, t, t->info->value->from->loc);
157 }
158
159 16 ANN static void deep_emit_init(const Emitter emit, struct DeepEmit *d, const m_int offset) {
160 char name[256];
161 16 sprintf(name, "@%u:%u", d->exp->pos.first.line, d->exp->pos.first.column);
162 16 d->val = new_value(emit->env, deep_type(emit->gwion, d->exp->type), name, d->exp->pos);
163 16 d->tmp = new_prim_id(emit->gwion->mp, insert_symbol(emit->gwion->st, d->val->name), d->exp->pos);
164 16 d->tmp->d.prim.value = d->val;
165 16 d->tmp->type = d->val->type;
166 16 check_deep_equal_exp(emit->env, d->exp, &d->vec);
167 16 d->val->from->offset = emit_localn(emit, d->val->type);
168 16 emit_regtomem(emit, d->val->from->offset, offset);
169 16 }
170
171 16 ANN static void deep_emit_release(const Emitter emit, struct DeepEmit *d) {
172 16 free_exp(emit->gwion->mp, d->tmp);
173 16 value_remref(d->val, emit->gwion);
174 16 vector_release(&d->vec);
175 16 }
176
177 struct DeepEmits {
178 struct DeepEmit *lhs;
179 struct DeepEmit *rhs;
180 struct Vector_ acc;
181 Exp_Binary *bin;
182 };
183
184 8 static void deep_emits_init(const Emitter emit, struct DeepEmits *ds) {
185 8 emit_regmove(emit, -SZ_INT);
186 8 deep_emit_init(emit, ds->lhs, -SZ_INT);
187 8 deep_emit_init(emit, ds->rhs, 0);
188 8 vector_init(&ds->acc);
189 8 }
190
191 8 ANN static void deep_emits_release(const Emitter emit, struct DeepEmits *ds) {
192 8 deep_emit_release(emit, ds->lhs);
193 8 deep_emit_release(emit, ds->rhs);
194 8 vector_release(&ds->acc);
195 8 }
196
197 8 ANN static void emit_deep_fail(const Emitter emit, const Vector v) {
198 8 const m_uint sz = emit_code_size(emit);
199
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
10 for(m_uint i = 0; i < vector_size(v); i++) {
200 2 const Instr branch = (Instr)vector_at(v, i);
201 2 branch->m_val = sz;
202 }
203 8 emit_add_instr(emit, RegSetImm)->m_val2 = -SZ_INT;
204 8 }
205
206 8 ANN static bool deep_emit(const Emitter emit, struct DeepEmits *ds) {
207
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
10 for(m_uint i = 0; i < vector_size(&ds->lhs->vec); i++) {
208 2 const Value lhs = (Value)vector_at(&ds->lhs->vec, i),
209 2 rhs = (Value)vector_at(&ds->rhs->vec, i);
210 2 struct Exp_ lexp = MK_DOT(emit, ds->lhs->tmp, lhs);
211 2 struct Exp_ rexp = MK_DOT(emit, ds->rhs->tmp, rhs);
212 2 struct Exp_ temp = MK_BIN(lexp, rexp, ds->bin);
213 2 temp.type=emit->gwion->type[et_bool];
214
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if(emit_exp(emit, &temp) < 0) return false;
215 2 vector_add(&ds->acc, (m_uint)emit_add_instr(emit, BranchEqInt));
216 }
217 8 const Instr jmp = emit_add_instr(emit, Goto);
218 8 emit_deep_fail(emit, &ds->acc);
219 8 jmp->m_val = emit_code_size(emit);
220 8 return true;
221 }
222
223 8 static OP_EMIT(opem_deep_equal) {
224 8 emit_push_scope(emit);
225 8 Exp_Binary *const bin = data;
226 8 struct DeepEmit dl = { .exp=bin->lhs };
227 8 struct DeepEmit dr = { .exp=bin->rhs };
228 8 struct DeepEmits ds = { .lhs=&dl, .rhs=&dr, .bin = bin };
229 8 deep_emits_init(emit, &ds);
230 8 const bool ret = deep_emit(emit, &ds);
231 8 deep_emits_release(emit, &ds);
232 8 emit_pop_scope(emit);
233
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 return ret ? GW_OK: GW_ERROR;
234 }
235
236 638 GWION_IMPORT(deep_equal) {
237
238 638 GWI_BB(gwi_oper_ini(gwi, (m_str)OP_ANY_TYPE, (m_str)OP_ANY_TYPE, "bool"))
239
240
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwidoc(gwi, "Deep Equality fallback");
241 638 GWI_BB(gwi_oper_add(gwi, opck_deep_eq_any))
242 638 GWI_BB(gwi_oper_emi(gwi, opem_deep_eq_any))
243 638 GWI_BB(gwi_oper_end(gwi, "?=", NULL))
244
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwidoc(gwi, "Deep Inequality fallback");
246 638 GWI_BB(gwi_oper_add(gwi, opck_deep_ne_any))
247 638 GWI_BB(gwi_oper_emi(gwi, opem_deep_ne_any))
248 638 GWI_BB(gwi_oper_end(gwi, "<>", NULL))
249
250 638 GWI_BB(gwi_oper_ini(gwi, "@Compound", "@Compound", "bool"))
251
252
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwidoc(gwi, "Deep Equality");
253 638 GWI_BB(gwi_oper_add(gwi, opck_deep_equal))
254 638 GWI_BB(gwi_oper_emi(gwi, opem_deep_equal))
255 638 GWI_BB(gwi_oper_end(gwi, "?=", NULL))
256
257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 638 times.
638 gwidoc(gwi, "Deep Inequality");
258 638 GWI_BB(gwi_oper_add(gwi, opck_deep_equal))
259 638 GWI_BB(gwi_oper_emi(gwi, opem_deep_equal))
260 638 GWI_BB(gwi_oper_end(gwi, "<>", NULL))
261
262 638 return GW_OK;
263 }
264