| 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 |