From ef1b0429e8f180e6eb650bc5f045275ccc72dfb3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Astor?= Date: Fri, 6 Mar 2020 03:06:35 +0100 Subject: [PATCH] :art: Unpack as a type --- src/emit/emit.c | 12 +-- src/lib/tuple.c | 104 ++++++++++++++++++- src/lib/vec.c | 4 + src/parse/check.c | 5 +- src/parse/scan1.c | 2 - tests/error/unused_unpack.gw | 2 +- tests/match/tuple.gw | 2 +- tests/tuple/tuple_skip.gw | 2 +- tests/tuple/tuple_unpack_already_declared.gw | 2 +- 9 files changed, 119 insertions(+), 16 deletions(-) diff --git a/src/emit/emit.c b/src/emit/emit.c index 126bde8c..289e9751 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -795,11 +795,11 @@ ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { } if(exp_call->args) CHECK_BB(emit_exp(emit, exp_call->args, 1)) - struct Op_Import opi = { .op=insert_symbol("@ctor"), .lhs=exp_call->func->type->e->d.base_type, .data=(uintptr_t)exp_call, .pos=exp_self(exp_call)->pos }; - CHECK_OB(op_emit(emit, &opi)) - const Exp e = exp_self(exp_call); - if(e->emit_var) - emit_vec_addr(emit, e->type->size); + struct Op_Import opi = { .op=insert_symbol("@ctor"), .lhs=exp_call->func->type->e->d.base_type, .data=(uintptr_t)exp_call, .pos=exp_self(exp_call)->pos }; + CHECK_OB(op_emit(emit, &opi)) + const Exp e = exp_self(exp_call); + if(e->emit_var) + emit_vec_addr(emit, e->type->size); return GW_OK; } @@ -1250,7 +1250,7 @@ DECL_EXP_FUNC(emit, m_bool, Emitter) ANN2(1) static m_bool emit_exp(const Emitter emit, Exp exp, const m_bool ref) { do { - CHECK_BB(emit_exp_func[exp->exp_type](emit, &exp->d)) + CHECK_BB(emit_exp_func[exp->exp_type](emit, &exp->d)) if(ref && isa(exp->type, emit->gwion->type[et_object]) > 0) { const Instr instr = emit_add_instr(emit, RegAddRef); instr->m_val = exp->emit_var; diff --git a/src/lib/tuple.c b/src/lib/tuple.c index b7d2402d..fe0eb5d6 100644 --- a/src/lib/tuple.c +++ b/src/lib/tuple.c @@ -34,7 +34,6 @@ struct UnpackInfo_ { static INSTR(TupleUnpack) { const M_Object o = *(M_Object*)(shred->reg - SZ_INT); struct UnpackInfo_ *info = (struct UnpackInfo_*)instr->m_val; -// memcpy(shred->mem + info->mem_offset, o->data + shred->info->vm->gwion->type[et_tuple]->nspc->info->offset + info->obj_offset, info->size); memcpy(shred->mem + info->mem_offset, o->data + info->obj_offset, info->size); } @@ -358,7 +357,8 @@ static OP_CHECK(opck_tuple) { static OP_CHECK(tuple_ck) { const Exp_Call *call = (Exp_Call*)data; const Exp exp = call->args; - CHECK_OO(check_exp(env, exp)) + if(exp) + CHECK_OO(check_exp(env, exp)) struct Vector_ v; vector_init(&v); Exp e = exp; @@ -376,6 +376,83 @@ static OP_EMIT(tuple_em) { return instr; } +static OP_CHECK(unpack_ck) { + const Exp_Call *call = (Exp_Call*)data; + const Symbol decl = insert_symbol("auto"); + const Symbol skip = insert_symbol("_"); + Exp e = call->args; +const Value v = nspc_lookup_value1(env->global_nspc, insert_symbol("false")); + while(e) { + if(e->exp_type != ae_exp_primary || e->d.prim.prim_type != ae_prim_id) + ERR_O(e->pos, _("invalid expression for unpack")) + if(e->d.prim.d.var != skip) { + const Symbol var = e->d.prim.d.var; + memset(&e->d, 0, sizeof(union exp_data)); +e->type = env->gwion->type[et_auto]; +e->d.exp_decl.type = env->gwion->type[et_auto]; + e->exp_type = ae_exp_decl; + e->d.exp_decl.td = new_type_decl(env->gwion->mp, new_id_list(env->gwion->mp, decl, loc_cpy(env->gwion->mp, e->pos))); + e->d.exp_decl.list = new_var_decl_list(env->gwion->mp, + new_var_decl(env->gwion->mp, var, NULL, loc_cpy(env->gwion->mp, e->pos)), NULL); +e->d.exp_decl.list->self->value = v; + } else { + e->d.prim.prim_type = ae_prim_nil; + e->type = env->gwion->type[et_null]; + } + e = e->next; + } + exp_self(call)->meta = ae_meta_var; + return call->func->type->e->d.base_type; +} + +static OP_EMIT(unpack_em) { + const Exp_Call *call = (Exp_Call*)data; + if(exp_self(call)->meta == ae_meta_value) + return (Instr)GW_OK; + env_err(emit->env, exp_self(call)->pos, _("unused Tuple unpack")); + return NULL; +} + +static OP_CHECK(opck_at_unpack) { + const Exp_Binary *bin = (Exp_Binary*)data; + Exp e = bin->rhs->d.exp_call.args; + int i = 0; + while(e) { + if(e->exp_type == ae_exp_decl) { + DECL_OO(const Type, t, = (Type)VPTR(&bin->lhs->type->e->tuple->types, i)) + e->d.exp_decl.td->xid->xid = insert_symbol(t->name); + const Exp next = e->next; + e->d.exp_decl.type = NULL; + e->next = NULL; + const m_bool ret = traverse_exp(env, e); + e->next = next; + CHECK_BO(ret) + bin->rhs->meta = ae_meta_value; + } + ++i; + e = e->next; + } + return bin->lhs->type; +} + +static OP_EMIT(opem_at_unpack) { + const Exp_Binary *bin = (Exp_Binary*)data; + if(bin->rhs->d.exp_call.args) { + const Type t_null = emit->gwion->type[et_null]; + Exp e = bin->rhs->d.exp_call.args; + m_uint sz = 0; + do if(e->type != t_null) + sz += e->type->size; + while((e = e->next)); + const Instr pop = emit_add_instr(emit, RegPop); + pop->m_val = sz; + const Vector v = &bin->lhs->type->e->tuple->types; + struct TupleEmit te = { .e=bin->rhs->d.exp_call.args, .v=v }; + emit_unpack_instr(emit, &te); + } + return (Instr)GW_OK; +} + GWION_IMPORT(tuple) { const Type t_tuple = gwi_mk_type(gwi, "Tuple", SZ_INT, "Object"); gwi_add_type(gwi, t_tuple); @@ -412,5 +489,28 @@ GWION_IMPORT(tuple) { // GWI_BB(gwi_oper_emi(gwi, opem_at_tuple)) GWI_BB(gwi_oper_end(gwi, "@array", NULL)) gwi_register_freearg(gwi, TupleUnpack, freearg_tuple_at); + + const Type t_unpack = gwi_mk_type(gwi, "Unpack", SZ_INT, "Tuple"); + gwi_add_type(gwi, t_unpack); + SET_FLAG(t_unpack, checked | ae_flag_scan2 | ae_flag_check | ae_flag_emit); + SET_FLAG(t_unpack, abstract | ae_flag_template); + GWI_BB(gwi_oper_ini(gwi, "Unpack", NULL, NULL)) + GWI_BB(gwi_oper_add(gwi, unpack_ck)) + GWI_BB(gwi_oper_emi(gwi, unpack_em)) + GWI_BB(gwi_oper_end(gwi, "@ctor", NULL)) + GWI_BB(gwi_oper_ini(gwi, "Object", "Unpack", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_at_unpack)) + GWI_BB(gwi_oper_emi(gwi, opem_at_unpack)) + GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_at_unpack)) + GWI_BB(gwi_oper_emi(gwi, opem_at_unpack)) + GWI_BB(gwi_oper_end(gwi, "==", NULL)) + GWI_BB(gwi_oper_ini(gwi, "Tuple", "Unpack", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_at_unpack)) + GWI_BB(gwi_oper_emi(gwi, opem_at_unpack)) + GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_at_unpack)) + GWI_BB(gwi_oper_emi(gwi, opem_at_unpack)) + GWI_BB(gwi_oper_end(gwi, "==", NULL)) return GW_OK; } diff --git a/src/lib/vec.c b/src/lib/vec.c index aaa92d88..2c6b2e90 100644 --- a/src/lib/vec.c +++ b/src/lib/vec.c @@ -6,6 +6,8 @@ #include "object.h" #include "gwion.h" #include "operator.h" +#include "traverse.h" +#include "parse.h" #include "import.h" #include "driver.h" #include "gwi.h" @@ -166,6 +168,8 @@ EQUALITY_OPER(vec3, SZ_VEC3); OP_CHECK(vecx_ck) { Exp_Call *call = (Exp_Call*)data; Exp e = call->args, last = NULL; + if(call->args) + CHECK_ON(check_exp(env, call->args)) size_t i = 0; const Type t_float = env->gwion->type[et_float]; while(e) { diff --git a/src/parse/check.c b/src/parse/check.c index ef9868ea..001794f9 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -715,10 +715,11 @@ ANN static Type check_lambda_call(const Env env, const Exp_Call *exp) { ANN Type check_exp_call1(const Env env, const Exp_Call *exp) { CHECK_OO(check_exp(env, exp->func)) if(isa(exp->func->type, env->gwion->type[et_function]) < 0) { + // use func flag? if(isa(exp->func->type, env->gwion->type[et_class]) < 0) ERR_O(exp->func->pos, _("function call using a non-function value")) - if(exp->args) - CHECK_OO(check_exp(env, exp->args)) +// if(exp->args) +// CHECK_OO(check_exp(env, exp->args)) struct Op_Import opi = { .op=insert_symbol("@ctor"), .lhs=exp->func->type->e->d.base_type, .data=(uintptr_t)exp, .pos=exp_self(exp)->pos }; const Type t = op_check(env, &opi); exp_self(exp)->nspc = t ? t->e->owner : NULL; diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 8916cce0..4fc66782 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -137,8 +137,6 @@ ANN static inline m_bool scan1_prim(const Env env, const Exp_Primary* prim) { return scan1_exp(env, prim->d.array->exp); if(prim->prim_type == ae_prim_range) return scan1_range(env, prim->d.range); -// if(prim->prim_type == ae_prim_unpack) -// return scan1_exp(env, prim->d.tuple.exp); return GW_OK; } diff --git a/tests/error/unused_unpack.gw b/tests/error/unused_unpack.gw index 5f161d80..e6e75962 100644 --- a/tests/error/unused_unpack.gw +++ b/tests/error/unused_unpack.gw @@ -1,2 +1,2 @@ #! [contains] unused Tuple unpack ->(a,b); +Unpack(a,b); diff --git a/tests/match/tuple.gw b/tests/match/tuple.gw index 90dbff2a..9c595568 100644 --- a/tests/match/tuple.gw +++ b/tests/match/tuple.gw @@ -8,5 +8,5 @@ C charles; 21 => charles.age; match charles { - case >(name, age): <<< name , " is ", age, " years old." >>>; + case Unpack(name, age): <<< name , " is ", age, " years old." >>>; } diff --git a/tests/tuple/tuple_skip.gw b/tests/tuple/tuple_skip.gw index cd289269..bad9d2a2 100644 --- a/tests/tuple/tuple_skip.gw +++ b/tests/tuple/tuple_skip.gw @@ -1,2 +1,2 @@ -Tuple(1, 2, 3) @=> >(b, _, c); +Tuple(1, 2, 3) @=> Unpack(b, _, c); <<< c >>>; diff --git a/tests/tuple/tuple_unpack_already_declared.gw b/tests/tuple/tuple_unpack_already_declared.gw index 20178d96..16336f58 100644 --- a/tests/tuple/tuple_unpack_already_declared.gw +++ b/tests/tuple/tuple_unpack_already_declared.gw @@ -1,3 +1,3 @@ #! [contains] already been defined in the same scope int i; -Tuple(12) @=> >(i); +Tuple(12) @=> Unpack(i); -- 2.43.0