| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include <stdlib.h> | ||
| 2 | #include <string.h> | ||
| 3 | #include "gwion_util.h" | ||
| 4 | #include "gwion_ast.h" | ||
| 5 | #include "gwion_env.h" | ||
| 6 | #include "vm.h" | ||
| 7 | #include "gwion.h" | ||
| 8 | #include "instr.h" | ||
| 9 | #include "object.h" | ||
| 10 | #include "operator.h" | ||
| 11 | #include "import.h" | ||
| 12 | #include "emit.h" | ||
| 13 | #include "traverse.h" | ||
| 14 | #include "parse.h" | ||
| 15 | #include "gwi.h" | ||
| 16 | #include "tmpl_info.h" | ||
| 17 | #include "array.h" | ||
| 18 | #include "looper.h" | ||
| 19 | #include "dict.h" | ||
| 20 | |||
| 21 | #define HMAP_MIN_CAP 32 | ||
| 22 | #define HMAP_MAX_LOAD 0.75 | ||
| 23 | |||
| 24 | typedef void (clear_fn)(const HMap*, const VM_Shred, const struct HMapInfo*, const m_uint); | ||
| 25 | |||
| 26 | // TODO: arch sensible hash | ||
| 27 | ✗ | static SFUN(mfun_int_h) { | |
| 28 | ✗ | m_int x = *(m_uint*)MEM(0); | |
| 29 | ✗ | x = (x ^ (x >> 30)) * UINT64_C(0xbf58476d1ce4e5b9); | |
| 30 | ✗ | x = (x ^ (x >> 27)) * UINT64_C(0x94d049bb133111eb); | |
| 31 | ✗ | x = x ^ (x >> 31); | |
| 32 | ✗ | *(m_int*) RETURN = x; | |
| 33 | } | ||
| 34 | |||
| 35 | 1 | static SFUN(mfun_float_h) { | |
| 36 | char c[1024]; | ||
| 37 | 1 | snprintf(c, 1024, "%f", *(m_float*)MEM(0)); | |
| 38 | 1 | *(m_uint*)RETURN = hash(c); | |
| 39 | 1 | } | |
| 40 | |||
| 41 | 9 | static SFUN(mfun_string_h) { | |
| 42 | 9 | *(m_int*)RETURN = hash(STRING(*(M_Object*)MEM(0))); | |
| 43 | 9 | } | |
| 44 | |||
| 45 | ✗ | ANN static void clear_oo(const HMap *a, const VM_Shred shred, const HMapInfo *info NUSED, const m_uint idx) { | |
| 46 | ✗ | release(*(M_Object*)(a->data + idx * SZ_INT*2), shred); | |
| 47 | ✗ | release(*(M_Object*)((a->data + idx * SZ_INT*2) + SZ_INT), shred); | |
| 48 | } | ||
| 49 | |||
| 50 | ✗ | ANN static void clear_ss(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 51 | ✗ | struct_release(shred, info->key, a->data + idx * info->sz); | |
| 52 | ✗ | struct_release(shred, info->val, a->data + idx * info->sz + info->key->size); | |
| 53 | } | ||
| 54 | |||
| 55 | ✗ | ANN static void clear_os(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 56 | ✗ | release(*(M_Object*)(a->data + idx * info->sz), shred); | |
| 57 | ✗ | struct_release(shred, info->val, a->data + idx * info->sz + SZ_INT); | |
| 58 | } | ||
| 59 | |||
| 60 | ✗ | ANN static void clear_so(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 61 | ✗ | struct_release(shred, info->key, a->data + idx * info->sz); | |
| 62 | ✗ | release(*(M_Object*)(a->data + idx * info->sz + info->key->size), shred); | |
| 63 | } | ||
| 64 | |||
| 65 | 3 | ANN static void clear_on(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 66 | 3 | release(*(M_Object*)(a->data + idx * info->sz), shred); | |
| 67 | 3 | } | |
| 68 | |||
| 69 | ✗ | ANN static void clear_sn(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 70 | ✗ | struct_release(shred, info->key, a->data + idx * info->sz); | |
| 71 | } | ||
| 72 | |||
| 73 | ✗ | ANN static void clear_no(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 74 | ✗ | release(*(M_Object*)(a->data + idx * info->sz + info->key->size), shred); | |
| 75 | } | ||
| 76 | |||
| 77 | |||
| 78 | ✗ | ANN static void clear_ns(const HMap *a, const VM_Shred shred, const HMapInfo *info, const m_uint idx) { | |
| 79 | ✗ | struct_release(shred, info->val, a->data + idx * info->sz + info->key->size); | |
| 80 | } | ||
| 81 | |||
| 82 | static clear_fn *const n_clear[3] = { NULL, clear_no, clear_ns }; | ||
| 83 | static clear_fn* o_clear[3] = { clear_on, clear_oo, clear_os }; | ||
| 84 | static clear_fn* s_clear[3] = { clear_sn, clear_so, clear_ss }; | ||
| 85 | static clear_fn*const* clear[3] = { n_clear, o_clear, s_clear }; | ||
| 86 | |||
| 87 | 5 | ANN static void hmapinfo_init(HMapInfo *const info, const Type key, const Type val) { | |
| 88 | 5 | info->key = key; | |
| 89 | 5 | info->val = val; | |
| 90 | 5 | info->sz = key->size + val->size; | |
| 91 | 5 | info->keyk = tflag(key, tflag_compound) + tflag(key, tflag_struct); | |
| 92 | 5 | info->valk = tflag(val, tflag_compound) + tflag(val, tflag_struct); | |
| 93 | 5 | } | |
| 94 | |||
| 95 | 1 | static DTOR(dict_clear_dtor) { | |
| 96 | 1 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 97 | 1 | clear_fn *fn = clear[hinfo->keyk][hinfo->valk]; | |
| 98 | 1 | HMap *a = &*(struct HMap*)o->data; | |
| 99 |
2/2✓ Branch 0 taken 31 times.
✓ Branch 1 taken 1 times.
|
32 | for(m_uint i = a->capacity; --i;) { |
| 100 | 31 | const HState state = *(HState*)(a->state + (i-1) * sizeof(HState)); | |
| 101 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
|
31 | if(!state.set || state.deleted) continue; |
| 102 | 2 | fn(a, shred, hinfo, i-1); | |
| 103 | } | ||
| 104 | 1 | } | |
| 105 | |||
| 106 | 2 | INSTR(dict_ctor_alt) { | |
| 107 | 2 | const Type t = (Type)instr->m_val2; | |
| 108 | 2 | const M_Object o = new_object(shred->info->mp, t); | |
| 109 | 2 | const HMapInfo *hinfo = (HMapInfo*)t->nspc->class_data; | |
| 110 | 2 | HMap *a = &*(struct HMap*)o->data; | |
| 111 | 2 | a->data = (m_bit*)mp_calloc2(shred->info->mp, hinfo->sz * instr->m_val); | |
| 112 | 2 | a->state = (m_bit*)mp_calloc2(shred->info->mp, sizeof(HState) * instr->m_val); | |
| 113 | 2 | a->capacity = instr->m_val; | |
| 114 | 2 | shred->reg += SZ_INT; | |
| 115 | 2 | *(M_Object*)REG(-SZ_INT) = o; | |
| 116 | 2 | } | |
| 117 | |||
| 118 | 2 | INSTR(dict_lit_ctor) { | |
| 119 | 2 | const M_Object o = *(M_Object*)REG(-SZ_INT); | |
| 120 | 2 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 121 | 2 | HMap *hmap = &*(struct HMap*)o->data; | |
| 122 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for(m_uint i = 0; i < instr->m_val; i += hinfo->sz + SZ_INT) { |
| 123 | 4 | m_uint hash = *(m_uint*)REG(i + hinfo->sz) % hmap->capacity; | |
| 124 | 1 | while(true) { | |
| 125 | 5 | HState *const state = (HState*)(hmap->state + hash * sizeof(HState)); | |
| 126 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
|
5 | if(!state->set) { |
| 127 | 4 | m_bit *const data = hmap->data + hinfo->sz * hash; | |
| 128 | 4 | memcpy(data, REG(i), hinfo->sz); | |
| 129 | 4 | state->set = true; | |
| 130 | 4 | break; | |
| 131 | } | ||
| 132 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if(++hash >= hmap->capacity) |
| 133 | 1 | hash = 0; | |
| 134 | } | ||
| 135 | } | ||
| 136 | 2 | hmap->count = instr->m_val2; | |
| 137 | 2 | } | |
| 138 | |||
| 139 | 1 | static CTOR(dict_ctor) { | |
| 140 | 1 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 141 | 1 | HMap *const a = &*(struct HMap*)o->data; | |
| 142 | 1 | a->data = (m_bit*)mp_calloc2(shred->info->mp, hinfo->sz * HMAP_MIN_CAP); | |
| 143 | 1 | a->state = (m_bit*)mp_calloc2(shred->info->mp, sizeof(HState) * HMAP_MIN_CAP); | |
| 144 | 1 | a->capacity = HMAP_MIN_CAP; | |
| 145 | 1 | a->count = 0; | |
| 146 | 1 | } | |
| 147 | |||
| 148 | 1 | static DTOR(dict_dtor) { | |
| 149 | 1 | HMap *const a = &*(struct HMap*)o->data; | |
| 150 | 1 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 151 | 1 | mp_free2(shred->info->mp, hinfo->sz * a->capacity, a->data); | |
| 152 | 1 | mp_free2(shred->info->mp, sizeof(HState) * a->capacity, a->state); | |
| 153 | 1 | } | |
| 154 | |||
| 155 | // bound the hash | ||
| 156 | // could be put in next func | ||
| 157 | 3 | static INSTR(hmap_iter_set_ini) { | |
| 158 | 3 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2 - instr->m_val); | |
| 159 | 3 | const HMap *hmap = (HMap*)o->data; | |
| 160 | 3 | const size_t h = *(m_uint*)REG(-SZ_INT - instr->m_val); | |
| 161 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if(h >= hmap->capacity) |
| 162 | 3 | *(m_uint*)REG(-SZ_INT - instr->m_val) = h % hmap->capacity; | |
| 163 | 3 | } | |
| 164 | |||
| 165 | ✗ | static INSTR(hmpa_set_inc) { | |
| 166 | ✗ | (*(m_uint*)REG(-SZ_INT - instr->m_val))++; | |
| 167 | } | ||
| 168 | |||
| 169 | 3 | static INSTR(hmap_iter_set) { | |
| 170 | 3 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2 - instr->m_val); | |
| 171 | 3 | HMap *const hmap = (HMap*)o->data; | |
| 172 | 3 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 173 | 3 | const size_t bucket = *(m_uint*)REG(-SZ_INT - instr->m_val); | |
| 174 | 3 | HState *const state = (HState*)(hmap->state + sizeof(HState) * bucket); | |
| 175 | 3 | m_bit *const data = hmap->data + hinfo->sz * bucket; | |
| 176 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
3 | if (!state->set || state->deleted) { |
| 177 | |||
| 178 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if(hinfo->keyk) { |
| 179 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | if(hinfo->keyk == HKIND_OBJ) |
| 180 | 3 | (*(M_Object*)REG(-instr->m_val))->ref++; | |
| 181 | else | ||
| 182 | ✗ | struct_addref(shred->info->vm->gwion, hinfo->key, REG(-instr->m_val)); | |
| 183 | } | ||
| 184 | |||
| 185 | 3 | state->set = true; | |
| 186 | 3 | state->deleted = false; | |
| 187 | 3 | memcpy(data, REG(-instr->m_val), instr->m_val); | |
| 188 | 3 | POP_REG(shred, instr->m_val); | |
| 189 | 3 | *(m_bit**)REG(-SZ_INT*2) = data + hinfo->key->size; | |
| 190 | 3 | *(m_uint*)REG(-SZ_INT) = 1; | |
| 191 | 3 | hmap->count++; | |
| 192 | } else { | ||
| 193 | ✗ | memcpy(REG(0), data, hinfo->key->size); | |
| 194 | ✗ | shred->reg += SZ_INT + hinfo->key->size; | |
| 195 | ✗ | *(m_uint**)REG(-SZ_INT) = 0; | |
| 196 | } | ||
| 197 | 3 | } | |
| 198 | |||
| 199 | 1 | static INSTR(hmap_iter_inc) { | |
| 200 | 1 | (*(m_uint*)(shred->reg - SZ_INT))++; | |
| 201 | 1 | } | |
| 202 | |||
| 203 | 4 | static INSTR(hmap_iter) { | |
| 204 | 4 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*3); | |
| 205 | 4 | const HMap *hmap = (HMap*)o->data; | |
| 206 | 4 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 207 | 4 | size_t bucket = *(m_uint*)(shred->reg - SZ_INT) % hmap->capacity; | |
| 208 | 4 | const HState *state = (HState*)(hmap->state + sizeof(HState) * bucket); | |
| 209 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (state->set) { |
| 210 | 3 | m_int *const tombstone = (m_int*)(shred->reg - SZ_INT*2); | |
| 211 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
3 | if (state->deleted && *tombstone == -1) { |
| 212 | 1 | *tombstone = bucket++; | |
| 213 | } | ||
| 214 | 3 | const m_bit *data = hmap->data + hinfo->sz * bucket; | |
| 215 | 3 | *(m_uint*)(shred->reg - SZ_INT) = bucket; | |
| 216 | 3 | memcpy(REG(0), data, hinfo->key->size); | |
| 217 | 3 | shred->reg += hinfo->key->size; | |
| 218 | 3 | return; | |
| 219 | } | ||
| 220 | 1 | handle(shred, "InvalidMapAccess"); | |
| 221 | } | ||
| 222 | |||
| 223 | 3 | static INSTR(hmap_grow) { | |
| 224 | 3 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT); | |
| 225 | 3 | const HMap *hmap = (HMap*)o->data; | |
| 226 | 3 | *(m_uint*)REG(0) = (hmap->count + 1) > (hmap->capacity * HMAP_MAX_LOAD); | |
| 227 | 3 | PUSH_REG(shred, SZ_INT); | |
| 228 | 3 | } | |
| 229 | |||
| 230 | ✗ | static INSTR(hmap_grow_init) { | |
| 231 | ✗ | const M_Object o = *(M_Object*)(shred->reg - SZ_INT); | |
| 232 | ✗ | HMap *const hmap = (HMap*)o->data; | |
| 233 | ✗ | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 234 | ✗ | *(m_bit**)REG(0) = hmap->data; | |
| 235 | ✗ | *(m_bit**)REG(SZ_INT) = hmap->state; | |
| 236 | ✗ | *(m_uint*)REG(SZ_INT*2) = hmap->capacity; | |
| 237 | ✗ | hmap->capacity *= 2; | |
| 238 | ✗ | hmap->count = 0; | |
| 239 | ✗ | hmap->state = mp_calloc2(shred->info->mp, hmap->capacity * sizeof(HState)); | |
| 240 | ✗ | hmap->data = mp_calloc2(shred->info->mp, hmap->capacity * hinfo->sz); | |
| 241 | |||
| 242 | ✗ | PUSH_REG(shred, SZ_INT*3); | |
| 243 | } | ||
| 244 | |||
| 245 | ✗ | static INSTR(hmap_grow_dec) { | |
| 246 | ✗ | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*4); | |
| 247 | ✗ | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 248 | ✗ | const m_bit *old_data = *(m_bit**)REG(-SZ_INT*3); | |
| 249 | ✗ | const m_bit *old_state = *(m_bit**)REG(-SZ_INT*2); | |
| 250 | ✗ | while((*(m_uint*)REG(-SZ_INT))--) { | |
| 251 | ✗ | const HState *state = (HState *)(old_state + (*(m_uint*)REG(-SZ_INT)) * sizeof(HState)); | |
| 252 | ✗ | if(!state->set || state->deleted)continue; | |
| 253 | ✗ | m_bit *const data = (m_bit*)(old_data + (*(m_uint*)REG(-SZ_INT)) * hinfo->sz); | |
| 254 | ✗ | memcpy(shred->reg + SZ_INT, data, hinfo->key->size); | |
| 255 | ✗ | PUSH_REG(shred, SZ_INT + hinfo->key->size); | |
| 256 | ✗ | *(m_uint*)shred->reg = 0; | |
| 257 | ✗ | PUSH_REG(shred, SZ_INT); | |
| 258 | ✗ | return; | |
| 259 | } | ||
| 260 | ✗ | POP_REG(shred, SZ_INT*2); | |
| 261 | ✗ | *(m_uint*)(shred->reg -SZ_INT) = 1; | |
| 262 | } | ||
| 263 | |||
| 264 | ✗ | static INSTR(hmap_find) { | |
| 265 | ✗ | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*6); | |
| 266 | ✗ | HMap *const hmap = (HMap*)o->data; | |
| 267 | ✗ | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 268 | ✗ | const m_bit *old_data = *(m_bit**)REG(-SZ_INT*5); | |
| 269 | ✗ | const m_bit *old_state = *(m_bit**)REG(-SZ_INT*4); | |
| 270 | ✗ | const m_uint h = *(m_uint*)REG(-SZ_INT); | |
| 271 | ✗ | const m_uint idx = *(m_uint*)REG(-SZ_INT*3); | |
| 272 | ✗ | m_uint bucket = h % hmap->capacity; | |
| 273 | ✗ | while(true) { | |
| 274 | ✗ | HState *const state = (HState *)(hmap->state + bucket * sizeof(HState)); | |
| 275 | ✗ | if(!state->set) { | |
| 276 | ✗ | const HState *prev_state = (HState *)(old_state + idx * sizeof(HState)); | |
| 277 | ✗ | memcpy(state, prev_state, sizeof(HState)); | |
| 278 | ✗ | m_bit *const data = hmap->data + bucket * hinfo->sz; | |
| 279 | ✗ | const m_bit *prev_data = old_data + idx * hinfo->sz; | |
| 280 | ✗ | memcpy(data, prev_data, hinfo->sz); | |
| 281 | ✗ | hmap->count++; | |
| 282 | ✗ | break; | |
| 283 | } | ||
| 284 | ✗ | if(++bucket > hmap->capacity) | |
| 285 | ✗ | bucket = 0; | |
| 286 | } | ||
| 287 | ✗ | if(!idx) | |
| 288 | ✗ | POP_REG(shred, SZ_INT*4 - instr->m_val) | |
| 289 | else | ||
| 290 | ✗ | POP_REG(shred, SZ_INT) | |
| 291 | ✗ | *(m_uint*)REG(-SZ_INT) = !idx; | |
| 292 | } | ||
| 293 | |||
| 294 | ✗ | static INSTR(hmap_addr) { | |
| 295 | ✗ | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2 - instr->m_val); | |
| 296 | ✗ | const HMap *hmap = (HMap*)o->data; | |
| 297 | ✗ | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 298 | ✗ | POP_REG(shred, SZ_INT + instr->m_val); | |
| 299 | ✗ | const m_uint bucket = *(m_uint*)REG(0); | |
| 300 | ✗ | *(HState *)(hmap->state + bucket * sizeof(HState)) = (HState) { true, false }; | |
| 301 | ✗ | *(m_bit**)REG(-SZ_INT) = hmap->data + hinfo->sz * bucket + hinfo->key->size; | |
| 302 | } | ||
| 303 | |||
| 304 | 1 | static INSTR(hmap_val) { | |
| 305 | 1 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2); | |
| 306 | 1 | const HMap *hmap = (HMap*)o->data; | |
| 307 | 1 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 308 | 1 | const m_uint bucket = *(m_uint*)REG(0); | |
| 309 | 1 | const m_bit *new_data = hmap->data + hinfo->sz * bucket; | |
| 310 | 1 | const m_int tombstone = *(m_int*)(shred->reg - SZ_INT); | |
| 311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (tombstone != -1) { |
| 312 | ✗ | m_bit *const old_data = hmap->data + (hinfo->key->size + hinfo->val->size) * tombstone; | |
| 313 | ✗ | HState *const old_state = (HState*)(hmap->state + sizeof(HState) * tombstone); | |
| 314 | ✗ | HState *const new_state = (HState*)(hmap->state + sizeof(HState) * bucket); | |
| 315 | ✗ | memcpy(old_state, new_state, sizeof(HState)); | |
| 316 | ✗ | memcpy(old_data, new_data, hinfo->sz); | |
| 317 | ✗ | new_state->deleted = true; | |
| 318 | } | ||
| 319 | |||
| 320 | 1 | shred->reg -= SZ_INT*2 - hinfo->val->size; | |
| 321 | 1 | memcpy(REG(-hinfo->val->size), new_data + hinfo->key->size, hinfo->val->size); | |
| 322 | 1 | } | |
| 323 | |||
| 324 | 1 | static INSTR(hmap_remove_clear) { | |
| 325 | 1 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2); | |
| 326 | 1 | const HMap *hmap = (HMap*)o->data; | |
| 327 | 1 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 328 | 1 | const m_uint bucket = *(m_uint*)REG(0); | |
| 329 | 1 | clear_fn *fn = (clear_fn*)instr->m_val; | |
| 330 | 1 | fn(hmap, shred, hinfo, bucket); | |
| 331 | 1 | } | |
| 332 | |||
| 333 | 1 | static INSTR(hmap_remove) { | |
| 334 | 1 | const M_Object o = *(M_Object*)(shred->reg - SZ_INT*2); | |
| 335 | 1 | HMap *const hmap = (HMap*)o->data; | |
| 336 | 1 | const HMapInfo *hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 337 | 1 | const m_uint bucket = *(m_uint*)REG(0); | |
| 338 | 1 | m_bit *data = hmap->data + hinfo->sz * bucket; | |
| 339 | 1 | hmap->count--; | |
| 340 | 1 | HState *const state = (HState *)(hmap->state + bucket * sizeof(HState)); | |
| 341 | 1 | state->deleted = true; | |
| 342 | 1 | shred->reg -= SZ_INT*3 - hinfo->val->size; | |
| 343 | 1 | memcpy(REG(-hinfo->val->size), data + hinfo->key->size, hinfo->val->size); | |
| 344 | 1 | } | |
| 345 | |||
| 346 | 1 | static OP_CHECK(opck_dict_remove_toop) { | |
| 347 | 1 | const Exp e = (Exp)data; | |
| 348 | 1 | const Exp_Call *call = &e->d.exp_call; | |
| 349 | 1 | const Exp func = call->func; | |
| 350 | 1 | const Exp args = call->args; | |
| 351 | 1 | e->exp_type = ae_exp_binary; | |
| 352 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | CHECK_OO(check_exp(env, e->d.exp_binary.rhs = cpy_exp(env->gwion->mp, func->d.exp_dot.base))); |
| 353 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | CHECK_OO(check_exp(env, e->d.exp_binary.lhs = args)); |
| 354 | 1 | e->d.exp_binary.op = insert_symbol("~~"); | |
| 355 | 1 | free_exp(env->gwion->mp, func); | |
| 356 | 1 | const Type t = e->d.exp_binary.rhs->type; | |
| 357 | 1 | HMapInfo *const hinfo = (HMapInfo*)t->nspc->class_data; | |
| 358 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if(isa(args->type, hinfo->key) < 0 || args->next) |
| 359 | ✗ | ERR_N(e->pos, "dict.remove must be called with one Key argument"); | |
| 360 | 1 | return e->type = env->gwion->type[et_void]; | |
| 361 | } | ||
| 362 | |||
| 363 | 3 | ANN static m_bool emit_dict_iter(const Emitter emit, const HMapInfo *hinfo, | |
| 364 | const struct Op_Import *opi, const Exp call, const Exp exp) { | ||
| 365 | 3 | emit_pushimm(emit, -1); // room for tombstone | |
| 366 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, call)); |
| 367 | 3 | const m_uint pc = emit_code_size(emit); | |
| 368 | 3 | const Instr iter = emit_add_instr(emit, hmap_iter); | |
| 369 | 3 | iter->m_val = hinfo->key->size + SZ_INT; | |
| 370 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, exp)); |
| 371 | 3 | op_emit(emit, opi); | |
| 372 | 3 | const Instr ok = emit_add_instr(emit, BranchNeqInt); | |
| 373 | 3 | emit_add_instr(emit, hmap_iter_inc); | |
| 374 | 3 | const Instr top = emit_add_instr(emit, Goto); | |
| 375 | 3 | top->m_val = pc; | |
| 376 | 3 | ok->m_val = emit_code_size(emit); | |
| 377 | 3 | emit_regmove(emit, -SZ_INT); | |
| 378 | 3 | return GW_OK; | |
| 379 | } | ||
| 380 | |||
| 381 | 5 | static OP_EMIT(_opem_dict_access) { | |
| 382 | 5 | struct ArrayAccessInfo *const info = (struct ArrayAccessInfo *const)data; | |
| 383 | 5 | Array_Sub array = &info->array; | |
| 384 | 5 | const Env env = emit->env; | |
| 385 | 5 | const HMapInfo *hinfo = (HMapInfo*)array->type->nspc->class_data; | |
| 386 | 5 | const Type key = *(Type*)array->type->nspc->class_data; | |
| 387 | |||
| 388 | 5 | struct Exp_ func = { .exp_type = ae_exp_primary, .d = { .prim = { .prim_type = ae_prim_id, .d = { .var = insert_symbol("hash") }} }}; | |
| 389 | |||
| 390 | 5 | struct Exp_ call = { | |
| 391 | .exp_type = ae_exp_call, | ||
| 392 | .d = { | ||
| 393 | .exp_call = { | ||
| 394 | .func = &func, | ||
| 395 | 5 | .args = array->exp // beware next | |
| 396 | } | ||
| 397 | } | ||
| 398 | }; | ||
| 399 | 5 | struct Exp_ lhs = { .exp_type = ae_exp_primary, .type = key, .d = { .prim = { .prim_type = ae_prim_id } }}; | |
| 400 | 5 | struct Exp_ rhs = { .exp_type = ae_exp_primary, .type = key, .d = { .prim = { .prim_type = ae_prim_id } }}; | |
| 401 | 5 | struct Exp_ bin = { .exp_type = ae_exp_binary, .d = { .exp_binary = { .lhs = &lhs, .rhs = &rhs, .op = insert_symbol("?=") } }}; | |
| 402 | 5 | struct Op_Import opi = { | |
| 403 | .lhs = key, | ||
| 404 | .rhs = key, | ||
| 405 | 5 | .op = bin.d.exp_binary.op, | |
| 406 | 5 | .data = (m_uint)&bin | |
| 407 | }; | ||
| 408 | |||
| 409 | |||
| 410 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | CHECK_BB(traverse_exp(env, &call)); |
| 411 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | if(info->is_var) { |
| 412 | |||
| 413 | 3 | const Instr instr = emit_add_instr(emit, hmap_grow); | |
| 414 | 3 | instr->m_val = key->size; | |
| 415 | 3 | const Instr nogrow = emit_add_instr(emit, BranchEqInt); | |
| 416 | 3 | emit_add_instr(emit, hmap_grow_init); | |
| 417 | 3 | const m_uint grow_pc = emit_code_size(emit); | |
| 418 | 3 | emit_add_instr(emit, hmap_grow_dec); | |
| 419 | 3 | const Instr endgrow = emit_add_instr(emit, BranchNeqInt); | |
| 420 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, call.d.exp_call.func)); |
| 421 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp_call1(emit, call.d.exp_call.func->type->info->func, true)); |
| 422 | 3 | emit_add_instr(emit, hmap_find); | |
| 423 | 3 | const Instr regrow = emit_add_instr(emit, BranchEqInt); | |
| 424 | 3 | regrow->m_val = grow_pc; | |
| 425 | 3 | nogrow->m_val = emit_code_size(emit); | |
| 426 | 3 | endgrow->m_val = emit_code_size(emit); | |
| 427 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, &call)); |
| 428 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, array->exp)); |
| 429 | 3 | const m_uint top_pc = emit_code_size(emit); | |
| 430 | 3 | const Instr idx = emit_add_instr(emit, hmap_iter_set_ini); | |
| 431 | 3 | idx->m_val = key->size; | |
| 432 | |||
| 433 | |||
| 434 | 3 | const Instr iter = emit_add_instr(emit, hmap_iter_set); | |
| 435 | 3 | iter->m_val = key->size; | |
| 436 | 3 | const Instr fast = emit_add_instr(emit, BranchNeqInt); | |
| 437 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | CHECK_BB(emit_exp(emit, array->exp)); |
| 438 | 3 | op_emit(emit, &opi); | |
| 439 | |||
| 440 | 3 | const Instr ok = emit_add_instr(emit, BranchNeqInt); | |
| 441 | 3 | const Instr inc = emit_add_instr(emit, hmpa_set_inc); | |
| 442 | 3 | inc->m_val = key->size; | |
| 443 | 3 | const Instr not_ok = emit_add_instr(emit, Goto); | |
| 444 | 3 | not_ok->m_val = top_pc; | |
| 445 | 3 | ok->m_val = emit_code_size(emit); | |
| 446 | |||
| 447 | 3 | const Instr iseq = emit_add_instr(emit, hmap_addr); | |
| 448 | 3 | iseq->m_val = key->size; | |
| 449 | 3 | fast->m_val = emit_code_size(emit); | |
| 450 | 3 | return GW_OK; | |
| 451 | } | ||
| 452 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | CHECK_BB(emit_dict_iter(emit, hinfo, &opi, &call, array->exp)); |
| 453 | 2 | const Instr pushval = emit_add_instr(emit, hmap_val); | |
| 454 | 2 | pushval->m_val2 = key->size; | |
| 455 | 2 | return GW_OK; | |
| 456 | } | ||
| 457 | |||
| 458 | 1 | static OP_EMIT(opem_dict_remove) { | |
| 459 | 1 | Exp_Binary *bin = (Exp_Binary*)data; | |
| 460 | 1 | const Env env = emit->env; | |
| 461 | 1 | struct Exp_ func = { .exp_type = ae_exp_primary, .d = { .prim = { .prim_type = ae_prim_id, .d = { .var = insert_symbol("hash") }} }}; | |
| 462 | |||
| 463 | 1 | struct Exp_ call = { | |
| 464 | .exp_type = ae_exp_call, | ||
| 465 | .d = { | ||
| 466 | .exp_call = { | ||
| 467 | .func = &func, | ||
| 468 | 1 | .args = bin->lhs // beware next | |
| 469 | } | ||
| 470 | } | ||
| 471 | }; | ||
| 472 | 1 | const Type t = bin->rhs->type; | |
| 473 | 1 | HMapInfo *const hinfo = (HMapInfo*)t->nspc->class_data; | |
| 474 | |||
| 475 | 1 | struct Exp_ lhs = { .exp_type = ae_exp_primary, .type = hinfo->key, .d = { .prim = { .prim_type = ae_prim_id } }}; | |
| 476 | 1 | struct Exp_ rhs = { .exp_type = ae_exp_primary, .type = hinfo->key, .d = { .prim = { .prim_type = ae_prim_id } }}; | |
| 477 | 1 | struct Exp_ _bin = { .exp_type = ae_exp_binary, .d = { .exp_binary = { .lhs = &lhs, .rhs = &rhs, .op = insert_symbol("?=") } }}; | |
| 478 | 1 | struct Op_Import opi = { | |
| 479 | 1 | .lhs = hinfo->key, | |
| 480 | 1 | .rhs = hinfo->key, | |
| 481 | 1 | .op = _bin.d.exp_binary.op, | |
| 482 | 1 | .data = (m_uint)&_bin | |
| 483 | }; | ||
| 484 | |||
| 485 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | CHECK_BB(traverse_exp(env, &call)); |
| 486 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | CHECK_BB(emit_dict_iter(emit, hinfo, &opi, &call, bin->lhs)); |
| 487 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | if(hinfo->keyk || hinfo->valk) { |
| 488 | 1 | clear_fn *const fn = clear[hinfo->keyk][hinfo->valk]; | |
| 489 | 1 | const Instr instr = emit_add_instr(emit, hmap_remove_clear); | |
| 490 | 1 | instr->m_val = (m_uint)fn; | |
| 491 | } | ||
| 492 | |||
| 493 | 1 | const Instr pushval = emit_add_instr(emit, hmap_remove); | |
| 494 | 1 | pushval->m_val2 = hinfo->key->size; | |
| 495 | 1 | return GW_OK; | |
| 496 | } | ||
| 497 | |||
| 498 | ✗ | ANN static m_bool emit_next_access(const Emitter emit, struct ArrayAccessInfo *const info) { | |
| 499 | ✗ | const struct Array_Sub_ array = info->array; | |
| 500 | ✗ | HMapInfo *const hinfo = (HMapInfo*)info->array.type->nspc->class_data; | |
| 501 | ✗ | info->array = (struct Array_Sub_){ | |
| 502 | ✗ | .exp = array.exp->next, | |
| 503 | ✗ | .type = hinfo->val, | |
| 504 | ✗ | .depth = array.depth - 1 | |
| 505 | }; | ||
| 506 | ✗ | return emit_array_access(emit, info); | |
| 507 | } | ||
| 508 | |||
| 509 | 5 | static OP_EMIT(opem_dict_access) { | |
| 510 | 5 | struct ArrayAccessInfo *const info = (struct ArrayAccessInfo *const)data; | |
| 511 | 5 | const Array_Sub array = &info->array; | |
| 512 | 5 | const Exp enext = array->exp->next; | |
| 513 | 5 | array->exp->next = NULL; | |
| 514 | 5 | const m_bool ret = _opem_dict_access(emit, data); | |
| 515 | 5 | array->exp->next = enext; | |
| 516 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | CHECK_BB(ret); |
| 517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | return !enext ? GW_OK : emit_next_access(emit, info); |
| 518 | } | ||
| 519 | |||
| 520 | 7 | static OP_CHECK(opck_dict_access) { | |
| 521 | 7 | const Array_Sub array = (Array_Sub)data; | |
| 522 | 7 | HMapInfo *const hinfo = (HMapInfo*)array->type->nspc->class_data; | |
| 523 | |||
| 524 | 7 | struct Exp_ func = { .exp_type = ae_exp_primary, .d = { .prim = { .prim_type = ae_prim_id, .d = { .var = insert_symbol("hash") }} }}; | |
| 525 | |||
| 526 | 7 | struct Exp_ call = { | |
| 527 | .exp_type = ae_exp_call, | ||
| 528 | .d = { | ||
| 529 | .exp_call = { | ||
| 530 | .func = &func, | ||
| 531 | 7 | .args = array->exp // beware next | |
| 532 | } | ||
| 533 | } | ||
| 534 | }; | ||
| 535 | 7 | struct Exp_ lhs = { .exp_type = ae_exp_primary, .type = hinfo->key, .d = { .prim = { .prim_type = ae_prim_id } }}; | |
| 536 | 7 | struct Exp_ rhs = { .exp_type = ae_exp_primary, .type = hinfo->key, .d = { .prim = { .prim_type = ae_prim_id } }}; | |
| 537 | 7 | struct Exp_ bin = { .exp_type = ae_exp_binary, .d = { .exp_binary = { .lhs = &lhs, .rhs = &rhs, .op = insert_symbol("?=") } }}; | |
| 538 | 7 | struct Op_Import opi = { | |
| 539 | 7 | .lhs = hinfo->key, | |
| 540 | 7 | .rhs = hinfo->key, | |
| 541 | 7 | .op = bin.d.exp_binary.op, | |
| 542 | 7 | .data = (m_uint)&bin | |
| 543 | }; | ||
| 544 | |||
| 545 | |||
| 546 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | CHECK_BN(traverse_exp(env, &call)); |
| 547 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
|
7 | CHECK_ON(op_check(env, &opi)); |
| 548 | |||
| 549 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if(!array->exp->next) return hinfo->val; |
| 550 | ✗ | struct Array_Sub_ next = { array->exp->next, hinfo->val, | |
| 551 | ✗ | array->depth - 1}; | |
| 552 | ✗ | return check_array_access(env, &next) ?: env->gwion->type[et_error]; | |
| 553 | } | ||
| 554 | |||
| 555 | ✗ | static INSTR(DictEach) { | |
| 556 | ✗ | const M_Object o = *(M_Object *)(shred->mem + instr->m_val2); | |
| 557 | ✗ | HMapInfo *const hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 558 | ✗ | const HMap *hmap = (HMap*)o->data; | |
| 559 | ✗ | m_uint bucket = ++*(m_uint *)(shred->mem + instr->m_val2 + SZ_INT); | |
| 560 | ✗ | while(bucket < hmap->capacity) { | |
| 561 | ✗ | const HState *state = (HState *)(hmap->state + bucket * sizeof(HState)); | |
| 562 | ✗ | if (state->set && !state->deleted) | |
| 563 | ✗ | break; | |
| 564 | ✗ | bucket++; | |
| 565 | } | ||
| 566 | ✗ | *(m_uint *)(shred->mem + instr->m_val2 + SZ_INT) = bucket; | |
| 567 | ✗ | memcpy(shred->mem + instr->m_val2 + SZ_INT*2, hmap->data + (bucket * hinfo->sz) + hinfo->key->size, hinfo->val->size); | |
| 568 | ✗ | *(m_uint*)shred->reg = (bucket == hmap->capacity); | |
| 569 | ✗ | PUSH_REG(shred, SZ_INT); | |
| 570 | } | ||
| 571 | |||
| 572 | ✗ | static INSTR(DictEachIdx) { | |
| 573 | ✗ | const M_Object o = *(M_Object *)(shred->mem + instr->m_val2); | |
| 574 | ✗ | HMapInfo *const hinfo = (HMapInfo*)o->type_ref->nspc->class_data; | |
| 575 | ✗ | const HMap *hmap = (HMap*)o->data; | |
| 576 | ✗ | DictEach(shred, instr); | |
| 577 | ✗ | const m_int bucket = *(m_uint *)(shred->mem + instr->m_val2 + SZ_INT); | |
| 578 | ✗ | memcpy(shred->mem + instr->m_val, hmap->data + (bucket * hinfo->sz), hinfo->key->size); | |
| 579 | } | ||
| 580 | |||
| 581 | ✗ | static OP_EMIT(opem_dict_each) { | |
| 582 | ✗ | Looper *loop = (Looper *)data; | |
| 583 | ✗ | HMapInfo *const hinfo = (HMapInfo*)loop->exp->type->nspc->class_data; | |
| 584 | ✗ | if(loop->idx && !loop->init) loop->idx->v->from->offset = emit_localn(emit, hinfo->key); | |
| 585 | ✗ | const Instr instr = emit_add_instr(emit, !loop->idx ? DictEach : DictEachIdx); | |
| 586 | ✗ | instr->m_val2 = loop->offset; | |
| 587 | ✗ | if(loop->idx) instr->m_val = loop->idx->v->from->offset; | |
| 588 | ✗ | if(loop->n)instr->m_val2 += SZ_INT; | |
| 589 | ✗ | const Instr go = emit_add_instr(emit, BranchNeqInt); | |
| 590 | ✗ | if(!loop->n) loop->instr = go; | |
| 591 | ✗ | else vector_add(&loop->unroll_v, (m_uint)go); | |
| 592 | ✗ | loop->init = true; | |
| 593 | ✗ | return GW_OK; | |
| 594 | } | ||
| 595 | |||
| 596 | ✗ | static INSTR(DictEachInit) { | |
| 597 | ✗ | const M_Object o = *(M_Object *)(shred->mem + instr->m_val + SZ_INT); | |
| 598 | ✗ | *(m_uint *)(shred->mem + instr->m_val) = ((HMap*)o->data)->capacity; | |
| 599 | } | ||
| 600 | |||
| 601 | ✗ | static OP_EMIT(opem_dict_each_init) { | |
| 602 | ✗ | const Looper *loop = (Looper *)data; | |
| 603 | ✗ | const Instr instr = emit_add_instr(emit, DictEachInit); | |
| 604 | ✗ | instr->m_val = loop->offset; | |
| 605 | ✗ | return GW_OK; | |
| 606 | } | ||
| 607 | |||
| 608 | ✗ | static OP_CHECK(opck_dict_each_key) { | |
| 609 | ✗ | const Exp exp = (const Exp)data; | |
| 610 | ✗ | HMapInfo *const hinfo = (HMapInfo*)exp->type->nspc->class_data; | |
| 611 | ✗ | return hinfo->key; | |
| 612 | } | ||
| 613 | |||
| 614 | ✗ | static OP_CHECK(opck_dict_each_val) { | |
| 615 | ✗ | const Exp exp = (const Exp)data; | |
| 616 | ✗ | HMapInfo *const hinfo = (HMapInfo*)exp->type->nspc->class_data; | |
| 617 | ✗ | return hinfo->val; | |
| 618 | } | ||
| 619 | |||
| 620 | 7 | static OP_CHECK(opck_dict_scan) { | |
| 621 | 7 | struct TemplateScan *ts = (struct TemplateScan *)data; | |
| 622 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if(ts->t->info->cdef->base.tmpl->call) return ts->t; |
| 623 | 7 | struct tmpl_info info = { | |
| 624 | 7 | .base = ts->t, .td = ts->td, .list = ts->t->info->cdef->base.tmpl->list}; | |
| 625 | 7 | const Type exists = tmpl_exists(env, &info); | |
| 626 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
7 | if (exists) return exists != env->gwion->type[et_error] ? exists : NULL; |
| 627 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
|
5 | if(!ts->td->types || ts->td->types->len != 2) return env->gwion->type[et_error]; |
| 628 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | DECL_ON(const Type, key, = known_type(env, *mp_vector_at(ts->td->types, Type_Decl*, 0))); |
| 629 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | DECL_ON(const Type, val, = known_type(env, *mp_vector_at(ts->td->types, Type_Decl*, 1))); |
| 630 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
|
5 | if(tflag(key, tflag_ref) || tflag(val, tflag_ref)) |
| 631 | ✗ | ERR_N(ts->td->pos, "can't use Ref:[] in dicts"); | |
| 632 | 5 | const Class_Def cdef = cpy_class_def(env->gwion->mp, env->gwion->type[et_dict]->info->cdef); | |
| 633 | 5 | cdef->base.ext = type2td(env->gwion, env->gwion->type[et_dict], (loc_t) {}); | |
| 634 | 5 | cdef->base.xid = info.name; | |
| 635 | 5 | cdef->base.tmpl->call = cpy_type_list(env->gwion->mp, info.td->types); | |
| 636 | |||
| 637 | 5 | const bool is_global = tmpl_global(env, ts->td->types); | |
| 638 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | const m_uint scope = is_global ? env_push_global(env) : env->scope->depth; |
| 639 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | CHECK_BN(scan0_class_def(env, cdef)); |
| 640 | 5 | const Type t = cdef->base.type; | |
| 641 | 5 | t->nspc->class_data_size = sizeof(struct HMapInfo); | |
| 642 | 5 | const m_bool ret = traverse_cdef(env, t); | |
| 643 | 5 | set_tflag(t, tflag_cdef); | |
| 644 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if(is_global) { |
| 645 | 5 | env_pop(env, scope); | |
| 646 | 5 | type_addref(t); | |
| 647 | } | ||
| 648 | 5 | HMapInfo *const hinfo = (HMapInfo*)t->nspc->class_data; | |
| 649 | 5 | hmapinfo_init(hinfo, key, val); | |
| 650 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
|
5 | if(hinfo->keyk + hinfo->valk) { |
| 651 | 4 | t->nspc->dtor = new_vmcode(env->gwion->mp, NULL, NULL, "@dtor", SZ_INT, true, false); | |
| 652 | 4 | t->nspc->dtor->native_func = (m_uint)dict_clear_dtor; | |
| 653 | 4 | set_tflag(t, tflag_dtor); | |
| 654 | } | ||
| 655 | 5 | struct Op_Func opfunc = { .ck = opck_dict_access, .em = opem_dict_access }; | |
| 656 | 5 | struct Op_Import opi = { .lhs = key, .rhs = t, .ret = val, .op = insert_symbol("[]"), .func = &opfunc }; | |
| 657 | 5 | add_op(env->gwion, &opi); | |
| 658 | 5 | opi.op = insert_symbol("~~"); | |
| 659 | 5 | opfunc.em = opem_dict_remove; | |
| 660 | 5 | add_op(env->gwion, &opi); | |
| 661 | |||
| 662 | { | ||
| 663 | 5 | const Func f = (Func)vector_at(&t->nspc->vtable, 1); | |
| 664 | 5 | const struct Op_Func opfunc = {.ck = opck_dict_remove_toop}; | |
| 665 | 5 | const struct Op_Import opi = { | |
| 666 | 5 | .rhs = f->value_ref->type, | |
| 667 | .func = &opfunc, | ||
| 668 | 5 | .data = (uintptr_t)f, | |
| 669 | 5 | .op = insert_symbol("@func_check")}; | |
| 670 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | CHECK_BN(add_op(env->gwion, &opi)); |
| 671 | |||
| 672 | } | ||
| 673 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | return ret > 0 ? t : NULL; |
| 674 | } | ||
| 675 | |||
| 676 | 638 | GWION_IMPORT(dict) { | |
| 677 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 638 times.
|
638 | DECL_OB(const Type, t_dict, = gwi_class_ini(gwi, "Dict:[Key,Val]", "Object")); |
| 678 | 638 | gwi_class_xtor(gwi, dict_ctor, dict_dtor); | |
| 679 | 638 | t_dict->nspc->offset += sizeof(struct HMap); | |
| 680 | 638 | gwi->gwion->type[et_dict] = t_dict; | |
| 681 | 638 | set_tflag(t_dict, tflag_infer); | |
| 682 | 638 | GWI_BB(gwi_func_ini(gwi, "void", "remove")); | |
| 683 | 638 | GWI_BB(gwi_func_arg(gwi, "Key", "key")); | |
| 684 | 638 | GWI_BB(gwi_func_end(gwi, (f_xfun)1, ae_flag_none)); | |
| 685 | |||
| 686 | 638 | GWI_BB(gwi_class_end(gwi)) | |
| 687 | |||
| 688 | 638 | GWI_BB(gwi_oper_ini(gwi, "Dict", NULL, NULL)) | |
| 689 | 638 | GWI_BB(gwi_oper_add(gwi, opck_dict_scan)) | |
| 690 | 638 | GWI_BB(gwi_oper_end(gwi, "class", NULL)) | |
| 691 | |||
| 692 | 638 | GWI_BB(gwi_oper_ini(gwi, "Dict", NULL, "int")) | |
| 693 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_dict_each)) | |
| 694 | 638 | GWI_BB(gwi_oper_end(gwi, "@each", NULL)) | |
| 695 | |||
| 696 | 638 | GWI_BB(gwi_oper_ini(gwi, "Dict", NULL, "void")) | |
| 697 | 638 | GWI_BB(gwi_oper_emi(gwi, opem_dict_each_init)) | |
| 698 | 638 | GWI_BB(gwi_oper_end(gwi, "@each_init", NULL)) | |
| 699 | |||
| 700 | 638 | GWI_BB(gwi_oper_ini(gwi, "Dict", NULL, NULL)) | |
| 701 | 638 | GWI_BB(gwi_oper_add(gwi, opck_dict_each_val)) | |
| 702 | 638 | GWI_BB(gwi_oper_end(gwi, "@each_val", NULL)) | |
| 703 | |||
| 704 | 638 | GWI_BB(gwi_oper_ini(gwi, "Dict", NULL, NULL)) | |
| 705 | 638 | GWI_BB(gwi_oper_add(gwi, opck_dict_each_key)) | |
| 706 | 638 | GWI_BB(gwi_oper_end(gwi, "@each_idx", NULL)) | |
| 707 | |||
| 708 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "hash")); | |
| 709 | 638 | GWI_BB(gwi_func_arg(gwi, "int", "key")); | |
| 710 | 638 | GWI_BB(gwi_func_end(gwi, mfun_int_h, ae_flag_none)); | |
| 711 | |||
| 712 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "hash")); | |
| 713 | 638 | GWI_BB(gwi_func_arg(gwi, "Object", "key")); | |
| 714 | 638 | GWI_BB(gwi_func_end(gwi, mfun_int_h, ae_flag_none)); | |
| 715 | |||
| 716 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "hash")); | |
| 717 | 638 | GWI_BB(gwi_func_arg(gwi, "float", "key")); | |
| 718 | 638 | GWI_BB(gwi_func_end(gwi, mfun_float_h, ae_flag_none)); | |
| 719 | |||
| 720 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "hash")); | |
| 721 | 638 | GWI_BB(gwi_func_arg(gwi, "time", "key")); | |
| 722 | 638 | GWI_BB(gwi_func_end(gwi, mfun_float_h, ae_flag_none)); | |
| 723 | |||
| 724 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "hash")); | |
| 725 | 638 | GWI_BB(gwi_func_arg(gwi, "dur", "key")); | |
| 726 | 638 | GWI_BB(gwi_func_end(gwi, mfun_float_h, ae_flag_none)); | |
| 727 | |||
| 728 | 638 | GWI_BB(gwi_func_ini(gwi, "int", "hash")); | |
| 729 | 638 | GWI_BB(gwi_func_arg(gwi, "string", "key")); | |
| 730 | 638 | GWI_BB(gwi_func_end(gwi, mfun_string_h, ae_flag_none)); | |
| 731 | |||
| 732 | 638 | return GW_OK; | |
| 733 | } | ||
| 734 |