From ddb99b8329b4158dc513503b9ed20896f17f8885 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Mon, 14 Dec 2020 16:28:30 +0100 Subject: [PATCH] :art: Add Union.is() --- include/opcode.h | 4 +++ opcode.txt | 2 ++ src/lib/object.c | 32 ++++++++++---------- src/lib/union.c | 76 ++++++++++++++++++++++++++++++++++------------- src/parse/check.c | 5 ++-- src/parse/scan1.c | 4 +-- src/vm/vm.c | 12 +++++++- 7 files changed, 94 insertions(+), 41 deletions(-) diff --git a/include/opcode.h b/include/opcode.h index 4385852b..3a698a5b 100644 --- a/include/opcode.h +++ b/include/opcode.h @@ -163,6 +163,8 @@ enum { eDotMember2, eDotMember3, eDotMember4, + eUnionSet, + eUnionCheck, eDotStatic, eDotStatic2, eDotStatic3, @@ -346,6 +348,8 @@ enum { #define DotMember2 (f_instr)eDotMember2 #define DotMember3 (f_instr)eDotMember3 #define DotMember4 (f_instr)eDotMember4 +#define UnionSet (f_instr)eUnionSet +#define UnionCheck (f_instr)eUnionCheck #define DotStatic (f_instr)eDotStatic #define DotStatic2 (f_instr)eDotStatic2 #define DotStatic3 (f_instr)eDotStatic3 diff --git a/opcode.txt b/opcode.txt index 18d94e12..3392b39a 100644 --- a/opcode.txt +++ b/opcode.txt @@ -160,6 +160,8 @@ DotMember DotMember2 DotMember3 DotMember4 +UnionSet +UnionCheck DotStatic DotStatic2 DotStatic3 diff --git a/src/lib/object.c b/src/lib/object.c index 1a9fec85..c4a02a64 100644 --- a/src/lib/object.c +++ b/src/lib/object.c @@ -66,22 +66,24 @@ ANN void __release(const M_Object o, const VM_Shred shred) { MemPool p = shred->info->mp; Type t = o->type_ref; do { - if(!t->nspc || isa(t, shred->info->vm->gwion->type[et_union]) > 0) + if(!t->nspc) continue; - struct scope_iter iter = { t->nspc->info->value, 0, 0 };\ - Value v; - while(scope_iter(&iter, &v) > 0) { - if(!GET_FLAG(v, static) && !vflag(v, vflag_union) && - isa(v->type, shred->info->vm->gwion->type[et_object]) > 0) - release(*(M_Object*)(o->data + v->from->offset), shred); - else if(tflag(v->type, tflag_struct) && - !GET_FLAG(v, static) && !vflag(v, vflag_union) && v->type->info->tuple) { - const TupleForm tf = v->type->info->tuple; - for(m_uint i = 0; i < vector_size(&tf->types); ++i) { - const m_bit *data = o->data + v->from->offset; - const Type t = (Type)vector_at(&tf->types, i); - if(isa(t, shred->info->vm->gwion->type[et_object]) > 0) - release(*(M_Object*)(data + vector_at(&tf->offset, i)), shred); + if(isa(t, shred->info->vm->gwion->type[et_union]) > 0) { + struct scope_iter iter = { t->nspc->info->value, 0, 0 };\ + Value v; + while(scope_iter(&iter, &v) > 0) { + if(!GET_FLAG(v, static) && !vflag(v, vflag_union) && + isa(v->type, shred->info->vm->gwion->type[et_object]) > 0) + release(*(M_Object*)(o->data + v->from->offset), shred); + else if(tflag(v->type, tflag_struct) && + !GET_FLAG(v, static) && !vflag(v, vflag_union) && v->type->info->tuple) { + const TupleForm tf = v->type->info->tuple; + for(m_uint i = 0; i < vector_size(&tf->types); ++i) { + const m_bit *data = o->data + v->from->offset; + const Type t = (Type)vector_at(&tf->types, i); + if(isa(t, shred->info->vm->gwion->type[et_object]) > 0) + release(*(M_Object*)(data + vector_at(&tf->offset, i)), shred); + } } } } diff --git a/src/lib/union.c b/src/lib/union.c index 1a33a181..fa8e7b42 100644 --- a/src/lib/union.c +++ b/src/lib/union.c @@ -16,31 +16,30 @@ static GACK(gack_none) { INTERP_PRINTF("None") } -static INSTR(UnionSet) { - const M_Object o = *(M_Object*)REG(-SZ_INT); - *(m_uint*)o->data = instr->m_val; - memcpy(o->data + SZ_INT, REG(-SZ_INT-instr->m_val2), instr->m_val2); - *(m_bit**)REG(-SZ_INT) = o->data + SZ_INT; -} +static const f_instr dotmember[] = { DotMember, DotMember2, DotMember3, DotMember4 }; -static INSTR(UnionCheck) { - const M_Object o = *(M_Object*)REG(-SZ_INT); - if(*(m_uint*)o->data != instr->m_val) - Except(shred, _("invalid union access")) - POP_REG(shred, SZ_INT - instr->m_val2); - memcpy(REG(-instr->m_val2), o->data + SZ_INT, instr->m_val2); -} +ANN Instr emit_kind(Emitter emit, const m_uint size, const uint addr, const f_instr func[]); static OP_EMIT(opem_union_dot) { const Exp_Dot *member = (Exp_Dot*)data; const Map map = &member->t_base->nspc->info->value->map; + CHECK_BO(emit_exp(emit, member->base)) + if(isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0) { + const Instr instr = emit_add_instr(emit, RegPushImm); + const Func f = (Func)vector_front(&member->t_base->info->parent->nspc->info->vtable); + instr->m_val = (m_uint)f->code; + return instr; + } for(m_uint i = 0; i < map_size(map); ++i) { if(VKEY(map, i) == (m_uint)member->xid) { - CHECK_BO(emit_exp(emit, member->base)) - const Instr instr = emit_add_instr(emit, - !exp_getvar(exp_self(member)) ? UnionCheck : UnionSet); - instr->m_val = i + 1; - instr->m_val2 = ((Value)VVAL(map, i))->type->size; + const Value v = (Value)VVAL(map, i); + const uint emit_addr = exp_getvar(exp_self(member)); + const Instr pre = emit_add_instr(emit, + !emit_addr ? UnionCheck : UnionSet); + pre->m_val = i + 1; + const Instr instr = emit_kind(emit, v->type->size, emit_addr, dotmember); + instr->m_val = SZ_INT; + instr->m_val2 = v->type->size; return instr; } } @@ -50,10 +49,37 @@ static OP_EMIT(opem_union_dot) { static DTOR(UnionDtor) { const m_uint idx = *(m_uint*)o->data; if(idx) { - const Type t = *(Type*)(o->type_ref->nspc->info->class_data + (idx-1) * SZ_INT); - if(isa(t, shred->info->vm->gwion->type[et_compound]) > 0) - compound_release(shred, t, (o->data + SZ_INT)); + const Map map = &o->type_ref->nspc->info->value->map; + const Value v = (Value)map_at(map, idx-1); + if(isa(v->type, shred->info->vm->gwion->type[et_compound]) > 0) + compound_release(shred, v->type, (o->data + SZ_INT)); + } +} + +static OP_CHECK(opck_union_is) { + const Exp e = (Exp)data; + const Exp_Call *call = &e->d.exp_call; + const Exp exp = call->args; + if(exp->exp_type != ae_exp_primary && exp->d.prim.prim_type != ae_prim_id) + ERR_N(exp->pos, "Union.is() argument must be of form id"); + const Type t = call->func->d.exp_dot.t_base; + const Value v = find_value(t, exp->d.prim.d.var); + if(!v) + ERR_N(exp->pos, "'%s' has no member '%s'", t->name, s_name(exp->d.prim.d.var)); + const Map map = &t->nspc->info->value->map; + for(m_uint i = 0; i < map_size(map); ++i) { + const Value v = (Value)VVAL(map, i); + if(!strcmp(s_name(exp->d.prim.d.var), v->name)) { + exp->d.prim.prim_type = ae_prim_num; + exp->d.prim.d.num = i+1; + return env->gwion->type[et_bool]; + } } + return env->gwion->type[et_error]; +} + +static MFUN(union_is) { + *(m_uint*)RETURN = *(m_uint*)MEM(SZ_INT) == *(m_uint*)o->data; } ANN GWION_IMPORT(union) { @@ -68,7 +94,15 @@ ANN GWION_IMPORT(union) { gwi_class_xtor(gwi, NULL, UnionDtor); GWI_BB(gwi_item_ini(gwi, "int", "@index")) GWI_BB(gwi_item_end(gwi, ae_flag_none, NULL)) + GWI_BB(gwi_func_ini(gwi, "bool", "is")) + GWI_BB(gwi_func_arg(gwi, "int", "member")) + GWI_BB(gwi_func_end(gwi, union_is, ae_flag_none)) GWI_BB(gwi_class_end(gwi)) + const Func f = (Func)vector_front(&t_union->nspc->info->vtable); + const struct Op_Func opfunc = { .ck=opck_union_is }; + const struct Op_Import opi = { .rhs=f->value_ref->type, + .func=&opfunc, .data=(uintptr_t)f, .pos=gwi->loc, .op=insert_symbol(gwi->gwion->st, "@func_check") }; + CHECK_BB(add_op(gwi->gwion, &opi)) gwi->gwion->type[et_union] = t_union; GWI_BB(gwi_oper_ini(gwi, "@Union", (m_str)OP_ANY_TYPE, NULL)) diff --git a/src/parse/check.c b/src/parse/check.c index 39108371..87324070 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -687,10 +687,11 @@ ANN static Type check_lambda_call(const Env env, const Exp_Call *exp) { ANN m_bool func_check(const Env env, const Exp_Call *exp) { CHECK_OB(check_exp(env, exp->func)) const Type t = actual_type(env->gwion, exp->func->info->type); + const Exp e = exp_self(exp); struct Op_Import opi = { .op=insert_symbol("@func_check"), - .rhs=t, .pos=exp_self(exp)->pos, .data=(uintptr_t)exp, .op_type=op_exp }; + .rhs=t, .pos=exp_self(exp)->pos, .data=(uintptr_t)e, .op_type=op_exp }; CHECK_NB(op_check(env, &opi)) // doesn't really return NULL - return exp_self(exp)->info->type != env->gwion->type[et_error] ? + return e->info->type != env->gwion->type[et_error] ? GW_OK : GW_ERROR; } diff --git a/src/parse/scan1.c b/src/parse/scan1.c index a91a7ec4..0d78487b 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -407,9 +407,9 @@ ANN static inline m_bool scan1_union_def_inner_loop(const Env env, Union_Def ude DECL_OB(const Type, t, = known_type(env, l->td)) if(nspc_lookup_value0(env->curr, l->xid)) ERR_B(l->pos, _("'%s' already declared in union"), s_name(l->xid)) -// check name -puts(env->curr->name); const Value v = new_value(env->gwion->mp, t, s_name(l->xid)); + if(!tflag(t, tflag_scan1)) + tuple_contains(env, v); v->from->offset = SZ_INT; valuefrom(env ,v->from); nspc_add_value_front(env->curr, l->xid, v); diff --git a/src/vm/vm.c b/src/vm/vm.c index ae258a3e..d010c946 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -323,6 +323,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto] &&arrayappend, &&autoloop, &&autoloopptr, &&autoloopcount, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid, &&newobj, &&addref, &&addrefaddr, &&objassign, &&assign, &&remref, &&except, &&allocmemberaddr, &&dotmember, &&dotfloat, &&dotother, &&dotaddr, + &&unionset, &&unioncheck, &&staticint, &&staticfloat, &&staticother, &&upvalueint, &&upvaluefloat, &&upvalueother, &&upvalueaddr, &&dotfunc, &&dotstaticfunc, @@ -757,7 +758,7 @@ arrayvalid: vector_pop(&shred->gc); goto regpush; newobj: - *(M_Object*)reg = new_object(vm->gwion->mp, shred, (Type)VAL2); + *(M_Object*)reg = new_object(vm->gwion->mp, NULL, (Type)VAL2); reg += SZ_INT; DISPATCH() addref: @@ -823,6 +824,15 @@ PRAGMA_POP() dotaddr: *(m_bit**)(reg-SZ_INT) = ((*(M_Object*)(reg-SZ_INT))->data + VAL); DISPATCH() +unionset: + *(m_uint*)(*(M_Object*)(reg-SZ_INT))->data = VAL; + DISPATCH() +unioncheck: + if(*(m_uint*)(*(M_Object*)(reg-SZ_INT))->data != VAL) { + exception(shred, "invalid union acces"); + continue; + } + DISPATCH() staticint: *(m_uint*)reg = *(m_uint*)VAL; reg += SZ_INT; -- 2.43.0