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 |