From: Jérémie Astor Date: Mon, 21 Dec 2020 22:04:55 +0000 (+0100) Subject: :art: Union as abstract types X-Git-Tag: nightly~1083 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=50eebb32a6fe3aa67dfeef60a5c5ef7a4a580130;p=gwion.git :art: Union as abstract types --- diff --git a/include/env/data.h b/include/env/data.h new file mode 100644 index 00000000..51281f5a --- /dev/null +++ b/include/env/data.h @@ -0,0 +1,24 @@ +#ifndef __AST_DATA +#define __AST_DATA + +typedef struct DataTable_* DataTable; +ANN DataTable new_datatable(MemPool p, size_t sz); +ANN void datatable_reset(DataTable); +ANN void free_datatable(DataTable); + +ANN struct Type_* dataget_type (DataTable, void*); +//ANN Type dataget_cast (Data, void*); +//ANN Value dataget_val (Data, void*); +//ANN Func dataget_func (Data, void*); +//ANN Nspc dataget_nspc (Data, void*); +//ANN Vector dataget_vec (Data, void*); +//ANN Instr dataget_instr (Data, void*); + +ANN void dataset_type (DataTable, void*, struct Type_*); +//ANN void dataset_cast (Data, void*); +//ANN void dataset_val (Data, void*); +//ANN void dataset_func (Data, void*); +//ANN void dataset_nspc (Data, void*); +//ANN void dataset_vec (Data, void*); +//ANN void dataset_instr (Data, void*); +#endif diff --git a/include/opcode.h b/include/opcode.h index 84550cfb..a94876d0 100644 --- a/include/opcode.h +++ b/include/opcode.h @@ -163,6 +163,7 @@ enum { eDotMember2, eDotMember3, eDotMember4, + eUnionCheck, eUnionMember, eUnionMember2, eUnionMember3, @@ -350,6 +351,7 @@ enum { #define DotMember2 (f_instr)eDotMember2 #define DotMember3 (f_instr)eDotMember3 #define DotMember4 (f_instr)eDotMember4 +#define UnionCheck (f_instr)eUnionCheck #define UnionMember (f_instr)eUnionMember #define UnionMember2 (f_instr)eUnionMember2 #define UnionMember3 (f_instr)eUnionMember3 diff --git a/opcode.txt b/opcode.txt index 58eae8de..840be081 100644 --- a/opcode.txt +++ b/opcode.txt @@ -160,6 +160,7 @@ DotMember DotMember2 DotMember3 DotMember4 +UnionCheck UnionMember UnionMember2 UnionMember3 diff --git a/src/emit/emit.c b/src/emit/emit.c index 724cd075..a0969d8e 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -1736,13 +1736,20 @@ ANN static m_bool emit_stmt_exp(const Emitter emit, const struct Stmt_Exp_* exp) return exp->val ? emit_exp(emit, exp->val) : GW_OK; } +ANN static inline m_bool emit_exp1(const Emitter emit, const Exp e) { + const Exp next = e->next; + e->next = NULL; + const m_bool ret = emit_exp(emit, e); + e->next = next; + return ret; +} + ANN static m_bool emit_case_head(const Emitter emit, const Exp base, const Exp e, const Symbol op, const Vector v) { - CHECK_BB(emit_exp(emit, base)) - CHECK_BB(emit_exp_pop_next(emit, e)) - const m_int size = -exp_size(e); - emit_exp_addref(emit, base, -exp_totalsize(base) + size); - emit_exp_addref1(emit, e, size); + CHECK_BB(emit_exp1(emit, base)) + emit_exp_addref1(emit, base, -exp_size(base)); + CHECK_BB(emit_exp1(emit, e)) + emit_exp_addref1(emit, e, -exp_size(e)); const Exp_Binary bin = { .lhs=base, .rhs=e, .op=op }; struct Exp_ ebin = { .d={.exp_binary=bin}, }; struct Op_Import opi = { .op=op, .lhs=base->type, .rhs=e->type, @@ -1767,51 +1774,92 @@ ANN static m_bool emit_case_body(const Emitter emit, const struct Stmt_Match_* s ANN static m_bool case_value(const Emitter emit, const Exp base, const Exp e) { const Value v = e->d.prim.value; +printf("base->type %s\n", base->type->name); v->from->offset = emit_local(emit, base->type); - CHECK_BB(emit_exp(emit, base)) - emit_exp_addref(emit, base, -exp_totalsize(base)); - regpop(emit, base->type->size); const Instr instr = emit_add_instr(emit, Reg2Mem4); instr->m_val = v->from->offset; instr->m_val2 = base->type->size; return GW_OK; } +// should be in src/lib/union.c +static const f_instr unionmember[] = { UnionMember, UnionMember2, UnionMember3, UnionMember4 }; #define CASE_PASS (Symbol)1 -ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e) { +ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e, const Vector vec, const uint n) { if(e->exp_type == ae_exp_primary) { if(e->d.prim.prim_type == ae_prim_id) { if(e->d.prim.d.var == insert_symbol("_")) return CASE_PASS; if(!nspc_lookup_value1(emit->env->curr, e->d.prim.d.var)) { + if(!n) { + CHECK_BO(emit_exp(emit, base)) + emit_exp_addref(emit, base, -exp_totalsize(base)); + regpop(emit, base->type->size); + } CHECK_BO(case_value(emit, base, e)) return CASE_PASS; } } + } else if(isa(actual_type(emit->gwion, base->type), emit->gwion->type[et_union]) > 0 && e->exp_type == ae_exp_call) { + const Exp func = e->d.exp_call.func; + if(func->d.prim.prim_type == ae_prim_id) { + const Map map = &actual_type(emit->gwion, base->type)->nspc->info->value->map; + for(m_uint i = 0; i < map_size(map); ++i) { + if(VKEY(map, i) == (m_uint)func->d.prim.d.var) { + const Value v = (Value)VVAL(map, i); + if(v) { + if(!n) + CHECK_BO(emit_exp(emit, base)) + else + regpush(emit, SZ_INT); + const Instr check = emit_add_instr(emit, UnionCheck); + check->m_val2 = i; + vector_add(vec, (m_uint)check); + const Instr instr = emit_kind(emit, v->type->size, 0 /*emit_addr*/, unionmember); + instr->m_val = i; + regpop(emit, v->type->size); + case_op(emit, e->d.exp_call.args, e->d.exp_call.args, vec, i + 1); + return CASE_PASS; + } + } + } + } } - return insert_symbol("=="); + if(!n) + return insert_symbol("=="); + regpush(emit, SZ_INT); + CHECK_BO(emit_exp(emit, e)) + const Exp_Binary bin = { .lhs=base, .rhs=e, .op=insert_symbol("==") }; + struct Exp_ ebin = { .d={.exp_binary=bin}, }; + struct Op_Import opi = { .op=insert_symbol("=="), .lhs=base->type, .rhs=e->type, + .data=(uintptr_t)&ebin.d.exp_binary, .pos=e->pos, .op_type=op_binary }; + CHECK_BO(op_emit(emit, &opi)) + const Instr instr = emit_add_instr(emit, BranchEqInt); + vector_add(vec, (vtype)instr); } ANN static m_bool _emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt, - const Vector v) { + const Vector v, struct Match_ *const match) { Exp e = stmt->cond; const Map map = &emit->env->scope->match->map; for(m_uint i = 0; i < map_size(map) && e; e = e->next, ++i) { const Exp base = (Exp)VKEY(map, i); - const Symbol op = case_op(emit, base, e); + const Symbol op = case_op(emit, base, e, v, 0); if(op != CASE_PASS) CHECK_BB(emit_case_head(emit, base, e, op, v)) +else puts("pass"); } CHECK_BB(emit_case_body(emit, stmt)) return GW_OK; } -ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt) { +ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt, + struct Match_ *match) { emit_push_scope(emit); struct Vector_ v; vector_init(&v); - const m_bool ret = _emit_stmt_match_case(emit, stmt, &v); + const m_bool ret = _emit_stmt_match_case(emit, stmt, &v, match); emit_pop_scope(emit); for(m_uint i = 0; i < vector_size(&v); ++i) { const Instr instr = (Instr)vector_at(&v, i); @@ -1821,7 +1869,7 @@ ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Mat return ret; } -ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) { +ANN static inline void match_unvec(struct Match_ *const match, const m_uint pc) { const Vector vec = &match->vec; for(m_uint i = 0; i < vector_size(vec); ++i) { const Instr instr = (Instr)VPTR(vec, i); @@ -1830,8 +1878,8 @@ ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) vector_release(vec); } -ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list) { - do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match)) +ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list, struct Match_ *match) { + do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match, match)) while((list = list->next)); return GW_OK; } @@ -1841,7 +1889,7 @@ ANN static m_bool emit_match(const Emitter emit, const struct Stmt_Match_* stmt) CHECK_BB(emit_stmt(emit, stmt->where, 1)) MATCH_INI(emit->env->scope) vector_init(&m.vec); - const m_bool ret = emit_stmt_cases(emit, stmt->list); + const m_bool ret = emit_stmt_cases(emit, stmt->list, &m); match_unvec(&m, emit_code_size(emit)); MATCH_END(emit->env->scope) return ret; diff --git a/src/lib/engine.c b/src/lib/engine.c index 9dc2eaf6..69a526b5 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -146,7 +146,6 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_BB(import_string(gwi)) GWI_BB(import_shred(gwi)) GWI_BB(import_modules(gwi)) - GWI_BB(import_union(gwi)) GWI_BB(import_foreach(gwi)) GWI_BB(gwi_oper_ini(gwi, "@Class", "@Class", "int")) @@ -156,11 +155,11 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_BB(gwi_oper_end(gwi, ">", instr_class_gt)) GWI_BB(gwi_oper_end(gwi, "<=", instr_class_le)) GWI_BB(gwi_oper_end(gwi, "<", instr_class_lt)) - +/* GWI_BB(gwi_oper_ini(gwi, NULL, (m_str)OP_ANY_TYPE, NULL)) GWI_BB(gwi_oper_add(gwi, opck_basic_ctor)) GWI_BB(gwi_oper_end(gwi, "@ctor", NULL)) - +*/ GWI_BB(gwi_oper_ini(gwi, "@Compound", (m_str)OP_ANY_TYPE, NULL)) GWI_BB(gwi_oper_add(gwi, opck_object_dot)) GWI_BB(gwi_oper_emi(gwi, opem_object_dot)) @@ -171,6 +170,7 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_BB(gwi_oper_emi(gwi, opem_object_dot)) GWI_BB(gwi_oper_end(gwi, "@dot", NULL)) + GWI_BB(import_union(gwi)) return GW_OK; } diff --git a/src/lib/union.c b/src/lib/union.c index 6308bb60..fff775c1 100644 --- a/src/lib/union.c +++ b/src/lib/union.c @@ -52,7 +52,7 @@ static OP_EMIT(opem_union_dot) { const Value v = (Value)VVAL(map, i); const uint emit_addr = exp_getvar(exp_self(member)); const Instr instr = emit_kind(emit, v->type->size, emit_addr, unionmember); - instr->m_val = i + 1; + instr->m_val = i;// + 1; instr->m_val2 = v->type->size; return GW_OK; } @@ -89,7 +89,8 @@ static OP_CHECK(opck_union_is) { e->exp_type = ae_exp_binary; e->d.exp_binary.lhs = cpy_exp(env->gwion->mp, exp_func); e->d.exp_binary.lhs->d.exp_dot.xid = insert_symbol(env->gwion->st, "@index"); - e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i+1, e->pos); +// e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i+1, e->pos); + e->d.exp_binary.rhs = new_prim_int(env->gwion->mp, i, e->pos); free_exp(env->gwion->mp, exp_func); free_exp(env->gwion->mp, exp_args); e->d.exp_binary.op = insert_symbol(env->gwion->st, "=="); @@ -104,6 +105,54 @@ static MFUN(union_is) { *(m_uint*)RETURN = *(m_uint*)MEM(SZ_INT) == *(m_uint*)o->data; } +static OP_CHECK(opck_union_ctor) { + Exp_Call *call = (Exp_Call*)data; + const Exp name = call->args; + if(!name || !name->next || name->next->next) + ERR_N(name->pos, "Union constructor takes two arguments, " + "'id' and 'value'") + if(name->exp_type != ae_exp_primary || + name->d.prim.prim_type != ae_prim_id) + return NULL; + const Exp val = name->next; + const Type base = actual_type(env->gwion, call->func->type); + const Map map = &base->nspc->info->value->map; + for(m_uint i = 0; i < map_size(map); ++i) { + if(VKEY(map, i) == (m_uint)name->d.prim.d.var) { + const Value v = (Value)VVAL(map, i); + name->d.prim.prim_type = ae_prim_num; + name->d.prim.d.num = i; + name->type = env->gwion->type[et_int]; + DECL_ON(const Type, t, = check_exp(env, val)) + if(isa(t, v->type) < 0) { + ERR_N(val->pos, "Invalid type '%s' for '%s', should be '%s'", + t->name, v->name, v->type->name) + } + return base; + } + } + return NULL; +} + +static INSTR(UnionCtor) { + POP_REG(shred, instr->m_val2); + POP_REG(shred, SZ_INT); + const Type t = *(Type*)REG(-SZ_INT*2); + const m_uint index = *(m_uint*)REG(-SZ_INT); + const M_Object o = *(M_Object*)REG(-SZ_INT) = new_object(shred->info->vm->gwion->mp, NULL, (Type)instr->m_val); + *(m_uint*)o->data = index;// + 1; + memcpy(o->data + SZ_INT, REG(0), instr->m_val2); +} + +static OP_EMIT(opem_union_ctor) { + Exp_Call *call = (Exp_Call*)data; + const Type base = actual_type(emit->gwion, call->func->type); + const Instr instr = emit_add_instr(emit, UnionCtor); + instr->m_val = base; + instr->m_val2 = call->args->next->type->size; + return GW_OK; +} + ANN GWION_IMPORT(union) { const Type t_none = gwi_mk_type(gwi, "None", 0, NULL); GWI_BB(gwi_set_global_type(gwi, t_none, et_none)) @@ -125,6 +174,12 @@ ANN GWION_IMPORT(union) { 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)) + + GWI_BB(gwi_oper_ini(gwi, NULL, "@Union", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_union_ctor)) + GWI_BB(gwi_oper_emi(gwi, opem_union_ctor)) + GWI_BB(gwi_oper_end(gwi, "@ctor", NULL)) + 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, diff --git a/src/parse/check.c b/src/parse/check.c index 6c936de7..0562f8bf 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -710,12 +710,10 @@ ANN Type check_exp_call1(const Env env, const Exp_Call *exp) { if(!ret) return exp_self(exp)->type; const Type t = actual_type(env->gwion, exp->func->type); - if(isa(t, env->gwion->type[et_function]) < 0) { - // use func flag? + if(isa(t, env->gwion->type[et_function]) < 0) { // use func flag? struct Op_Import opi = { .op=insert_symbol("@ctor"), .rhs=actual_type(env->gwion, exp->func->type), .data=(uintptr_t)exp, .pos=exp_self(exp)->pos, .op_type=op_exp }; const Type t = op_check(env, &opi); -// exp_self(exp)->info->nspc = t ? t->info->owner : NULL; return t; } if(t == env->gwion->type[et_lambda]) @@ -1028,23 +1026,34 @@ ANN static m_bool check_stmt_exp(const Env env, const Stmt_Exp stmt) { return stmt->val ? check_exp(env, stmt->val) ? 1 : -1 : 1; } -ANN static Value match_value(const Env env, const Exp_Primary* prim, const m_uint i) { +ANN static Value match_value(const Env env, const Type base, const Exp_Primary* prim, const m_uint i) { const Symbol sym = prim->d.var; - const Value v = new_value(env->gwion->mp, - ((Exp)VKEY(&env->scope->match->map, i))->type, s_name(sym)); + const Value v = new_value(env->gwion->mp, base, s_name(sym)); set_vflag(v, vflag_valid); nspc_add_value(env->curr, sym, v); VVAL(&env->scope->match->map, i) = (vtype)v; return v; } -ANN static Symbol case_op(const Env env, const Exp e, const m_uint i) { +ANN static Symbol case_op(const Env env, const Type base, const Exp e, const m_uint i) { if(e->exp_type == ae_exp_primary) { if(e->d.prim.prim_type == ae_prim_id) { if(e->d.prim.d.var == insert_symbol("_")) return NULL; if(!nspc_lookup_value1(env->curr, e->d.prim.d.var)) { - e->d.prim.value = match_value(env, &e->d.prim, i); + e->d.prim.value = match_value(env, base, &e->d.prim, i); + return NULL; + } + } + } else if(isa(actual_type(env->gwion, base), env->gwion->type[et_union]) > 0 && e->exp_type == ae_exp_call) { + const Exp func = e->d.exp_call.func; + if(func->d.prim.prim_type == ae_prim_id) { + const Value v= find_value(actual_type(env->gwion, base), func->d.prim.d.var); + if(v) { + if(!i) + e->type = v->type; + case_op(env, v->type, e->d.exp_call.args, i); + e->d.exp_call.args->type = v->type; return NULL; } } @@ -1058,17 +1067,19 @@ ANN static m_bool match_case_exp(const Env env, Exp e) { if(!e) ERR_B(last->pos, _("no enough to match")) last = e; - const Symbol op = case_op(env, e, i); + const Exp base = (Exp)VKEY(&env->scope->match->map, i); + const Symbol op = case_op(env, base->type, e, i); if(op) { - const Exp base = (Exp)VKEY(&env->scope->match->map, i); - CHECK_OB(check_exp(env, e)) + const Exp next = e->next; + e->next = NULL; + const Type t = check_exp(env, e); + e->next = next; + CHECK_OB(t) Exp_Binary bin = { .lhs=base, .rhs=e, .op=op }; struct Exp_ ebin = { .d={.exp_binary=bin} }; struct Op_Import opi = { .op=op, .lhs=base->type, .rhs=e->type, .data=(uintptr_t)&ebin.d.exp_binary, .pos=e->pos, .op_type=op_binary }; CHECK_OB(op_check(env, &opi)) -// e->info->nspc= info.nspc; - return GW_OK; } } if(e) diff --git a/src/parse/operator.c b/src/parse/operator.c index 0beaf43b..479dc5bb 100644 --- a/src/parse/operator.c +++ b/src/parse/operator.c @@ -34,6 +34,10 @@ ANN void free_op_map(Map map, struct Gwion_ *gwion) { map_release(map); } +static m_str type_name(const Type t) { + return t ? t == OP_ANY_TYPE ? "any" : t->name : ""; +} + static m_bool op_match(const restrict Type t, const restrict Type mo) { if(t == OP_ANY_TYPE || mo == OP_ANY_TYPE) return GW_OK; @@ -102,10 +106,6 @@ ANN static Vector op_vector(MemPool p, const struct OpChecker *ock) { return create; } -static m_str type_name(const Type t) { - return t ? t == OP_ANY_TYPE ? "any" : t->name : ""; -} - ANN static m_bool _op_exist(const struct OpChecker* ock, const Nspc n) { const Vector v = (Vector)map_get(&n->info->op_map, (vtype)ock->opi->op); if(!v || !operator_find2(v, ock->opi->lhs, ock->opi->rhs)) diff --git a/src/parse/scan0.c b/src/parse/scan0.c index 0077367a..291dc8fe 100644 --- a/src/parse/scan0.c +++ b/src/parse/scan0.c @@ -218,7 +218,7 @@ ANN static Type union_type(const Env env, const Symbol s) { t->info->tuple = new_tupleform(env->gwion->mp, NULL); // ??? add_type(env, env->curr, t); mk_class(env, t); - SET_FLAG(t, final); + SET_FLAG(t, final | ae_flag_abstract); return t; } diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 7c75c0f2..0835087a 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -414,7 +414,7 @@ ANN static inline m_bool scan1_union_def_inner_loop(const Env env, Union_Def ude if(t->size > sz) sz = t->size; } while((l = l->next)); -udef->type->nspc->info->offset = SZ_INT +sz; + udef->type->nspc->info->offset = SZ_INT +sz; return GW_OK; } diff --git a/src/vm/vm.c b/src/vm/vm.c index 311cc85b..3dd682e7 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -324,7 +324,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, - &&unionint, &&unionfloat, &&unionother, &&unionaddr, + &&unioncheck, &&unionint, &&unionfloat, &&unionother, &&unionaddr, &&staticint, &&staticfloat, &&staticother, &&upvalueint, &&upvaluefloat, &&upvalueother, &&upvalueaddr, &&dotfunc, &&dotstaticfunc, @@ -833,6 +833,14 @@ dotaddr: continue;\ } +unioncheck: +{ + if(*(m_uint*)(*(M_Object*)(reg-SZ_INT))->data != VAL2) { + reg -= SZ_INT; + PC_DISPATCH(VAL); + } + DISPATCH() +} unionint: { UNION_CHECK