| GCC Code Coverage Report | |||||||||||||||||||||
| 
 | |||||||||||||||||||||
| 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 "gwion.h" | ||
| 6 | #include "instr.h" | ||
| 7 | #include "emit.h" | ||
| 8 | #include "object.h" | ||
| 9 | #include "array.h" | ||
| 10 | #include "traverse.h" | ||
| 11 | #include "template.h" | ||
| 12 | #include "escape.h" | ||
| 13 | #include "parse.h" | ||
| 14 | #include "memoize.h" | ||
| 15 | #include "operator.h" | ||
| 16 | #include "import.h" | ||
| 17 | #include "match.h" | ||
| 18 | #include "parser.h" | ||
| 19 | #include "specialid.h" | ||
| 20 | #include "vararg.h" | ||
| 21 | |||
| 22 | #undef insert_symbol | ||
| 23 | #define insert_symbol(a) insert_symbol(emit->gwion->st, (a)) | ||
| 24 | |||
| 25 | #undef ERR_B | ||
| 26 | #define ERR_B(a, b, ...) { env_err(emit->env, (a), (b), ## __VA_ARGS__); return GW_ERROR; } | ||
| 27 | #undef ERR_O | ||
| 28 | #define ERR_O(a, b, ...) { env_err(emit->env, (a), (b), ## __VA_ARGS__); return NULL; } | ||
| 29 | |||
| 30 | typedef struct Local_ { | ||
| 31 | Type type; | ||
| 32 | m_uint offset; | ||
| 33 | } Local; | ||
| 34 | |||
| 35 | 70 | static inline void emit_pop(const Emitter emit, const m_uint scope) { env_pop(emit->env, scope); } | |
| 36 | 53 | static inline m_uint emit_push(const Emitter emit, const Type type, const Nspc nspc) { | |
| 37 | 53 | return env_push(emit->env, type, nspc); | |
| 38 | } | ||
| 39 | 10 | static inline m_uint emit_push_type(const Emitter emit, const Type type) { | |
| 40 | 10 | return env_push_type(emit->env, type); | |
| 41 | } | ||
| 42 | 6 | static inline m_uint emit_push_global(const Emitter emit) { | |
| 43 | 6 | return env_push_global(emit->env); | |
| 44 | } | ||
| 45 | |||
| 46 | 813 | ANEW static Frame* new_frame(MemPool p) { | |
| 47 | 813 | Frame* frame = mp_calloc(p, Frame); | |
| 48 | 813 | vector_init(&frame->stack); | |
| 49 | 813 | vector_add(&frame->stack, (vtype)NULL); | |
| 50 | 813 | return frame; | |
| 51 | } | ||
| 52 | |||
| 53 | 813 | ANN static void free_frame(MemPool p, Frame* a) { | |
| 54 | LOOP_OPTIM | ||
| 55 | ✓✓ | 2672 | for(vtype i = vector_size(&a->stack) + 1; --i;) | 
| 56 | ✓✓ | 1046 | if(vector_at(&a->stack, i - 1)) | 
| 57 | 233 | mp_free(p, Local, (Local*)vector_at(&a->stack, i - 1)); | |
| 58 | 813 | vector_release(&a->stack); | |
| 59 | 813 | mp_free(p, Frame, a); | |
| 60 | 813 | } | |
| 61 | |||
| 62 | 1014 | ANN static Local* new_local(MemPool p, const Type type) { | |
| 63 | 1014 | Local* local = mp_calloc(p, Local); | |
| 64 | 1014 | local->type = type; | |
| 65 | 1014 | return local; | |
| 66 | } | ||
| 67 | |||
| 68 | 1014 | ANN static m_uint frame_local(MemPool p, Frame* frame, const Type t) { | |
| 69 | 1014 | Local* local = new_local(p, t); | |
| 70 | 1014 | local->offset = frame->curr_offset; | |
| 71 | 1014 | frame->curr_offset += t->size; | |
| 72 | 1014 | vector_add(&frame->stack, (vtype)local); | |
| 73 | 1014 | return local->offset; | |
| 74 | } | ||
| 75 | |||
| 76 | 1070 | ANN static inline void frame_push(Frame* frame) { | |
| 77 | 1070 | vector_add(&frame->stack, (vtype)NULL); | |
| 78 | 1070 | } | |
| 79 | |||
| 80 | 9 | ANN static void struct_pop(const Emitter emit, const Type type, const m_uint offset) { | |
| 81 | ✓✓ | 25 |   for(m_uint i = 0; i < vector_size(&type->e->tuple->types); ++i) { | 
| 82 | 16 | const Type t = (Type)vector_at(&type->e->tuple->types, i); | |
| 83 | ✓✓ | 16 |     if(isa(t, emit->gwion->type[et_object]) > 0) { | 
| 84 | 1 | const Instr instr = emit_add_instr(emit, ObjectRelease); | |
| 85 | 1 | instr->m_val = offset + vector_at(&type->e->tuple->offset, i); | |
| 86 | ✗✓ | 15 | } else if(GET_FLAG(t, struct)) | 
| 87 | struct_pop(emit, t, offset + vector_at(&type->e->tuple->offset, i)); | ||
| 88 | } | ||
| 89 | 9 | } | |
| 90 | |||
| 91 | 1851 | ANN static m_int frame_pop(const Emitter emit) { | |
| 92 | 1851 | Frame *frame = emit->code->frame; | |
| 93 | ✓✓ | 1851 | DECL_OB(const Local*, l, = (Local*)vector_pop(&frame->stack)) | 
| 94 | 781 | frame->curr_offset -= l->type->size; | |
| 95 | ✓✓ | 781 |   if(GET_FLAG(l->type, struct)) { | 
| 96 | 9 | struct_pop(emit, l->type, l->offset); | |
| 97 | 9 | return frame_pop(emit); | |
| 98 | } | ||
| 99 | ✓✓ | 772 | return isa(l->type, emit->gwion->type[et_object]) > 0 ? (m_int)l->offset : frame_pop(emit); | 
| 100 | } | ||
| 101 | |||
| 102 | ANN /*static */m_bool emit_exp(const Emitter emit, Exp exp); | ||
| 103 | ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop); | ||
| 104 | ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List list); | ||
| 105 | ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member); | ||
| 106 | ANN static m_bool emit_func_def(const Emitter emit, const Func_Def func_def); | ||
| 107 | |||
| 108 | 813 | ANEW static Code* new_code(const Emitter emit, const m_str name) { | |
| 109 | 813 | Code* code = mp_calloc(emit->gwion->mp, Code); | |
| 110 | 813 | code->name = code_name_set(emit->gwion->mp, name, emit->env->name); | |
| 111 | 813 | vector_init(&code->instr); | |
| 112 | 813 | vector_init(&code->stack_break); | |
| 113 | 813 | vector_init(&code->stack_cont); | |
| 114 | 813 | vector_init(&code->stack_return); | |
| 115 | 813 | code->frame = new_frame(emit->gwion->mp); | |
| 116 | 813 | return code; | |
| 117 | } | ||
| 118 | |||
| 119 | 813 | ANN static void free_code(MemPool p, Code* code) { | |
| 120 | 813 | vector_release(&code->instr); | |
| 121 | 813 | vector_release(&code->stack_break); | |
| 122 | 813 | vector_release(&code->stack_cont); | |
| 123 | 813 | vector_release(&code->stack_return); | |
| 124 | 813 | free_frame(p, code->frame); | |
| 125 | 813 | free_mstr(p, code->name); | |
| 126 | 813 | mp_free(p, Code, code); | |
| 127 | 813 | } | |
| 128 | |||
| 129 | 1070 | ANN static void emit_pop_scope(const Emitter emit) { | |
| 130 | m_int offset; | ||
| 131 | ✓✓ | 2386 |   while((offset = frame_pop(emit)) > -1) { | 
| 132 | 246 | Instr instr = emit_add_instr(emit, ObjectRelease); | |
| 133 | 246 | instr->m_val = (m_uint)offset; | |
| 134 | } | ||
| 135 | 1070 | vector_pop(&emit->info->pure); | |
| 136 | 1070 | } | |
| 137 | |||
| 138 | 412 | ANN static inline void emit_push_code(const Emitter emit, const m_str name) { | |
| 139 | 412 | vector_add(&emit->stack, (vtype)emit->code); | |
| 140 | 412 | emit->code = new_code(emit, name); | |
| 141 | 412 | } | |
| 142 | |||
| 143 | ANN static inline void emit_pop_code(const Emitter emit) { | ||
| 144 | emit->code = (Code*)vector_pop(&emit->stack); | ||
| 145 | } | ||
| 146 | |||
| 147 | 1070 | ANN static inline void emit_push_scope(const Emitter emit) { | |
| 148 | 1070 | frame_push(emit->code->frame); | |
| 149 | 1070 | vector_add(&emit->info->pure, 0); | |
| 150 | 1070 | } | |
| 151 | |||
| 152 | 530 | ANN static inline m_uint emit_code_size(const Emitter emit) { | |
| 153 | 530 | return vector_size(&emit->code->instr); | |
| 154 | } | ||
| 155 | |||
| 156 | 1742 | ANN m_uint emit_code_offset(const Emitter emit) { | |
| 157 | 1742 | return emit->code->frame->curr_offset; | |
| 158 | } | ||
| 159 | |||
| 160 | 1014 | ANN m_uint emit_local(const Emitter emit, const Type t) { | |
| 161 | 1014 | return frame_local(emit->gwion->mp, emit->code->frame, t); | |
| 162 | } | ||
| 163 | |||
| 164 | ANN void emit_ext_ctor(const Emitter emit, const Type t); | ||
| 165 | |||
| 166 | 626 | ANN static inline void maybe_ctor(const Emitter emit, const Type t) { | |
| 167 | ✓✓✓✓ | 626 | if(!GET_FLAG(t, nonnull) && GET_FLAG(t, ctor)) | 
| 168 | 151 | emit_ext_ctor(emit, t); | |
| 169 | 626 | } | |
| 170 | |||
| 171 | 626 | ANN static void emit_pre_ctor(const Emitter emit, const Type type) { | |
| 172 | ✓✓ | 626 | if(type->e->parent) | 
| 173 | 428 | emit_pre_ctor(emit, type->e->parent); | |
| 174 | 626 | maybe_ctor(emit, type); | |
| 175 | ✓✓✓✓ | 626 | if(GET_FLAG(type, typedef) && type->e->parent->array_depth) | 
| 176 | 8 | emit_array_extend(emit, type->e->parent, type->e->def->base.ext->array->exp); | |
| 177 | 626 | } | |
| 178 | |||
| 179 | #define regxxx(name, instr) \ | ||
| 180 | ANN static inline Instr reg##name(const Emitter emit, const m_uint sz) { \ | ||
| 181 | const Instr instr = emit_add_instr(emit, Reg##instr); \ | ||
| 182 | instr->m_val = sz; \ | ||
| 183 | return instr; \ | ||
| 184 | } | ||
| 185 | 1896 | regxxx(pop, Pop) | |
| 186 | 27 | regxxx(push, Push) | |
| 187 | 1799 | regxxx(pushi, PushImm) | |
| 188 | 3051 | regxxx(seti, SetImm) | |
| 189 | |||
| 190 | 12 | ANN static void struct_expand(const Emitter emit, const Type t) { | |
| 191 | 12 | const Instr instr = emit_add_instr(emit, Reg2RegDeref); | |
| 192 | 12 | instr->m_val = -SZ_INT; | |
| 193 | 12 | instr->m_val2 = t->size; | |
| 194 | // regpush(emit, t->size - SZ_INT); | ||
| 195 | 12 | } | |
| 196 | |||
| 197 | |||
| 198 | INSTR(ArrayStruct); | ||
| 199 | |||
| 200 | 12 | ANN static void emit_pre_constructor_array(const Emitter emit, const Type type) { | |
| 201 | 12 | const m_uint start_index = emit_code_size(emit); | |
| 202 | 12 | const Instr top = emit_add_instr(emit, ArrayTop); | |
| 203 | 12 | top->m_val2 = (m_uint)type; | |
| 204 | ✗✓ | 12 |   if(GET_FLAG(type, struct)) { | 
| 205 | const Instr instr = emit_add_instr(emit, ArrayStruct); | ||
| 206 | instr->m_val = type->size; | ||
| 207 | } | ||
| 208 | 12 | emit_pre_ctor(emit, type); | |
| 209 | ✓✗ | 12 | if(!GET_FLAG(type, struct)) | 
| 210 | 12 | emit_add_instr(emit, ArrayBottom); | |
| 211 | else | ||
| 212 | regpop(emit, SZ_INT); | ||
| 213 | 12 | regpop(emit, SZ_INT); | |
| 214 | 12 | const Instr pc = emit_add_instr(emit, Goto); | |
| 215 | 12 | pc->m_val = start_index; | |
| 216 | 12 | top->m_val = emit_code_size(emit); | |
| 217 | 12 | regpop(emit, SZ_INT*3); | |
| 218 | 12 | emit_add_instr(emit, ArrayPost); | |
| 219 | 12 | } | |
| 220 | |||
| 221 | 41 | ANN2(1) static m_bool extend_indices(const Emitter emit, Exp e, const m_uint depth) { | |
| 222 | ✓✓ | 41 | if(e) | 
| 223 | ✗✓ | 37 | CHECK_BB(emit_exp(emit, e)) | 
| 224 | 41 | m_uint count = 0; | |
| 225 | ✓✓ | 140 |   while(e) { | 
| 226 | 58 | ++count; | |
| 227 | 58 | e = e->next; | |
| 228 | } | ||
| 229 | ✓✓ | 47 | for(m_uint i = count; i < depth; ++i) | 
| 230 | 6 | regpushi(emit, 0); | |
| 231 | 41 | return GW_OK; | |
| 232 | } | ||
| 233 | |||
| 234 | 41 | ANEW ANN static ArrayInfo* new_arrayinfo(const Emitter emit, const Type t) { | |
| 235 | 41 | const Type base = array_base(t); | |
| 236 | 41 | ArrayInfo* info = mp_calloc(emit->gwion->mp, ArrayInfo); | |
| 237 | 41 | vector_init(&info->type); | |
| 238 | ✓✓ | 64 | for(m_uint i = 1; i < t->array_depth; ++i) | 
| 239 | 23 | vector_add(&info->type, (vtype)array_type(emit->env, base, i)); | |
| 240 | 41 | vector_add(&info->type, (vtype)t); | |
| 241 | 41 | info->depth = (m_int)t->array_depth; | |
| 242 | 41 | info->base = base; | |
| 243 | 41 | return info; | |
| 244 | } | ||
| 245 | |||
| 246 | 41 | ANN static inline void arrayinfo_ctor(const Emitter emit, ArrayInfo *info) { | |
| 247 | 41 | const Type base = info->base; | |
| 248 | ✓✓✓✗ | 41 |   if(isa(base, emit->gwion->type[et_compound]) > 0 && !GET_FLAG(base, abstract)) { | 
| 249 | 12 | emit_pre_constructor_array(emit, base); | |
| 250 | // if(isa(base, emit->gwion->type[et_object]) > 0) | ||
| 251 | 12 | info->is_obj = 1; | |
| 252 | } | ||
| 253 | 41 | } | |
| 254 | |||
| 255 | 41 | ANN2(1,2) static ArrayInfo* emit_array_extend_inner(const Emitter emit, const Type t, const Exp e) { | |
| 256 | ✗✓ | 41 | CHECK_BO(extend_indices(emit, e, t->array_depth)) | 
| 257 | 41 | ArrayInfo* info = new_arrayinfo(emit, t); | |
| 258 | 41 | const Instr alloc = emit_add_instr(emit, ArrayAlloc); | |
| 259 | 41 | alloc->m_val = (m_uint)info; | |
| 260 | 41 | arrayinfo_ctor(emit, info); | |
| 261 | 41 | return info; | |
| 262 | } | ||
| 263 | |||
| 264 | 163 | ANN void emit_ext_ctor(const Emitter emit, const Type t) { | |
| 265 | 163 | const Instr cpy = emit_add_instr(emit, Reg2Reg); | |
| 266 | 163 | cpy->m_val2 = -SZ_INT; | |
| 267 | ✓✓ | 163 |   if(t->nspc->pre_ctor) { | 
| 268 | 161 | const Instr set_code = regseti(emit, (m_uint)t->nspc->pre_ctor); | |
| 269 | 161 | set_code->m_val2 = SZ_INT; | |
| 270 |   } else { | ||
| 271 | 2 | const Instr instr = emit_add_instr(emit, SetCtor); | |
| 272 | 2 | instr->m_val = (m_uint)t; | |
| 273 | } | ||
| 274 | 163 | const m_uint offset = emit_code_offset(emit); | |
| 275 | 163 | const Instr regset = regseti(emit, offset); | |
| 276 | 163 | regset->m_val2 = SZ_INT *2; | |
| 277 | 163 | const Instr push = emit_add_instr(emit, RegPush); | |
| 278 | 163 | push->m_val = SZ_INT *2; | |
| 279 | 163 | const Instr prelude = emit_add_instr(emit, SetCode); | |
| 280 | 163 | prelude->m_val2 = 2; | |
| 281 | 163 | prelude->m_val = SZ_INT; | |
| 282 | 163 | emit_add_instr(emit, Reg2Mem); | |
| 283 | 163 | const Instr next = emit_add_instr(emit, Overflow); | |
| 284 | 163 | next->m_val2 = offset; | |
| 285 | 163 | } | |
| 286 | |||
| 287 | 8 | ANN m_bool emit_array_extend(const Emitter emit, const Type t, const Exp e) { | |
| 288 | ✗✓ | 8 | CHECK_OB(emit_array_extend_inner(emit, t, e)) | 
| 289 | 8 | emit_add_instr(emit, PopArrayClass); | |
| 290 | 8 | emit_add_instr(emit, RegAddRef); | |
| 291 | 8 | return GW_OK; | |
| 292 | } | ||
| 293 | |||
| 294 | 231 | ANN static inline void emit_notpure(const Emitter emit) { | |
| 295 | 231 | ++VPTR(&emit->info->pure, VLEN(&emit->info->pure) - 1); | |
| 296 | 231 | } | |
| 297 | |||
| 298 | 219 | ANN2(1,2) m_bool emit_instantiate_object(const Emitter emit, const Type type, | |
| 299 |       const Array_Sub array, const m_bool is_ref) { | ||
| 300 | 219 | emit_notpure(emit); | |
| 301 | ✓✓ | 219 |   if(type->array_depth) { | 
| 302 | ✓✓ | 33 | ArrayInfo* info = emit_array_extend_inner(emit, type, array ? array->exp : NULL); | 
| 303 | ✓✗ | 33 | if(info) | 
| 304 | 33 | info->is_ref = is_ref; | |
| 305 | ✓✗ | 33 | return info ? GW_OK : GW_ERROR; | 
| 306 | ✓✗ | 186 |   } else if(!is_ref) { | 
| 307 | 186 | const Instr instr = emit_add_instr(emit, ObjectInstantiate); | |
| 308 | 186 | instr->m_val2 = (m_uint)type; | |
| 309 | 186 | emit_pre_ctor(emit, type); | |
| 310 | } | ||
| 311 | 186 | return GW_OK; | |
| 312 | } | ||
| 313 | |||
| 314 | 2168 | static inline enum Kind kindof(const m_uint size, const uint emit_var) { | |
| 315 | ✓✓ | 2168 | if(emit_var) | 
| 316 | 470 | return KIND_ADDR; | |
| 317 | ✓✓✓✓ | 1698 | return size == SZ_INT ? KIND_INT : size == SZ_FLOAT ? KIND_FLOAT : KIND_OTHER; | 
| 318 | } | ||
| 319 | |||
| 320 | 2168 | ANN /*static */Instr emit_kind(Emitter emit, const m_uint size, const uint addr, const f_instr func[]) { | |
| 321 | 2168 | const enum Kind kind = kindof(size, addr); | |
| 322 | 2168 | const Instr instr = emit_add_instr(emit, func[kind]); | |
| 323 | 2168 | instr->m_val2 = size; | |
| 324 | 2168 | return instr; | |
| 325 | } | ||
| 326 | |||
| 327 | static const f_instr regpushimm[] = { RegPushImm, RegPushImm2, RegPushImm3, RegPushImm4 }; | ||
| 328 | static const f_instr regpushmem[] = { RegPushMem, RegPushMem2, RegPushMem3, RegPushMem4 }; | ||
| 329 | static const f_instr regpushbase[] = { RegPushBase, RegPushBase2, RegPushBase3, RegPushBase4 }; | ||
| 330 | static const f_instr dotstatic[]  = { DotStatic, DotStatic2, DotStatic3, RegPushImm }; | ||
| 331 | static const f_instr allocmember[]  = { RegPushImm, RegPushImm2, RegPushImm3, AllocMember4 }; | ||
| 332 | static const f_instr allocword[]  = { AllocWord, AllocWord2, AllocWord3, RegPushMem4 }; | ||
| 333 | static const f_instr structmember[]  = { StructMember, StructMemberFloat, StructMemberOther, StructMemberAddr }; | ||
| 334 | |||
| 335 | ANN Exp symbol_owned_exp(const Gwion gwion, const Symbol *data); | ||
| 336 | 142 | ANN static m_bool emit_symbol_owned(const Emitter emit, const Symbol *data) { | |
| 337 | 142 | const Exp dot = symbol_owned_exp(emit->gwion, data); | |
| 338 | 142 | dot->info->nspc = prim_exp(data)->info->nspc; | |
| 339 | 142 | const m_bool ret = emit_exp_dot(emit, &dot->d.exp_dot); | |
| 340 | 142 | free_exp(emit->gwion->mp, dot); | |
| 341 | 142 | return ret; | |
| 342 | } | ||
| 343 | |||
| 344 | 164 | ANN static m_bool emit_symbol_builtin(const Emitter emit, const Symbol *data) { | |
| 345 | 164 | const Value v = prim_self(data)->value; | |
| 346 | ✓✓ | 164 |   if(GET_FLAG(v, union)) { | 
| 347 | 7 | const m_uint size = v->type->size; | |
| 348 | 7 | const Instr instr = emit_kind(emit, size, exp_getvar(prim_exp(data)), dotstatic); | |
| 349 | 7 | instr->m_val = (m_uint)v->d.ptr; | |
| 350 |   } else { | ||
| 351 | 157 | const m_uint size = v->type->size; | |
| 352 | 157 | const Instr instr = emit_kind(emit, size, exp_getvar(prim_exp(data)), regpushimm); | |
| 353 | ✓✓✓✓ | 157 |     if(!exp_getvar(prim_exp(data)) && size == SZ_INT) { | 
| 354 | ✓✓ | 160 | if(isa(v->type, emit->gwion->type[et_object]) > 0) | 
| 355 | 46 | instr->m_val = (m_uint)v->d.ptr; | |
| 356 | ✓✗ | 34 | else if(v->d.ptr) | 
| 357 | 34 | instr->m_val = *(m_uint*)v->d.ptr; | |
| 358 |     } else { | ||
| 359 | assert(v->d.ptr); // instr->m_val = v->d.ptr; | ||
| 360 | 77 | memcpy(&instr->m_val, v->d.ptr, v->type->size); | |
| 361 | } | ||
| 362 | 157 | instr->m_val2 = size; | |
| 363 | } | ||
| 364 | 164 | return GW_OK; | |
| 365 | } | ||
| 366 | |||
| 367 | 1383 | ANN static m_bool _emit_symbol(const Emitter emit, const Symbol *data) { | |
| 368 | 1383 | const Value v = prim_self(data)->value; | |
| 369 | ✓✓ | 1383 |   if(is_class(emit->gwion, v->type)) { | 
| 370 | 11 | regpushi(emit, (m_uint)actual_type(emit->gwion, v->type)); | |
| 371 | 11 | return GW_OK; | |
| 372 | } | ||
| 373 | ✓✓ | 1372 | if(v->from->owner_class) | 
| 374 | 142 | return emit_symbol_owned(emit, data); | |
| 375 | ✓✓✓✓ ✓✓ | 1230 | if(GET_FLAG(v, builtin) || GET_FLAG(v, union) || GET_FLAG(v, enum)) | 
| 376 | 164 | return emit_symbol_builtin(emit, data); | |
| 377 | 1066 | const m_uint size = v->type->size; | |
| 378 | ✓✓ | 1066 | const Instr instr = emit_kind(emit, size, exp_getvar(prim_exp(data)), !GET_FLAG(v, global) ? regpushmem : regpushbase); | 
| 379 | 1066 | instr->m_val = v->from->offset; | |
| 380 | 1066 | return GW_OK; | |
| 381 | } | ||
| 382 | |||
| 383 | 1383 | ANN static m_bool emit_symbol(const Emitter emit, const Exp_Primary* prim) { | |
| 384 | 1383 | return _emit_symbol(emit, &prim->d.var); | |
| 385 | } | ||
| 386 | |||
| 387 | 809 | ANN static VM_Code finalyze(const Emitter emit, const f_instr exec) { | |
| 388 | 809 | emit_add_instr(emit, exec); | |
| 389 | 809 | const VM_Code code = emit->info->emit_code(emit); | |
| 390 | 809 | free_code(emit->gwion->mp, emit->code); | |
| 391 | 809 | emit->code = (Code*)vector_pop(&emit->stack); | |
| 392 | 809 | return code; | |
| 393 | } | ||
| 394 | |||
| 395 | 12 | ANN static m_bool emit_prim_array(const Emitter emit, const Array_Sub *data) { | |
| 396 | 12 | Exp e = (*data)->exp; | |
| 397 | ✗✓ | 12 | CHECK_BB(emit_exp(emit, e)) | 
| 398 | 12 | m_uint count = 0; | |
| 399 | 39 | do ++count; | |
| 400 | ✓✓ | 39 | while((e = e->next)); | 
| 401 | 12 | const Type type = (*data)->type; | |
| 402 | 12 | regseti(emit, count); | |
| 403 | 12 | const Instr instr = emit_add_instr(emit, ArrayInit); | |
| 404 | 12 | instr->m_val = (m_uint)type; | |
| 405 | ✓✓ | 12 | instr->m_val2 = type->array_depth == 1 ? array_base(type)->size : SZ_INT; | 
| 406 | 12 | emit_add_instr(emit, GcAdd); | |
| 407 | 12 | emit_notpure(emit); | |
| 408 | 12 | return GW_OK; | |
| 409 | } | ||
| 410 | |||
| 411 | ANN static inline m_bool emit_exp_pop_next(const Emitter emit, Exp e); | ||
| 412 | |||
| 413 | 9 | ANN static m_bool emit_range(const Emitter emit, Range *range) { | |
| 414 | ✓✓ | 9 | if(range->start) | 
| 415 | ✗✓ | 8 | CHECK_BB(emit_exp_pop_next(emit, range->start)) | 
| 416 | else | ||
| 417 | 1 | regpushi(emit, 0); | |
| 418 | ✓✓ | 9 | if(range->end) | 
| 419 | ✗✓ | 7 | CHECK_BB(emit_exp_pop_next(emit, range->end)) | 
| 420 | else | ||
| 421 | 2 | regpushi(emit, -1); | |
| 422 | 9 | return GW_OK; | |
| 423 | } | ||
| 424 | |||
| 425 | 2 | ANN static m_bool emit_prim_range(const Emitter emit, Range **data) { | |
| 426 | 2 | Range *range = *data; | |
| 427 | ✗✓ | 2 | CHECK_BB(emit_range(emit, range)) | 
| 428 | ✓✗ | 2 | const Exp e = range->start ?: range->end; | 
| 429 | 2 |   const Symbol sym = insert_symbol("@range"); | |
| 430 | 6 |   struct Op_Import opi = { .op=sym, .rhs=e->info->type, | |
| 431 | 4 | .pos=e->pos, .data=(uintptr_t)prim_exp(data), .op_type=op_exp }; | |
| 432 | ✗✓ | 2 | CHECK_OB(op_emit(emit, &opi)) | 
| 433 | 2 | emit_add_instr(emit, GcAdd); | |
| 434 | 2 | return GW_OK; | |
| 435 | } | ||
| 436 | |||
| 437 | 25 | ANN m_bool emit_array_access(const Emitter emit, struct ArrayAccessInfo *const info) { | |
| 438 | ✗✓ | 25 |   if(GET_FLAG(info->array.type, typedef)) { | 
| 439 | info->array.type = info->array.type->e->parent; | ||
| 440 | return emit_array_access(emit, info); | ||
| 441 | } | ||
| 442 | // look mum no pos | ||
| 443 | 50 |   struct Op_Import opi = { .op=insert_symbol("@array"), .lhs=info->array.exp->info->type, .rhs=info->array.type, | |
| 444 | 25 | .data=(uintptr_t)info, .op_type=op_array }; | |
| 445 | ✓✗ | 25 | return op_emit(emit, &opi) != (Instr)GW_ERROR ? GW_OK : GW_ERROR; | 
| 446 | } | ||
| 447 | |||
| 448 | 25 | ANN static m_bool emit_exp_array(const Emitter emit, const Exp_Array* array) { | |
| 449 | ✗✓ | 25 | CHECK_BB(emit_exp(emit, array->base)) | 
| 450 | 25 | const Exp e = exp_self(array); | |
| 451 | 25 |   struct ArrayAccessInfo info = { *array->array, e->info->type, exp_getvar(e) }; | |
| 452 | 25 | return emit_array_access(emit, &info); | |
| 453 | } | ||
| 454 | |||
| 455 | 7 | ANN static m_bool emit_exp_slice(const Emitter emit, const Exp_Slice* range) { | |
| 456 | ✗✓ | 7 | CHECK_BB(emit_exp(emit, range->base)) | 
| 457 | ✗✓ | 7 | CHECK_BB(emit_range(emit, range->range)) | 
| 458 | 7 |   const Symbol sym = insert_symbol("@slice"); | |
| 459 | ✓✓ | 7 | const Exp e = range->range->start ?: range->range->end; | 
| 460 | 21 |   struct Op_Import opi = { .op=sym, .lhs=e->info->type, .rhs=range->base->info->type, | |
| 461 | 14 | .pos=e->pos, .data=(uintptr_t)exp_self(range), .op_type=op_exp }; | |
| 462 | ✗✓ | 7 | CHECK_OB(op_emit(emit, &opi)) | 
| 463 | 7 | return GW_OK; | |
| 464 | } | ||
| 465 | |||
| 466 | 1739 | ANN static m_bool emit_prim_id(const Emitter emit, const Symbol *data) { | |
| 467 | 1739 | struct SpecialId_ * spid = specialid_get(emit->gwion, *data); | |
| 468 | ✓✓ | 1739 | if(spid) | 
| 469 | ✓✗ | 356 | return specialid_instr(emit, spid, prim_self(data)) ? GW_OK : GW_ERROR; | 
| 470 | 1383 | return emit_symbol(emit, prim_self(data)); | |
| 471 | } | ||
| 472 | |||
| 473 | 537 | ANN static m_bool emit_prim_num(const Emitter emit, const m_uint *num) { | |
| 474 | 537 | regpushi(emit, *num); | |
| 475 | 537 | return GW_OK; | |
| 476 | } | ||
| 477 | |||
| 478 | 118 | ANN static m_bool emit_prim_float(const Emitter emit, const m_float *fnum) { | |
| 479 | 118 | const Instr instr = emit_add_instr(emit, RegPushImm2); | |
| 480 | 118 | instr->f = *fnum; | |
| 481 | 118 | return GW_OK; | |
| 482 | } | ||
| 483 | |||
| 484 | 15 | ANN static m_bool emit_prim_char(const Emitter emit, const m_str *str) { | |
| 485 | 15 | const char c = str2char(emit, *str, prim_pos(str)); | |
| 486 | 15 | regpushi(emit, c); | |
| 487 | 15 | return GW_OK; | |
| 488 | } | ||
| 489 | |||
| 490 | 523 | ANN static Instr emit_addref(const Emitter emit, const m_bool emit_var) { | |
| 491 | ✓✓ | 523 | const f_instr exec = !emit_var ? RegAddRef : RegAddRefAddr; | 
| 492 | 523 | const Instr instr = emit_add_instr(emit, exec); | |
| 493 | 523 | instr->m_val = -SZ_INT; | |
| 494 | 523 | return instr; | |
| 495 | } | ||
| 496 | |||
| 497 | 302 | ANN static m_bool emit_prim_str(const Emitter emit, const m_str *str) { | |
| 498 | 302 | char c[strlen(*str) + 1]; | |
| 499 | ✓✓ | 302 |   if(strlen(*str)) { | 
| 500 | 296 | strcpy(c, *str); | |
| 501 | ✓✓ | 296 | CHECK_BB(escape_str(emit, c, prim_pos(str))); | 
| 502 | 6 | } else c[0] = '\0'; | |
| 503 | 300 | const Value v = prim_self(str)->value; | |
| 504 | 300 | const Symbol sym = insert_symbol(c); | |
| 505 | ✓✓ | 300 | if(!v->d.ptr) | 
| 506 | 240 | v->d.ptr = (m_uint*)new_string2(emit->gwion, NULL, s_name(sym)); | |
| 507 | 300 | regpushi(emit, (m_uint)v->d.ptr); | |
| 508 | 300 | emit_addref(emit, 0); | |
| 509 | 300 | return GW_OK; | |
| 510 | } | ||
| 511 | |||
| 512 | #define emit_prim_nil (void*)dummy_func | ||
| 513 | |||
| 514 | 23 | ANN static m_bool emit_prim_typeof(const Emitter emit, const Exp *exp) { | |
| 515 | 23 | const Exp e = *exp; | |
| 516 | ✓✓ | 23 | if(!e->info->type->array_depth) | 
| 517 | 22 | regpushi(emit, (m_uint)(actual_type(emit->gwion, e->info->type))); | |
| 518 | else | ||
| 519 | 1 | regpushi(emit, (m_uint)e->info->type); | |
| 520 | 23 | return GW_OK; | |
| 521 | } | ||
| 522 | |||
| 523 | 23 | ANN static void interp_multi(const Emitter emit, const Exp e) { | |
| 524 | 23 | Var_Decl_List list = e->d.exp_decl.list; | |
| 525 | 23 | const int emit_var = exp_getvar(e); | |
| 526 | 23 | m_uint offset = 0; | |
| 527 | ✗✓ | 46 | while((list = list->next)) | 
| 528 | offset += !emit_var ? list->self->value->type->size : SZ_INT; | ||
| 529 | ✗✓ | 23 | if(offset) | 
| 530 | regpop(emit, offset); | ||
| 531 | 23 | } | |
| 532 | |||
| 533 | 1136 | ANN static inline void interp_size(const Emitter emit, const Type t) { | |
| 534 | 1136 | const Instr instr = regseti(emit, t->size); | |
| 535 | 1136 | instr->m_val2 = SZ_INT; | |
| 536 | 1136 | } | |
| 537 | |||
| 538 | 880 | ANN static m_bool emit_interp(const Emitter emit, const Exp exp) { | |
| 539 | 880 | regpushi(emit, 0); | |
| 540 | 880 | Exp e = exp, next = NULL; | |
| 541 |   do { | ||
| 542 | 1138 | next = e->next; | |
| 543 | 1138 | e->next = NULL; | |
| 544 | ✓✓ | 1138 |     if(emit_exp(emit, e) < 0) { | 
| 545 | 2 | e->next = next; | |
| 546 | 2 | return GW_ERROR; | |
| 547 | } | ||
| 548 | ✓✓ | 1136 | if(e->exp_type == ae_exp_decl) // why only objects? | 
| 549 | 23 | interp_multi(emit, e); | |
| 550 | 1136 | regseti(emit, (m_uint)e->info->type); | |
| 551 | 1136 | interp_size(emit, e->info->type); | |
| 552 | 1136 | const m_bool isobj = isa(e->info->type, emit->gwion->type[et_object]) > 0; | |
| 553 | ✓✓✓✓ | 1136 | if(isobj && !GET_FLAG(e->info->type, force)) | 
| 554 | 485 | emit_add_instr(emit, GackType); | |
| 555 | 1136 | const Instr instr = emit_add_instr(emit, Gack); | |
| 556 | 1136 | instr->m_val = emit_code_offset(emit); | |
| 557 | ✓✓ | 1136 | } while((e = e->next = next)); | 
| 558 | 878 | return GW_OK; | |
| 559 | } | ||
| 560 | |||
| 561 | 875 | ANN static m_bool emit_prim_hack(const Emitter emit, const Exp *exp) { | |
| 562 | ✓✓ | 875 | CHECK_BB(emit_interp(emit, *exp)) | 
| 563 | ✓✓✓✓ | 873 |   if(!(emit->env->func && emit->env->func->def->base->xid == insert_symbol("@gack"))) | 
| 564 | 871 | emit_add_instr(emit, GackEnd); | |
| 565 |   else { | ||
| 566 | 2 | const Instr instr = emit_add_instr(emit, Reg2Mem); | |
| 567 | 2 | instr->m_val = SZ_INT; | |
| 568 | 2 | instr->m_val2 = -SZ_INT; | |
| 569 | } | ||
| 570 | 873 | return GW_OK; | |
| 571 | } | ||
| 572 | |||
| 573 | 5 | ANN static m_bool emit_prim_interp(const Emitter emit, const Exp *exp) { | |
| 574 | 5 | const Exp e = *exp; | |
| 575 | ✗✓ | 5 | CHECK_BB(emit_interp(emit, e)) | 
| 576 | 5 | const Instr instr = emit_add_instr(emit, GackEnd); | |
| 577 | 5 | instr->m_val = 1; | |
| 578 | 5 | return GW_OK; | |
| 579 | } | ||
| 580 | |||
| 581 | DECL_PRIM_FUNC(emit, m_bool , Emitter); | ||
| 582 | 3635 | ANN static m_bool emit_prim(const Emitter emit, Exp_Primary *const prim) { | |
| 583 | 3635 | return emit_prim_func[prim->prim_type](emit, &prim->d); | |
| 584 | } | ||
| 585 | |||
| 586 | 19 | ANN static m_bool emit_dot_static_data(const Emitter emit, const Value v, const uint emit_var) { | |
| 587 | 19 | const m_uint size = v->type->size; | |
| 588 | 19 | const Instr instr = emit_kind(emit, size, emit_var, dotstatic); | |
| 589 | 19 | instr->m_val = (m_uint)(v->from->owner->info->class_data + v->from->offset); | |
| 590 | 19 | instr->m_val2 = size; | |
| 591 | 19 | return GW_OK; | |
| 592 | } | ||
| 593 | |||
| 594 | 5 | ANN static m_bool decl_static(const Emitter emit, const Var_Decl var_decl, const uint is_ref) { | |
| 595 | 5 | const Value v = var_decl->value; | |
| 596 | 5 | Code* code = emit->code; | |
| 597 | 5 | emit->code = (Code*)vector_back(&emit->stack); | |
| 598 | ✗✓ | 5 | CHECK_BB(emit_instantiate_object(emit, v->type, var_decl->array, is_ref)) | 
| 599 | ✗✓ | 5 | CHECK_BB(emit_dot_static_data(emit, v, 1)) | 
| 600 | 5 | emit_add_instr(emit, Assign); | |
| 601 | 5 | (void)emit_addref(emit, 0); | |
| 602 | 5 | regpop(emit, SZ_INT); | |
| 603 | 5 | emit->code = code; | |
| 604 | 5 | return GW_OK; | |
| 605 | } | ||
| 606 | |||
| 607 | 1057 | ANN static inline int struct_ctor(const Value v) { | |
| 608 | ✓✓✓✗ | 1057 | return GET_FLAG(v->type, struct) && v->type->nspc->pre_ctor; | 
| 609 | } | ||
| 610 | |||
| 611 | 12 | ANN static void decl_expand(const Emitter emit, const Type t) { | |
| 612 | 12 | struct_expand(emit, t); | |
| 613 | 12 | regpush(emit, t->size - SZ_INT); | |
| 614 | 12 | } | |
| 615 | |||
| 616 | 12 | ANN static void emit_struct_decl_finish(const Emitter emit, const Type t, const uint emit_addr) { | |
| 617 | 12 | emit->code->frame->curr_offset += t->size + SZ_INT; | |
| 618 | 12 | emit_ext_ctor(emit, t); | |
| 619 | ✓✗ | 12 | if(!emit_addr) | 
| 620 | 12 | decl_expand(emit, t); | |
| 621 | 12 | emit->code->frame->curr_offset -= t->size + SZ_INT; | |
| 622 | 12 | } | |
| 623 | |||
| 624 | 14 | ANN static m_bool emit_exp_decl_static(const Emitter emit, const Var_Decl var_decl, const uint is_ref, const uint emit_addr) { | |
| 625 | 14 | const Value v = var_decl->value; | |
| 626 | ✓✓✓✗ | 14 | if(isa(v->type, emit->gwion->type[et_object]) > 0 && !is_ref) | 
| 627 | ✗✓ | 5 | CHECK_BB(decl_static(emit, var_decl, 0)) | 
| 628 | ✓✓✗✓ | 14 | CHECK_BB(emit_dot_static_data(emit, v, !struct_ctor(v) ? emit_addr : 1)) | 
| 629 | ✓✓ | 14 | if(struct_ctor(v) /* && !GET_FLAG(decl->td, ref) */) | 
| 630 | 1 | emit_struct_decl_finish(emit, v->type, emit_addr); | |
| 631 | 14 | return GW_OK; | |
| 632 | } | ||
| 633 | |||
| 634 | 26 | ANN static Instr emit_struct_decl(const Emitter emit, const Value v, const m_bool emit_addr) { | |
| 635 | 26 | emit_add_instr(emit, RegPushMem); | |
| 636 | 26 | const Instr instr = emit_kind(emit, v->type->size, emit_addr, structmember); | |
| 637 | ✓✓ | 26 | if(!emit_addr) | 
| 638 | 15 | regpush(emit, v->type->size - SZ_INT); | |
| 639 | 26 | return instr; | |
| 640 | } | ||
| 641 | |||
| 642 | 606 | ANN static m_bool emit_exp_decl_non_static(const Emitter emit, const Exp_Decl *decl, const Var_Decl var_decl, | |
| 643 |   const uint is_ref, const uint emit_var) { | ||
| 644 | 606 | const Value v = var_decl->value; | |
| 645 | 606 | const Type type = v->type; | |
| 646 | 606 | const Array_Sub array = var_decl->array; | |
| 647 | ✓✓✓✓ | 606 | const m_bool is_array = (array && array->exp) /*|| GET_FLAG(decl->td, force)*/; | 
| 648 | 606 | const m_bool is_obj = isa(type, emit->gwion->type[et_object]) > 0; | |
| 649 | ✓✓✓✓ ✓✗ | 606 | const uint emit_addr = (!is_obj || (is_ref && !is_array)) ? emit_var : 1; | 
| 650 | ✓✓✓✓ ✓✓✓✗ | 606 | if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) | 
| 651 | ✗✓ | 193 | CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) | 
| 652 | 606 | f_instr *exec = (f_instr*)allocmember; | |
| 653 | ✓✓ | 606 |   if(!GET_FLAG(v, member)) { | 
| 654 | 487 | v->from->offset = emit_local(emit, type); | |
| 655 | 487 | exec = (f_instr*)(allocword); | |
| 656 | ✓✓ | 487 |     if(GET_FLAG(v, ref)) { // ref or emit_var ? | 
| 657 | 46 | const Instr clean = emit_add_instr(emit, MemSetImm); | |
| 658 | 46 | clean->m_val = v->from->offset; | |
| 659 | } | ||
| 660 | } | ||
| 661 | ✓✓✗✓ | 1338 | const Instr instr = !(SAFE_FLAG(emit->env->class_def, struct) && !emit->env->scope->depth) ? | 
| 662 | ✓✓✓✓ ✓✗ | 1186 | emit_kind(emit, v->type->size, !struct_ctor(v) ? emit_addr : 1, exec) : emit_struct_decl(emit, v, !struct_ctor(v) ? emit_addr : 1); | 
| 663 | 606 | instr->m_val = v->from->offset; | |
| 664 | ✓✓✓✓ ✓✓✓✗ | 799 |   if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) { | 
| 665 | ✓✗ | 193 | if(!emit_var) | 
| 666 | 193 | emit_add_instr(emit, Assign); | |
| 667 |     else { | ||
| 668 | regpop(emit, SZ_INT); | ||
| 669 | const Instr instr = emit_add_instr(emit, Reg2Reg); | ||
| 670 | instr->m_val = -SZ_INT; | ||
| 671 | } | ||
| 672 | ✓✓ | 193 | const size_t missing_depth = type->array_depth - (array ? array->depth : 0); | 
| 673 | ✓✓✓✓ | 193 |     if(missing_depth && !GET_FLAG(decl->td, force)) { | 
| 674 | 2 | const Instr push = emit_add_instr(emit, Reg2Reg); | |
| 675 | 2 | push->m_val = -(missing_depth) * SZ_INT; | |
| 676 | } | ||
| 677 | ✓✓ | 413 | } else if(struct_ctor(v) /* && !GET_FLAG(decl->td, ref) */) | 
| 678 | 10 | emit_struct_decl_finish(emit, v->type, emit_addr); | |
| 679 | 606 | return GW_OK; | |
| 680 | } | ||
| 681 | |||
| 682 | 6 | ANN static m_bool emit_exp_decl_global(const Emitter emit, const Exp_Decl *decl, const Var_Decl var_decl, | |
| 683 |   const uint is_ref, const uint emit_var) { | ||
| 684 | 6 | const Value v = var_decl->value; | |
| 685 | 6 | const Type type = v->type; | |
| 686 | 6 | const Array_Sub array = var_decl->array; | |
| 687 | ✗✓✗✗ | 6 | const m_bool is_array = array && array->exp; | 
| 688 | 6 | const m_bool is_obj = isa(type, emit->gwion->type[et_object]) > 0; | |
| 689 | ✓✓✗✓ ✗✗ | 6 | const uint emit_addr = (!is_obj || (is_ref && !is_array)) ? emit_var : 1; | 
| 690 | ✓✓✓✗ ✓✗✓✗ | 6 | if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) | 
| 691 | ✗✓ | 2 | CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) | 
| 692 | ✓✓ | 6 | const Instr instr = emit_kind(emit, v->type->size, !struct_ctor(v) ? emit_addr : 1, dotstatic); | 
| 693 | 6 | v->d.ptr = mp_calloc2(emit->gwion->mp, v->type->size); | |
| 694 | 6 | SET_FLAG(v, union); | |
| 695 | 6 | instr->m_val = (m_uint)v->d.ptr; | |
| 696 | 6 | instr->m_val2 = v->type->size; | |
| 697 | ✓✓✓✗ ✓✗✓✗ | 8 |   if(is_obj && (is_array || !is_ref) && !GET_FLAG(v, ref)) { | 
| 698 | 2 | const Instr assign = emit_add_instr(emit, Assign); | |
| 699 | ✗✓ | 2 | const size_t missing_depth = type->array_depth - (array ? array->depth : 0); | 
| 700 | ✗✓✗✗ | 2 |     if(missing_depth && !GET_FLAG(decl->td, force)) { | 
| 701 | const Instr push = emit_add_instr(emit, Reg2Reg); | ||
| 702 | push->m_val = -(missing_depth) * SZ_INT; | ||
| 703 | } | ||
| 704 | 2 | assign->m_val = emit_var; | |
| 705 | 2 | (void)emit_addref(emit, emit_var); | |
| 706 | ✓✓ | 4 | } else if(struct_ctor(v) /* && !GET_FLAG(decl->td, ref) */) | 
| 707 | 1 | emit_struct_decl_finish(emit, v->type, emit_addr); | |
| 708 | 6 | return GW_OK; | |
| 709 | } | ||
| 710 | |||
| 711 | ANN static m_bool emit_class_def(const Emitter, const Class_Def); | ||
| 712 | ANN static m_bool emit_cdef(const Emitter, const Class_Def); | ||
| 713 | |||
| 714 | 30 | ANN static inline m_bool ensure_emit(const Emitter emit, const Type t) { | |
| 715 | 60 |   struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, | |
| 716 | 30 | .scope=emit->env->scope->depth, .flag=ae_flag_emit }; | |
| 717 | 30 | return envset_run(&es, t); | |
| 718 | } | ||
| 719 | |||
| 720 | 619 | ANN static m_bool emit_decl(const Emitter emit, const Exp_Decl* decl) { | |
| 721 | 619 | const m_bool global = GET_FLAG(decl->td, global); | |
| 722 | 619 | const uint var = exp_getvar(exp_self(decl)); | |
| 723 | ✓✓✗✓ | 619 | const uint ref = GET_FLAG(decl->td, ref) || type_ref(decl->type); | 
| 724 | 619 | Var_Decl_List list = decl->list; | |
| 725 |   do { | ||
| 726 | 626 | const uint r = GET_FLAG(list->self->value, ref) + ref; | |
| 727 | ✓✓ | 626 | if(GET_FLAG(decl->td, static)) | 
| 728 | ✗✓ | 14 | CHECK_BB(emit_exp_decl_static(emit, list->self, r, var)) | 
| 729 | ✓✓ | 612 | else if(!global) | 
| 730 | ✗✓ | 606 | CHECK_BB(emit_exp_decl_non_static(emit, decl, list->self, r, var)) | 
| 731 | else | ||
| 732 | ✗✓ | 6 | CHECK_BB(emit_exp_decl_global(emit, decl, list->self, r, var)) | 
| 733 | ✓✓ | 626 | if(GET_FLAG(list->self->value->type, nonnull)) | 
| 734 | 14 | emit_add_instr(emit, GWOP_EXCEPT); | |
| 735 | ✓✓ | 626 | } while((list = list->next)); | 
| 736 | 619 | return GW_OK; | |
| 737 | } | ||
| 738 | |||
| 739 | 619 | ANN /*static */m_bool emit_exp_decl(const Emitter emit, const Exp_Decl* decl) { | |
| 740 | 619 | const Type t = get_type(decl->type); | |
| 741 | ✓✓✓✓ | 619 | if(!GET_FLAG(t, emit) && t->e->def) | 
| 742 | ✗✓ | 24 | CHECK_BB(ensure_emit(emit, t)) | 
| 743 | 619 | const m_bool global = GET_FLAG(decl->td, global); | |
| 744 | ✓✓ | 619 | const m_uint scope = !global ? emit->env->scope->depth : emit_push_global(emit); | 
| 745 | 619 | const m_bool ret = emit_decl(emit, decl); | |
| 746 | ✓✓ | 619 | if(global) | 
| 747 | 6 | emit_pop(emit, scope); | |
| 748 | 619 | return ret; | |
| 749 | } | ||
| 750 | |||
| 751 | 18 | ANN static m_uint vararg_size(const Exp_Call* exp_call, const Vector kinds) { | |
| 752 | 18 | Exp e = exp_call->args; | |
| 753 | 18 | Arg_List l = exp_call->m_func->def->base->args; | |
| 754 | 18 | m_uint size = 0; | |
| 755 | ✓✓ | 84 |   while(e) { | 
| 756 | ✓✓ | 48 |     if(!l) { | 
| 757 | 41 | size += e->info->type->size; | |
| 758 | 41 | vector_add(kinds, (vtype)e->info->type); // ->size | |
| 759 | } else | ||
| 760 | 7 | l = l->next; | |
| 761 | 48 | e = e->next; | |
| 762 | } | ||
| 763 | 18 | return size; | |
| 764 | } | ||
| 765 | |||
| 766 | 18 | ANN static void emit_func_arg_vararg(const Emitter emit, const Exp_Call* exp_call) { | |
| 767 | 18 | const Instr instr = emit_add_instr(emit, VarargIni); | |
| 768 | 18 | const Vector kinds = new_vector(emit->gwion->mp); | |
| 769 | ✓✓ | 18 | if((instr->m_val = vararg_size(exp_call, kinds))) | 
| 770 | 15 | instr->m_val2 = (m_uint)kinds; | |
| 771 | else | ||
| 772 | 3 | free_vector(emit->gwion->mp, kinds); | |
| 773 | 18 | } | |
| 774 | |||
| 775 | ANN static inline m_uint exp_size(Exp e); | ||
| 776 | 260 | ANN static inline m_uint exp_totalsize(Exp e) { | |
| 777 | 260 | m_uint size = 0; | |
| 778 | 335 | do size += exp_size(e); | |
| 779 | ✓✓ | 335 | while((e = e->next)); | 
| 780 | 260 | return size; | |
| 781 | } | ||
| 782 | ANN static /*inline */void emit_exp_addref1(const Emitter emit, Exp, const m_int size); | ||
| 783 | ANN static /*inline */void emit_exp_addref(const Emitter emit, Exp, const m_int size); | ||
| 784 | |||
| 785 | 435 | ANN static m_bool emit_func_args(const Emitter emit, const Exp_Call* exp_call) { | |
| 786 | ✓✓ | 435 |   if(exp_call->args) { | 
| 787 | ✗✓ | 217 | CHECK_BB(emit_exp(emit, exp_call->args)) | 
| 788 | 217 | emit_exp_addref(emit, exp_call->args, -exp_totalsize(exp_call->args)); | |
| 789 | } | ||
| 790 | ✓✗✓✓ | 435 | if(exp_call->m_func && GET_FLAG(exp_call->m_func->def, variadic)) | 
| 791 | 18 | emit_func_arg_vararg(emit, exp_call); | |
| 792 | 435 | return GW_OK; | |
| 793 | } | ||
| 794 | |||
| 795 | 434 | ANN static m_bool prepare_call(const Emitter emit, const Exp_Call* exp_call) { | |
| 796 | ✗✓ | 434 | CHECK_BB(emit_func_args(emit, exp_call)) | 
| 797 | 434 | return emit_exp(emit, exp_call->func); | |
| 798 | } | ||
| 799 | |||
| 800 | 407 | ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { | |
| 801 | ✗✓ | 407 | CHECK_BB(prepare_call(emit, exp_call)) | 
| 802 | ✓✗ | 407 | if(exp_call->m_func) | 
| 803 | ✗✓ | 407 | CHECK_OB(emit_exp_call1(emit, exp_call->m_func)) | 
| 804 |   else { | ||
| 805 |     struct Op_Import opi = { .op=insert_symbol("@ctor"), .rhs=exp_call->func->info->type->e->d.base_type, | ||
| 806 | .data=(uintptr_t)exp_call, .pos=exp_self(exp_call)->pos, .op_type=op_exp }; | ||
| 807 | CHECK_OB(op_emit(emit, &opi)) | ||
| 808 | } | ||
| 809 | 407 | const Exp e = exp_self(exp_call); | |
| 810 | ✓✓ | 407 |   if(exp_getvar(e)) { | 
| 811 | 2 | regpop(emit, exp_self(exp_call)->info->type->size - SZ_INT); | |
| 812 | 2 | const Instr instr = emit_add_instr(emit, Reg2RegAddr); | |
| 813 | 2 | instr->m_val = -SZ_INT; | |
| 814 | 2 | instr->m_val2 = -SZ_INT; | |
| 815 | ✗✓✗✗ | 405 | } else if(!exp_call->m_func && GET_FLAG(e->info->type, struct)) | 
| 816 | regpop(emit, SZ_INT); | ||
| 817 | 407 | return GW_OK; | |
| 818 | } | ||
| 819 | |||
| 820 | 462 | ANN static m_uint get_decl_size(Var_Decl_List a, uint emit_addr) { | |
| 821 | 462 | m_uint size = 0; | |
| 822 | do //if(GET_FLAG(a->self->value, used)) | ||
| 823 | ✓✗ | 469 | size += !emit_addr ? a->self->value->type->size : SZ_INT; | 
| 824 | ✓✓ | 469 | while((a = a->next)); | 
| 825 | 462 | return size; | |
| 826 | } | ||
| 827 | |||
| 828 | 1984 | ANN static m_uint pop_exp_size(Exp e) { | |
| 829 | 1984 | const uint emit_addr = exp_getvar(e); | |
| 830 | 1984 | m_uint size = 0; | |
| 831 |   do { // account for emit_var ? | ||
| 832 | 3968 | size += (e->exp_type == ae_exp_decl ? | |
| 833 | ✓✓ | 1984 | get_decl_size(e->d.exp_decl.list, emit_addr) : e->info->type->size); | 
| 834 | ✗✓ | 1984 | } while((e = e->next)); | 
| 835 | 1984 | return size; | |
| 836 | } | ||
| 837 | |||
| 838 | 1984 | ANN static inline void pop_exp(const Emitter emit, Exp e) { | |
| 839 | 1984 | const m_uint size = pop_exp_size(e); | |
| 840 | ✓✓ | 1984 | if(size) | 
| 841 | 1796 | regpop(emit, size); | |
| 842 | 1984 | } | |
| 843 | |||
| 844 | 1250 | ANN static inline m_bool emit_exp_pop_next(const Emitter emit, Exp e) { | |
| 845 | ✗✓ | 1250 | CHECK_BB(emit_exp(emit, e)) | 
| 846 | ✓✓ | 1250 |   if(e->exp_type == ae_exp_decl) { | 
| 847 | 119 | Var_Decl_List list = e->d.exp_decl.list->next; | |
| 848 | ✗✓ | 238 |     while(list) { | 
| 849 | regpop(emit, !exp_getvar(e) ? list->self->value->type->size : SZ_INT); | ||
| 850 | list = list->next; | ||
| 851 | } | ||
| 852 | } | ||
| 853 | ✓✓ | 1250 | if(e->next) | 
| 854 | 1 | pop_exp(emit, e->next); | |
| 855 | 1250 | return GW_OK; | |
| 856 | } | ||
| 857 | |||
| 858 | 1246 | ANN static inline m_bool op_emit_bool(const Emitter emit, const struct Op_Import* opi) { | |
| 859 | ✗✓ | 1246 | DECL_OB(const Instr, instr, = op_emit(emit, opi)) | 
| 860 | 1246 | return GW_OK; | |
| 861 | } | ||
| 862 | |||
| 863 | 519 | ANN static m_bool emit_exp_binary(const Emitter emit, const Exp_Binary* bin) { | |
| 864 | 519 | const Exp lhs = bin->lhs; | |
| 865 | 519 | const Exp rhs = bin->rhs; | |
| 866 | 1557 |   struct Op_Import opi = { .op=bin->op, .lhs=lhs->info->type, .rhs=rhs->info->type, | |
| 867 | 1038 | .pos=exp_self(bin)->pos, .data=(uintptr_t)bin, .op_type=op_binary }; | |
| 868 | ✗✓ | 519 | CHECK_BB(emit_exp_pop_next(emit, lhs)) | 
| 869 | ✗✓ | 519 | CHECK_BB(emit_exp_pop_next(emit, rhs)) | 
| 870 | 519 | const m_int size = exp_size(rhs); | |
| 871 | 519 | emit_exp_addref1(emit, lhs, -exp_size(lhs) - size); | |
| 872 | 519 | emit_exp_addref1(emit, rhs, -size); | |
| 873 | 519 | return op_emit_bool(emit, &opi); | |
| 874 | } | ||
| 875 | |||
| 876 | 30 | ANN static m_bool emit_exp_cast(const Emitter emit, const Exp_Cast* cast) { | |
| 877 | // no pos ? | ||
| 878 | 60 |   struct Op_Import opi = { .op=insert_symbol("$"), .lhs=cast->exp->info->type, .rhs=exp_self(cast)->info->type, | |
| 879 | 30 | .data=(uintptr_t)cast, .op_type=op_cast}; | |
| 880 | ✗✓ | 30 | CHECK_BB(emit_exp(emit, cast->exp)) | 
| 881 | 30 | (void)op_emit(emit, &opi); | |
| 882 | 30 | return GW_OK; | |
| 883 | } | ||
| 884 | |||
| 885 | 35 | ANN static m_bool emit_exp_post(const Emitter emit, const Exp_Postfix* post) { | |
| 886 | // no pos ? | ||
| 887 | 70 |   struct Op_Import opi = { .op=post->op, .lhs=post->exp->info->type, | |
| 888 | 35 | .data=(uintptr_t)post, .op_type=op_postfix }; | |
| 889 | ✗✓ | 35 | CHECK_BB(emit_exp(emit, post->exp)) | 
| 890 | 35 | emit_exp_addref(emit, post->exp, -exp_totalsize(post->exp)); | |
| 891 | 35 | return op_emit_bool(emit, &opi); | |
| 892 | } | ||
| 893 | |||
| 894 | 222 | ANN static inline m_bool is_special(const Emitter emit, const Type t) { | |
| 895 | ✓✗ | 227 | return isa(t, emit->gwion->type[et_object]) < 0 && | 
| 896 | 5 | isa(t, emit->gwion->type[et_class]) < 0 ? | |
| 897 | ✓✓ | 227 | GW_OK : GW_ERROR; | 
| 898 | } | ||
| 899 | |||
| 900 | 20 | ANN static inline m_bool traverse_emit_func_def(const Emitter emit, const Func_Def fdef) { | |
| 901 | ✓✗ | 20 | if(!fdef->base->ret_type) | 
| 902 | ✓✓ | 20 | CHECK_BB(traverse_func_def(emit->env, fdef)) | 
| 903 | 18 | return emit_func_def(emit, fdef); | |
| 904 | } | ||
| 905 | |||
| 906 | 20 | ANN m_bool traverse_dot_tmpl(const Emitter emit, const struct dottmpl_ *dt) { | |
| 907 | 20 | const m_uint scope = emit->env->scope->depth; | |
| 908 | 20 |   struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, | |
| 909 | .scope=scope, .flag=ae_flag_emit }; | ||
| 910 | ✗✓ | 20 | CHECK_BB(envset_push(&es, dt->owner_class, dt->owner)) | 
| 911 | 20 | (void)emit_push(emit, dt->owner_class, dt->owner); | |
| 912 | 20 | const m_bool ret = traverse_emit_func_def(emit, dt->def); | |
| 913 | ✓✓ | 20 | if(es.run) | 
| 914 | 4 | envset_pop(&es, dt->owner_class); | |
| 915 | 20 | emit_pop(emit, scope); | |
| 916 | 20 | return ret; | |
| 917 | } | ||
| 918 | |||
| 919 | 170 | static inline m_bool push_func_code(const Emitter emit, const Func f) { | |
| 920 | ✓✓ | 170 | if(!vector_size(&emit->code->instr)) | 
| 921 | 10 | return GW_OK; | |
| 922 | 160 | const Instr instr = (Instr)vector_back(&emit->code->instr); | |
| 923 | ✓✓ | 160 |   if(instr->opcode == eDotTmplVal) { | 
| 924 | 31 | size_t len = strlen(f->name); | |
| 925 | 31 | size_t sz = len - strlen(f->value_ref->from->owner_class->name); | |
| 926 | 31 | char c[sz + 1]; | |
| 927 | 31 | memcpy(c, f->name, sz); | |
| 928 | 31 | c[sz] = '\0'; | |
| 929 | 31 | struct dottmpl_ *dt = mp_calloc(emit->gwion->mp, dottmpl); | |
| 930 | 31 | dt->name = s_name(insert_symbol(c)); | |
| 931 | 31 | dt->vt_index = f->def->base->tmpl->base; | |
| 932 | 31 | dt->tl = cpy_type_list(emit->gwion->mp, f->def->base->tmpl->call); | |
| 933 | 31 | dt->base = f->def; | |
| 934 | 31 | instr->opcode = eOP_MAX; | |
| 935 | 31 | instr->m_val = (m_uint)dt; | |
| 936 | 31 | instr->m_val2 = strlen(c); | |
| 937 | 31 | instr->execute = DotTmpl; | |
| 938 | 31 | return GW_OK; | |
| 939 | } | ||
| 940 | 129 | instr->opcode = eRegPushImm; | |
| 941 | 129 | instr->m_val = (m_uint)f->code; | |
| 942 | 129 | return GW_OK; | |
| 943 | } | ||
| 944 | |||
| 945 | 33 | ANN static m_bool emit_template_code(const Emitter emit, const Func f) { | |
| 946 | 33 | const Value v = f->value_ref; | |
| 947 | 33 | const size_t scope = emit->env->scope->depth; | |
| 948 | 33 |   struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, | |
| 949 | .scope=scope, .flag=ae_flag_emit }; | ||
| 950 | ✗✓ | 33 | CHECK_BB(envset_push(&es, v->from->owner_class, v->from->owner)) | 
| 951 | 33 | (void)emit_push(emit, v->from->owner_class, v->from->owner); | |
| 952 | 33 | const m_bool ret = emit_func_def(emit, f->def); | |
| 953 | ✓✓ | 33 | if(es.run) | 
| 954 | 18 | envset_pop(&es, v->from->owner_class); | |
| 955 | 33 | emit_pop(emit, scope); | |
| 956 | ✓✗ | 33 | return ret > 0 ? push_func_code(emit, f) : GW_ERROR; | 
| 957 | } | ||
| 958 | |||
| 959 | 18 | ANN static void tmpl_prelude(const Emitter emit, const Func f) { | |
| 960 | 18 | struct dottmpl_ *dt = (struct dottmpl_*)mp_calloc(emit->gwion->mp, dottmpl); | |
| 961 | 18 | size_t len = strlen(f->name); | |
| 962 | 18 | size_t slen = strlen(f->value_ref->from->owner->name); | |
| 963 | assert(len > slen); | ||
| 964 | 18 | size_t sz = len - slen; | |
| 965 | 18 | char c[sz + 1]; | |
| 966 | 18 | memcpy(c, f->name, sz); | |
| 967 | 18 | c[sz] = '\0'; | |
| 968 | 18 | dt->tl = cpy_type_list(emit->gwion->mp, f->def->base->tmpl->call); | |
| 969 | 18 | dt->name = s_name(insert_symbol(c)); | |
| 970 | 18 | dt->vt_index = f->def->base->tmpl->base; | |
| 971 | 18 | dt->base = f->def; | |
| 972 | 18 | dt->owner = f->value_ref->from->owner; | |
| 973 | 18 | dt->owner_class = f->value_ref->from->owner_class; | |
| 974 | 18 | const Instr gtmpl = emit_add_instr(emit, GTmpl); | |
| 975 | 18 | gtmpl->m_val = (m_uint)dt; | |
| 976 | 18 | gtmpl->m_val2 = strlen(c); | |
| 977 | 18 | } | |
| 978 | |||
| 979 | 443 | ANN static Instr get_prelude(const Emitter emit, const Func f) { | |
| 980 | 443 | const Type t = actual_type(emit->gwion, f->value_ref->type); | |
| 981 | ✓✓ | 443 |   if(is_fptr(emit->gwion, t)) { | 
| 982 | 56 | emit_except(emit, t); | |
| 983 | ✓✓ | 56 | if(f->def->base->tmpl) | 
| 984 | 18 | tmpl_prelude(emit, f); | |
| 985 | } | ||
| 986 | 443 | const Instr instr = emit_add_instr(emit, SetCode); | |
| 987 | 443 | instr->m_val2 = 1; | |
| 988 | 443 | return instr; | |
| 989 | } | ||
| 990 | |||
| 991 | 223 | ANN static void emit_args(const Emitter emit, const Func f) { | |
| 992 | 223 | const m_uint member = GET_FLAG(f, member) ? SZ_INT : 0; | |
| 993 | ✓✓ | 223 |   if((f->def->stack_depth - member) == SZ_INT) { | 
| 994 | 150 | const Instr instr = emit_add_instr(emit, Reg2Mem); | |
| 995 | 150 | instr->m_val = member; | |
| 996 |   } else { | ||
| 997 | 73 | const Instr instr = emit_add_instr(emit, Reg2Mem4); | |
| 998 | 73 | instr->m_val = member; | |
| 999 | 73 | instr->m_val2 = f->def->stack_depth - member; | |
| 1000 | } | ||
| 1001 | 223 | } | |
| 1002 | |||
| 1003 | typedef struct { | ||
| 1004 | const Emitter emit; | ||
| 1005 | const Func_Def fdef; | ||
| 1006 | struct Vector_ branch; | ||
| 1007 | const m_uint offset; | ||
| 1008 | m_uint arg_offset; | ||
| 1009 | } MemoizeEmitter; | ||
| 1010 | |||
| 1011 | 2 | ANN static Instr me_push(const MemoizeEmitter *me, const m_uint sz) { | |
| 1012 | 2 | const Instr instr = emit_kind(me->emit, sz, 0, regpushmem); | |
| 1013 | 2 | instr->m_val = me->arg_offset; | |
| 1014 | 2 | return instr; | |
| 1015 | } | ||
| 1016 | |||
| 1017 | 1 | static m_bool me_cmp(MemoizeEmitter *me, const Arg_List arg) { | |
| 1018 | 1 | const Emitter emit = me->emit; | |
| 1019 | 1 |   const Symbol sym = insert_symbol("=="); | |
| 1020 | 1 |   struct ExpInfo_ info = { .nspc=me->fdef->base->func->value_ref->from->owner }; | |
| 1021 | 1 |   struct Exp_ exp = { .info=&info }; | |
| 1022 | 3 |   struct Op_Import opi = { .op=sym, .lhs=arg->type, .rhs=arg->type, | |
| 1023 | 2 | .pos=me->fdef->pos, .data=(uintptr_t)&exp.d, .op_type=op_binary }; | |
| 1024 | ✗✓ | 1 | CHECK_BB(op_emit_bool(emit, &opi)) | 
| 1025 | 1 | const Instr instr = emit_add_instr(emit, BranchEqInt); | |
| 1026 | 1 | vector_add(&me->branch, (vtype)instr); | |
| 1027 | 1 | return GW_OK; | |
| 1028 | } | ||
| 1029 | |||
| 1030 | 1 | ANN static m_bool me_arg(MemoizeEmitter *me) { | |
| 1031 | 1 | Arg_List arg = me->fdef->base->args; | |
| 1032 |   do { | ||
| 1033 | 1 | const m_uint sz = arg->type->size; | |
| 1034 | 1 | (void)me_push(me, sz); | |
| 1035 | 1 | const Instr instr = me_push(me, sz); | |
| 1036 | 1 | instr->m_val += me->offset + SZ_INT *2; | |
| 1037 | ✗✓ | 1 | CHECK_BB(me_cmp(me, arg)) | 
| 1038 | 1 | me->arg_offset += arg->type->size; | |
| 1039 | ✗✓ | 1 | } while((arg = arg->next)); | 
| 1040 | 1 | return GW_OK; | |
| 1041 | } | ||
| 1042 | |||
| 1043 | 443 | ANN static Instr emit_call(const Emitter emit, const Func f) { | |
| 1044 | 443 | const Instr prelude = get_prelude(emit, f); | |
| 1045 | 443 | prelude->m_val = f->def->stack_depth; | |
| 1046 | 443 | const m_uint member = GET_FLAG(f, member) ? SZ_INT : 0; | |
| 1047 | ✓✓ | 443 |   if(member) { | 
| 1048 | 241 | const Instr instr = emit_add_instr(emit, Reg2Mem); | |
| 1049 | 241 | instr->m_val2 = f->def->stack_depth - SZ_INT; | |
| 1050 | 241 | ++prelude->m_val2; | |
| 1051 | } | ||
| 1052 | ✓✓ | 443 |   if(f->def->stack_depth - member) { | 
| 1053 | 222 | emit_args(emit, f); | |
| 1054 | 222 | ++prelude->m_val2; | |
| 1055 | } | ||
| 1056 | 443 | return emit_add_instr(emit, Overflow); | |
| 1057 | } | ||
| 1058 | |||
| 1059 | 443 | ANN Instr emit_exp_call1(const Emitter emit, const Func f) { | |
| 1060 | ✓✓✓✓ ✓✗ | 443 |   if(!f->code || (GET_FLAG(f, ref) && !GET_FLAG(f, builtin))) { | 
| 1061 | ✓✓✓✗ | 216 |     if(GET_FLAG(f, template) && !is_fptr(emit->gwion, f->value_ref->type)) { | 
| 1062 | ✓✓ | 76 | if(emit->env->func != f) | 
| 1063 | ✗✓ | 33 | CHECK_BO(emit_template_code(emit, f)) | 
| 1064 |       else { // recursive function. (maybe should be used only for global funcs) | ||
| 1065 | 10 | const Instr back = (Instr) vector_size(&emit->code->instr) ? | |
| 1066 | ✓✗ | 5 | (Instr)vector_back(&emit->code->instr) : emit_add_instr(emit, RegPushImm); | 
| 1067 | 5 | back->opcode = eOP_MAX; | |
| 1068 | 5 | back->execute = SetRecurs; | |
| 1069 | 5 | back->m_val = 0; | |
| 1070 | } | ||
| 1071 | ✓✓✓✓ ✓✗✓✓ | 70 |     } else if(emit->env->func != f && !f->value_ref->from->owner_class && !f->code && !is_fptr(emit->gwion, f->value_ref->type)) { | 
| 1072 | ✗✓ | 1 |       if(GET_FLAG(f->def, op)) { | 
| 1073 | const Instr back = (Instr)vector_back(&emit->code->instr); | ||
| 1074 | back->m_val = (m_uint)f; | ||
| 1075 |       } else { | ||
| 1076 | // ensure env? | ||
| 1077 | ✗✓ | 1 | CHECK_BO(emit_func_def(emit, f->def)) | 
| 1078 | 1 | const Instr instr = emit_add_instr(emit, RegSetImm); | |
| 1079 | 1 | instr->m_val = (m_uint)f->code; | |
| 1080 | 1 | instr->m_val2 = -SZ_INT; | |
| 1081 | } | ||
| 1082 | } | ||
| 1083 | ✓✓✓✓ ✓✓ | 665 | } else if((f->value_ref->from->owner_class && is_special(emit, f->value_ref->from->owner_class) > 0) || | 
| 1084 | ✓✓✓✗ | 566 | !f->value_ref->from->owner_class || (GET_FLAG(f, template) && | 
| 1085 | 19 | !is_fptr(emit->gwion, f->value_ref->type))) | |
| 1086 | 137 | push_func_code(emit, f); | |
| 1087 | ✓✓ | 198 |   else if(vector_size(&emit->code->instr)) { | 
| 1088 | 187 | const Instr back = (Instr)vector_back(&emit->code->instr); | |
| 1089 | ✓✓✓✓ | 187 | if((f_instr)(m_uint)back->opcode == DotFunc || (f_instr)(m_uint)back->opcode == DotStaticFunc) | 
| 1090 | 169 | back->m_val = f->vt_index; | |
| 1091 | } | ||
| 1092 | ✓✓✓✓ ✓✓ | 670 | if(vector_size(&emit->code->instr) && GET_FLAG(f, member) && | 
| 1093 | 251 |         is_fptr(emit->gwion, f->value_ref->type)) { | |
| 1094 | 24 | const Instr back = (Instr)vector_back(&emit->code->instr); | |
| 1095 | 24 | m_bit exec = back->opcode; | |
| 1096 | 24 | m_uint val = back->m_val; | |
| 1097 | 24 | m_uint val2 = back->m_val2; | |
| 1098 | 24 | back->opcode = eRegPushMem; | |
| 1099 | 24 | back->m_val = back->m_val2 = 0; | |
| 1100 | 24 | const Instr instr = emit_add_instr(emit, (f_instr)(m_uint)exec); | |
| 1101 | 24 | instr->m_val = val; | |
| 1102 | 24 | instr->m_val2 = val2; | |
| 1103 | ✓✓✓✓ ✓✓ | 419 |   } else if(f != emit->env->func && !f->code && !is_fptr(emit->gwion, f->value_ref->type)){ | 
| 1104 | // not yet emitted static func | ||
| 1105 | ✓✗ | 2 |     if(f->value_ref->from->owner_class) { | 
| 1106 | 4 | const Instr instr = vector_size(&emit->code->instr) ? | |
| 1107 | ✓✗ | 2 | (Instr)vector_back(&emit->code->instr) : emit_add_instr(emit, SetFunc); | 
| 1108 | 2 | instr->opcode = eOP_MAX; | |
| 1109 | 2 | instr->execute = SetFunc; | |
| 1110 | 2 | instr->m_val = (m_uint)f; | |
| 1111 |     } else { | ||
| 1112 | const Instr instr = emit_add_instr(emit, SetFunc); | ||
| 1113 | instr->m_val = (m_uint)f; | ||
| 1114 | } | ||
| 1115 | } | ||
| 1116 | 443 | const m_uint offset = emit_code_offset(emit); | |
| 1117 | 443 | regseti(emit, offset); | |
| 1118 | 443 | const Instr instr = emit_call(emit, f); | |
| 1119 | 443 | instr->m_val = f->def->base->ret_type->size; | |
| 1120 | 443 | instr->m_val2 = offset; | |
| 1121 | 443 | return instr; | |
| 1122 | } | ||
| 1123 | |||
| 1124 | 24 | ANN static void emit_exp_spork_finish(const Emitter emit, const m_uint depth) { | |
| 1125 | 24 | regpop(emit, depth); | |
| 1126 | 24 | const Instr spork = emit_add_instr(emit, SporkFunc); | |
| 1127 | 24 | spork->m_val = depth + SZ_INT; | |
| 1128 | 24 | spork->m_val2 = -SZ_INT; | |
| 1129 | 24 | } | |
| 1130 | |||
| 1131 | 241 | static inline void stack_alloc(const Emitter emit) { // maybe vararg could use t_vararg instead | |
| 1132 | 241 | emit_local(emit, emit->gwion->type[et_int]); // hiding the fact it is an object | |
| 1133 | 241 | emit->code->stack_depth += SZ_INT; | |
| 1134 | 241 | } | |
| 1135 | |||
| 1136 | 233 | static inline void stack_alloc_this(const Emitter emit) { | |
| 1137 | 233 | SET_FLAG(emit->code, member); | |
| 1138 | 233 | stack_alloc(emit); | |
| 1139 | 233 | } | |
| 1140 | |||
| 1141 | 345 | static m_bool scoped_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { | |
| 1142 | 345 | ++emit->env->scope->depth; | |
| 1143 | 345 | emit_push_scope(emit); | |
| 1144 | 345 | const Instr gc = emit_add_instr(emit, NoOp); | |
| 1145 | 345 | const m_bool ret = emit_stmt(emit, stmt, pop); | |
| 1146 | ✓✗ | 345 |   if(ret > 0) { | 
| 1147 | 345 | const m_bool pure = !vector_back(&emit->info->pure); | |
| 1148 | ✓✓ | 345 |     if(!pure) { | 
| 1149 | 7 | gc->opcode = eGcIni; | |
| 1150 | 7 | emit_add_instr(emit, GcEnd); | |
| 1151 | } | ||
| 1152 | } | ||
| 1153 | 345 | emit_pop_scope(emit); | |
| 1154 | 345 | --emit->env->scope->depth; | |
| 1155 | 345 | return ret; | |
| 1156 | } | ||
| 1157 | |||
| 1158 | #define SPORK_FUNC_PREFIX "spork~func:%i" | ||
| 1159 | #define FORK_FUNC_PREFIX "fork~func:%i" | ||
| 1160 | #define SPORK_CODE_PREFIX "spork~code:%i" | ||
| 1161 | #define FORK_CODE_PREFIX "fork~code:%i" | ||
| 1162 | |||
| 1163 | 52 | static void push_spork_code(const Emitter emit, const m_str prefix, const loc_t pos) { | |
| 1164 | 52 | char c[strlen(SPORK_FUNC_PREFIX) + num_digit(pos->first.line) + 1]; | |
| 1165 | 52 | sprintf(c, prefix, pos->first.line); | |
| 1166 | 52 | emit_push_code(emit, c); | |
| 1167 | 52 | } | |
| 1168 | |||
| 1169 | 27 | ANN static m_bool call_spork_func(const Emitter emit, const Exp_Call *exp) { | |
| 1170 | ✓✓ | 27 | if(GET_FLAG(exp->m_func, member)) | 
| 1171 | 14 | SET_FLAG(emit->code, member); | |
| 1172 | ✓✗ | 27 | return emit_exp_call1(emit, exp->m_func) ? GW_OK : GW_ERROR; | 
| 1173 | } | ||
| 1174 | |||
| 1175 | struct Sporker { | ||
| 1176 | const Stmt code; | ||
| 1177 | const Exp exp; | ||
| 1178 | VM_Code vm_code; | ||
| 1179 | const m_bool emit_var; | ||
| 1180 | const m_bool is_spork; | ||
| 1181 | }; | ||
| 1182 | |||
| 1183 | 25 | ANN static m_bool spork_prepare_code(const Emitter emit, const struct Sporker *sp) { | |
| 1184 | 25 | emit_add_instr(emit, RegPushImm); | |
| 1185 | ✓✓ | 25 | push_spork_code(emit, sp->is_spork ? SPORK_CODE_PREFIX : FORK_CODE_PREFIX, sp->code->pos); | 
| 1186 | ✓✓✓✓ | 25 | if(SAFE_FLAG(emit->env->func, member)) | 
| 1187 | 2 | stack_alloc_this(emit); | |
| 1188 | 25 | return scoped_stmt(emit, sp->code, 0); | |
| 1189 | } | ||
| 1190 | |||
| 1191 | 27 | ANN static m_bool spork_prepare_func(const Emitter emit, const struct Sporker *sp) { | |
| 1192 | ✓✗ | 27 | push_spork_code(emit, sp->is_spork ? SPORK_FUNC_PREFIX : FORK_CODE_PREFIX, sp->exp->pos); | 
| 1193 | 27 | return call_spork_func(emit, &sp->exp->d.exp_call); | |
| 1194 | } | ||
| 1195 | |||
| 1196 | 52 | ANN static VM_Code spork_prepare(const Emitter emit, const struct Sporker *sp) { | |
| 1197 | ✓✓ | 52 | if(!sp->code) | 
| 1198 | ✗✓ | 27 | CHECK_BO(prepare_call(emit, &sp->exp->d.exp_call)) | 
| 1199 | ✓✓✓✗ | 52 | if((sp->code ? spork_prepare_code : spork_prepare_func)(emit, sp) > 0) | 
| 1200 | 52 | return finalyze(emit, EOC); | |
| 1201 | emit_pop_code(emit); | ||
| 1202 | return NULL; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | 25 | ANN void spork_code(const Emitter emit, const struct Sporker *sp) { | |
| 1206 | 25 | const Instr args = emit_add_instr(emit, SporkExp); | |
| 1207 | 25 | args->m_val = emit->code->stack_depth; | |
| 1208 | 25 | const Instr instr = emit_add_instr(emit, SporkEnd); | |
| 1209 | 25 | instr->m_val = sp->emit_var; | |
| 1210 | 25 | } | |
| 1211 | |||
| 1212 | 27 | ANN void spork_func(const Emitter emit, const struct Sporker *sp) { | |
| 1213 | 27 | const Func f = sp->exp->d.exp_call.m_func; | |
| 1214 | ✓✓✓✓ | 30 |   if(GET_FLAG(f, member) && is_fptr(emit->gwion, f->value_ref->type)) { | 
| 1215 | 3 | const m_uint depth = f->def->stack_depth; | |
| 1216 | 3 | regpop(emit, depth -SZ_INT); | |
| 1217 | 3 | const Instr spork = emit_add_instr(emit, SporkMemberFptr); | |
| 1218 | 3 | spork->m_val = depth; | |
| 1219 | } else | ||
| 1220 | 24 | emit_exp_spork_finish(emit, f->def->stack_depth); | |
| 1221 | 27 | (void)emit_add_instr(emit, SporkEnd); | |
| 1222 | 27 | } | |
| 1223 | |||
| 1224 | 52 | ANN static Instr spork_ini(const Emitter emit, const struct Sporker *sp) { | |
| 1225 | ✓✓ | 52 |   if(sp->is_spork) { | 
| 1226 | 45 | const Instr instr = emit_add_instr(emit, SporkIni); | |
| 1227 | 45 | instr->m_val = (m_uint)sp->vm_code; | |
| 1228 | 45 | instr->m_val2 = sp->is_spork; | |
| 1229 | 45 | return instr; | |
| 1230 | } | ||
| 1231 | ✗✓ | 7 | const Func f = !sp->code ? sp->exp->d.exp_call.m_func : NULL; | 
| 1232 | 7 | const Instr instr = emit_add_instr(emit, ForkIni); | |
| 1233 | 7 | instr->m_val = (m_uint)sp->vm_code; | |
| 1234 | ✗✓ | 7 | instr->m_val2 = f ? f->def->base->ret_type->size : 0; | 
| 1235 | 7 | return instr; | |
| 1236 | } | ||
| 1237 | |||
| 1238 | 52 | ANN Instr emit_exp_spork(const Emitter emit, const Exp_Unary* unary) { | |
| 1239 | 260 |   struct Sporker sporker = { | |
| 1240 | 52 | .exp=unary->exp, | |
| 1241 | 52 | .code=unary->code, | |
| 1242 | 52 |     .is_spork=(unary->op == insert_symbol("spork")), | |
| 1243 | 52 | .emit_var=exp_getvar(exp_self(unary)) | |
| 1244 | }; | ||
| 1245 | ✗✓ | 52 | CHECK_OO((sporker.vm_code = spork_prepare(emit, &sporker))) | 
| 1246 | 52 | const Instr ini = spork_ini(emit, &sporker); | |
| 1247 | ✓✓ | 52 | (unary->code ? spork_code : spork_func)(emit, &sporker); | 
| 1248 | 52 | return ini; | |
| 1249 | } | ||
| 1250 | |||
| 1251 | 124 | ANN static m_bool emit_exp_unary(const Emitter emit, const Exp_Unary* unary) { | |
| 1252 | 124 | const Type t = exp_self(unary)->info->type; | |
| 1253 | 124 | const Type base = get_type(actual_type(emit->gwion, t)); | |
| 1254 | ✓✓✗✓ | 124 | if(base->e->def && !GET_FLAG(base, emit)) | 
| 1255 | CHECK_BB(ensure_emit(emit, base)) | ||
| 1256 | // no pos ? | ||
| 1257 | 124 |   struct Op_Import opi = { .op=unary->op, .data=(uintptr_t)unary, .op_type=op_unary }; | |
| 1258 | ✓✓✓✓ ✓✓ | 124 |   if(unary->op != insert_symbol("spork") && unary->op != insert_symbol("fork") && unary->exp) { | 
| 1259 | ✗✓ | 53 | CHECK_BB(emit_exp_pop_next(emit, unary->exp)) | 
| 1260 | 53 | emit_exp_addref1(emit, unary->exp, -exp_size(unary->exp)); | |
| 1261 | 53 | opi.rhs = unary->exp->info->type; | |
| 1262 | } | ||
| 1263 | 124 | return op_emit_bool(emit, &opi); | |
| 1264 | } | ||
| 1265 | |||
| 1266 | 34 | ANN static m_bool emit_implicit_cast(const Emitter emit, | |
| 1267 |     const restrict Exp  from, const restrict Type to) { | ||
| 1268 | 34 |   const struct Implicit imp = { from, to, from->pos }; | |
| 1269 | // no pos | ||
| 1270 | 68 |   struct Op_Import opi = { .op=insert_symbol("@implicit"), .lhs=from->info->type, .rhs=to, | |
| 1271 | 34 | .data=(m_uint)&imp, .op_type=op_implicit }; | |
| 1272 | 34 | return op_emit_bool(emit, &opi); | |
| 1273 | } | ||
| 1274 | |||
| 1275 | 81 | ANN static Instr _flow(const Emitter emit, const Exp e, const m_bool b) { | |
| 1276 | ✗✓ | 81 | CHECK_BO(emit_exp_pop_next(emit, e)) | 
| 1277 | 81 | emit_exp_addref1(emit, e, -exp_size(e)); | |
| 1278 | ✓✓ | 324 |   struct Op_Import opi = { .op=insert_symbol(b ? "@conditionnal" : "@unconditionnal"), | 
| 1279 | 243 | .rhs=e->info->type, .pos=e->pos, .data=(uintptr_t)e, .op_type=op_exp }; | |
| 1280 | 81 | const Instr instr = op_emit(emit, &opi); | |
| 1281 | assert(instr != (Instr)GW_OK); | ||
| 1282 | 81 | return instr; | |
| 1283 | } | ||
| 1284 | #define emit_flow(emit,b) _flow(emit, b, 1) | ||
| 1285 | |||
| 1286 | 7 | ANN static m_bool emit_exp_if(const Emitter emit, const Exp_If* exp_if) { | |
| 1287 | ✗✓ | 7 | DECL_OB(const Instr, op, = emit_flow(emit, exp_if->cond)) | 
| 1288 | ✓✓✗✓ | 7 | CHECK_BB(emit_exp_pop_next(emit, exp_if->if_exp ?: exp_if->cond)) | 
| 1289 | 7 | const Instr op2 = emit_add_instr(emit, Goto); | |
| 1290 | 7 | op->m_val = emit_code_size(emit); | |
| 1291 | 7 | const m_bool ret = emit_exp_pop_next(emit, exp_if->else_exp); | |
| 1292 | 7 | op2->m_val = emit_code_size(emit); | |
| 1293 | 7 | return ret; | |
| 1294 | } | ||
| 1295 | |||
| 1296 | 13 | ANN static m_bool emit_lambda(const Emitter emit, const Exp_Lambda * lambda) { | |
| 1297 | ✗✓ | 13 | CHECK_BB(emit_func_def(emit, lambda->def)) | 
| 1298 | ✓✓✓✓ | 13 | if(GET_FLAG(lambda->def, member) && !exp_getvar(exp_self(lambda))) | 
| 1299 | 7 | emit_add_instr(emit, RegPushMem); | |
| 1300 | 13 | regpushi(emit, (m_uint)lambda->def->base->func->code); | |
| 1301 | 13 | return GW_OK; | |
| 1302 | } | ||
| 1303 | |||
| 1304 | 14 | ANN static m_bool emit_exp_lambda(const Emitter emit, const Exp_Lambda * lambda) { | |
| 1305 | ✓✓ | 14 |   if(!lambda->def->base->func) { | 
| 1306 | 1 | regpushi(emit, SZ_INT); | |
| 1307 | 1 | return GW_OK; | |
| 1308 | } | ||
| 1309 | 26 |   struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, | |
| 1310 | 13 | .scope=emit->env->scope->depth, .flag=ae_flag_emit }; | |
| 1311 | ✗✓ | 13 | CHECK_BB(envset_push(&es, lambda->owner, lambda->def->base->func->value_ref->from->owner)) | 
| 1312 | 13 | const m_bool ret = emit_lambda(emit, lambda); | |
| 1313 | ✓✓ | 13 | if(es.run) | 
| 1314 | 5 | envset_pop(&es, lambda->owner); | |
| 1315 | 13 | return ret; | |
| 1316 | } | ||
| 1317 | |||
| 1318 | DECL_EXP_FUNC(emit, m_bool, Emitter) | ||
| 1319 | |||
| 1320 | |||
| 1321 | ANN static void struct_addref(const Emitter emit, const Type type, | ||
| 1322 |     const m_int size, const m_bool offset, const m_bool emit_var) { | ||
| 1323 |   for(m_uint i = 0; i < vector_size(&type->e->tuple->types); ++i) { | ||
| 1324 | const Type t = (Type)vector_at(&type->e->tuple->types, i); | ||
| 1325 |     if(isa(t, emit->gwion->type[et_object]) > 0) { | ||
| 1326 | const Instr instr = emit_addref(emit, emit_var); | ||
| 1327 | instr->m_val = size; | ||
| 1328 | instr->m_val2 = vector_at(&type->e->tuple->offset, i); | ||
| 1329 | } else if(GET_FLAG(t, struct)) | ||
| 1330 | struct_addref(emit, t, size, offset + vector_at(&type->e->tuple->offset, i), emit_var); | ||
| 1331 | } | ||
| 1332 | } | ||
| 1333 | |||
| 1334 | 1849 | ANN static inline m_uint exp_size(const Exp e) { | |
| 1335 | ✓✓ | 1849 | if(exp_getvar(e)) | 
| 1336 | 354 | return SZ_INT; | |
| 1337 | ✓✓ | 1495 | const Type type = e->info->cast_to ?: e->info->type; | 
| 1338 | 1495 | return type->size; | |
| 1339 | } | ||
| 1340 | |||
| 1341 | 1514 | ANN2(1) static void emit_exp_addref1(const Emitter emit, /* const */Exp exp, m_int size) { | |
| 1342 | ✓✓✓✓ ✓✓ | 1740 | if(isa(exp->info->type, emit->gwion->type[et_object]) > 0 && | 
| 1343 | 438 |     (exp->info->cast_to ? isa(exp->info->cast_to, emit->gwion->type[et_object]) > 0 : 1)) { | |
| 1344 | 212 | const Instr instr = emit_addref(emit, exp_getvar(exp)); | |
| 1345 | 212 | instr->m_val = size; | |
| 1346 | ✗✓ | 1302 | } else if(GET_FLAG(exp->info->type, struct)) // check cast_to ? | 
| 1347 | struct_addref(emit, exp->info->type, size, 0, exp_getvar(exp)); | ||
| 1348 | 1514 | } | |
| 1349 | |||
| 1350 | 335 | ANN2(1) static void emit_exp_addref(const Emitter emit, /* const */Exp exp, m_int size) { | |
| 1351 |   do { | ||
| 1352 | 335 | emit_exp_addref1(emit, exp, size); | |
| 1353 | 335 | size += exp_size(exp); | |
| 1354 | ✓✓ | 335 | } while((exp = exp->next)); | 
| 1355 | 260 | } | |
| 1356 | |||
| 1357 | 5664 | ANN2(1) /*static */m_bool emit_exp(const Emitter emit, /* const */Exp e) { | |
| 1358 | 5664 | Exp exp = e; | |
| 1359 |   do { | ||
| 1360 | ✓✓ | 5800 | CHECK_BB(emit_exp_func[exp->exp_type](emit, &exp->d)) | 
| 1361 | ✓✓ | 5796 | if(exp_getnonnull(exp)) | 
| 1362 | 87 | emit_except(emit, exp->info->type); | |
| 1363 | ✓✓ | 5796 | if(exp->info->cast_to) | 
| 1364 | ✗✓ | 34 | CHECK_BB(emit_implicit_cast(emit, exp, exp->info->cast_to)) | 
| 1365 | ✓✓ | 5796 | } while((exp = exp->next)); | 
| 1366 | 5660 | return GW_OK; | |
| 1367 | } | ||
| 1368 | |||
| 1369 | 34 | ANN static m_bool emit_if(const Emitter emit, const Stmt_If stmt) { | |
| 1370 | ✗✓ | 34 | DECL_OB(const Instr, op, = emit_flow(emit, stmt->cond)) | 
| 1371 | ✗✓ | 34 | CHECK_BB(scoped_stmt(emit, stmt->if_body, 1)) | 
| 1372 | 34 | const Instr op2 = emit_add_instr(emit, Goto); | |
| 1373 | 34 | op->m_val = emit_code_size(emit); | |
| 1374 | ✓✓ | 34 | if(stmt->else_body) | 
| 1375 | ✗✓ | 12 | CHECK_BB(scoped_stmt(emit, stmt->else_body, 1)) | 
| 1376 | 34 | op2->m_val = emit_code_size(emit); | |
| 1377 | 34 | return GW_OK; | |
| 1378 | } | ||
| 1379 | |||
| 1380 | 34 | ANN static m_bool emit_stmt_if(const Emitter emit, const Stmt_If stmt) { | |
| 1381 | 34 | emit_push_scope(emit); | |
| 1382 | 34 | const m_bool ret = emit_if(emit, stmt); | |
| 1383 | 34 | emit_pop_scope(emit); | |
| 1384 | 34 | return ret; | |
| 1385 | } | ||
| 1386 | |||
| 1387 | 371 | ANN static m_bool emit_stmt_code(const Emitter emit, const Stmt_Code stmt) { | |
| 1388 | 371 | ++emit->env->scope->depth; | |
| 1389 | ✓✓ | 371 | const m_bool ret = stmt->stmt_list ? emit_stmt_list(emit, stmt->stmt_list) : 1; | 
| 1390 | 371 | --emit->env->scope->depth; | |
| 1391 | 371 | return ret; | |
| 1392 | } | ||
| 1393 | |||
| 1394 | 1 | ANN static m_bool optimize_taill_call(const Emitter emit, const Exp_Call* e) { | |
| 1395 | ✓✗ | 1 |   if(e->args) { | 
| 1396 | 1 | emit_func_args(emit, e); | |
| 1397 | 1 | regpop(emit, e->m_func->def->stack_depth); | |
| 1398 | 1 | emit_args(emit, e->m_func); | |
| 1399 | } | ||
| 1400 | 1 | emit_add_instr(emit, Goto); | |
| 1401 | 1 | return GW_OK; | |
| 1402 | } | ||
| 1403 | |||
| 1404 | 38 | ANN static m_bool emit_stmt_return(const Emitter emit, const Stmt_Exp stmt) { | |
| 1405 | ✓✓ | 38 |   if(stmt->val) { | 
| 1406 | ✓✓✓✗ | 36 | if(stmt->val->exp_type == ae_exp_call && emit->env->func == stmt->val->d.exp_call.m_func) | 
| 1407 | 1 | return optimize_taill_call(emit, &stmt->val->d.exp_call); | |
| 1408 | ✗✓ | 35 | CHECK_BB(emit_exp_pop_next(emit, stmt->val)) | 
| 1409 | } | ||
| 1410 | 37 | vector_add(&emit->code->stack_return, (vtype)emit_add_instr(emit, Goto)); | |
| 1411 | 37 | return GW_OK; | |
| 1412 | } | ||
| 1413 | |||
| 1414 | 9 | ANN static inline m_bool emit_stmt_continue(const Emitter emit, const Stmt stmt NUSED) { | |
| 1415 | 9 | vector_add(&emit->code->stack_cont, (vtype)emit_add_instr(emit, Goto)); | |
| 1416 | 9 | return GW_OK; | |
| 1417 | } | ||
| 1418 | |||
| 1419 | 8 | ANN static inline m_bool emit_stmt_break(const Emitter emit, const Stmt stmt NUSED) { | |
| 1420 | 8 | vector_add(&emit->code->stack_break, (vtype)emit_add_instr(emit, Goto)); | |
| 1421 | 8 | return GW_OK; | |
| 1422 | } | ||
| 1423 | |||
| 1424 | 53 | ANN static inline void emit_push_stack(const Emitter emit) { | |
| 1425 | 53 | emit_push_scope(emit); | |
| 1426 | 53 | vector_add(&emit->code->stack_cont, (vtype)NULL); | |
| 1427 | 53 | vector_add(&emit->code->stack_break, (vtype)NULL); | |
| 1428 | 53 | } | |
| 1429 | |||
| 1430 | 106 | ANN static void pop_vector(Vector v, const  m_uint pc) { | |
| 1431 | Instr instr; | ||
| 1432 | ✓✓ | 229 | while((instr = (Instr)vector_pop(v))) | 
| 1433 | 17 | instr->m_val = pc; | |
| 1434 | 106 | } | |
| 1435 | |||
| 1436 | 53 | ANN static void emit_pop_stack(const Emitter emit, const m_uint index) { | |
| 1437 | 53 | pop_vector(&emit->code->stack_cont, index); | |
| 1438 | 53 | pop_vector(&emit->code->stack_break, emit_code_size(emit)); | |
| 1439 | 53 | emit_pop_scope(emit); | |
| 1440 | 53 | } | |
| 1441 | |||
| 1442 | 26 | ANN static m_bool _emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt, const m_uint index) { | |
| 1443 | 26 | Instr op = NULL; | |
| 1444 | ✓✓ | 26 | if(!stmt->is_do) | 
| 1445 | 12 | op = _flow(emit, stmt->cond, stmt_self(stmt)->stmt_type == ae_stmt_while); | |
| 1446 | ✗✓ | 26 | CHECK_BB(scoped_stmt(emit, stmt->body, 1)) | 
| 1447 | ✓✓ | 26 |   if(stmt->is_do) { | 
| 1448 | ✗✓ | 14 | CHECK_OB((op = _flow(emit, stmt->cond, stmt_self(stmt)->stmt_type != ae_stmt_while))) | 
| 1449 | 14 | op->m_val = index; | |
| 1450 |   } else { | ||
| 1451 | 12 | const Instr goto_ = emit_add_instr(emit, Goto); | |
| 1452 | 12 | goto_->m_val = index; | |
| 1453 | 12 | op->m_val = emit_code_size(emit); | |
| 1454 | } | ||
| 1455 | 26 | return GW_OK; | |
| 1456 | } | ||
| 1457 | |||
| 1458 | 26 | ANN static m_bool emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt) { | |
| 1459 | 26 | const m_uint index = emit_code_size(emit); | |
| 1460 | 26 | emit_push_stack(emit); | |
| 1461 | 26 | const m_bool ret = _emit_stmt_flow(emit, stmt, index); | |
| 1462 | 26 | emit_pop_stack(emit, index); | |
| 1463 | 26 | return ret; | |
| 1464 | } | ||
| 1465 | |||
| 1466 | 10 | ANN static m_bool variadic_state(const Emitter emit, const Stmt_VarLoop stmt, const m_uint status) { | |
| 1467 | 10 | regpushi(emit, status); | |
| 1468 | ✗✓ | 10 | CHECK_BB(emit_exp(emit, stmt->exp)) | 
| 1469 | 10 | emit_add_instr(emit, SetObj); | |
| 1470 | 10 | const Instr member = emit_add_instr(emit, DotMember4); | |
| 1471 | 10 | member->m_val = SZ_INT; | |
| 1472 | 10 | emit_add_instr(emit, int_r_assign); | |
| 1473 | 10 | regpop(emit, SZ_INT); | |
| 1474 | 10 | return GW_OK; | |
| 1475 | } | ||
| 1476 | |||
| 1477 | 5 | ANN static m_bool emit_stmt_varloop(const Emitter emit, const Stmt_VarLoop stmt) { | |
| 1478 | ✗✓ | 5 | CHECK_BB(variadic_state(emit, stmt, 1)) | 
| 1479 | ✗✓ | 5 | CHECK_BB(emit_exp(emit, stmt->exp)) | 
| 1480 | 5 | const Instr member = emit_add_instr(emit, DotMember4); | |
| 1481 | 5 | member->m_val = SZ_INT*2; | |
| 1482 | 5 | const Instr instr = emit_add_instr(emit, BranchEqInt); | |
| 1483 | 5 | const m_uint pc = emit_code_size(emit); | |
| 1484 | 5 | emit_stmt(emit, stmt->body, 1); | |
| 1485 | ✗✓ | 5 | CHECK_BB(emit_exp(emit, stmt->exp)) | 
| 1486 | 5 | emit_vararg_end(emit, pc); | |
| 1487 | 5 | instr->m_val = emit_code_size(emit); | |
| 1488 | ✗✓ | 5 | CHECK_BB(variadic_state(emit, stmt, 0)) | 
| 1489 | 5 | instr->m_val = emit_code_size(emit); | |
| 1490 | 5 | return GW_OK; | |
| 1491 | } | ||
| 1492 | |||
| 1493 | 10 | ANN static m_bool _emit_stmt_for(const Emitter emit, const Stmt_For stmt, m_uint *action_index) { | |
| 1494 | ✗✓ | 10 | CHECK_BB(emit_stmt(emit, stmt->c1, 1)) | 
| 1495 | 10 | const m_uint index = emit_code_size(emit); | |
| 1496 | ✗✓ | 10 | DECL_OB(const Instr, op, = emit_flow(emit, stmt->c2->d.stmt_exp.val)) | 
| 1497 | ✗✓ | 10 | CHECK_BB(scoped_stmt(emit, stmt->body, 1)) | 
| 1498 | 10 | *action_index = emit_code_size(emit); | |
| 1499 | ✓✓ | 10 |   if(stmt->c3) { | 
| 1500 | ✗✓ | 9 | CHECK_BB(emit_exp(emit, stmt->c3)) | 
| 1501 | 9 | pop_exp(emit, stmt->c3); | |
| 1502 | } | ||
| 1503 | 10 | const Instr _goto = emit_add_instr(emit, Goto); | |
| 1504 | 10 | _goto->m_val = index; | |
| 1505 | 10 | op->m_val = emit_code_size(emit); | |
| 1506 | 10 | return GW_OK; | |
| 1507 | } | ||
| 1508 | |||
| 1509 | 10 | ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) { | |
| 1510 | 10 | emit_push_stack(emit); | |
| 1511 | 10 | m_uint action_index = 0; | |
| 1512 | 10 | const m_bool ret = _emit_stmt_for(emit, stmt, &action_index); | |
| 1513 | 10 | emit_pop_stack(emit, action_index); | |
| 1514 | 10 | return ret; | |
| 1515 | } | ||
| 1516 | |||
| 1517 | 4 | ANN static Instr emit_stmt_autoptr_init(const Emitter emit, const Type type) { | |
| 1518 | 4 | const Instr new_obj = emit_add_instr(emit, ObjectInstantiate); | |
| 1519 | 4 | new_obj->m_val2 = (m_uint)type; | |
| 1520 | 4 | (void)emit_addref(emit, 0); | |
| 1521 | 4 | regpop(emit, SZ_INT); | |
| 1522 | 4 | return emit_add_instr(emit, Reg2Mem); | |
| 1523 | } | ||
| 1524 | |||
| 1525 | 10 | ANN static m_bool _emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt, m_uint *end_pc) { | |
| 1526 | 10 | const Instr s1 = emit_add_instr(emit, MemSetImm); | |
| 1527 | ✓✓ | 10 | Instr cpy = stmt->is_ptr ? emit_stmt_autoptr_init(emit, stmt->v->type) : NULL; | 
| 1528 | 10 | emit_local(emit, emit->gwion->type[et_int]); | |
| 1529 | 10 | const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); | |
| 1530 | 10 | emit_local(emit, emit->gwion->type[et_int]); | |
| 1531 | 10 | stmt->v->from->offset = offset + SZ_INT; | |
| 1532 | 10 | const m_uint ini_pc = emit_code_size(emit); | |
| 1533 | 10 | emit_except(emit, stmt->exp->info->type); | |
| 1534 | ✓✓ | 10 | const Instr loop = emit_add_instr(emit, stmt->is_ptr ? AutoLoopPtr : AutoLoop); | 
| 1535 | 10 | const Instr end = emit_add_instr(emit, BranchEqInt); | |
| 1536 | 10 | const m_bool ret = scoped_stmt(emit, stmt->body, 1); | |
| 1537 | 10 | *end_pc = emit_code_size(emit); | |
| 1538 | ✓✓ | 10 |   if(stmt->is_ptr) { | 
| 1539 | 4 | loop->m_val2 = (m_uint)stmt->v->type; | |
| 1540 | 4 | cpy->m_val = stmt->v->from->offset; | |
| 1541 | } | ||
| 1542 | 10 | const Instr tgt = emit_add_instr(emit, Goto); | |
| 1543 | 10 | end->m_val = emit_code_size(emit); | |
| 1544 | 10 | tgt->m_val = ini_pc; | |
| 1545 | 10 | s1->m_val = loop->m_val = offset; | |
| 1546 | 10 | return ret; | |
| 1547 | } | ||
| 1548 | |||
| 1549 | 10 | ANN static m_bool emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt) { | |
| 1550 | ✗✓ | 10 | CHECK_BB(emit_exp(emit, stmt->exp)) | 
| 1551 | 10 | emit_push_stack(emit); | |
| 1552 | 10 | m_uint end_pc = 0; | |
| 1553 | 10 | const m_bool ret = _emit_stmt_auto(emit, stmt, &end_pc); | |
| 1554 | 10 | emit_pop_stack(emit, end_pc); | |
| 1555 | 10 | regpop(emit, SZ_INT); | |
| 1556 | 10 | return ret; | |
| 1557 | } | ||
| 1558 | |||
| 1559 | 7 | ANN static m_bool _emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt, m_uint *index) { | |
| 1560 | ✗✓ | 7 | CHECK_BB(emit_exp_pop_next(emit, stmt->cond)) | 
| 1561 | 7 | const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); | |
| 1562 | 7 | const Instr tomem = emit_add_instr(emit, Reg2Mem); | |
| 1563 | 7 | tomem->m_val = offset; | |
| 1564 | 7 | tomem->m_val2 = -SZ_INT; | |
| 1565 | 7 | regpop(emit, SZ_INT); | |
| 1566 | 7 | *index = emit_code_size(emit); | |
| 1567 | 7 | const Instr cpy = emit_add_instr(emit, RegPushMem4); | |
| 1568 | 7 | cpy->m_val = offset; | |
| 1569 | 7 | emit_add_instr(emit, int_post_dec); | |
| 1570 | 7 | const Instr op = emit_add_instr(emit, BranchEqInt); | |
| 1571 | ✗✓ | 7 | CHECK_BB(scoped_stmt(emit, stmt->body, 1)) | 
| 1572 | 7 | const Instr _goto = emit_add_instr(emit, Goto); | |
| 1573 | 7 | _goto->m_val = *index; | |
| 1574 | 7 | op->m_val = emit_code_size(emit); | |
| 1575 | 7 | return GW_OK; | |
| 1576 | } | ||
| 1577 | |||
| 1578 | 7 | ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { | |
| 1579 | 7 | emit_push_stack(emit); | |
| 1580 | 7 | m_uint index = 0; | |
| 1581 | 7 | const m_bool ret = _emit_stmt_loop(emit, stmt, &index); | |
| 1582 | 7 | emit_pop_stack(emit, index); | |
| 1583 | 7 | return ret; | |
| 1584 | } | ||
| 1585 | |||
| 1586 | 8 | ANN static m_bool emit_stmt_jump(const Emitter emit, const Stmt_Jump stmt) { | |
| 1587 | ✓✓ | 8 | if(!stmt->is_label) | 
| 1588 | 3 | stmt->data.instr = emit_add_instr(emit, Goto); | |
| 1589 |   else { | ||
| 1590 | assert(stmt->data.v.ptr); | ||
| 1591 | 5 | const m_uint size = vector_size(&stmt->data.v); | |
| 1592 | ✓✓ | 5 | if(!size) | 
| 1593 | //return GW_OK; | ||
| 1594 | 1 |       ERR_B(stmt_self(stmt)->pos, _("label '%s' defined but not used."), s_name(stmt->name)) | |
| 1595 | LOOP_OPTIM | ||
| 1596 | ✓✓ | 11 |     for(m_uint i = size + 1; --i;) { | 
| 1597 | 4 | const Stmt_Jump label = (Stmt_Jump)vector_at(&stmt->data.v, i - 1); | |
| 1598 | ✓✓ | 4 | if(!label->data.instr) | 
| 1599 | 1 |         ERR_B(stmt_self(label)->pos, _("you are trying to use a upper label.")) | |
| 1600 | 3 | label->data.instr->m_val = emit_code_size(emit); | |
| 1601 | } | ||
| 1602 | } | ||
| 1603 | 6 | return GW_OK; | |
| 1604 | } | ||
| 1605 | |||
| 1606 | 15 | ANN static m_bool emit_type_def(const Emitter emit, const Type_Def tdef) { | |
| 1607 | ✓✓ | 15 | return tdef->type->e->def ? emit_class_def(emit, tdef->type->e->def) : GW_OK; | 
| 1608 | } | ||
| 1609 | |||
| 1610 | 5 | ANN static m_bool emit_enum_def(const Emitter emit, const Enum_Def edef) { | |
| 1611 | LOOP_OPTIM | ||
| 1612 | ✓✓ | 18 |   for(m_uint i = 0; i < vector_size(&edef->values); ++i) { | 
| 1613 | 13 | const Value v = (Value)vector_at(&edef->values, i); | |
| 1614 | ✓✓ | 13 |     if(!emit->env->class_def) { | 
| 1615 | 7 | ALLOC_PTR(emit->gwion->mp, addr, m_uint, i); | |
| 1616 | 7 | v->from->offset = emit_local(emit, emit->gwion->type[et_int]); | |
| 1617 | 7 | v->d.ptr = addr; | |
| 1618 | } else | ||
| 1619 | 6 | *(m_bit*)(emit->env->class_def->nspc->info->class_data + v->from->offset) = i; | |
| 1620 | } | ||
| 1621 | 5 | return GW_OK; | |
| 1622 | } | ||
| 1623 | |||
| 1624 | 34 | ANN void emit_union_offset(Decl_List l, const m_uint o) { | |
| 1625 |   do { | ||
| 1626 | 34 | Var_Decl_List v = l->self->d.exp_decl.list; | |
| 1627 | 34 | do v->self->value->from->offset = o; | |
| 1628 | ✗✓ | 34 | while((v = v->next)); | 
| 1629 | ✓✓ | 34 | } while((l = l->next)); | 
| 1630 | 18 | } | |
| 1631 | |||
| 1632 | 10 | ANN static inline void union_allocdata(MemPool mp, const Union_Def udef) { | |
| 1633 | ✓✓ | 10 | const Nspc nspc = (udef->xid ? udef->value->type : udef->type)->nspc; | 
| 1634 | 10 | nspc_allocdata(mp, nspc); | |
| 1635 | 10 | nspc->info->offset = udef->s; | |
| 1636 | 10 | } | |
| 1637 | |||
| 1638 | 18 | ANN static m_bool emit_union_def(const Emitter emit, const Union_Def udef) { | |
| 1639 | ✓✓ | 18 | if(tmpl_base(udef->tmpl)) | 
| 1640 | 3 | return GW_OK; | |
| 1641 | 15 | Decl_List l = udef->l; | |
| 1642 | 15 | m_uint scope = emit->env->scope->depth; | |
| 1643 | 15 | const m_bool global = GET_FLAG(udef, global); | |
| 1644 | ✓✓ | 15 |   if(udef->xid) { | 
| 1645 | 6 | union_allocdata(emit->gwion->mp, udef); | |
| 1646 | 12 | Type_Decl *type_decl = new_type_decl(emit->gwion->mp, | |
| 1647 | 6 | udef->xid, loc_cpy(emit->gwion->mp, udef->pos)); | |
| 1648 | 6 | type_decl->flag = udef->flag; | |
| 1649 | 6 | const Var_Decl var_decl = new_var_decl(emit->gwion->mp, udef->xid, NULL, loc_cpy(emit->gwion->mp, udef->pos)); | |
| 1650 | 6 | const Var_Decl_List var_decl_list = new_var_decl_list(emit->gwion->mp, var_decl, NULL); | |
| 1651 | 6 | const Exp exp = new_exp_decl(emit->gwion->mp, type_decl, var_decl_list); | |
| 1652 | 6 | exp->d.exp_decl.type = udef->value->type; | |
| 1653 | 6 | var_decl->value = udef->value; | |
| 1654 | 6 | const m_bool ret = emit_exp_decl(emit, &exp->d.exp_decl); | |
| 1655 | 6 | free_exp(emit->gwion->mp, exp); | |
| 1656 | ✗✓ | 6 | CHECK_BB(ret) | 
| 1657 | ✓✓ | 6 |     if(global) { | 
| 1658 | 1 | const M_Object o = new_object(emit->gwion->mp, NULL, udef->value->type); | |
| 1659 | 1 | udef->value->d.ptr = (m_uint*)o; | |
| 1660 | 1 | SET_FLAG(udef->value, builtin); | |
| 1661 | 1 | UNSET_FLAG(udef->value, union); | |
| 1662 | } | ||
| 1663 | 6 | scope = emit_push_type(emit, udef->value->type); | |
| 1664 | ✓✓ | 9 |   } else if(udef->type_xid) { | 
| 1665 | 4 | union_allocdata(emit->gwion->mp, udef); | |
| 1666 | 4 | scope = emit_push_type(emit, udef->type); | |
| 1667 | ✓✓ | 5 |   } else if(global) { | 
| 1668 | // TODO: use mpool allocation | ||
| 1669 | 1 | void* ptr = (void*)xcalloc(1, udef->s); | |
| 1670 | 1 | l = udef->l; | |
| 1671 | 1 | udef->value->d.ptr = ptr; | |
| 1672 | 1 | SET_FLAG(udef->value, enum); | |
| 1673 | 1 | SET_FLAG(udef->value, dtor); | |
| 1674 |     do { | ||
| 1675 | 2 | Var_Decl_List list = l->self->d.exp_decl.list; | |
| 1676 | 2 | list->self->value->d.ptr = ptr; | |
| 1677 | 2 | SET_FLAG(list->self->value, union); | |
| 1678 | ✓✓ | 2 | } while((l = l->next)); | 
| 1679 | 1 | SET_FLAG(udef->l->self->d.exp_decl.list->self->value, enum); | |
| 1680 | 1 | SET_FLAG(udef->l->self->d.exp_decl.list->self->value, dtor); | |
| 1681 | } | ||
| 1682 | ✓✓ | 15 | if(udef->xid) | 
| 1683 | 6 | regpop(emit, SZ_INT); | |
| 1684 | 15 | emit_union_offset(udef->l, udef->o); | |
| 1685 | ✓✓✓✓ ✓✓ | 15 | if(udef->xid || udef->type_xid || global) | 
| 1686 | 11 | emit_pop(emit, scope); | |
| 1687 | 15 | union_flag(udef, ae_flag_emit); | |
| 1688 | 15 | return GW_OK; | |
| 1689 | } | ||
| 1690 | |||
| 1691 | 1991 | ANN static m_bool emit_stmt_exp(const Emitter emit, const struct Stmt_Exp_* exp) { | |
| 1692 | ✓✓ | 1991 | return exp->val ? emit_exp(emit, exp->val) : GW_OK; | 
| 1693 | } | ||
| 1694 | |||
| 1695 | 7 | ANN static m_bool emit_case_head(const Emitter emit, const Exp base, | |
| 1696 |     const Exp e, const Symbol op, const Vector v) { | ||
| 1697 | ✗✓ | 7 | CHECK_BB(emit_exp(emit, base)) | 
| 1698 | ✗✓ | 7 | CHECK_BB(emit_exp_pop_next(emit, e)) | 
| 1699 | 7 | const m_int size = -exp_size(e); | |
| 1700 | 7 | emit_exp_addref(emit, base, -exp_totalsize(base) - size); | |
| 1701 | 7 | emit_exp_addref1(emit, e, -size); | |
| 1702 | 7 |   const Exp_Binary bin = { .lhs=base, .rhs=e, .op=op }; | |
| 1703 | 7 |   struct ExpInfo_ info = { .nspc=e->info->nspc }; | |
| 1704 | 7 |   struct Exp_ ebin = { .d={.exp_binary=bin}, .info=&info }; | |
| 1705 | 21 |   struct Op_Import opi = { .op=op, .lhs=base->info->type, .rhs=e->info->type, | |
| 1706 | 14 | .data=(uintptr_t)&ebin.d.exp_binary, .pos=e->pos, .op_type=op_binary }; | |
| 1707 | ✗✓ | 7 | CHECK_BB(op_emit_bool(emit, &opi)) | 
| 1708 | 7 | const Instr instr = emit_add_instr(emit, BranchEqInt); | |
| 1709 | 7 | vector_add(v, (vtype)instr); | |
| 1710 | 7 | return GW_OK; | |
| 1711 | } | ||
| 1712 | |||
| 1713 | 10 | ANN static m_bool emit_case_body(const Emitter emit, const struct Stmt_Match_* stmt) { | |
| 1714 | ✓✓ | 10 | const Instr when = stmt->when ? emit_flow(emit, stmt->when) : NULL; | 
| 1715 | ✓✓ | 10 | if(stmt->when) | 
| 1716 | ✗✓ | 4 | CHECK_OB(when) | 
| 1717 | ✗✓ | 10 | CHECK_BB(emit_stmt_list(emit, stmt->list)) | 
| 1718 | 10 | const Instr instr = emit_add_instr(emit, Goto); | |
| 1719 | 10 | vector_add(&emit->env->scope->match->vec, (vtype)instr); | |
| 1720 | ✓✓ | 10 | if(when) | 
| 1721 | 4 | when->m_val = emit_code_size(emit); | |
| 1722 | 10 | return GW_OK; | |
| 1723 | } | ||
| 1724 | |||
| 1725 | 1 | ANN static m_bool case_value(const Emitter emit, const Exp base, const Exp e) { | |
| 1726 | 1 | const Value v = e->d.prim.value; | |
| 1727 | 1 | v->from->offset = emit_local(emit, base->info->type); | |
| 1728 | ✗✓ | 1 | CHECK_BB(emit_exp(emit, base)) | 
| 1729 | 1 | emit_exp_addref(emit, base, -exp_totalsize(base)); | |
| 1730 | 1 | regpop(emit, base->info->type->size); | |
| 1731 | 1 | const Instr instr = emit_add_instr(emit, Reg2Mem4); | |
| 1732 | 1 | instr->m_val = v->from->offset; | |
| 1733 | 1 | instr->m_val2 = base->info->type->size; | |
| 1734 | 1 | return GW_OK; | |
| 1735 | } | ||
| 1736 | |||
| 1737 | |||
| 1738 | #define CASE_PASS (Symbol)1 | ||
| 1739 | 10 | ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e) { | |
| 1740 | ✓✗ | 10 |   if(e->exp_type == ae_exp_primary) { | 
| 1741 | ✓✓ | 10 |     if(e->d.prim.prim_type == ae_prim_id) { | 
| 1742 | ✓✓ | 3 |       if(e->d.prim.d.var == insert_symbol("_")) | 
| 1743 | 2 | return CASE_PASS; | |
| 1744 | ✓✗ | 1 |       if(!nspc_lookup_value1(emit->env->curr, e->d.prim.d.var)) { | 
| 1745 | ✗✓ | 1 | CHECK_BO(case_value(emit, base, e)) | 
| 1746 | 1 | return CASE_PASS; | |
| 1747 | } | ||
| 1748 | } | ||
| 1749 | } | ||
| 1750 | 7 |   return insert_symbol("=="); | |
| 1751 | } | ||
| 1752 | |||
| 1753 | 10 | ANN static m_bool _emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt, | |
| 1754 |     const Vector v) { | ||
| 1755 | 10 | Exp e = stmt->cond; | |
| 1756 | 10 | const Map map = &emit->env->scope->match->map; | |
| 1757 | ✓✓✓✗ | 20 |   for(m_uint i = 0; i < map_size(map) && e; e = e->next, ++i) { | 
| 1758 | 10 | const Exp base = (Exp)VKEY(map, i); | |
| 1759 | 10 | const Symbol op = case_op(emit, base, e); | |
| 1760 | ✓✓ | 10 | if(op != CASE_PASS) | 
| 1761 | ✗✓ | 7 | CHECK_BB(emit_case_head(emit, base, e, op, v)) | 
| 1762 | } | ||
| 1763 | ✗✓ | 10 | CHECK_BB(emit_case_body(emit, stmt)) | 
| 1764 | 10 | return GW_OK; | |
| 1765 | } | ||
| 1766 | |||
| 1767 | 10 | ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt) { | |
| 1768 | 10 | emit_push_scope(emit); | |
| 1769 | struct Vector_ v; | ||
| 1770 | 10 | vector_init(&v); | |
| 1771 | 10 | const m_bool ret = _emit_stmt_match_case(emit, stmt, &v); | |
| 1772 | 10 | emit_pop_scope(emit); | |
| 1773 | ✓✓ | 17 |   for(m_uint i = 0; i < vector_size(&v); ++i) { | 
| 1774 | 7 | const Instr instr = (Instr)vector_at(&v, i); | |
| 1775 | 7 | instr->m_val = emit_code_size(emit); | |
| 1776 | } | ||
| 1777 | 10 | vector_release(&v); | |
| 1778 | 10 | return ret; | |
| 1779 | } | ||
| 1780 | |||
| 1781 | 6 | ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) { | |
| 1782 | 6 | const Vector vec = &match->vec; | |
| 1783 | ✓✓ | 16 |   for(m_uint i = 0; i < vector_size(vec); ++i) { | 
| 1784 | 10 | const Instr instr = (Instr)VPTR(vec, i); | |
| 1785 | 10 | instr->m_val = pc; | |
| 1786 | } | ||
| 1787 | 6 | vector_release(vec); | |
| 1788 | 6 | } | |
| 1789 | |||
| 1790 | 10 | ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list) { | |
| 1791 | ✗✓ | 10 | do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match)) | 
| 1792 | ✓✓ | 10 | while((list = list->next)); | 
| 1793 | 6 | return GW_OK; | |
| 1794 | } | ||
| 1795 | |||
| 1796 | 6 | ANN static m_bool emit_match(const Emitter emit, const struct Stmt_Match_* stmt) { | |
| 1797 | ✓✓ | 6 | if(stmt->where) | 
| 1798 | ✗✓ | 2 | CHECK_BB(emit_stmt(emit, stmt->where, 1)) | 
| 1799 | 6 | MATCH_INI(emit->env->scope) | |
| 1800 | 6 | vector_init(&m.vec); | |
| 1801 | 6 | const m_bool ret = emit_stmt_cases(emit, stmt->list); | |
| 1802 | 6 | match_unvec(&m, emit_code_size(emit)); | |
| 1803 | 6 | MATCH_END(emit->env->scope) | |
| 1804 | 6 | return ret; | |
| 1805 | } | ||
| 1806 | |||
| 1807 | 6 | ANN static m_bool emit_stmt_match(const Emitter emit, const struct Stmt_Match_* stmt) { | |
| 1808 | 6 | emit_push_scope(emit); | |
| 1809 | 6 | const m_bool ret = emit_match(emit, stmt); | |
| 1810 | 6 | emit_pop_scope(emit); | |
| 1811 | 6 | return ret; | |
| 1812 | } | ||
| 1813 | |||
| 1814 | 1 | ANN static m_bool emit_stmt_pp(const Emitter emit, const struct Stmt_PP_* stmt) { | |
| 1815 | ✓✗ | 1 |   if(stmt->pp_type == ae_pp_pragma) { | 
| 1816 | ✓✗ | 1 |     if(!strncmp(stmt->data, "memoize", strlen("memoize"))) | 
| 1817 | 1 | emit->info->memoize = strtol(stmt->data + 7, NULL, 10); | |
| 1818 | } | ||
| 1819 | 1 | return GW_OK; | |
| 1820 | } | ||
| 1821 | |||
| 1822 | #define emit_stmt_while emit_stmt_flow | ||
| 1823 | #define emit_stmt_until emit_stmt_flow | ||
| 1824 | DECL_STMT_FUNC(emit, m_bool , Emitter) | ||
| 1825 | |||
| 1826 | 2524 | ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { | |
| 1827 | ✓✓ | 2524 | CHECK_BB(emit_stmt_func[stmt->stmt_type](emit, &stmt->d)) | 
| 1828 | ✓✓✓✓ ✓✓ | 2520 |   if(pop && stmt->stmt_type == ae_stmt_exp && stmt->d.stmt_exp.val) { | 
| 1829 | 1974 | pop_exp(emit, stmt->d.stmt_exp.val); | |
| 1830 | } | ||
| 1831 | 2520 | return GW_OK; | |
| 1832 | } | ||
| 1833 | |||
| 1834 | 2162 | ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List l) { | |
| 1835 | ✓✓ | 2162 | do CHECK_BB(emit_stmt(emit, l->stmt, 1)) | 
| 1836 | ✓✓ | 2158 | while((l = l->next)); | 
| 1837 | 858 | return GW_OK; | |
| 1838 | } | ||
| 1839 | |||
| 1840 | 526 | ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member) { | |
| 1841 | 2104 |   struct Op_Import opi = { .op=insert_symbol("@dot"), .lhs=member->t_base, | |
| 1842 | 1578 | .rhs=exp_self(member)->info->type, .data=(uintptr_t)member, .pos=exp_self(member)->pos, .op_type=op_dot }; | |
| 1843 | 526 | return op_emit_bool(emit, &opi); | |
| 1844 | } | ||
| 1845 | |||
| 1846 | 82 | ANN static inline void emit_func_def_global(const Emitter emit, const Value value) { | |
| 1847 | 82 | const Instr set_mem = emit_add_instr(emit, MemSetImm); | |
| 1848 | 82 | set_mem->m_val = value->from->offset; | |
| 1849 | 82 | set_mem->m_val2 = (m_uint)value->d.func_ref->code; | |
| 1850 | 82 | } | |
| 1851 | |||
| 1852 | 221 | ANN static void emit_func_def_init(const Emitter emit, const Func func) { | |
| 1853 | 221 | const Type t = emit->env->class_def; | |
| 1854 | ✓✓ | 221 | char c[(t ? strlen(t->name) + 1 : 0) + strlen(func->name) + 6]; | 
| 1855 | ✓✓✓✓ | 221 | sprintf(c, "%s%s%s(...)", t ? t->name : "", t ? "." : "", func->name); | 
| 1856 | 221 | emit_push_code(emit, c); | |
| 1857 | 221 | } | |
| 1858 | |||
| 1859 | 157 | ANN static void emit_func_def_args(const Emitter emit, Arg_List a) { | |
| 1860 |   do { | ||
| 1861 | 157 | const Type type = a->var_decl->value->type; | |
| 1862 | 157 | emit->code->stack_depth += type->size; | |
| 1863 | 157 | a->var_decl->value->from->offset = emit_local(emit, type); | |
| 1864 | ✓✓ | 157 | } while((a = a->next)); | 
| 1865 | 122 | } | |
| 1866 | |||
| 1867 | 221 | ANN static void emit_func_def_ensure(const Emitter emit, const Func_Def fdef) { | |
| 1868 | 221 | const m_uint size = fdef->base->ret_type->size; | |
| 1869 | ✓✓ | 221 |   if(size) { | 
| 1870 | 68 | const Instr instr = emit_kind(emit, size, 0, regpushimm); | |
| 1871 | 68 | instr->m_val2 = size; | |
| 1872 | } | ||
| 1873 | 221 | vector_add(&emit->code->stack_return, (vtype)emit_add_instr(emit, Goto)); | |
| 1874 | 221 | } | |
| 1875 | |||
| 1876 | 221 | ANN static void emit_func_def_return(const Emitter emit) { | |
| 1877 | 221 | const m_uint val = emit_code_size(emit); | |
| 1878 | LOOP_OPTIM | ||
| 1879 | ✓✓ | 700 |   for(m_uint i = vector_size(&emit->code->stack_return) + 1; --i; ) { | 
| 1880 | 258 | const Instr instr = (Instr)vector_at(&emit->code->stack_return, i-1); | |
| 1881 | 258 | instr->m_val = val; | |
| 1882 | } | ||
| 1883 | 221 | vector_clear(&emit->code->stack_return); | |
| 1884 | ✓✓✓✗ | 221 |   if(emit->info->memoize && GET_FLAG(emit->env->func, pure)) { | 
| 1885 | 1 | const Instr instr = emit_add_instr(emit, MemoizeStore); | |
| 1886 | 1 | instr->m_val = emit->env->func->def->stack_depth; | |
| 1887 | } | ||
| 1888 | 221 | } | |
| 1889 | |||
| 1890 | 11 | ANN static VM_Code emit_internal(const Emitter emit, const Func f) { | |
| 1891 | ✓✓ | 11 |   if(f->def->base->xid == insert_symbol("@dtor")) { | 
| 1892 | 6 | emit->env->class_def->nspc->dtor = f->code = finalyze(emit, DTOR_EOC); | |
| 1893 | 6 | ADD_REF(f->code) | |
| 1894 | 6 | return f->code; | |
| 1895 | ✓✓ | 5 |   } else if(f->def->base->xid == insert_symbol("@gack")) { | 
| 1896 | 2 | regpop(emit, SZ_INT + f->value_ref->from->owner_class->size); | |
| 1897 | 2 | const Instr instr = emit_add_instr(emit, RegPushMem); | |
| 1898 | 2 | instr->m_val = SZ_INT; | |
| 1899 | 2 | f->code = finalyze(emit, FuncReturn); | |
| 1900 | 2 | return emit->env->class_def->e->gack = f->code; | |
| 1901 | } | ||
| 1902 | 3 | return finalyze(emit, FuncReturn); | |
| 1903 | } | ||
| 1904 | |||
| 1905 | 221 | ANN static VM_Code emit_func_def_code(const Emitter emit, const Func func) { | |
| 1906 | ✓✓ | 221 | if(GET_FLAG(func->def, typedef)) | 
| 1907 | 11 | return emit_internal(emit, func); | |
| 1908 | else | ||
| 1909 | 210 | return finalyze(emit, FuncReturn); | |
| 1910 | } | ||
| 1911 | |||
| 1912 | 221 | ANN static m_bool emit_func_def_body(const Emitter emit, const Func_Def fdef) { | |
| 1913 | ✓✓ | 221 | if(fdef->base->args) | 
| 1914 | 122 | emit_func_def_args(emit, fdef->base->args); | |
| 1915 | ✓✓ | 221 | if(GET_FLAG(fdef, variadic)) | 
| 1916 | 8 | stack_alloc(emit); | |
| 1917 | ✓✗ | 221 | if(fdef->d.code) | 
| 1918 | ✗✓ | 221 | CHECK_BB(scoped_stmt(emit, fdef->d.code, 1)) | 
| 1919 | 221 | emit_func_def_ensure(emit, fdef); | |
| 1920 | 221 | return GW_OK; | |
| 1921 | } | ||
| 1922 | |||
| 1923 | 1 | ANN static Instr me_top(MemoizeEmitter *me) { | |
| 1924 | 1 | const Instr idx = emit_add_instr(me->emit, MemSetImm); | |
| 1925 | 1 | idx->m_val = me->offset; | |
| 1926 | 1 | const Instr pc = emit_add_instr(me->emit, MemSetImm); | |
| 1927 | 1 | pc->m_val = me->offset + SZ_INT; | |
| 1928 | 1 | return pc; | |
| 1929 | } | ||
| 1930 | |||
| 1931 | 1 | ANN static void me_ini(MemoizeEmitter *me) { | |
| 1932 | 1 | const Instr ini = emit_add_instr(me->emit, MemoizeIni); | |
| 1933 | 1 | ini->m_val = me->offset; | |
| 1934 | 1 | ini->m_val2 = me->fdef->stack_depth + me->fdef->base->ret_type->size; | |
| 1935 | 1 | } | |
| 1936 | |||
| 1937 | 1 | ANN static void me_end(MemoizeEmitter *me, const m_uint pc) { | |
| 1938 | ✓✓ | 2 | for(m_uint i = 0; i < vector_size(&me->branch); ++i) | 
| 1939 | 1 | ((Instr)vector_at(&me->branch, i))->m_val = pc; | |
| 1940 | 1 | } | |
| 1941 | |||
| 1942 | 1 | ANN static void me_bottom(MemoizeEmitter *me, const m_uint pc) { | |
| 1943 | 1 | const Instr idx = emit_add_instr(me->emit, RegPushMem4); | |
| 1944 | 1 | idx->m_val = me->offset; | |
| 1945 | 1 | emit_add_instr(me->emit, int_pre_inc); | |
| 1946 | 1 | regpop(me->emit, SZ_INT); | |
| 1947 | 1 | const Instr loop = emit_add_instr(me->emit, Goto); | |
| 1948 | 1 | loop->m_val = pc; | |
| 1949 | 1 | } | |
| 1950 | |||
| 1951 | 1 | ANN static void me_ret(MemoizeEmitter *me) { | |
| 1952 | 1 | const Instr instr = emit_kind(me->emit, me->fdef->base->ret_type->size, 0, regpushmem); | |
| 1953 | 1 | instr->m_val = (me->offset + SZ_INT)*2; | |
| 1954 | 1 | emit_add_instr(me->emit, FuncReturn); | |
| 1955 | 1 | } | |
| 1956 | |||
| 1957 | 1 | ANN static m_bool me_run(MemoizeEmitter *me, const m_uint pc) { | |
| 1958 | 1 | me_ini(me); | |
| 1959 | ✓✗ | 1 | if(me->fdef->base->args) | 
| 1960 | ✗✓ | 1 | CHECK_BB(me_arg(me)) | 
| 1961 | 1 | me_ret(me); | |
| 1962 | 1 | me_end(me, emit_code_size(me->emit)); | |
| 1963 | 1 | me_bottom(me, pc); | |
| 1964 | 1 | return GW_OK; | |
| 1965 | } | ||
| 1966 | |||
| 1967 | 1 | ANN static m_bool emit_memoize(const Emitter emit, const Func_Def fdef) { | |
| 1968 | 1 |   MemoizeEmitter me = { .emit=emit, .fdef=fdef, .offset=fdef->stack_depth }; | |
| 1969 | 1 | const Instr pc = me_top(&me); | |
| 1970 | 1 | const m_uint top = emit_code_size(emit); | |
| 1971 | 1 | vector_init(&me.branch); | |
| 1972 | 1 | const m_bool ret = me_run(&me, top); | |
| 1973 | 1 | vector_release(&me.branch); | |
| 1974 | 1 | pc->m_val2 = emit_code_size(emit); | |
| 1975 | 1 | return ret; | |
| 1976 | } | ||
| 1977 | |||
| 1978 | 221 | ANN static m_bool emit_fdef(const Emitter emit, const Func_Def fdef) { | |
| 1979 | ✓✓✓✗ | 221 | if(emit->info->memoize && GET_FLAG(fdef->base->func, pure)) | 
| 1980 | ✗✓ | 1 | CHECK_BB(emit_memoize(emit, fdef)) | 
| 1981 | ✗✓ | 221 | CHECK_BB(emit_func_def_body(emit, fdef)) | 
| 1982 | 221 | emit_func_def_return(emit); | |
| 1983 | 221 | return GW_OK; | |
| 1984 | } | ||
| 1985 | |||
| 1986 | 442 | static ANN int fdef_is_file_global(const Emitter emit, const Func_Def fdef) { | |
| 1987 | ✓✓ | 868 | return isa(fdef->base->func->value_ref->type, emit->gwion->type[et_lambda]) < 0 && | 
| 1988 | ✓✓✓✓ ✓✓✓✓ | 826 | !emit->env->class_def && !GET_FLAG(fdef, global) && !fdef->base->tmpl && | 
| 1989 | 166 | !emit->env->scope->depth; | |
| 1990 | } | ||
| 1991 | |||
| 1992 | 221 | ANN static void emit_fdef_finish(const Emitter emit, const Func_Def fdef) { | |
| 1993 | 221 | const Func func = fdef->base->func; | |
| 1994 | 221 | func->code = emit_func_def_code(emit, func); | |
| 1995 | ✓✓ | 221 | if(fdef_is_file_global(emit, fdef)) | 
| 1996 | 82 | emit_func_def_global(emit, func->value_ref); | |
| 1997 | ✓✓✓✗ | 221 | if(emit->info->memoize && GET_FLAG(func, pure)) | 
| 1998 | 1 | func->code->memoize = memoize_ini(emit, func); | |
| 1999 | 221 | } | |
| 2000 | |||
| 2001 | 264 | ANN static m_bool emit_func_def(const Emitter emit, const Func_Def f) { | |
| 2002 | 264 | const Func func = f->base->func; | |
| 2003 | 264 | const Func_Def fdef = func->def; | |
| 2004 | 264 | const Func former = emit->env->func; | |
| 2005 | ✓✓✓✓ | 264 | if(func->code || tmpl_base(fdef->base->tmpl)) | 
| 2006 | 43 | return GW_OK; | |
| 2007 | ✓✓✗✓ ✗✗ | 221 | if(SAFE_FLAG(emit->env->class_def, builtin) && GET_FLAG(emit->env->class_def, template)) | 
| 2008 | return GW_OK; | ||
| 2009 | ✓✓ | 221 | if(fdef_is_file_global(emit, fdef)) | 
| 2010 | 82 | func->value_ref->from->offset = emit_local(emit, emit->gwion->type[et_int]); | |
| 2011 | 221 | emit_func_def_init(emit, func); | |
| 2012 | ✓✓ | 221 | if(GET_FLAG(func, member)) | 
| 2013 | 92 | stack_alloc_this(emit); | |
| 2014 | 221 | emit->env->func = func; | |
| 2015 | 221 | emit_push_scope(emit); | |
| 2016 | ✓✓ | 221 |   if(!strcmp(s_name(fdef->base->xid), "@gack")) { | 
| 2017 | 2 | emit_local(emit, emit->gwion->type[et_int]); | |
| 2018 | 2 | const Instr instr = emit_add_instr(emit, MemSetImm); | |
| 2019 | 2 | instr->m_val = SZ_INT; | |
| 2020 | } | ||
| 2021 | 221 | const m_bool ret = scanx_fdef(emit->env, emit, fdef, (_exp_func)emit_fdef); | |
| 2022 | 221 | emit_pop_scope(emit); | |
| 2023 | 221 | emit->env->func = former; | |
| 2024 | ✓✗ | 221 | if(ret > 0) | 
| 2025 | 221 | emit_fdef_finish(emit, fdef); | |
| 2026 | else | ||
| 2027 | emit_pop_code(emit); | ||
| 2028 | 221 | return ret; | |
| 2029 | } | ||
| 2030 | |||
| 2031 | #define emit_fptr_def dummy_func | ||
| 2032 | 932 | HANDLE_SECTION_FUNC(emit, m_bool, Emitter) | |
| 2033 | |||
| 2034 | 139 | ANN Code* emit_class_code(const Emitter emit, const m_str name) { | |
| 2035 | 139 | const m_uint len = strlen(name) + 7; | |
| 2036 | 139 | char c[len]; | |
| 2037 | 139 | snprintf(c, len, "class %s", name); | |
| 2038 | 139 | emit_push_code(emit, c); | |
| 2039 | 139 | stack_alloc_this(emit); | |
| 2040 | 139 | return emit->code; | |
| 2041 | } | ||
| 2042 | |||
| 2043 | 6 | ANN static m_bool emit_parent(const Emitter emit, const Class_Def cdef) { | |
| 2044 | 6 | const Type parent = cdef->base.type->e->parent; | |
| 2045 | ✓✗ | 6 | return !GET_FLAG(parent, emit) ? ensure_emit(emit, parent) : GW_OK; | 
| 2046 | } | ||
| 2047 | |||
| 2048 | 30 | ANN static inline m_bool emit_cdef(const Emitter emit, const Class_Def cdef) { | |
| 2049 | 30 | return scanx_cdef(emit->env, emit, cdef, | |
| 2050 | (_exp_func)emit_class_def, (_exp_func)emit_union_def); | ||
| 2051 | } | ||
| 2052 | |||
| 2053 | 139 | ANN void emit_class_finish(const Emitter emit, const Nspc nspc) { | |
| 2054 | 139 | nspc->pre_ctor = finalyze(emit, FuncReturn); | |
| 2055 | 139 | SET_FLAG(nspc->pre_ctor, ctor); | |
| 2056 | 139 | } | |
| 2057 | |||
| 2058 | 6 | ANN static m_bool cdef_parent(const Emitter emit, const Class_Def cdef) { | |
| 2059 | ✓✓✓✗ | 6 | if(cdef->base.tmpl && cdef->base.tmpl->list) | 
| 2060 | ✗✓ | 4 | CHECK_BB(template_push_types(emit->env, cdef->base.tmpl)) | 
| 2061 | 6 | const m_bool ret = emit_parent(emit, cdef); | |
| 2062 | ✓✓✓✗ | 6 | if(cdef->base.tmpl && cdef->base.tmpl->list) | 
| 2063 | 4 | nspc_pop_type(emit->gwion->mp, emit->env->curr); | |
| 2064 | 6 | return ret; | |
| 2065 | } | ||
| 2066 | |||
| 2067 | 182 | ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { | |
| 2068 | ✓✓ | 182 | if(tmpl_base(cdef->base.tmpl)) | 
| 2069 | 19 | return GW_OK; | |
| 2070 | 163 | const Type t = cdef->base.type; | |
| 2071 | ✗✓ | 163 | if(GET_FLAG(t, emit)) | 
| 2072 | return GW_OK; | ||
| 2073 | 163 | SET_FLAG(t, emit); | |
| 2074 | ✓✓✗✓ | 163 | if(t->e->owner_class && !GET_FLAG(t->e->owner_class, emit)) | 
| 2075 | CHECK_BB(ensure_emit(emit, t->e->owner_class)) | ||
| 2076 | ✓✓✓✓ ✓✓ | 163 | if(cdef->base.ext && t->e->parent->e->def && !GET_FLAG(t->e->parent, emit)) | 
| 2077 | ✗✓ | 6 | CHECK_BB(cdef_parent(emit, cdef)) | 
| 2078 | 163 | nspc_allocdata(emit->gwion->mp, t->nspc); | |
| 2079 | ✓✓ | 163 |   if(cdef->body) { | 
| 2080 | 139 | emit_class_code(emit, t->name); | |
| 2081 | ✓✗ | 139 | if(scanx_body(emit->env, cdef, (_exp_func)emit_section, emit) > 0) | 
| 2082 | 139 | emit_class_finish(emit, t->nspc); | |
| 2083 |     else { | ||
| 2084 | free_code(emit->gwion->mp, emit->code); | ||
| 2085 | emit_pop_code(emit); | ||
| 2086 | return GW_ERROR; | ||
| 2087 | } | ||
| 2088 | } | ||
| 2089 | 163 | return GW_OK; | |
| 2090 | } | ||
| 2091 | |||
| 2092 | 4 | ANN static inline void emit_free_code(const Emitter emit, Code* code) { | |
| 2093 | ✓✓ | 4 | if(vector_size(&code->instr)) | 
| 2094 | 2 | free_code_instr(&code->instr, emit->gwion); | |
| 2095 | 4 | free_code(emit->gwion->mp, code); | |
| 2096 | 4 | } | |
| 2097 | |||
| 2098 | 4 | ANN static VM_Code emit_free_stack(const Emitter emit) { | |
| 2099 | LOOP_OPTIM | ||
| 2100 | ✗✓ | 8 | for(m_uint i = vector_size(&emit->stack) + 1; --i;) | 
| 2101 | emit_free_code(emit, (Code*)vector_at(&emit->stack, i - 1)); | ||
| 2102 | 4 | vector_clear(&emit->stack); | |
| 2103 | 4 | vector_clear(&emit->info->pure); | |
| 2104 | 4 | emit_free_code(emit, emit->code); | |
| 2105 | 4 | return NULL; | |
| 2106 | } | ||
| 2107 | |||
| 2108 | 667 | ANN static inline m_bool emit_ast_inner(const Emitter emit, Ast ast) { | |
| 2109 | ✓✓ | 667 | do CHECK_BB(emit_section(emit, ast->section)) | 
| 2110 | ✓✓ | 663 | while((ast = ast->next)); | 
| 2111 | 397 | return GW_OK; | |
| 2112 | } | ||
| 2113 | |||
| 2114 | 401 | ANN m_bool emit_ast(const Env env, Ast ast) { | |
| 2115 | 401 | const Emitter emit = env->gwion->emit; | |
| 2116 | 401 | emit->info->memoize = 0; | |
| 2117 | 401 | emit->code = new_code(emit, emit->env->name); | |
| 2118 | 401 | emit_push_scope(emit); | |
| 2119 | 401 | const m_bool ret = emit_ast_inner(emit, ast); | |
| 2120 | 401 | emit_pop_scope(emit); | |
| 2121 | ✓✓ | 401 | if(ret > 0) | 
| 2122 | 397 | emit->info->code = finalyze(emit, emit->info->finalyzer); | |
| 2123 | else | ||
| 2124 | 4 | emit_free_stack(emit); | |
| 2125 | 401 | return ret; | |
| 2126 | } | 
| Generated by: GCOVR (Version 4.2) |