From 9b3667dd583a28fcc7527dc073fa9729e1c6ce6c Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Thu, 8 Aug 2019 15:30:00 +0200 Subject: [PATCH] :art: Initial tuple implementation --- ast | 2 +- include/cpy_ast.h | 4 + include/instr.h | 3 + include/lang_private.h | 1 + include/operator.h | 2 +- include/type.h | 9 +- src/emit/emit.c | 76 +++++- src/lib/engine.c | 6 +- src/lib/func.c | 4 +- src/lib/object.c | 6 +- src/lib/prim.c | 2 +- src/lib/ptr.c | 2 +- src/lib/tuple.c | 231 +++++++++++++++++++ src/oo/nspc.c | 2 +- src/oo/type.c | 26 ++- src/parse/check.c | 103 ++++++--- src/parse/cpy_ast.c | 4 +- src/parse/scan1.c | 33 ++- src/parse/scan2.c | 13 +- src/parse/scanx.c | 6 +- src/parse/template.c | 76 +++--- src/parse/tuple.c | 86 +++++++ src/vm/vm.c | 1 + tests/nonnull/ref.gw | 1 + tests/tuple/object2tuple.gw | 8 + tests/tuple/object2tuple_err.gw | 8 + tests/tuple/object_array_access_multi.gw | 9 + tests/tuple/tupl_decl.gw | 1 + tests/tuple/tuple.gw | 1 + tests/tuple/tuple_abstract.gw | 2 + tests/tuple/tuple_aray_access.gw | 6 + tests/tuple/tuple_aray_access_exceed.gw | 1 + tests/tuple/tuple_aray_access_multi.gw | 11 + tests/tuple/tuple_aray_access_not_prim.gw | 2 + tests/tuple/tuple_array_access_invalid.gw | 1 + tests/tuple/tuple_at.gw | 4 + tests/tuple/tuple_at_err.gw | 4 + tests/tuple/tuple_at_lit.gw | 2 + tests/tuple/tuple_cast.gw | 4 + tests/tuple/tuple_cast2.gw | 4 + tests/tuple/tuple_decl.gw | 1 + tests/tuple/tuple_implicit.gw | 8 + tests/tuple/tuple_lit_error.gw | 1 + tests/tuple/tuple_skip.gw | 2 + tests/tuple/tuple_skip2.gw | 6 + tests/tuple/tuple_unknown.gw | 2 + tests/tuple/tuple_unpack_already_declared.gw | 3 + 47 files changed, 687 insertions(+), 103 deletions(-) create mode 100644 src/lib/tuple.c create mode 100644 src/parse/tuple.c create mode 100644 tests/nonnull/ref.gw create mode 100644 tests/tuple/object2tuple.gw create mode 100644 tests/tuple/object2tuple_err.gw create mode 100644 tests/tuple/object_array_access_multi.gw create mode 100644 tests/tuple/tupl_decl.gw create mode 100644 tests/tuple/tuple.gw create mode 100644 tests/tuple/tuple_abstract.gw create mode 100644 tests/tuple/tuple_aray_access.gw create mode 100644 tests/tuple/tuple_aray_access_exceed.gw create mode 100644 tests/tuple/tuple_aray_access_multi.gw create mode 100644 tests/tuple/tuple_aray_access_not_prim.gw create mode 100644 tests/tuple/tuple_array_access_invalid.gw create mode 100644 tests/tuple/tuple_at.gw create mode 100644 tests/tuple/tuple_at_err.gw create mode 100644 tests/tuple/tuple_at_lit.gw create mode 100644 tests/tuple/tuple_cast.gw create mode 100644 tests/tuple/tuple_cast2.gw create mode 100644 tests/tuple/tuple_decl.gw create mode 100644 tests/tuple/tuple_implicit.gw create mode 100644 tests/tuple/tuple_lit_error.gw create mode 100644 tests/tuple/tuple_skip.gw create mode 100644 tests/tuple/tuple_skip2.gw create mode 100644 tests/tuple/tuple_unknown.gw create mode 100644 tests/tuple/tuple_unpack_already_declared.gw diff --git a/ast b/ast index ac133c43..d309c7d2 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit ac133c43c04c4e53331321c18596d22b214d93f8 +Subproject commit d309c7d2f7152d08e0880fdd068666ebc963738a diff --git a/include/cpy_ast.h b/include/cpy_ast.h index eaf91151..61ae846f 100644 --- a/include/cpy_ast.h +++ b/include/cpy_ast.h @@ -1,5 +1,9 @@ #ifndef __CPY_AST #define __CPY_AST +ANN Array_Sub cpy_array_sub(MemPool, Array_Sub); +ANN Type_Decl* cpy_type_decl(MemPool, const Type_Decl*); +ANN Type_List cpy_type_list(MemPool, const Type_List); +ANN Func_Def cpy_func_def(MemPool, const Func_Def); ANN Func_Def cpy_func_def(MemPool, Func_Def); ANN struct Func_Base_* cpy_func_base(MemPool, struct Func_Base_*); ANN Class_Def cpy_class_def(MemPool, Class_Def); diff --git a/include/instr.h b/include/instr.h index 1f97a27d..cd95e22e 100644 --- a/include/instr.h +++ b/include/instr.h @@ -64,6 +64,9 @@ INSTR(PopArrayClass); INSTR(DotTmpl); INSTR(GTmpl); +INSTR(TupleCtor); +INSTR(TupleMember); + struct dottmpl_ { size_t len; m_str name; diff --git a/include/lang_private.h b/include/lang_private.h index f7bb22fe..251f18be 100644 --- a/include/lang_private.h +++ b/include/lang_private.h @@ -14,4 +14,5 @@ ANN m_bool import_array(const Gwi gwi); ANN m_bool import_ptr(const Gwi gwi); ANN m_bool import_func(const Gwi gwi); ANN m_bool import_modules(const Gwi gwi); +ANN m_bool import_tuple(const Gwi gwi); #endif diff --git a/include/operator.h b/include/operator.h index 27ab6673..f7f8dbf0 100644 --- a/include/operator.h +++ b/include/operator.h @@ -17,7 +17,7 @@ struct Op_Import { }; struct Implicit { - void* e; + Exp e; Type t; loc_t pos; }; diff --git a/include/type.h b/include/type.h index 082bf705..ddb647eb 100644 --- a/include/type.h +++ b/include/type.h @@ -10,6 +10,9 @@ struct TypeInfo_ { Type base_type; } d; struct Vector_ contains; + struct Vector_ tuple_form; + struct Vector_ tuple_offset; + Type_List tuple_tl; }; struct Type_ { @@ -25,7 +28,7 @@ struct Type_ { extern Type t_void, t_int, t_bool, t_float, t_dur, t_time, t_now, t_complex, t_polar, t_vec3, t_vec4, t_null, t_object, t_shred, t_fork, t_event, t_ugen, t_string, t_ptr, t_array, t_gack, - t_function, t_fptr, t_vararg, t_lambda, t_class, t_union, t_undefined, t_auto; + t_function, t_fptr, t_vararg, t_lambda, t_class, t_union, t_undefined, t_auto, t_tuple; ANN2(1,3) ANEW Type new_type(MemPool, const m_uint xid, const m_str name, const Type); ANEW ANN Type type_copy(MemPool, const Type type); @@ -51,5 +54,9 @@ ANN static inline m_bool is_fptr(const Type t) { return isa(actual_type(t), t_fptr) > 0; } ANN m_uint get_depth(const Type type); + + +ANN Type tuple_type(const Env, const Vector, const loc_t); +ANN void tuple_info(const Env, Type_Decl*, const Var_Decl); #endif diff --git a/src/emit/emit.c b/src/emit/emit.c index 303061b6..9737a985 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -145,11 +145,11 @@ ANN static inline m_uint emit_code_size(const Emitter emit) { return vector_size(&emit->code->instr); } -ANN static inline m_uint emit_code_offset(const Emitter emit) { +ANN /*static inline */m_uint emit_code_offset(const Emitter emit) { return emit->code->frame->curr_offset; } -ANN static inline m_uint emit_local(const Emitter emit, const m_uint size, const m_bool is_obj) { +ANN /*static inline */m_uint emit_local(const Emitter emit, const m_uint size, const m_bool is_obj) { return frame_local(emit->gwion->mp, emit->code->frame, size, is_obj); } @@ -202,7 +202,7 @@ ANN ArrayInfo* emit_array_extend_inner(const Emitter emit, const Type t, const E info->base = base; const Instr alloc = emit_add_instr(emit, ArrayAlloc); alloc->m_val = (m_uint)info; - if(isa(base, t_object) > 0) { + if(isa(base, t_object) > 0 && !GET_FLAG(base, abstract)) { emit_pre_constructor_array(emit, base); info->is_obj = 1; } @@ -395,8 +395,54 @@ ANN static m_bool prim_array(const Emitter emit, const Exp_Primary * primary) { ANN static m_bool emit_exp_array(const Emitter emit, const Exp_Array* array) { const m_uint is_var = exp_self(array)->emit_var; - const m_uint depth = get_depth(array->base->type) - get_depth(exp_self(array)->type); CHECK_BB(emit_exp(emit, array->base, 0)) + const m_uint depth = get_depth(array->base->type) - get_depth(exp_self(array)->type); + +const Type t_base = array->base->type; +Type type = array_base(t_base) ?: t_base; +if(isa(type, t_tuple) > 0 && isa(exp_self(array)->type, t_tuple) < 0) { + Exp e = array->array->exp; + while(e->next && e->next->next) + e = e->next; + const Exp next = e->next; + if(!next) { + emit_add_instr(emit, GWOP_EXCEPT); + const Instr instr = emit_add_instr(emit, TupleMember); + instr->m_val = array->array->exp->d.exp_primary.d.num; + instr->m_val2 = is_var; + emit_add_instr(emit, DotMember); // just a place holder. + return GW_OK; + } + emit_add_instr(emit, GcAdd); + e->next = NULL; + CHECK_BB(emit_exp(emit, array->array->exp, 0)) + e->next = next; + regpop(emit, (depth) * SZ_INT); + emit_add_instr(emit, GWOP_EXCEPT); +assert(depth); + if(depth) + for(m_uint i = 0; i < depth-1; ++i) { + const Instr access = emit_add_instr(emit, ArrayAccess); + access->m_val = i; + const Instr get = emit_add_instr(emit, ArrayGet); + get->m_val = i; + get->m_val2 = -SZ_INT; + emit_add_instr(emit, GWOP_EXCEPT); + } + regpop(emit, SZ_INT); + const Instr access = emit_add_instr(emit, ArrayAccess); + access->m_val = depth; + const Instr get = emit_add_instr(emit, ArrayGet); + get->m_val = depth; + const Instr push = emit_add_instr(emit, ArrayValid); + push->m_val = SZ_INT; + emit_add_instr(emit, GWOP_EXCEPT); + const Instr instr = emit_add_instr(emit, TupleMember); + instr->m_val = next->d.exp_primary.d.num; + instr->m_val2 = is_var; + emit_add_instr(emit, DotMember); // just a place holder. + return GW_OK; + } emit_add_instr(emit, GcAdd); CHECK_BB(emit_exp(emit, array->array->exp, 0)) regpop(emit, depth * SZ_INT); @@ -452,6 +498,13 @@ ANN static m_bool prim_id(const Emitter emit, const Exp_Primary* prim) { return GW_OK; } +ANN static m_bool prim_tuple(const Emitter emit, const Exp_Primary * primary) { + CHECK_BB(emit_exp(emit, primary->d.tuple.exp, 1)) + const Instr instr = emit_add_instr(emit, TupleCtor); + instr->m_val = (m_uint)exp_self(primary)->type; + return GW_OK; +} + ANN static m_bool prim_num(const Emitter emit, const Exp_Primary * primary) { regpushi(emit, primary->d.num); return GW_OK; @@ -503,10 +556,12 @@ ANN static m_bool prim_gack(const Emitter emit, const Exp_Primary* primary) { return GW_OK; } +#define prim_unpack dummy_func static const _exp_func prim_func[] = { (_exp_func)prim_id, (_exp_func)prim_num, (_exp_func)prim_float, (_exp_func)prim_str, (_exp_func)prim_array, (_exp_func)prim_gack, (_exp_func)prim_vec, (_exp_func)prim_vec, - (_exp_func)prim_vec, (_exp_func)prim_char, (_exp_func)dummy_func, + (_exp_func)prim_vec, (_exp_func)prim_tuple, (_exp_func)prim_unpack, + (_exp_func)prim_char, (_exp_func)dummy_func, }; ANN static m_bool emit_exp_primary(const Emitter emit, const Exp_Primary* prim) { @@ -551,7 +606,7 @@ ANN static m_bool emit_exp_decl_non_static(const Emitter emit, const Var_Decl va const m_bool is_obj = isa(type, t_object) > 0; const uint emit_addr = ((is_ref && !array) || isa(type, t_object) < 0) ? emit_var : 1; - if(is_obj && (is_array || !is_ref) && !GET_FLAG(var_decl->value, ref)) + if(is_obj && (is_array || !is_ref)/* && !GET_FLAG(var_decl->value, ref)*/) CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) f_instr *exec = (f_instr*)allocmember; if(!GET_FLAG(v, member)) { @@ -614,14 +669,14 @@ ANN static inline m_bool emit_exp_decl_template(const Emitter emit, const Exp_De ANN static m_bool emit_exp_decl(const Emitter emit, const Exp_Decl* decl) { Var_Decl_List list = decl->list; - const uint ref = GET_FLAG(decl->td, ref) || type_ref(decl->type); + const uint ref = GET_FLAG(decl->td, ref) || type_ref(decl->type); const uint var = exp_self(decl)->emit_var; if(GET_FLAG(decl->type, template)) CHECK_BB(emit_exp_decl_template(emit, decl)) const m_bool global = GET_FLAG(decl->td, global); const m_uint scope = !global ? emit->env->scope->depth : emit_push_global(emit); do { - const uint r = (uint)(GET_FLAG(list->self->value, ref) + ref); + const uint r = (list->self->array && list->self->array->exp && ref) ? 0 : (uint)(GET_FLAG(list->self->value, ref) + ref); // if(!GET_FLAG(list->self->value, used)) // continue; if(GET_FLAG(decl->td, static)) @@ -924,7 +979,7 @@ ANN static m_bool spork_func(const Emitter emit, const Exp_Call* exp) { ANN m_bool emit_exp_spork(const Emitter emit, const Exp_Unary* unary) { const m_bool is_spork = unary->op == insert_symbol("spork"); const Func f = !unary->code ? unary->exp->d.exp_call.m_func : NULL; - if(!f) { + if(unary->code) { emit_add_instr(emit, RegPushImm); push_spork_code(emit, is_spork ? SPORK_CODE_PREFIX : FORK_CODE_PREFIX, unary->code->pos); if(!SAFE_FLAG(emit->env->func, member)) @@ -1386,8 +1441,9 @@ ANN static m_bool emit_union_def(const Emitter emit, const Union_Def udef) { const Exp exp = new_exp_decl(emit->gwion->mp, type_decl, var_decl_list); exp->d.exp_decl.type = udef->value->type; var_decl->value = udef->value; - CHECK_BB(emit_exp_decl(emit, &exp->d.exp_decl)) + const m_bool ret = emit_exp_decl(emit, &exp->d.exp_decl); free_exp(emit->gwion->mp, exp); + CHECK_BB(ret) if(global) { const M_Object o = new_object(emit->gwion->mp, NULL, udef->value->type); udef->value->d.ptr = (m_uint*)o; diff --git a/src/lib/engine.c b/src/lib/engine.c index a3f498ad..4313a2a3 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -35,9 +35,10 @@ static FREEARG(freearg_gack) { } ANN static m_bool import_core_libs(const Gwi gwi) { - GWI_OB((t_undefined = gwi_mk_type(gwi, "@Undefined", SZ_INT, NULL))) // size = SZ_INT to enable declarations GWI_OB((t_class = gwi_mk_type(gwi, "Class", SZ_INT, NULL))) GWI_BB(gwi_add_type(gwi, t_class)) + GWI_OB((t_undefined = gwi_mk_type(gwi, "@Undefined", SZ_INT, NULL))) // size = SZ_INT to enable declarations + GWI_BB(gwi_add_type(gwi, t_undefined)) GWI_OB((t_auto = gwi_mk_type(gwi, "auto", SZ_INT, NULL))) // size = SZ_INT to enable declarations GWI_BB(gwi_add_type(gwi, t_auto)) SET_FLAG(t_class, abstract); @@ -50,7 +51,7 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_OB((t_fptr = gwi_mk_type(gwi, "@func_ptr", SZ_INT, t_function))) GWI_BB(gwi_add_type(gwi, t_fptr)) GWI_OB((t_lambda = gwi_mk_type(gwi, "@lambda", SZ_INT, t_function))) - GWI_BB(gwi_add_type(gwi, t_fptr)) + GWI_BB(gwi_add_type(gwi, t_lambda)) GWI_OB((t_gack = gwi_mk_type(gwi, "@Gack", SZ_INT, NULL))) GWI_BB(gwi_add_type(gwi, t_gack)) GWI_OB((t_int = gwi_mk_type(gwi, "int", SZ_INT, NULL))) @@ -71,6 +72,7 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_OB((t_union = gwi_mk_type(gwi, "@Union", SZ_INT, t_object))) GWI_BB(gwi_class_ini(gwi, t_union, NULL, NULL)) GWI_BB(gwi_class_end(gwi)) + GWI_BB(import_tuple(gwi)) GWI_BB(import_array(gwi)) GWI_BB(import_event(gwi)) GWI_BB(import_ugen(gwi)) diff --git a/src/lib/func.c b/src/lib/func.c index 68778e62..bb431858 100644 --- a/src/lib/func.c +++ b/src/lib/func.c @@ -241,8 +241,8 @@ static OP_EMIT(opem_fptr_cast) { static OP_CHECK(opck_fptr_impl) { struct Implicit *impl = (struct Implicit*)data; - struct FptrInfo info = { ((Exp)impl->e)->type->e->d.func, impl->t->e->d.func, - (Exp)impl->e, ((Exp)impl->e)->pos }; + struct FptrInfo info = { impl->e->type->e->d.func, impl->t->e->d.func, + impl->e, impl->e->pos }; CHECK_BO(fptr_do(env, &info)) return ((Exp)impl->e)->cast_to = impl->t; } diff --git a/src/lib/object.c b/src/lib/object.c index 932ccff4..e1c451fe 100644 --- a/src/lib/object.c +++ b/src/lib/object.c @@ -183,17 +183,17 @@ static OP_EMIT(opem_object_cast) { static OP_CHECK(opck_implicit_null2obj) { const struct Implicit* imp = (struct Implicit*)data; - const Type l = ((Exp)imp->e)->type; + const Type l = imp->e->type; const Type r = imp->t; if(check_nonnull(env, l, r, "implicitly cast", imp->pos) == t_null) return t_null; - ((Exp)imp->e)->cast_to = r; + imp->e->cast_to = r; return imp->t; } static OP_EMIT(opem_implicit_null2obj) { const struct Implicit* imp = (struct Implicit*)data; - const Type l = ((Exp)imp->e)->type; + const Type l = imp->e->type; const Type r = imp->t; if(nonnull_check(l, r)) emit_add_instr(emit, GWOP_EXCEPT); diff --git a/src/lib/prim.c b/src/lib/prim.c index b52318ee..e6788d6f 100644 --- a/src/lib/prim.c +++ b/src/lib/prim.c @@ -139,7 +139,7 @@ static OP_CHECK(opck_implicit_f2i) { static OP_CHECK(opck_implicit_i2f) { struct Implicit* imp = (struct Implicit*)data; - ((Exp)imp->e)->cast_to = t_float; + imp->e->cast_to = t_float; return t_float; } diff --git a/src/lib/ptr.c b/src/lib/ptr.c index 117ff5d4..73388a52 100644 --- a/src/lib/ptr.c +++ b/src/lib/ptr.c @@ -54,7 +54,7 @@ static OP_CHECK(opck_ptr_cast) { static OP_CHECK(opck_implicit_ptr) { const struct Implicit* imp = (struct Implicit*)data; - const Exp e = (Exp)imp->e; + const Exp e = imp->e; if(!strcmp(get_type_name(env, imp->t->name, 1), e->type->name)) { if(e->meta == ae_meta_value) ERR_N(e->pos, _("can't cast constant to Ptr")); diff --git a/src/lib/tuple.c b/src/lib/tuple.c new file mode 100644 index 00000000..7426d6eb --- /dev/null +++ b/src/lib/tuple.c @@ -0,0 +1,231 @@ +#include "gwion_util.h" +#include "gwion_ast.h" +#include "oo.h" +#include "vm.h" +#include "env.h" +#include "instr.h" +#include "nspc.h" +#include "type.h" +#include "object.h" +#include "emit.h" +#include "env.h" +#include "vm.h" +#include "gwion.h" +#include "operator.h" +#include "import.h" +#include "gwi.h" +#include "engine.h" +#include "parser.h" +#include "value.h" +#include "cpy_ast.h" +#include "traverse.h" + +struct TupleEmit { + Exp e; + Vector v; + m_uint obj_offset; + m_uint tmp_offset; + m_uint mem_offset; + m_uint sz; + m_uint idx; +}; + +struct UnpackInfo_ { + m_uint obj_offset; + m_uint mem_offset; + m_uint size; +}; + +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 + t_tuple->nspc->info->offset + info->obj_offset, info->size); +} + +INSTR(TupleMember) { + const M_Object o = *(M_Object*)(shred->reg - SZ_INT); + const Type base = o->type_ref; + const m_bit* byte = shred->code->bytecode + shred->pc * BYTECODE_SZ; + const Type t = (Type)vector_at(&base->e->tuple_form, instr->m_val); + const m_uint offset = vector_at(&base->e->tuple_offset, instr->m_val); + *(m_uint*)(byte + SZ_INT) = offset; + if(!instr->m_val2) { + if(t->size == SZ_INT) + *(m_uint*)(byte) = eDotMember; + else if(t->size == SZ_FLOAT) + *(m_uint*)(byte) = eDotMember2; + else { + *(m_uint*)(byte) = eDotMember3; + *(m_uint*)(byte + SZ_INT*2) = t->size; + } + } else + *(m_uint*)(byte) = eDotMember4; +} + +static FREEARG(freearg_tuple_at) { + mp_free(((Gwion)gwion)->mp, UnpackInfo, (struct UnpackInfo*)instr->m_val); +} + +ANN static void emit_unpack_instr_inner(const Emitter emit, struct TupleEmit *te) { + const Instr instr = emit_add_instr(emit, TupleUnpack); + struct UnpackInfo_ *info = mp_malloc2(emit->gwion->mp, sizeof(struct UnpackInfo_)); + info->obj_offset = te->tmp_offset; + info->mem_offset = te->mem_offset; + info->size = te->sz; + instr->m_val = (m_uint)info; +} + +ANN static int tuple_continue(struct TupleEmit *te) { + const m_bool ret = (te->e = te->e->next) && + ++te->idx < VLEN(te->v); + if(!ret) + te->e = NULL; + return ret; +} + +ANN static void unpack_instr_decl(const Emitter emit, struct TupleEmit *te) { + m_uint sz = 0; + te->sz = 0; + do { + if(te->e->exp_type == ae_exp_decl) { + const Value value = te->e->d.exp_decl.list->self->value; + te->sz += value->type->size; + value->offset = emit_local(emit, value->type->size, 0); + te->tmp_offset = te->obj_offset; + te->obj_offset += ((Type)vector_at(te->v, te->idx))->size; + } else { + sz = ((Type)vector_at(te->v, te->idx))->size; + break; + } + } while(tuple_continue(te)); + te->obj_offset += sz; +} + +ANN void emit_unpack_instr(const Emitter emit, struct TupleEmit *te) { + te->mem_offset = emit_code_offset(emit); + unpack_instr_decl(emit, te); + if(te->sz) + emit_unpack_instr_inner(emit, te); + if(te->e && (te->e = te->e->next)) + emit_unpack_instr(emit, te); +} + +static m_bool tuple_match(const Env env, const Type type[2]) { + const Vector lv = &type[0]->e->tuple_form; + const Vector rv = &type[1]->e->tuple_form; + for(m_uint i = 0; i < vector_size(rv); i++) { + DECL_OB(const Type, l, = (Type)vector_at(lv, i)) + const Type r = (Type)vector_at(rv, i); + if(r != t_undefined) + CHECK_BB(isa(l, r)) + } + return GW_OK; +} + +static OP_CHECK(opck_at_tuple) { + const Exp_Binary *bin = (Exp_Binary*)data; + if(bin->rhs->exp_type == ae_exp_primary && + bin->rhs->d.exp_primary.primary_type == ae_primary_unpack) { + Exp e = bin->rhs->d.exp_primary.d.tuple.exp; + int i = 0; + do { + if(e->exp_type == ae_exp_decl) { + e->d.exp_decl.td->xid->xid = insert_symbol(env->gwion->st, // could be better + ((Type)VPTR(&bin->lhs->type->e->tuple_form, i))->name); + CHECK_BO(traverse_decl(env, &e->d.exp_decl)) + } + ++i; + } while((e = e->next)); + } else { + if(opck_rassign(env, data, mut) == t_null) + return t_null; + const Type type[2] = { bin->lhs->type, bin->rhs->type }; + if(tuple_match(env, type) < 0) + return t_null; + bin->rhs->emit_var = 1; + } + return bin->lhs->type; +} + +static OP_CHECK(opck_cast_tuple) { + Exp_Cast *cast = (Exp_Cast*)data; + if(exp_self(cast)->type->e->def && cast->exp->type->e->def) { + const Type type[2] = { exp_self(cast)->type, cast->exp->type }; + CHECK_BO(tuple_match(env, type)) + } + return exp_self(cast)->type; +} + +static OP_CHECK(opck_impl_tuple) { + struct Implicit *imp = (struct Implicit*)data; + const Type type[2] = { imp->e->type, imp->t }; + CHECK_BO(tuple_match(env, type)) + return imp->t; +} + +static OP_EMIT(opem_at_tuple) { + const Exp_Binary *bin = (Exp_Binary*)data; + if(!(bin->rhs->exp_type == ae_exp_primary && + bin->rhs->d.exp_primary.primary_type == ae_primary_unpack)) { + emit_add_instr(emit, ObjectAssign); +// emit_add_instr(emit, int_r_assign); +// const Instr instr = emit_add_instr(emit, RegAddRef); +//instr->m_val = 1; + return GW_OK; + } + const Exp e = bin->rhs->d.exp_primary.d.tuple.exp; + const Vector v = &bin->lhs->type->e->tuple_form; + struct TupleEmit te = { .e=e, .v=v }; + emit_unpack_instr(emit, &te); + return GW_OK; +} + +ANN void tuple_info(const Env env, Type_Decl *base, const Var_Decl var) { + const Value v = var->value; + if(v->name[0] != '@') { + const m_uint offset = vector_back(&env->class_def->e->tuple_offset); + vector_add(&env->class_def->e->tuple_form, (vtype)v->type); + vector_add(&env->class_def->e->tuple_offset, offset + v->type->size); + Type_Decl *td = cpy_type_decl(env->gwion->mp, base); + if(var->array) { + if(td->array) + td->array->depth += var->array->depth; + else + td->array = cpy_array_sub(env->gwion->mp, var->array); + } + if(env->class_def->e->tuple_tl) { + Type_List tl = env->class_def->e->tuple_tl; + while(tl->next) + tl = tl->next; + tl->next = new_type_list(env->gwion->mp, td, NULL); + } else + env->class_def->e->tuple_tl = new_type_list(env->gwion->mp, td, NULL); + } +} + +INSTR(TupleCtor) { + const Type t = (Type)instr->m_val; + const M_Object o = new_object(shred->info->vm->gwion->mp, shred, t); + const size_t sz = t_tuple->nspc->info->offset; + memcpy(o->data + t_tuple->nspc->info->offset, + shred->reg - (t->nspc->info->offset - sz), (t->nspc->info->offset - sz)); + shred->reg -= (t->nspc->info->offset - sz - SZ_INT); + *(M_Object*)(shred->reg - SZ_INT) = o; +} + +GWION_IMPORT(tuple) { + GWI_OB((t_tuple = gwi_mk_type(gwi, "Tuple", SZ_INT, t_object))) + GWI_BB(gwi_class_ini(gwi, t_tuple, NULL, NULL)) + GWI_BB(gwi_class_end(gwi)) + SET_FLAG(t_tuple, abstract | ae_flag_template); + GWI_BB(gwi_oper_ini(gwi, "Object", "Tuple", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_at_tuple)) + GWI_BB(gwi_oper_emi(gwi, opem_at_tuple)) + GWI_BB(gwi_oper_end(gwi, "@=>", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_cast_tuple)) + GWI_BB(gwi_oper_end(gwi, "$", NULL)) + GWI_BB(gwi_oper_add(gwi, opck_impl_tuple)) + GWI_BB(gwi_oper_end(gwi, "@implicit", NULL)) + register_freearg(gwi, TupleUnpack, freearg_tuple_at); + return GW_OK; +} diff --git a/src/oo/nspc.c b/src/oo/nspc.c index 4da25de4..c3105d3f 100644 --- a/src/oo/nspc.c +++ b/src/oo/nspc.c @@ -58,7 +58,7 @@ ANN static void free_nspc(Nspc a, Gwion gwion) { if(a->info->op_map.ptr) free_op_map(&a->info->op_map, gwion); nspc_free_type(a, gwion); - if(a->info->class_data) + if(a->info->class_data && a->info->class_data_size) mp_free2(gwion->mp, a->info->class_data_size, a->info->class_data); if(a->info->vtable.ptr) vector_release(&a->info->vtable); diff --git a/src/oo/type.c b/src/oo/type.c index 60b49054..d62b8397 100644 --- a/src/oo/type.c +++ b/src/oo/type.c @@ -18,11 +18,17 @@ ANN static void free_type(Type a, Gwion gwion) { free_union_def(gwion->mp, a->e->def->union_def); } a->e->def->union_def = NULL; - } else + } else if(a->e->def) free_class_def(gwion->mp, a->e->def); } if(a->nspc) REM_REF(a->nspc, gwion); + if(a->e->tuple_form.ptr) + vector_release(&a->e->tuple_form); + if(a->e->tuple_offset.ptr) + vector_release(&a->e->tuple_offset); + if(a->e->tuple_tl) + free_type_list(gwion->mp, a->e->tuple_tl); if(a->e->contains.ptr) { for(m_uint i = 0; i < vector_size(&a->e->contains); ++i) REM_REF((Type)vector_at(&a->e->contains, i), gwion); @@ -38,8 +44,12 @@ Type new_type(MemPool p, const m_uint xid, const m_str name, const Type parent) type->name = name; type->e = mp_calloc(p, TypeInfo); type->e->parent = parent; - if(type->e->parent) + if(type->e->parent) { type->size = parent->size; + vector_init(&type->e->tuple_form); + vector_init(&type->e->tuple_offset); + vector_add(&type->e->tuple_offset, 0); + } type->ref = new_refcount(p, free_type); return type; } @@ -52,6 +62,12 @@ ANN Type type_copy(MemPool p, const Type type) { a->e->d.base_type = type->e->d.base_type; a->array_depth = type->array_depth; a->e->def = type->e->def; + if(t_function && isa(type, t_function) > 0) { + vector_release(&a->e->tuple_form); + a->e->tuple_form.ptr = NULL; + vector_release(&a->e->tuple_offset); + a->e->tuple_offset.ptr = NULL; + } return a; } @@ -138,8 +154,8 @@ ANN m_str get_type_name(const Env env, const m_str s, const m_uint index) { m_uint n = 1; const size_t len = name ? strlen(name) : 0; const size_t slen = strlen(s); - const size_t tlen = slen -len + 1; - char c[slen]; + const size_t tlen = slen - len + 1; + char c[slen + 1]; if(!name) return index ? NULL : s_name(insert_symbol(s)); @@ -178,4 +194,4 @@ ANN m_uint get_depth(const Type type) { Type t_void, t_int, t_bool, t_float, t_dur, t_time, t_now, t_complex, t_polar, t_vec3, t_vec4, t_null, t_object, t_shred, t_fork, t_event, t_ugen, t_string, t_ptr, t_array, t_gack, - t_function, t_fptr, t_vararg, t_lambda, t_class, t_union, t_undefined, t_auto; + t_function, t_fptr, t_vararg, t_lambda, t_class, t_union, t_undefined, t_auto, t_tuple; diff --git a/src/parse/check.c b/src/parse/check.c index cbedfca5..a40180e4 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -42,7 +42,8 @@ ANN static inline m_bool check_exp_decl_parent(const Env env, const Var_Decl var } #define describe_check_decl(a, b) \ -ANN static inline void decl_##a(const Nspc nspc, const Value v) { \ +ANN static inline void decl_##a(const Env env, const Value v) { \ + const Nspc nspc = env->curr;\ SET_FLAG(v, a); \ v->offset = nspc->info->b; \ nspc->info->b += v->type->size; \ @@ -115,10 +116,13 @@ ANN Type check_exp_decl(const Env env, const Exp_Decl* decl) { CHECK_BO(check_exp_decl_parent(env, var)) if(var->array && var->array->exp) CHECK_BO(check_exp_array_subscripts(env, var->array->exp)) - if(GET_FLAG(decl->td, member)) - decl_member(env->curr, v); + if(GET_FLAG(decl->td, member) && env->class_def) { + decl_member(env, v); + if(isa(env->class_def, t_object) > 0) + tuple_info(env, decl->td, var); + } else if(GET_FLAG(decl->td, static)) - decl_static(env->curr, v); + decl_static(env, v); else if(global || (env->func && GET_FLAG(env->func->def, global))) SET_FLAG(v, abstract); if(isa(decl->type, t_fptr) > 0) @@ -220,17 +224,11 @@ ANN static Type check_exp_prim_this(const Env env, const Exp_Primary* primary) { ANN static Type prim_str(const Env env, Exp_Primary *const prim) { if(!prim->value) { const m_str str = prim->d.str; + const Value v = new_value(env->gwion->mp, t_string, str); char c[strlen(str) + 8]; sprintf(c, "%s:string", str); - const Symbol sym = insert_symbol(c); - const Value exist = nspc_lookup_value0(env->global_nspc, sym); - if(exist) - prim->value = exist; - else { - const Value v = new_value(env->gwion->mp, t_string, s_name(sym)); - nspc_add_value(env->global_nspc, sym, v); - prim->value = v; - } + nspc_add_value(env_nspc(env), insert_symbol(c), v); + prim->value = v; } return t_string; } @@ -305,6 +303,19 @@ ANN static Type prim_gack(const Env env, const Exp_Primary * primary) { return t_gack; } +ANN static Type prim_tuple(const Env env, const Exp_Primary * primary) { + CHECK_OO(check_exp(env, primary->d.tuple.exp)) + Exp e = primary->d.tuple.exp; + struct Vector_ v; + vector_init(&v); + do { + vector_add(&v, (m_uint)e->type); + } while((e = e->next)); + const Type ret = tuple_type(env, &v, exp_self(primary)->pos); + vector_release(&v); + return ret; +} + #define describe_prim_xxx(name, type) \ ANN static Type prim_##name(const Env env NUSED, const Exp_Primary * primary NUSED) {\ return type; \ @@ -312,12 +323,14 @@ ANN static Type prim_##name(const Env env NUSED, const Exp_Primary * primary NUS describe_prim_xxx(num, t_int) describe_prim_xxx(float, t_float) describe_prim_xxx(nil, t_void) +describe_prim_xxx(unpack, t_tuple) typedef Type (*_type_func)(const Env, const void*); static const _type_func prim_func[] = { - (_type_func)prim_id, (_type_func)prim_num, (_type_func)prim_float, (_type_func)prim_str, - (_type_func)prim_array, (_type_func)prim_gack, (_type_func)prim_vec, (_type_func)prim_vec, - (_type_func)prim_vec, (_type_func)prim_num, (_type_func)prim_nil, + (_type_func)prim_id, (_type_func)prim_num, (_type_func)prim_float, (_type_func)prim_str, + (_type_func)prim_array, (_type_func)prim_gack, (_type_func)prim_vec, (_type_func)prim_vec, + (_type_func)prim_vec, (_type_func)prim_tuple, (_type_func)prim_unpack, + (_type_func)prim_num, (_type_func)prim_nil, }; ANN static Type check_exp_primary(const Env env, const Exp_Primary* primary) { @@ -325,11 +338,13 @@ ANN static Type check_exp_primary(const Env env, const Exp_Primary* primary) { } ANN Type at_depth(const Env env, const Type t, const m_uint depth) { + if(!depth) + return t; if(GET_FLAG(t, typedef)) - return !depth ? t : at_depth(env, t->e->parent, depth); + return at_depth(env, t->e->parent, depth); if(depth > t->array_depth) return at_depth(env, t->e->d.base_type, depth - t->array_depth); - return !depth ? t : array_type(env, array_base(t), t->array_depth - depth); + return array_type(env, array_base(t), t->array_depth - depth); } static inline m_bool index_is_int(const Env env, Exp e, m_uint *depth) { @@ -346,16 +361,40 @@ static m_bool array_access_valid(const Env env, const Exp_Array* array) { if(depth != array->array->depth) ERR_B(exp_self(array)->pos, _("invalid array acces expression.")) DECL_OB(const Type, t_base, = check_exp(env, array->base)) - if(depth > get_depth(t_base)) + if(depth > get_depth(t_base)) { + const Type type = array_base(t_base) ?: t_base; + if(isa(type, t_tuple) > 0 && depth - get_depth(t_base) == 1) { + Exp e = array->array->exp; + while(e->next) + e = e->next; + if(e->exp_type != ae_exp_primary || + e->d.exp_primary.primary_type != ae_primary_num) + ERR_B(exp_self(array)->pos, _("tuple subscripts must be litteral")) + if((Type)vector_at(&type->e->tuple_form, e->d.exp_primary.d.num) == t_undefined) + ERR_B(exp_self(array)->pos, _("tuple subscripts is undefined")) + return 0; + } ERR_B(exp_self(array)->pos, _("array subscripts (%i) exceeds defined dimension (%i)"), - array->array->depth, depth) + array->array->depth, get_depth(t_base)) + } return GW_OK; } static ANN Type check_exp_array(const Env env, const Exp_Array* array) { CHECK_OO(check_exp(env, array->array->exp)) - CHECK_BO(array_access_valid(env, array)) + const m_bool ret = array_access_valid(env, array); + CHECK_BO(ret); + if(!ret) { + Exp e = array->array->exp; + while(e->next) + e = e->next; + // if we implement tuple with no type, err_msg + const Type type = array_base(array->base->type) ?: array->base->type; + if(e->d.exp_primary.d.num >= vector_size(&type->e->tuple_form)) + ERR_O(exp_self(array)->pos, "Invalid tuple subscript") + return (Type)vector_at(&type->e->tuple_form, e->d.exp_primary.d.num); + } return at_depth(env, array->base->type, array->array->depth); } @@ -486,7 +525,7 @@ ANN static m_bool check_func_args(const Env env, Arg_List arg_list) { } ANN static Func _find_template_match(const Env env, const Value v, const Exp_Call* exp) { - CHECK_BO(check_call(env, exp)) +CHECK_BO(check_call(env, exp)) const Type_List types = exp->tmpl->call; Func m_func = NULL, former = env->func; DECL_OO(const m_str, tmpl_name, = tl2str(env, types)) @@ -498,7 +537,7 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal Func_Base *fbase = cpy_func_base(env->gwion->mp, base->base); fbase->xid = sym; fbase->tmpl->base = 0; - fbase->tmpl->call = cpy_type_list(env->gwion->mp, types); + fbase->tmpl->call = types; if(template_push_types(env, fbase->tmpl) > 0) { const Fptr_Def fptr = new_fptr_def(env->gwion->mp, fbase, base->flag); if(value) { @@ -534,7 +573,7 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal continue; const Func_Def fdef = (Func_Def)cpy_func_def(env->gwion->mp, value->d.func_ref->def); SET_FLAG(fdef, template); - fdef->base->tmpl->call = cpy_type_list(env->gwion->mp, types); + fdef->base->tmpl->call = types; fdef->base->tmpl->base = i; if((m_func = ensure_tmpl(env, fdef, exp))) break; @@ -604,7 +643,6 @@ ANN static Func get_template_func(const Env env, const Exp_Call* func, const Val if(f) { Tmpl* tmpl = new_tmpl_call(env->gwion->mp, func->tmpl->call); tmpl->list = v->d.func_ref ? v->d.func_ref->def->base->tmpl->list : func->func->type->e->d.func->def->base->tmpl->list; -// tmpl->list = cpy_id_list(env->gwion->mp, tmpl->list); ((Exp_Call*)func)->tmpl = tmpl; return ((Exp_Call*)func)->m_func = f; } @@ -701,6 +739,10 @@ ANN Type check_exp_call1(const Env env, const Exp_Call *exp) { CHECK_BO(check_exp_call1_check(env, exp->func)) if(exp->func->type == t_lambda) return check_lambda_call(env, exp); + if(GET_FLAG(exp->func->type->e->d.func, ref)) { + const Value value = exp->func->type->e->d.func->value_ref; + CHECK_BO(traverse_class_def(env, value->owner_class->e->def)) + } if(exp->args) CHECK_OO(check_exp(env, exp->args)) if(GET_FLAG(exp->func->type, func)) @@ -871,7 +913,7 @@ ANN static inline Type check_exp(const Env env, const Exp exp) { ANN m_bool check_enum_def(const Env env, const Enum_Def edef) { if(env->class_def) { ID_List list = edef->list; - do decl_static(env->curr, nspc_lookup_value0(env->curr, list->xid)); + do decl_static(env, nspc_lookup_value0(env->curr, list->xid)); while((list = list->next)); } return GW_OK; @@ -917,7 +959,7 @@ ANN static m_bool do_stmt_auto(const Env env, const Stmt_Auto stmt) { const m_uint depth = t->array_depth - 1; if(GET_FLAG(t, typedef)) t = t->e->parent; - if(!t || !ptr || isa(t, t_array) < 0) + if(!ptr || isa(t, t_array) < 0) ERR_B(stmt_self(stmt)->pos, _("type '%s' is not array.\n" " This is not allowed in auto loop"), stmt->exp->type->name) if(stmt->is_ptr) { @@ -941,10 +983,11 @@ ANN static m_bool do_stmt_auto(const Env env, const Stmt_Auto stmt) { array.depth = depth; td.array = &array; } - ptr = type_decl_resolve(env, &td); +// ptr = type_decl_resolve(env, &td); exit(3); + ptr = known_type(env, &td); if(!GET_FLAG(ptr, checked)) check_class_def(env, ptr->e->def); -// CHECK_BB(traverse_class_def(env, ptr->e->def)) +// traverse_class_def(env, ptr->e->def); } t = depth ? array_type(env, ptr, depth) : ptr; stmt->v = new_value(env->gwion->mp, t, s_name(stmt->sym)); @@ -1054,7 +1097,7 @@ ANN m_bool check_union_def(const Env env, const Union_Def udef) { return GW_OK; if(udef->xid) { if(env->class_def) - (!GET_FLAG(udef, static) ? decl_member : decl_static)(env->curr, udef->value); + (!GET_FLAG(udef, static) ? decl_member : decl_static)(env, udef->value); } else if(env->class_def) { if(!GET_FLAG(udef, static)) udef->o = env->class_def->nspc->info->offset; diff --git a/src/parse/cpy_ast.c b/src/parse/cpy_ast.c index a92b6dc3..c91ee089 100644 --- a/src/parse/cpy_ast.c +++ b/src/parse/cpy_ast.c @@ -21,7 +21,7 @@ ANN static void cpy_exp_lambda(MemPool p, Exp_Lambda *a, const Exp_Lambda *src) a->name = src->name; } -ANN static Array_Sub cpy_array_sub(MemPool p, const Array_Sub src) { +ANN Array_Sub cpy_array_sub(MemPool p, const Array_Sub src) { Array_Sub a = mp_calloc(p, Array_Sub); if(src->exp) a->exp = cpy_exp(p, src->exp); @@ -51,7 +51,7 @@ ANN static Var_Decl_List cpy_var_decl_list(MemPool p, const Var_Decl_List src) { return a; } -ANN static Type_Decl* cpy_type_decl(MemPool p, const Type_Decl* src) { +ANN Type_Decl* cpy_type_decl(MemPool p, const Type_Decl* src) { Type_Decl* a = mp_calloc(p, Type_Decl); if(src->xid) a->xid = cpy_id_list(p, src->xid); // 1 diff --git a/src/parse/scan1.c b/src/parse/scan1.c index a4827218..d4954890 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -16,6 +16,8 @@ ANN static m_bool scan1_stmt(const Env env, Stmt stmt); ANN static Type void_type(const Env env, const Type_Decl* td) { DECL_OO(const Type, t, = known_type(env, td)) + if(t->e->def && !GET_FLAG(t, scan1)) + CHECK_BO(scan1_cdef(env, t->e->def)) if(t->size) return t; ERR_O(td_pos(td), _("cannot declare variables of size '0' (i.e. 'void')...")) @@ -64,8 +66,8 @@ ANN static Type scan1_exp_decl_type(const Env env, Exp_Decl* decl) { if(!GET_FLAG(decl->td, static)) SET_FLAG(decl->td, member); } - if(GET_FLAG(t, abstract) && !GET_FLAG(decl->td, ref)) - ERR_O(exp_self(decl)->pos, _("Type '%s' is abstract, declare as ref. (use @)"), t->name) +// if(GET_FLAG(t, abstract) && !GET_FLAG(decl->td, ref)) +// ERR_O(exp_self(decl)->pos, _("Type '%s' is abstract, declare as ref. (use @)"), t->name) if(GET_FLAG(t, private) && t->e->owner != env->curr) ERR_O(exp_self(decl)->pos, _("can't use private type %s"), t->name) if(GET_FLAG(t, protect) && (!env->class_def || isa(t, env->class_def) < 0)) @@ -87,22 +89,26 @@ ANN m_bool scan1_exp_decl(const Env env, const Exp_Decl* decl) { CHECK_BB(isres(env, var->xid, exp_self(decl)->pos)) Type t = decl->type; const Value former = nspc_lookup_value0(env->curr, var->xid); - if(former) + if(former && t != t_auto) ERR_B(var->pos, _("variable %s has already been defined in the same scope..."), s_name(var->xid)) if(var->array) { if(var->array->exp) { - if(GET_FLAG(decl->td, ref)) +// if(GET_FLAG(decl->td, ref)) + if(GET_FLAG(decl->td, ref) && isa(t, t_object) < 0) ERR_B(td_pos(decl->td), _("ref array must not have array expression.\n" - "e.g: int @my_array[];\nnot: @int my_array[2];")) + "e.g: int @my_array[];\nnot: int @my_array[2];")) CHECK_BB(scan1_exp(env, var->array->exp)) } t = array_type(env, decl->type, var->array->depth); - } - assert(!var->value); - const Value v = var->value = new_value(env->gwion->mp, t, s_name(var->xid)); + } else if(GET_FLAG(t, abstract) && !GET_FLAG(decl->td, ref)) + ERR_B(exp_self(decl)->pos, _("Type '%s' is abstract, declare as ref. (use @)"), t->name) + + //assert(!var->value); + const Value v = var->value = former ?: new_value(env->gwion->mp, t, s_name(var->xid)); nspc_add_value(nspc, var->xid, v); v->flag = decl->td->flag; + v->type = t; if(var->array && !var->array->exp) SET_FLAG(v, ref); if(!env->scope->depth && !env->class_def) @@ -127,6 +133,10 @@ ANN static inline m_bool scan1_exp_primary(const Env env, const Exp_Primary* pri return scan1_exp(env, prim->d.exp); if(prim->primary_type == ae_primary_array && prim->d.array->exp) return scan1_exp(env, prim->d.array->exp); + if(prim->primary_type == ae_primary_tuple) + return scan1_exp(env, prim->d.tuple.exp); +// if(prim->primary_type == ae_primary_unpack) +// return scan1_exp(env, prim->d.tuple.exp); return GW_OK; } @@ -246,7 +256,9 @@ ANN m_bool scan1_fptr_def(const Env env, const Fptr_Def fptr) { } ANN m_bool scan1_type_def(const Env env, const Type_Def tdef) { - return tdef->type->e->def ? scan1_cdef(env, tdef->type->e->def) : GW_OK; + if(!tdef->type->e->def)return GW_OK; +// return tdef->type->e->def ? scan1_cdef(env, tdef->type->e->def) : GW_OK; + return isa(tdef->type, t_fptr) < 0 ? scan1_cdef(env, tdef->type->e->def) : GW_OK; } ANN m_bool scan1_union_def(const Env env, const Union_Def udef) { @@ -358,7 +370,8 @@ ANN static m_bool scan1_parent(const Env env, const Class_Def cdef) { if(isa(parent, t_object) < 0) ERR_B(pos, _("cannot extend primitive type '%s'"), parent->name) if(parent->e->def && !GET_FLAG(parent, scan1)) - CHECK_BB(scanx_parent(parent, scan1_cdef, env)) +// CHECK_BB(scanx_parent(parent, scan1_cdef, env)) + CHECK_BB(scan1_cdef(env, parent->e->def)) if(type_ref(parent)) ERR_B(pos, _("can't use ref type in class extend")) return GW_OK; diff --git a/src/parse/scan2.c b/src/parse/scan2.c index d717fca9..ca970270 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -21,7 +21,7 @@ ANN m_bool scan2_exp_decl(const Env env, const Exp_Decl* decl) { const m_bool global = GET_FLAG(decl->td, global); const m_uint scope = !global ? env->scope->depth : env_push_global(env); const Type type = decl->type; - if(GET_FLAG(type, template) && !GET_FLAG(type, scan2)) + if(type->e->def && /*GET_FLAG(type, template) &&*/ !GET_FLAG(type, scan2)) CHECK_BB(scan2_cdef(env, decl->type->e->def)) Var_Decl_List list = decl->list; do { @@ -86,11 +86,14 @@ ANN m_bool scan2_fptr_def(const Env env, const Fptr_Def fptr) { CHECK_BB(scan2_args(env, def)) } else SET_FLAG(fptr->type, func); +// nspc_add_func(fptr->type->e->owner, fptr->base->xid, fptr->base->func); return GW_OK; } ANN m_bool scan2_type_def(const Env env, const Type_Def tdef) { - return tdef->type->e->def ? scan2_class_def(env, tdef->type->e->def) : GW_OK; +// return tdef->type->e->def ? scan2_class_def(env, tdef->type->e->def) : GW_OK; + if(!tdef->type->e->def) return GW_OK; + return isa(tdef->type, t_fptr) < 0 ? scan2_class_def(env, tdef->type->e->def) : GW_OK; } ANN static inline Value prim_value(const Env env, const Symbol s) { @@ -119,6 +122,10 @@ ANN static inline m_bool scan2_exp_primary(const Env env, const Exp_Primary* pri SET_FLAG(v, used); } else if(prim->primary_type == ae_primary_array && prim->d.array->exp) return scan2_exp(env, prim->d.array->exp); + if(prim->primary_type == ae_primary_tuple) + return scan2_exp(env, prim->d.tuple.exp); +// if(prim->primary_type == ae_primary_unpack) +// return scan2_exp(env, prim->d.tuple.exp); return GW_OK; } @@ -308,7 +315,7 @@ ANN static Type func_type(const Env env, const Func func) { ANN2(1,2) static Value func_value(const Env env, const Func f, const Value overload) { const Type t = func_type(env, f); - const Value v = new_value(env->gwion->mp, t, s_name(insert_symbol(t->name))); + const Value v = new_value(env->gwion->mp, t, t->name); CHECK_OO(scan2_func_assign(env, f->def, f, v)) if(!overload) { ADD_REF(v); diff --git a/src/parse/scanx.c b/src/parse/scanx.c index 3dc5882b..1bcf1c51 100644 --- a/src/parse/scanx.c +++ b/src/parse/scanx.c @@ -17,7 +17,7 @@ ANN static inline m_bool _body(const Env e, Class_Body b, const _exp_func f) { } ANN static inline int actual(const Tmpl *tmpl) { - return tmpl->call && tmpl->call != (Type_List)1; + return tmpl->call && tmpl->call != (Type_List)1 && tmpl->list; } ANN static inline m_bool tmpl_push(const Env env, const Tmpl* tmpl) { @@ -31,7 +31,7 @@ ANN static inline m_int _push(const Env env, const Class_Def c) { } ANN static inline void _pop(const Env e, const Class_Def c, const m_uint s) { - if(c->base.tmpl && actual(c->base.tmpl)) + if(c->base.tmpl && actual(c->base.tmpl) && c->base.tmpl->list) nspc_pop_type(e->gwion->mp, e->curr); env_pop(e, s); } @@ -72,7 +72,7 @@ scanx_parent(const Type t, const _exp_func f, void* d) { ANN m_bool scanx_cdef(const Env env, void* opt, const Class_Def cdef, const _exp_func f_cdef, const _exp_func f_union) { - if(cdef->base.type && cdef->base.type->e->parent != t_union) + if(cdef->base.type->e->parent != t_union) return f_cdef(opt, cdef); CHECK_BB(template_push_types(env, cdef->base.tmpl)) const m_bool ret = f_union(opt, cdef->union_def); diff --git a/src/parse/template.c b/src/parse/template.c index d279925f..03c955fd 100644 --- a/src/parse/template.c +++ b/src/parse/template.c @@ -155,6 +155,22 @@ extern ANN m_bool scan1_class_def(const Env, const Class_Def); extern ANN m_bool traverse_func_def(const Env, const Func_Def); extern ANN m_bool traverse_class_def(const Env, const Class_Def); +ANN Type scan_tuple(const Env env, const Type_Decl *td) { + struct Vector_ v; + vector_init(&v); + Type_List tl = td->types; + do { + const Type t = tl->td->xid->xid != insert_symbol("_") ? + known_type(env, tl->td) : 1; + if(!t) + break; + vector_add(&v, (m_uint)t); + } while((tl = tl->next)); + const Type ret = tuple_type(env, &v, td_pos(td)); + vector_release(&v); + return ret; +} + ANN Tmpl* mk_tmpl(const Env env, const Type t, const Tmpl *tm, const Type_List types) { Tmpl *tmpl = new_tmpl(env->gwion->mp, get_total_type_list(env, t, tm), 0); tmpl->call = cpy_type_list(env->gwion->mp, types); @@ -165,34 +181,40 @@ ANN Type scan_type(const Env env, const Type t, const Type_Decl* type) { if(GET_FLAG(t, template)) { if(GET_FLAG(t, ref)) return t; - if(!type->types) - ERR_O(t->e->def->pos, - _("you must provide template types for type '%s'"), t->name) - if(template_match(t->e->def->base.tmpl->list, type->types) < 0) - ERR_O(type->xid->pos, _("invalid template types number")) - DECL_OO(const Class_Def, a, = template_class(env, t->e->def, type->types)) - SET_FLAG(a, ref); - if(a->base.type) - return a->base.type; - a->base.tmpl = mk_tmpl(env, t, t->e->def->base.tmpl, type->types); - if(t->e->parent != t_union) { - CHECK_BO(scan0_class_def(env, a)) - map_set(&env->curr->info->type->map, (vtype)a->base.xid, (vtype)a->base.type); - } else { - a->union_def = new_union_def(env->gwion->mp, a->list, t->e->def->pos); - a->union_def->type_xid = a->base.xid; - CHECK_BO(scan0_union_def(env, a->union_def)) - a->base.type = a->union_def->type; - a->base.type->e->def = a; - assert(GET_FLAG(a, union)); - } - SET_FLAG(a->base.type, template | ae_flag_ref); - a->base.type->e->owner = t->e->owner; - if(GET_FLAG(t, builtin)) + if(!type->types) { + if(t != t_tuple) + ERR_O(t->e->def->pos, + _("you must provide template types for type '%s'"), t->name) + return t; + } + if(t->e->def) {// not tuple + if(template_match(t->e->def->base.tmpl->list, type->types) < 0) + ERR_O(type->xid->pos, _("invalid template types number")) + DECL_OO(const Class_Def, a, = template_class(env, t->e->def, type->types)) + SET_FLAG(a, ref); + if(a->base.type) + return a->base.type; + a->base.tmpl = mk_tmpl(env, t, t->e->def->base.tmpl, type->types); + if(t->e->parent != t_union) { + CHECK_BO(scan0_class_def(env, a)) + map_set(&env->curr->info->type->map, (vtype)a->base.xid, (vtype)a->base.type); + } else { + a->union_def = new_union_def(env->gwion->mp, a->list, t->e->def->pos); + a->union_def->type_xid = a->base.xid; + CHECK_BO(scan0_union_def(env, a->union_def)) + a->base.type = a->union_def->type; + a->base.type->e->def = a; + assert(GET_FLAG(a, union)); + } + SET_FLAG(a->base.type, template | ae_flag_ref); + a->base.type->e->owner = t->e->owner; + if(GET_FLAG(t, builtin)) SET_FLAG(a->base.type, builtin); - CHECK_BO(scan1_cdef(env, a)) - return a->base.type; - } else if(type->types) { // TODO: clean me + CHECK_BO(scan1_cdef(env, a)) + return a->base.type; + } else + return scan_tuple(env, type); + } else if(type->types) { // TODO: clean me if(isa(t, t_function) > 0 && t->e->d.func->def->base->tmpl) { DECL_OO(const m_str, tl_name, = tl2str(env, type->types)) const Symbol sym = func_symbol(env, t->e->owner->name, t->e->d.func->name, tl_name, 0); diff --git a/src/parse/tuple.c b/src/parse/tuple.c new file mode 100644 index 00000000..38b88ea2 --- /dev/null +++ b/src/parse/tuple.c @@ -0,0 +1,86 @@ +#include +#include "gwion_util.h" +#include "gwion_ast.h" +#include "oo.h" +#include "vm.h" +#include "env.h" +#include "type.h" +#include "func.h" +#include "value.h" +#include "nspc.h" +#include "traverse.h" +#include "template.h" +#include "vm.h" +#include "parse.h" +#include "gwion.h" +#include "cpy_ast.h" + + +ANN static Symbol tuple_sym(const Env env, const Vector v) { + GwText text = { .mp=env->gwion->mp }; + text_add(&text, t_tuple->name); + text_add(&text, "<~"); + for(m_uint i = 0; i < vector_size(v); ++i) { + const Type t = (Type)vector_at(v, i); + text_add(&text, t != 1 ? t->name : "_"); + if(i+1 < vector_size(v)) + text_add(&text, ","); + } + text_add(&text, "~>"); + const Symbol sym = insert_symbol(text.str); + text_release(&text); + return sym; +} + +ANN Type tuple_type(const Env env, const Vector v, const loc_t pos) { + const Symbol sym = tuple_sym(env, v); + const Type exists = nspc_lookup_type1(env->curr, sym); + if(exists) + return exists; + Stmt_List base = NULL, curr = NULL; + Type_List tlbase = NULL, tl = NULL; + for(m_uint i = 0; i < vector_size(v); ++i) { + char name[num_digit(i) + 2]; + sprintf(name, "e%lu", i); + const Symbol sym = insert_symbol(name); + const Type t = (Type)vector_at(v, i); + const Symbol tsym = insert_symbol(t != 1 ? t->name : "@Undefined"); +// const Symbol tsym = t != 1 ? insert_symbol(t->name) : insert_symbol("@undefined"); + Exp decl = decl_from_id(env->gwion->mp, tsym, sym, loc_cpy(env->gwion->mp, pos)); + const Stmt stmt = new_stmt_exp(env->gwion->mp, ae_stmt_exp, decl); + const Stmt_List slist = new_stmt_list(env->gwion->mp, stmt, NULL); + if(curr) + curr->next = slist; + if(!base) + base = slist; +{// build Type_List + const ID_List ilist = new_id_list(env->gwion->mp, tsym, + loc_cpy(env->gwion->mp, pos)); + Type_Decl *td = new_type_decl(env->gwion->mp, ilist); + Type_List tmp_tl = new_type_list(env->gwion->mp, td, NULL); + if(tl) + tl->next = tmp_tl; + if(!tlbase) + tlbase = tl = tmp_tl; + +} + curr = slist; + } + Section * section = new_section_stmt_list(env->gwion->mp, base); + Class_Body body = new_class_body(env->gwion->mp, section, NULL); + const ID_List ilist = new_id_list(env->gwion->mp, insert_symbol(t_tuple->name), + loc_cpy(env->gwion->mp, pos)); + Type_Decl *td = new_type_decl(env->gwion->mp, ilist); + Class_Def cdef = new_class_def(env->gwion->mp, ae_flag_template, + sym, td, body, loc_cpy(env->gwion->mp, pos)); + Tmpl* tmpl = new_tmpl_call(env->gwion->mp, tlbase); + cdef->base.tmpl = tmpl; + CHECK_BO(scan0_class_def(env, cdef)) + SET_FLAG(cdef->base.type, abstract); + cdef->base.type->e->tuple_tl = tlbase; +// CHECK_BO(scan1_cdef(env, cdef)) + CHECK_BO(traverse_cdef(env, cdef)) + nspc_add_type(env->curr, sym, cdef->base.type); +// map_set((Map)vector_front(&env->curr->info->type), sym, cdef->base.type); + return cdef->base.type; +} diff --git a/src/vm/vm.c b/src/vm/vm.c index db8e46c4..129eba1d 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -762,6 +762,7 @@ allocmemberaddr: reg += SZ_INT; DISPATCH() dotmember: +//printf("VAL %lu %p\n", VAL, ); *(m_uint*)(reg-SZ_INT) = *(m_uint*)(a.obj->data + VAL); DISPATCH() dotfloat: diff --git a/tests/nonnull/ref.gw b/tests/nonnull/ref.gw new file mode 100644 index 00000000..34c99852 --- /dev/null +++ b/tests/nonnull/ref.gw @@ -0,0 +1 @@ +new Object @=> Object ! @ o; diff --git a/tests/tuple/object2tuple.gw b/tests/tuple/object2tuple.gw new file mode 100644 index 00000000..4bb432e3 --- /dev/null +++ b/tests/tuple/object2tuple.gw @@ -0,0 +1,8 @@ +class Person { + "Phil" @=> string @name; + 45 => int age; +} + +Person p @=> <~string,int~>Tuple @t; +<<>>; +<<>>; diff --git a/tests/tuple/object2tuple_err.gw b/tests/tuple/object2tuple_err.gw new file mode 100644 index 00000000..525c774e --- /dev/null +++ b/tests/tuple/object2tuple_err.gw @@ -0,0 +1,8 @@ +class Person { + "Phil" @=> string @name; + 45 => int age; +} + +Person p @=> <~string,string~>Tuple @t; +<<>>; +<<>>; diff --git a/tests/tuple/object_array_access_multi.gw b/tests/tuple/object_array_access_multi.gw new file mode 100644 index 00000000..e9f2f9f8 --- /dev/null +++ b/tests/tuple/object_array_access_multi.gw @@ -0,0 +1,9 @@ +Object t[2]; +#!<<< t[0] >>>; +#!null @=> t[0]; +<<< t >>>; +<("tom", 12) @=> t[0]; +#!t << <("tom", 12); +#!<<< t.size() >>>; +#!<<< t[0][0] >>>; +#!<<< t[0][1] >>>; diff --git a/tests/tuple/tupl_decl.gw b/tests/tuple/tupl_decl.gw new file mode 100644 index 00000000..9ee94d53 --- /dev/null +++ b/tests/tuple/tupl_decl.gw @@ -0,0 +1 @@ +Tuple @u; diff --git a/tests/tuple/tuple.gw b/tests/tuple/tuple.gw new file mode 100644 index 00000000..9ee94d53 --- /dev/null +++ b/tests/tuple/tuple.gw @@ -0,0 +1 @@ +Tuple @u; diff --git a/tests/tuple/tuple_abstract.gw b/tests/tuple/tuple_abstract.gw new file mode 100644 index 00000000..3335d05b --- /dev/null +++ b/tests/tuple/tuple_abstract.gw @@ -0,0 +1,2 @@ +#! [contains] Type 'Tuple' is abstract, declare as ref +Tuple u; diff --git a/tests/tuple/tuple_aray_access.gw b/tests/tuple/tuple_aray_access.gw new file mode 100644 index 00000000..1c043df2 --- /dev/null +++ b/tests/tuple/tuple_aray_access.gw @@ -0,0 +1,6 @@ +<<< <("Tom", 12)[0] >>> ; +#! <<< <("Tom", 12)[1] >>> ; + +#! <<< <("Tom", 12) @=> <~string, int~>Tuple @t >>> ; +#! <<< t[0] >>> ; +#! <<< t[1] >>> ; diff --git a/tests/tuple/tuple_aray_access_exceed.gw b/tests/tuple/tuple_aray_access_exceed.gw new file mode 100644 index 00000000..69fd159f --- /dev/null +++ b/tests/tuple/tuple_aray_access_exceed.gw @@ -0,0 +1 @@ +<("Tom", 12)[0][2]; diff --git a/tests/tuple/tuple_aray_access_multi.gw b/tests/tuple/tuple_aray_access_multi.gw new file mode 100644 index 00000000..0a30f810 --- /dev/null +++ b/tests/tuple/tuple_aray_access_multi.gw @@ -0,0 +1,11 @@ +<~string,int~>Tuple t[2]; +#!<<< t[0] >>>; +#!null @=> t[0]; +<<< t >>>; +<<< t[0] >>>; +<<< <("tom", 12) @=> t[0] >>> ; + +#!t << <("tom", 12); +#!<<< t.size() >>>; +#!<<< t[0][0] >>>; +#!<<< t[0][1] >>>; diff --git a/tests/tuple/tuple_aray_access_not_prim.gw b/tests/tuple/tuple_aray_access_not_prim.gw new file mode 100644 index 00000000..3afc0e14 --- /dev/null +++ b/tests/tuple/tuple_aray_access_not_prim.gw @@ -0,0 +1,2 @@ +int i; +<("Tom", 12)[i]; diff --git a/tests/tuple/tuple_array_access_invalid.gw b/tests/tuple/tuple_array_access_invalid.gw new file mode 100644 index 00000000..6b23d6b2 --- /dev/null +++ b/tests/tuple/tuple_array_access_invalid.gw @@ -0,0 +1 @@ +<(1.2,"test")[3]; diff --git a/tests/tuple/tuple_at.gw b/tests/tuple/tuple_at.gw new file mode 100644 index 00000000..59549565 --- /dev/null +++ b/tests/tuple/tuple_at.gw @@ -0,0 +1,4 @@ +<("Tom", 6) @=> +<~string, int~>Tuple @tup; +<<< typeof(tup) >>>; +<<< tup >>>; diff --git a/tests/tuple/tuple_at_err.gw b/tests/tuple/tuple_at_err.gw new file mode 100644 index 00000000..3ec6aa60 --- /dev/null +++ b/tests/tuple/tuple_at_err.gw @@ -0,0 +1,4 @@ +<("Tom", 6) @=> +<~float, int~>Tuple @tup; +<<< typeof(tup) >>>; +<<< tup >>>; diff --git a/tests/tuple/tuple_at_lit.gw b/tests/tuple/tuple_at_lit.gw new file mode 100644 index 00000000..981b5e02 --- /dev/null +++ b/tests/tuple/tuple_at_lit.gw @@ -0,0 +1,2 @@ +#! [contains] cannot assign +<("Tom", 6) @=> <("Pat", 22); diff --git a/tests/tuple/tuple_cast.gw b/tests/tuple/tuple_cast.gw new file mode 100644 index 00000000..2c036120 --- /dev/null +++ b/tests/tuple/tuple_cast.gw @@ -0,0 +1,4 @@ +<~int~>Tuple @a; + +<<< a >>>; +<<< a $ Tuple >>>; diff --git a/tests/tuple/tuple_cast2.gw b/tests/tuple/tuple_cast2.gw new file mode 100644 index 00000000..df197328 --- /dev/null +++ b/tests/tuple/tuple_cast2.gw @@ -0,0 +1,4 @@ +<~int,int~>Tuple @a; + +<<< a >>>; +<<< a $ <~int~>Tuple >>>; diff --git a/tests/tuple/tuple_decl.gw b/tests/tuple/tuple_decl.gw new file mode 100644 index 00000000..c14ce68b --- /dev/null +++ b/tests/tuple/tuple_decl.gw @@ -0,0 +1 @@ +<~int~>Tuple @a; diff --git a/tests/tuple/tuple_implicit.gw b/tests/tuple/tuple_implicit.gw new file mode 100644 index 00000000..c589d309 --- /dev/null +++ b/tests/tuple/tuple_implicit.gw @@ -0,0 +1,8 @@ +#! [contains] Tom +fun void test(<~string~>Tuple t) { +#! <<< t.e0 >>>; + <<< t[0] >>>; +} + +<( "Tom", 21) => test; +#!<("Tom") => test; diff --git a/tests/tuple/tuple_lit_error.gw b/tests/tuple/tuple_lit_error.gw new file mode 100644 index 00000000..2e89d2dd --- /dev/null +++ b/tests/tuple/tuple_lit_error.gw @@ -0,0 +1 @@ +<( new int); diff --git a/tests/tuple/tuple_skip.gw b/tests/tuple/tuple_skip.gw new file mode 100644 index 00000000..73c6499f --- /dev/null +++ b/tests/tuple/tuple_skip.gw @@ -0,0 +1,2 @@ +<(1, 2, 3) @=> >(b, _, c); +<<< c >>>; diff --git a/tests/tuple/tuple_skip2.gw b/tests/tuple/tuple_skip2.gw new file mode 100644 index 00000000..bc0abe75 --- /dev/null +++ b/tests/tuple/tuple_skip2.gw @@ -0,0 +1,6 @@ +<("Tom", 2, "Taxi driver") @=> <~string,_, string~>Tuple @t; +<<< t>>>; +<<< t[0]>>>; +<("Tom", 2.3, "Cook") @=> t; +#!<<< t[1]>>>; +<<< t[2]>>>; diff --git a/tests/tuple/tuple_unknown.gw b/tests/tuple/tuple_unknown.gw new file mode 100644 index 00000000..2e9ca60d --- /dev/null +++ b/tests/tuple/tuple_unknown.gw @@ -0,0 +1,2 @@ +<~int, strong~>Tuple @a; +<~int, string~>Tuple @a; diff --git a/tests/tuple/tuple_unpack_already_declared.gw b/tests/tuple/tuple_unpack_already_declared.gw new file mode 100644 index 00000000..e44abee7 --- /dev/null +++ b/tests/tuple/tuple_unpack_already_declared.gw @@ -0,0 +1,3 @@ +#! [contains] already been defined in the same scope +int i; +<(12) @=> >(i); -- 2.43.0