From: Jérémie Astor Date: Mon, 4 May 2020 21:22:37 +0000 (+0200) Subject: :bomb: Big commit (missing fork) X-Git-Tag: nightly~1686 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=c3219009a4939b6fd76548d720cb34206eb6f4f9;p=gwion.git :bomb: Big commit (missing fork) --- diff --git a/ast b/ast index 50ab3bf5..a65a3503 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit 50ab3bf5f4dbbbc493e382d0a74cd8a9cd6f2b7b +Subproject commit a65a350359e30f6b8da0af1ba98d282fc9ea1b2f diff --git a/examples/fork.gw b/examples/fork.gw deleted file mode 100644 index 63256ea8..00000000 --- a/examples/fork.gw +++ /dev/null @@ -1,11 +0,0 @@ -fork { - <<< "start" >>>; - 12::samp => now; - me.test_cancel(); - <<< "stop" >>>; -} @=> Fork ref f; - -1 => f.set_cancel; -2::samp => now; -0 => f.set_cancel; -f.join(); diff --git a/include/driver.h b/include/driver.h index af2a71b6..06b20f52 100644 --- a/include/driver.h +++ b/include/driver.h @@ -16,7 +16,7 @@ typedef void (*f_bbqset)(struct DriverData_*); typedef void (*f_bbqrun)(const struct VM_*); typedef struct BBQ_ { - uint64_t pos; + volatile uint64_t pos; m_float* in; m_float* out; struct SoundInfo_ *si; @@ -27,7 +27,7 @@ typedef struct BBQ_ { } Driver; #define DRVINI(a) ANN m_bool a(struct VM_ *vm NUSED, Driver* di NUSED) -#define DRVRUN(a) ANN void a(struct VM_ *vm NUSED, Driver* di NUSED) +#define DRVRUN(a) ANN void a(struct VM_ *vm NUSED, Driver *di NUSED) #define DRVDEL(a) ANN void a(struct VM_ *vm NUSED, Driver* di NUSED) ANN void dummy_driver(DriverData*); diff --git a/include/env/env.h b/include/env/env.h index 7b05267c..1615a0fd 100644 --- a/include/env/env.h +++ b/include/env/env.h @@ -34,19 +34,20 @@ ANN2(1,3) m_uint env_push(const Env, const Type, const Nspc); ANN static inline m_uint env_push_global(const Env env) { return env_push(env, NULL, env->global_nspc); } ANN void env_pop(const Env, const m_uint); ANN Map env_label(const Env); -ANN Type scan_type(const Env, const Type, const Type_Decl*); -ANN Type type_decl_resolve(const Env, const Type_Decl*); +ANN Type scan_type(const Env, const Type, Type_Decl*); +//ANN Type type_decl_resolve(const Env, const Type_Decl*); +ANN Type type_decl_resolve(const Env, Type_Decl*); ANN Value mk_class(const Env env, const Type base); // tl2str returns a mp_alloced string ANEW ANN m_str tl2str(const Env, const Type_List); // in type_decl.c ANN m_bool compat_func(const __restrict__ Func_Def, const __restrict__ Func_Def); -ANN Type known_type(const Env env, const Type_Decl*); +ANN Type known_type(const Env env, Type_Decl*); ANN Type type_nonnull(const Env env, const Type base); ANN Type prim_ref(const Env env, const Type t, const Type_Decl* td); ANN m_bool env_access(const Env env, const ae_flag flag, const loc_t pos); ANN m_bool env_storage(const Env env, ae_flag flag, const loc_t pos); ANN void env_add_type(const Env, const Type); -ANN Type find_type(const Env, ID_List); +ANN Type find_type(const Env, Type_Decl*); ANN m_bool already_defined(const Env env, const Symbol s, const loc_t pos); ANN m_bool type_engine_check_prog(const Env, const Ast); ANN m_bool traverse_func_template(const Env, const Func_Def); diff --git a/include/env/envset.h b/include/env/envset.h new file mode 100644 index 00000000..e6d54985 --- /dev/null +++ b/include/env/envset.h @@ -0,0 +1,17 @@ +#ifndef __ENVSET +#define __ENVSET + +typedef m_bool (*envset_func)(const void*,const void*); +struct EnvSet { + const Env env; + const envset_func func; + const void *data; + const m_int scope; + const ae_flag flag; + m_bool run; +}; + +ANN m_bool envset_run(struct EnvSet *es, const Type t); +ANN m_bool envset_push(struct EnvSet *es, const Type t); +ANN void envset_pop(struct EnvSet *es, const Type t); +#endif diff --git a/include/env/tuple.h b/include/env/tuple.h index b4af992b..a39d2b7d 100644 --- a/include/env/tuple.h +++ b/include/env/tuple.h @@ -8,7 +8,7 @@ struct TupleForm_ { }; ANN Type tuple_type(const Env, const Vector, const loc_t); -ANN void tuple_info(const Env, Type_Decl*, const Var_Decl); +ANN void tuple_info(const Env, const Value); ANN2(1) TupleForm new_tupleform(MemPool p, const Type parent_type); ANN void free_tupleform(const TupleForm tuple); diff --git a/include/env/type.h b/include/env/type.h index 874bdf7f..5f4ce826 100644 --- a/include/env/type.h +++ b/include/env/type.h @@ -2,14 +2,14 @@ #define __TYPE struct TypeInfo_ { - Type parent; - Nspc owner; + Type parent; + Nspc owner; + Type owner_class; Class_Def def; union type_data { Func func; Type base_type; } d; - struct Vector_ contains; struct TupleForm_* tuple; struct VM_Code_ *gack; struct Context_ *ctx; diff --git a/include/gwion_env.h b/include/gwion_env.h index 0c53207f..61762f18 100644 --- a/include/gwion_env.h +++ b/include/gwion_env.h @@ -10,4 +10,5 @@ #include "env/func.h" #include "env/context.h" #include "env/tuple.h" +#include "env/envset.h" #endif diff --git a/include/import/checker.h b/include/import/checker.h index 52e8b7a3..4465172a 100644 --- a/include/import/checker.h +++ b/include/import/checker.h @@ -43,20 +43,11 @@ typedef struct OperCK { // name_checker ? m_str rhs;// oper } OperCK; -struct array_checker { - m_str str; - Exp base, exp; - m_uint depth; - m_uint sz; - m_bool is_exp; -}; - ANN void func_checker_clean(const Gwi gwi, struct ImportCK *ck); ANN m_bool check_typename_def(const Gwi gwi, struct ImportCK *ck); ANN ID_List tmpl_valid(const Gwi gwi, const m_str str); ANN Symbol str2sym(const Gwi gwi, const m_str path); ANN ID_List str2symlist(const Gwi gwi, const m_str path); -ANN ID_List ck2list(const Gwi gwi, struct array_checker *ck); ANN m_bool ck_ini(const Gwi, const enum importck_type); ANN m_bool ck_ok(const Gwi, const enum importck_type); diff --git a/include/import/internals.h b/include/import/internals.h index d014f5c6..fc58056c 100644 --- a/include/import/internals.h +++ b/include/import/internals.h @@ -1,8 +1,9 @@ #ifndef __IMPORT_INTERNALS #define __IMPORT_INTERNALS -#define GWI_ERR_B(a,...) { env_err(gwi->gwion->env, gwi->loc, (a), ## __VA_ARGS__); return GW_ERROR; } -#define GWI_ERR_O(a,...) { env_err(gwi->gwion->env, gwi->loc, (a), ## __VA_ARGS__); return NULL; } +#define GWI_ERR(a,...) { env_err(gwi->gwion->env, gwi->loc, (a), ## __VA_ARGS__); } +#define GWI_ERR_B(a,...) { GWI_ERR((a), ## __VA_ARGS__); return GW_ERROR; } +#define GWI_ERR_O(a,...) { GWI_ERR((a), ## __VA_ARGS__); return NULL; } #define ENV_ERR_B(pos, a,...) { env_err(env, pos, (a), ## __VA_ARGS__); return GW_ERROR; } #define ENV_ERR_O(pos, a,...) { env_err(env, pos, (a), ## __VA_ARGS__); return NULL; } diff --git a/include/object.h b/include/object.h index 00f76e7f..dfad90a5 100644 --- a/include/object.h +++ b/include/object.h @@ -5,7 +5,7 @@ struct M_Object_ { m_bit* data; Type type_ref; Vector vtable; - /* volatile */size_t ref; + volatile size_t ref; }; ANN void instantiate_object(const VM_Shred, const Type); @@ -21,6 +21,7 @@ ANN void fork_launch(VM const*, const M_Object, const m_uint); ANN void __release(const M_Object, const VM_Shred); ANN void exception(const VM_Shred, const m_str); ANN void broadcast(const M_Object); + #define STRING(o) (*(m_str*) ((M_Object)o)->data) #define ME(o) (*(VM_Shred*) ((M_Object)o)->data) #define EV_SHREDS(o) (*(Vector*) ((M_Object)o)->data) diff --git a/include/opcode.h b/include/opcode.h index 1dc04395..2b33fe5b 100644 --- a/include/opcode.h +++ b/include/opcode.h @@ -130,10 +130,10 @@ enum { eFuncUsrEnd, eFuncMemberEnd, eSporkIni, + eForkIni, eSporkFunc, eSporkMemberFptr, eSporkExp, - eForkEnd, eSporkEnd, eBranchEqInt, eBranchNeqInt, @@ -308,10 +308,10 @@ enum { #define FuncUsrEnd (f_instr)eFuncUsrEnd #define FuncMemberEnd (f_instr)eFuncMemberEnd #define SporkIni (f_instr)eSporkIni +#define ForkIni (f_instr)eForkIni #define SporkFunc (f_instr)eSporkFunc #define SporkMemberFptr (f_instr)eSporkMemberFptr #define SporkExp (f_instr)eSporkExp -#define ForkEnd (f_instr)eForkEnd #define SporkEnd (f_instr)eSporkEnd #define BranchEqInt (f_instr)eBranchEqInt #define BranchNeqInt (f_instr)eBranchNeqInt diff --git a/include/template.h b/include/template.h index b8db06a2..df61fe13 100644 --- a/include/template.h +++ b/include/template.h @@ -1,6 +1,7 @@ #ifndef __TEMPLATE #define __TEMPLATE ANN m_bool template_push_types(const Env, const Tmpl*); +ANN m_bool template_push(const Env env, const Type t); ANN Tmpl* mk_tmpl(const Env, const Tmpl*, const Type_List); #define POP_RET(a) { nspc_pop_type(env->gwion->mp, env->curr); return (a); } #endif diff --git a/opcode.txt b/opcode.txt index 8c1b8863..62c4fb4b 100644 --- a/opcode.txt +++ b/opcode.txt @@ -127,10 +127,10 @@ Overflow FuncUsrEnd FuncMemberEnd SporkIni +ForkIni SporkFunc SporkMemberFptr SporkExp -ForkEnd SporkEnd BranchEqInt BranchNeqInt diff --git a/src/emit/emit.c b/src/emit/emit.c index f7988a87..93096d75 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -491,6 +491,16 @@ ANN static inline void struct_interp(const Emitter emit, const Exp e) { } } +ANN static void interp_multi(const Emitter emit, Var_Decl_List list) { + m_uint offset = 0; + while(list->next) { + offset += SZ_INT; + list = list->next; + } + if(offset) + regpop(emit, offset); +} + ANN static m_bool emit_interp(const Emitter emit, const Exp exp) { regpushi(emit, 0); Exp e = exp, next = NULL; @@ -502,8 +512,11 @@ ANN static m_bool emit_interp(const Emitter emit, const Exp exp) { e->next = next; return GW_ERROR; } + const m_bool isobj = isa(e->info->type, emit->gwion->type[et_object]) > 0; + if(isobj && e->exp_type == ae_exp_decl) // why only objects? + interp_multi(emit, e->d.exp_decl.list); regseti(emit, (m_uint)e->info->type); - if(isa(e->info->type, emit->gwion->type[et_object]) > 0 && !GET_FLAG(e->info->type, force)) + if(isobj && !GET_FLAG(e->info->type, force)) emit_add_instr(emit, GackType); const Instr instr = emit_add_instr(emit, Gack); instr->m_val = emit_code_offset(emit); @@ -582,8 +595,7 @@ ANN static m_bool emit_exp_decl_non_static(const Emitter emit, const Exp_Decl *d const Array_Sub array = var_decl->array; const m_bool is_array = (array && array->exp) || GET_FLAG(decl->td, force); const m_bool is_obj = isa(type, emit->gwion->type[et_object]) > 0; - const uint emit_addr = ((is_ref && !array) || isa(type, emit->gwion->type[et_object]) < 0) ? - emit_var : 1; + const uint emit_addr = (!is_obj || (is_ref && !is_array)) ? emit_var : 1; if(is_obj && (is_array || !is_ref)) CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) f_instr *exec = (f_instr*)allocmember; @@ -618,11 +630,9 @@ ANN static m_bool emit_exp_decl_global(const Emitter emit, const Exp_Decl *decl, const Array_Sub array = var_decl->array; const m_bool is_array = array && array->exp; const m_bool is_obj = isa(type, emit->gwion->type[et_object]) > 0; - const uint emit_addr = ((is_ref && !array) || isa(type, emit->gwion->type[et_object]) < 0) ? - emit_var : 1; + const uint emit_addr = (!is_obj || (is_ref && !is_array)) ? emit_var : 1; if(is_obj && (is_array || !is_ref)) CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) -// const Instr instr = emit_kind(emit, v->type->size, emit_addr, dotstatic); const Instr instr = emit_kind(emit, v->type->size, !struct_ctor(v) ? emit_addr : 1, dotstatic); v->d.ptr = mp_calloc2(emit->gwion->mp, v->type->size); SET_FLAG(v, union); @@ -645,9 +655,10 @@ ANN static m_bool emit_exp_decl_global(const Emitter emit, const Exp_Decl *decl, ANN static m_bool emit_class_def(const Emitter, const Class_Def); ANN static m_bool emit_cdef(const Emitter, const Class_Def); -ANN static inline m_bool emit_exp_decl_template(const Emitter emit, const Exp_Decl* decl) { - const Type t = get_type(decl->type); - return !GET_FLAG(t, emit) ? emit_cdef(emit, t->e->def) : GW_OK; +ANN static inline m_bool ensure_emit(const Emitter emit, const Type t) { + struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, + .scope=emit->env->scope->depth, .flag=ae_flag_emit }; + return envset_run(&es, t); } ANN static m_bool emit_decl(const Emitter emit, const Exp_Decl* decl) { @@ -670,8 +681,9 @@ ANN static m_bool emit_decl(const Emitter emit, const Exp_Decl* decl) { } ANN /*static */m_bool emit_exp_decl(const Emitter emit, const Exp_Decl* decl) { - if(GET_FLAG(decl->type, template)) - CHECK_BB(emit_exp_decl_template(emit, decl)) + const Type t = get_type(decl->type); + if(!GET_FLAG(t, emit) && t->e->def) + CHECK_BB(ensure_emit(emit, t)) const m_bool global = GET_FLAG(decl->td, global); const m_uint scope = !global ? emit->env->scope->depth : emit_push_global(emit); const m_bool ret = emit_decl(emit, decl); @@ -828,8 +840,15 @@ ANN static inline m_bool traverse_emit_func_def(const Emitter emit, const Func_D } ANN m_bool traverse_dot_tmpl(const Emitter emit, const struct dottmpl_ *dt) { - const m_uint scope = emit_push(emit, dt->owner_class, dt->owner); + const m_uint scope = emit->env->scope->depth; + struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, + .scope=scope, .flag=ae_flag_emit }; + if(dt->owner_class) + envset_push(&es, dt->owner_class); + (void)emit_push(emit, dt->owner_class, dt->owner); const m_bool ret = traverse_emit_func_def(emit, dt->def); + if(dt->owner_class && dt->owner_class->e->owner_class) + envset_pop(&es, dt->owner_class->e->owner_class); emit_pop(emit, scope); return ret; } @@ -862,8 +881,15 @@ static inline m_bool push_func_code(const Emitter emit, const Func f) { ANN static m_bool emit_template_code(const Emitter emit, const Func f) { const Value v = f->value_ref; - size_t scope = emit_push(emit, v->from->owner_class, v->from->owner); + size_t scope = emit->env->scope->depth; + struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, + .scope=scope, .flag=ae_flag_emit }; + if(v->from->owner_class) + envset_push(&es, v->from->owner_class); + (void)emit_push(emit, v->from->owner_class, v->from->owner); const m_bool ret = emit_func_def(emit, f->def); + if(v->from->owner_class && v->from->owner_class->e->owner_class) + envset_pop(&es, v->from->owner_class->e->owner_class); emit_pop(emit, scope); return ret > 0 ? push_func_code(emit, f) : GW_ERROR; } @@ -1087,13 +1113,10 @@ ANN static VM_Code spork_prepare(const Emitter emit, const struct Sporker *sp) { } ANN void spork_code(const Emitter emit, const struct Sporker *sp) { - if(sp->is_spork) { - const Instr instr = emit_add_instr(emit, SporkExp); - instr->m_val = emit->code->stack_depth; - } else { - const Instr instr = emit_add_instr(emit, ForkEnd); - instr->m_val = sp->emit_var; - } + const Instr args = emit_add_instr(emit, SporkExp); + args->m_val = emit->code->stack_depth; + const Instr instr = emit_add_instr(emit, SporkEnd); + instr->m_val = sp->emit_var; } ANN void spork_func(const Emitter emit, const struct Sporker *sp) { @@ -1105,14 +1128,20 @@ ANN void spork_func(const Emitter emit, const struct Sporker *sp) { spork->m_val = depth; } else emit_exp_spork_finish(emit, f->def->stack_depth); - const Instr end = emit_add_instr(emit, sp->is_spork ? SporkEnd : ForkEnd); - end->m_val2 = f->def->base->ret_type->size; + (void)emit_add_instr(emit, SporkEnd); } ANN static Instr spork_ini(const Emitter emit, const struct Sporker *sp) { - const Instr instr = emit_add_instr(emit, SporkIni); + if(sp->is_spork) { + const Instr instr = emit_add_instr(emit, SporkIni); + instr->m_val = (m_uint)sp->vm_code; + instr->m_val2 = sp->is_spork; + return instr; + } + const Func f = !sp->code ? sp->exp->d.exp_call.m_func : NULL; + const Instr instr = emit_add_instr(emit, ForkIni); instr->m_val = (m_uint)sp->vm_code; - instr->m_val2 = sp->is_spork; + instr->m_val2 = f ? f->def->base->ret_type->size : 0; return instr; } @@ -1134,9 +1163,7 @@ ANN static m_bool emit_exp_unary(const Emitter emit, const Exp_Unary* unary) { struct Op_Import opi = { .op=unary->op, .data=(uintptr_t)unary, .op_type=op_unary }; if(unary->op != insert_symbol("spork") && unary->op != insert_symbol("fork") && unary->exp) { CHECK_BB(emit_exp_pop_next(emit, unary->exp)) -const Exp next = unary->exp->next; emit_exp_addref(emit, unary->exp, -exp_size(unary->exp)); -unary->exp->next = next; opi.rhs = unary->exp->info->type; } return op_emit_bool(emit, &opi); @@ -1185,11 +1212,13 @@ ANN static m_bool emit_exp_lambda(const Emitter emit, const Exp_Lambda * lambda) regpushi(emit, SZ_INT); return GW_OK; } - const m_uint scope = !lambda->owner ? - emit->env->scope->depth : emit_push_type(emit, lambda->owner); + struct EnvSet es = { .env=emit->env, .data=emit, .func=(_exp_func)emit_cdef, + .scope=emit->env->scope->depth, .flag=ae_flag_emit }; + if(lambda->owner) + envset_push(&es, lambda->owner); const m_bool ret = emit_lambda(emit, lambda); if(lambda->owner) - emit_pop(emit, scope); + envset_push(&es, lambda->owner); return ret; } @@ -1328,11 +1357,8 @@ ANN static void emit_pop_stack(const Emitter emit, const m_uint index) { emit_pop_scope(emit); } -// scope push problem -ANN static m_bool emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt) { - const m_uint index = emit_code_size(emit); +ANN static m_bool _emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt, const m_uint index) { Instr op = NULL; - emit_push_stack(emit); if(!stmt->is_do) op = _flow(emit, stmt->cond, stmt_self(stmt)->stmt_type == ae_stmt_while); CHECK_BB(scoped_stmt(emit, stmt->body, 1)) @@ -1344,10 +1370,17 @@ ANN static m_bool emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt) { goto_->m_val = index; op->m_val = emit_code_size(emit); } - emit_pop_stack(emit, index); return GW_OK; } +ANN static m_bool emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt) { + const m_uint index = emit_code_size(emit); + emit_push_stack(emit); + const m_bool ret = _emit_stmt_flow(emit, stmt, index); + emit_pop_stack(emit, index); + return ret; +} + ANN static Instr variadic_state0(const Emitter emit, const Stmt_VarLoop stmt) { CHECK_BO(emit_exp(emit, stmt->exp)) return emit_add_instr(emit, BranchEqInt); @@ -1379,14 +1412,12 @@ ANN static m_bool emit_stmt_varloop(const Emitter emit, const Stmt_VarLoop stmt) return GW_OK; } -// scope push problem -ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) { - emit_push_stack(emit); +ANN static m_bool _emit_stmt_for(const Emitter emit, const Stmt_For stmt, m_uint *action_index) { CHECK_BB(emit_stmt(emit, stmt->c1, 1)) const m_uint index = emit_code_size(emit); const Instr op = emit_flow(emit, stmt->c2->d.stmt_exp.val); CHECK_BB(scoped_stmt(emit, stmt->body, 1)) - const m_uint action_index = emit_code_size(emit); + *action_index = emit_code_size(emit); if(stmt->c3) { CHECK_BB(emit_exp(emit, stmt->c3)) pop_exp(emit, stmt->c3); @@ -1394,10 +1425,17 @@ ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) { const Instr _goto = emit_add_instr(emit, Goto); _goto->m_val = index; op->m_val = emit_code_size(emit); - emit_pop_stack(emit, action_index); return GW_OK; } +ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) { + emit_push_stack(emit); + m_uint action_index; + const m_bool ret = _emit_stmt_for(emit, stmt, &action_index); + emit_pop_stack(emit, action_index); + return ret; +} + ANN static Instr emit_stmt_autoptr_init(const Emitter emit, const Type type) { const Instr new_obj = emit_add_instr(emit, ObjectInstantiate); new_obj->m_val2 = (m_uint)type; @@ -1406,11 +1444,8 @@ ANN static Instr emit_stmt_autoptr_init(const Emitter emit, const Type type) { return emit_add_instr(emit, Reg2Mem); } -// scope push problem -ANN static m_bool emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt) { - CHECK_BB(emit_exp(emit, stmt->exp)) +ANN static m_bool _emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt, m_uint *end_pc) { const Instr s1 = emit_add_instr(emit, MemSetImm); - emit_push_stack(emit); Instr cpy = stmt->is_ptr ? emit_stmt_autoptr_init(emit, stmt->v->type) : NULL; emit_local(emit, emit->gwion->type[et_int]); // is ptr released? const m_uint offset = emit_local(emit, emit->gwion->type[et_int]); @@ -1420,7 +1455,7 @@ ANN static m_bool emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt) { const Instr loop = emit_add_instr(emit, stmt->is_ptr ? AutoLoopPtr : AutoLoop); const Instr end = emit_add_instr(emit, BranchEqInt); CHECK_BB(emit_stmt(emit, stmt->body, 1)) - const m_uint end_pc = emit_code_size(emit); + *end_pc = emit_code_size(emit); if(stmt->is_ptr) { loop->m_val2 = (m_uint)stmt->v->type; cpy->m_val = stmt->v->from->offset; @@ -1430,15 +1465,21 @@ ANN static m_bool emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt) { tgt->m_val = ini_pc; s1->m_val = loop->m_val = offset; regpop(emit, SZ_INT); - emit_pop_stack(emit, end_pc); return GW_OK; } -// scope push problem -ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { +ANN static m_bool emit_stmt_auto(const Emitter emit, const Stmt_Auto stmt) { + CHECK_BB(emit_exp(emit, stmt->exp)) emit_push_stack(emit); + m_uint end_pc; + const m_bool ret = _emit_stmt_auto(emit, stmt, &end_pc); + emit_pop_stack(emit, end_pc); + return ret; +} + +ANN static m_bool _emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt, m_uint *index) { CHECK_BB(emit_exp_pop_next(emit, stmt->cond)) - const m_uint index = emit_code_size(emit); + *index = emit_code_size(emit); const Instr cpy = emit_add_instr(emit, Reg2RegAddr); cpy->m_val2 = -SZ_INT; regpush(emit, SZ_INT); @@ -1446,13 +1487,20 @@ ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { const Instr op = emit_add_instr(emit, BranchEqInt); CHECK_BB(scoped_stmt(emit, stmt->body, 1)) const Instr _goto = emit_add_instr(emit, Goto); - _goto->m_val = index; + _goto->m_val = *index; op->m_val = emit_code_size(emit); - emit_pop_stack(emit, index); regpop(emit, SZ_INT); return GW_OK; } +ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { + emit_push_stack(emit); + m_uint index; + const m_bool ret = _emit_stmt_loop(emit, stmt, &index); + emit_pop_stack(emit, index); + return ret; +} + ANN static m_bool emit_stmt_jump(const Emitter emit, const Stmt_Jump stmt) { if(!stmt->is_label) stmt->data.instr = emit_add_instr(emit, Goto); @@ -1513,7 +1561,7 @@ ANN static m_bool emit_union_def(const Emitter emit, const Union_Def udef) { if(udef->xid) { union_allocdata(emit->gwion->mp, udef); Type_Decl *type_decl = new_type_decl(emit->gwion->mp, - new_id_list(emit->gwion->mp, udef->xid, loc_cpy(emit->gwion->mp, udef->pos))); + udef->xid, loc_cpy(emit->gwion->mp, udef->pos)); type_decl->flag = udef->flag; const Var_Decl var_decl = new_var_decl(emit->gwion->mp, udef->xid, NULL, loc_cpy(emit->gwion->mp, udef->pos)); const Var_Decl_List var_decl_list = new_var_decl_list(emit->gwion->mp, var_decl, NULL); @@ -1654,14 +1702,14 @@ ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) } 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)) // beware push + do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match)) while((list = list->next)); return GW_OK; } ANN static m_bool emit_match(const Emitter emit, const struct Stmt_Match_* stmt) { if(stmt->where) - CHECK_BB(emit_stmt(emit, stmt->where, 1)) // beware, we have push scope + 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); @@ -1702,15 +1750,7 @@ ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List l) { return GW_OK; } -ANN static inline m_bool ensure_emit(const Emitter emit, const Type type) { - const Type t = actual_type(emit->gwion, type) ?: type; - if(!GET_FLAG(t, emit) && t->e->def) - CHECK_BB(emit_class_def(emit, t->e->def)) - return GW_OK; -} - ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member) { - CHECK_BB(ensure_emit(emit, member->t_base)) struct Op_Import opi = { .op=insert_symbol("@dot"), .lhs=member->t_base, .rhs=exp_self(member)->info->type, .data=(uintptr_t)member, .pos=exp_self(member)->pos, .op_type=op_dot }; return op_emit_bool(emit, &opi); @@ -1952,24 +1992,24 @@ ANN static m_bool emit_struct_body2(const Emitter emit, Section *const section) ANN static m_bool emit_class_def(const Emitter emit, const Class_Def c) { if(tmpl_base(c->base.tmpl)) return GW_OK; - const Class_Def cdef = c->base.type->e->def; + const Type t = c->base.type; + const Class_Def cdef = t->e->def; if(GET_FLAG(cdef->base.type, emit)) return GW_OK; - const Type type = cdef->base.type; - const Nspc nspc = type->nspc; - if(cdef->base.ext && type->e->parent->e->def && !GET_FLAG(type->e->parent, emit)) + if(cdef->base.ext && t->e->parent->e->def && !GET_FLAG(t->e->parent, emit)) CHECK_BB(cdef_parent(emit, cdef)) - SET_FLAG(type, emit); + const Nspc nspc = t->nspc; + SET_FLAG(t, emit); nspc_allocdata(emit->gwion->mp, nspc); if(cdef->body) { if(!no_ctor(emit, cdef)) { - emit_class_code(emit, type->name); + emit_class_code(emit, t->name); CHECK_BB(scanx_body(emit->env, cdef, (_exp_func)emit_section, emit)) emit_class_finish(emit, nspc); } else CHECK_BB(scanx_body(emit->env, cdef, (_exp_func)emit_struct_body2, emit)) } - SET_FLAG(type, emit); + SET_FLAG(t, emit); return GW_OK; } diff --git a/src/env/env.c b/src/env/env.c index ca70b0d5..c0d606b4 100644 --- a/src/env/env.c +++ b/src/env/env.c @@ -87,8 +87,12 @@ ANN void env_add_type(const Env env, const Type type) { const Value v = new_value(env->gwion->mp, v_type, s_name(sym)); SET_FLAG(v, checked | ae_flag_const | ae_flag_global | ae_flag_builtin); nspc_add_value(env->curr, insert_symbol(type->name), v); +// valuefrom(env, v->from); +// typefrom(env, type->e->from); +// v->from->owner = type->e->from->owner = env->curr; +// type->e->owner = env->curr; v->from->owner = type->e->owner = env->curr; - v->from->owner_class = env->class_def; + v->from->owner_class = type->e->owner_class = env->class_def; // t owner_class ? type->xid = ++env->scope->type_xid; } diff --git a/src/env/env_utils.c b/src/env/env_utils.c index ae2db2ef..9fa39596 100644 --- a/src/env/env_utils.c +++ b/src/env/env_utils.c @@ -41,9 +41,8 @@ ANN Type _find_type(const Env env, const Symbol xid) { return type; } -ANN Type find_type(const Env env, ID_List path) { - Type type = _find_type(env, path->xid); - CHECK_OO(type) +ANN Type find_type(const Env env, Type_Decl *path) { + DECL_OO(Type, type, = _find_type(env, path->xid)) Nspc nspc = type->nspc; path = path->next; while(path) { @@ -86,10 +85,8 @@ ANN Value mk_class(const Env env, const Type base) { const Type t = class_type(env, base); const Symbol sym = insert_symbol(base->name); const Value v = new_value(env->gwion->mp, t, s_name(sym)); - // set from - v->from->owner = base->e->owner; + valuefrom(env, v->from); SET_FLAG(v, const | ae_flag_checked); - // should we add t to front, too? nspc_add_value_front(base->e->owner, sym, v); return v; } diff --git a/src/env/envset.c b/src/env/envset.c new file mode 100644 index 00000000..a523d77a --- /dev/null +++ b/src/env/envset.c @@ -0,0 +1,54 @@ +#include "gwion_util.h" +#include "gwion_ast.h" +#include "gwion_env.h" +#include "vm.h" +#include "gwion.h" +#include "template.h" + +ANN static void check(struct EnvSet *es, const Type t) { + const Vector v = &es->env->scope->class_stack; + Type owner = t->e->owner_class; + for(vtype i = vector_size(v); owner && --i;) { + if(owner != (Type)vector_at(v, i - 1)) { + es->run = 1; + return; + } + owner = owner->e->owner_class; + } +} + +ANN m_bool push(struct EnvSet *es, const Type t) { + if(t->e->owner_class) + CHECK_BB(push(es, t->e->owner_class)) + if(!(t->flag & es->flag)) + CHECK_BB(es->func((void*)es->data, t->e->def)) + if(GET_FLAG(t, template)) + CHECK_BB(template_push_types(es->env, t->e->def->base.tmpl)) + env_push_type((void*)es->env, t); + return GW_OK; +} + +ANN m_bool envset_push(struct EnvSet *es, const Type t) { + check(es, t); + if(es->run) + CHECK_BB(envset_push(es, t->e->owner_class)) + return GW_OK; +} + +ANN void envset_pop(struct EnvSet *es, const Type t) { + env_pop(es->env, es->scope); + if(GET_FLAG(t, template)) + nspc_pop_type(es->env->gwion->mp, es->env->curr); + if(t->e->owner_class) + envset_pop(es, t->e->owner_class); +} + +ANN m_bool envset_run(struct EnvSet *es, const Type t) { + check(es, t); + if(es->run) + CHECK_BB(push(es, t->e->owner_class)) + const m_bool ret = es->func(es->data, t->e->def); + if(es->run) + envset_pop(es, t->e->owner_class); + return ret; +} diff --git a/src/env/tupleform.c b/src/env/tupleform.c index 8a8aef40..f5403217 100644 --- a/src/env/tupleform.c +++ b/src/env/tupleform.c @@ -15,14 +15,10 @@ #include "parse.h" #include "array.h" -ANN void tuple_info(const Env env, Type_Decl *base, const Var_Decl var) { - const Value v = var->value; +ANN void tuple_info(const Env env, const Value v) { const m_uint offset = vector_back(&env->class_def->e->tuple->offset); vector_add(&env->class_def->e->tuple->types, (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) - td->array = cpy_array_sub(env->gwion->mp, var->array); } ANN2(1) TupleForm new_tupleform(MemPool p, const Type parent_type) { diff --git a/src/env/type.c b/src/env/type.c index 1249dd30..564e8f17 100644 --- a/src/env/type.c +++ b/src/env/type.c @@ -29,11 +29,6 @@ ANN static void free_type(Type a, Gwion gwion) { REM_REF(a->nspc, gwion); if(a->e->tuple) free_tupleform(a->e->tuple); - 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); - vector_release(&a->e->contains); - } mp_free(gwion->mp, TypeInfo, a->e); mp_free(gwion->mp, Type, a); } @@ -53,7 +48,8 @@ Type new_type(MemPool p, const m_uint xid, const m_str name, const Type parent) ANN Type type_copy(MemPool p, const Type type) { const Type a = new_type(p, type->xid, type->name, type->e->parent); a->nspc = type->nspc; - a->e->owner = type->e->owner; + a->e->owner = type->e->owner; + a->e->owner_class = type->e->owner_class; a->size = type->size; a->e->d.base_type = type->e->d.base_type; a->array_depth = type->array_depth; @@ -117,7 +113,7 @@ ANN Type array_type(const Env env, const Type src, const m_uint depth) { t->e->owner = src->e->owner; ADD_REF((t->nspc = env->gwion->type[et_array]->nspc)) SET_FLAG(t, checked); - mk_class(env, t); // maybe add_type_front could go in mk_class ? + mk_class(env, t); nspc_add_type_front(src->e->owner, sym, t); return t; } diff --git a/src/import/cdef.c b/src/import/cdef.c index a751416b..60a3e5bc 100644 --- a/src/import/cdef.c +++ b/src/import/cdef.c @@ -49,8 +49,9 @@ ANN2(1,2) static void import_class_ini(const Env env, const Type t) { t->nspc = new_nspc(env->gwion->mp, t->name); t->nspc->parent = env->curr; if(isa(t, env->gwion->type[et_object]) > 0) - inherit(t); + inherit(t); t->e->owner = env->curr; + t->e->owner_class = env->class_def; SET_FLAG(t, checked); env_push_type(env, t); } @@ -80,8 +81,12 @@ ANN2(1,2) Type gwi_class_ini(const Gwi gwi, const m_str name, const m_str parent DECL_OO(Type_Decl *,td, = str2decl(gwi, parent ?: "Object")) Tmpl* tmpl = ck.tmpl ? new_tmpl_base(gwi->gwion->mp, ck.tmpl) : NULL; if(tmpl) - template_push_types(gwi->gwion->env, tmpl); + CHECK_BO(template_push_types(gwi->gwion->env, tmpl)) const Type p = known_type(gwi->gwion->env, td); // check + if(!p) { + env_pop(gwi->gwion->env, 0); + return NULL; + } if(tmpl) nspc_pop_type(gwi->gwion->mp, gwi->gwion->env->curr); const Type t = new_type(gwi->gwion->mp, ++gwi->gwion->env->scope->type_xid, s_name(ck.sym), p); diff --git a/src/import/checker.c b/src/import/checker.c index 58d8b60f..1da445e3 100644 --- a/src/import/checker.c +++ b/src/import/checker.c @@ -15,286 +15,128 @@ #include "import.h" #include "gwi.h" -ANN m_bool array_check(const Gwi gwi, struct array_checker *ck); - __attribute__((returns_nonnull)) ANN static Symbol gwisym(const Gwi gwi, const m_str str) { return insert_symbol(gwi->gwion->st, str); } -//! check that there is no illegal character in the string -// TODO: get rid of second argument, make it useless -ANN static m_bool check_illegal(const char c, const m_uint i) { - return isalnum(c) || c == '_' || (!i && c == '@'); +struct td_checker { + m_str str; +}; + +struct AC { + m_str str; + Exp base; + Exp exp; + m_uint depth; +}; + +ANN static m_bool ac_run(const Gwi gwi, struct AC *ac); +ANN static Array_Sub mk_array(MemPool mp, struct AC *ac) { + const Array_Sub array = new_array_sub(mp, ac->base); + array->depth = ac->depth; + return array; } -/** convert a string to a symbol, with error checking **/ -ANN Symbol str2sym(const Gwi gwi, const m_str path) { - const size_t sz = strlen(path); - m_uint i; - char curr[sz + 1]; - for(i = 0; i < sz; ++i) { - const char c = path[i]; - if(c != '.') { - if(!check_illegal(c, i)) - GWI_ERR_O(_("illegal character '%c' in path '%s'."), c, path) - curr[i] = c; - } else + +ANN static Symbol __str2sym(const Gwi gwi, struct td_checker *tdc) { + char buf[strlen(tdc->str) + 1]; + m_str tmp = buf; + if(*tdc->str == '@') + *tmp++ = *tdc->str++; + while(*tdc->str) { + const char c = *tdc->str; + if(!isalnum(c) && c != '_') break; + *tmp++ = *tdc->str++; } - curr[i++] = '\0'; - return gwisym(gwi, curr); + if(tmp == buf) + GWI_ERR_O("empty symbol"); + *tmp = '\0'; + return gwisym(gwi, buf); } -ANN ID_List str2symlist(const Gwi gwi, const m_str path) { - DECL_OO(const Symbol, sym, = str2sym(gwi, path)) - return new_id_list(gwi->gwion->mp, sym, loc(gwi)); +ANN static inline Symbol _str2sym(const Gwi gwi, struct td_checker *tdc, const m_str path) { + const Symbol sym = __str2sym(gwi, tdc); + if(*tdc->str) + GWI_ERR_O(_("illegal character '%c' in path '%s'."), *tdc->str, path) + return sym; } -ANN ID_List path_valid(const Gwi gwi, const m_str path) { - const size_t sz = strlen(path); - if(path[0] == '.' || path[sz] == '.') - GWI_ERR_O(_("path '%s' must not ini or end with '.'."), path) - DECL_OO(const ID_List, list, = str2symlist(gwi, path)) - if(strlen(s_name(list->xid)) < sz) - list->next = path_valid(gwi, path + strlen(s_name(list->xid))); - return list; +/** convert a string to a symbol, with error checking **/ +ANN Symbol str2sym(const Gwi gwi, const m_str path) { + struct td_checker tdc = { .str=path }; + return _str2sym(gwi, &tdc, path); } -// similar to import array_sub ? -ANN Array_Sub ck_array(MemPool mp, const m_uint depth) { - if(!depth) - return NULL; - const Array_Sub array = new_array_sub(mp, NULL); - array->depth = depth; - return array; +// only in enum.c +ANN ID_List str2symlist(const Gwi gwi, const m_str path) { + DECL_OO(const Symbol, sym, = str2sym(gwi, path)) + return new_id_list(gwi->gwion->mp, sym, loc(gwi)); } ANN Var_Decl str2var(const Gwi gwi, const m_str path) { - struct array_checker ck = { .str=path }; - CHECK_BO(array_check(gwi, &ck)) - const m_uint sz = strlen(path); - const m_uint len = sz - ck.sz; - char curr[len + 1]; - memcpy(curr, path, len); - curr[len] = '\0'; - DECL_OO(const Symbol, sym, = str2sym(gwi, curr)) - const Array_Sub array = ck_array(gwi->gwion->mp, ck.depth); + struct td_checker tdc = { .str=path }; + DECL_OO(const Symbol, sym, = __str2sym(gwi, &tdc)) + struct AC ac = { .str = tdc.str }; + CHECK_BO(ac_run(gwi, &ac)) + const Array_Sub array = ac.depth ? + mk_array(gwi->gwion->mp, &ac) : NULL; return new_var_decl(gwi->gwion->mp, sym, array, loc(gwi)); } +// only in udef.c ANN Var_Decl_List str2varlist(const Gwi gwi, const m_str path) { DECL_OO(const Var_Decl, var, = str2var(gwi, path)) return new_var_decl_list(gwi->gwion->mp, var, NULL); } -struct tmpl_checker { - const m_str str; - ID_List list; -}; - -ANN static m_bool tmpl_list(const Gwi gwi, struct tmpl_checker *ck) { - m_str s = ck->str; - const size_t sz = strlen(s); - char c[sz + 1]; - for(m_uint i = 0; i < sz; ++i) { - if(isalnum(s[i]) || s[i] == '_') { - c[i] = s[i]; - continue; - } - if(s[i] == '~') { - if(!i || s[i+1] != '>') - break; - c[i] = '\0'; - ck->list = new_id_list(gwi->gwion->mp, gwisym(gwi, c), loc(gwi)); - return GW_OK; - } - if(s[i] == ',') { - if(!i)break; - c[i] = '\0'; - ck->list = new_id_list(gwi->gwion->mp, gwisym(gwi, c), loc(gwi)); - struct tmpl_checker _ck = { .str=ck->str + i + 1 }; - CHECK_BB(tmpl_list(gwi, &_ck)) - ck->list->next = _ck.list; - return GW_OK; - } - break; +ANN static ID_List _tmpl_list(const Gwi gwi, struct td_checker *tdc) { + DECL_OO(const Symbol, sym, = __str2sym(gwi, tdc)) + ID_List next = NULL; + if(*tdc->str == ',') { + ++tdc->str; + if(!(next = _tmpl_list(gwi, tdc)) || next == (ID_List)GW_ERROR) + return (ID_List)GW_ERROR; } - return GW_ERROR; -} - -ANN static m_bool tmpl_check(const m_str str) { - if(str[0] != '<') - return 0; // TODO: make it GW_PASS - if(str[1] != '~') - return GW_ERROR; - return GW_OK; + const ID_List list = new_id_list(gwi->gwion->mp, sym, loc(gwi)); + list->next = next; + return list; } -ANN static ID_List _tmpl_valid(const Gwi gwi, const m_str str) { - const m_bool ret = tmpl_check(str); - if(ret == GW_ERROR) - return (ID_List)GW_ERROR; - if(!ret) +ANN static ID_List __tmpl_list(const Gwi gwi, struct td_checker *tdc) { + if(tdc->str[0] != '<') return NULL; - struct tmpl_checker ck = { .str=str+2 }; - if(tmpl_list(gwi, &ck) == GW_ERROR) + if(tdc->str[1] != '~') + return (ID_List)GW_ERROR; + tdc->str += 2; + const ID_List list = _tmpl_list(gwi, tdc); + if(list == (ID_List)GW_ERROR) + return (ID_List)GW_ERROR; + if(tdc->str[0] != '~' || tdc->str[1] != '>') { +// unfinished template + if(list) + free_id_list(gwi->gwion->mp, list); return (ID_List)GW_ERROR; - return ck.list; -} - -ANN ID_List tmpl_valid(const Gwi gwi, const m_str str) { - const ID_List ret = _tmpl_valid(gwi, str); - if(ret == (ID_List)GW_ERROR) - env_err(gwi->gwion->env, gwi->loc, _("invalid templating definition")); - return ret; -} - -ANN ID_List ck2list(const Gwi gwi, struct array_checker *ck) { - const m_str base = ck->str; - CHECK_BO(array_check(gwi, ck)) - const m_uint sz = strlen(base); - const m_uint len = sz - ck->sz; - char curr[len + 1]; - memcpy(curr, base, len); - curr[len] = '\0'; - return path_valid(gwi, curr); -} - -ANN static Type_List str2tl(const Gwi gwi, const m_str s); -ANN static Type_List _str2tl(const Gwi gwi, const m_str s) { - DECL_OO(Type_Decl*, td, = str2decl(gwi, s)) - return new_type_list(gwi->gwion->mp, td, NULL); -} - -ANN Type_List tlnext(const Gwi gwi, const m_str s, size_t split) { - char curr[split+1]; - memcpy(curr, s, split); - curr[split] = '\0'; - const Type_List tl = _str2tl(gwi, curr); - tl->next = str2tl(gwi, s + split + 1); - return tl; -} - -struct GetTl { - const m_str str; - m_uint i; - m_uint lvl; - const size_t sz; -}; - -//! a funtion factory to open/close the template -#define tl_xxx(name, tgt, op) \ -ANN m_bool tl_##name(struct GetTl *gtl, const m_uint i) { \ - if(!(i < gtl->sz && gtl->str[i] == tgt)) \ - return GW_ERROR; \ - op gtl->lvl; \ - return GW_OK; \ -} -tl_xxx(open, '~', ++) -tl_xxx(close, '>', --) - -ANN static Type_List str2tl(const Gwi gwi, const m_str s) { - struct GetTl gtl = { .str=s, .sz = strlen(s) }; - for(m_uint i = 0; i < gtl.sz; ++i) { - if(s[i] == '<') - CHECK_BO(tl_open(>l, ++i)) - else if(s[i] == '~') - CHECK_BO(tl_close(>l, ++i)) - else if(s[i] == ',' && !gtl.lvl) - return tlnext(gwi, s, i); - } - return _str2tl(gwi, s); -} - -//! convert a string to a Type_Decl -ANN Type_Decl* str2decl(const Gwi gwi, const m_str str) { - const ae_flag flag = strncmp(str, "nonnull ", 8) ? ae_flag_none : ae_flag_nonnull; - const m_str s = strncmp(str, "nonnull ", 8) ? str : str + 8; -// we can do better - DECL_OO(const m_str, type_name, = get_type_name(gwi->gwion->env, s, 0)) - struct array_checker ck = { .str=type_name }; - DECL_OO(const ID_List, id, = ck2list(gwi, &ck)) - Type_Decl* td = new_type_decl(gwi->gwion->mp, id); - const m_str tl_name = get_type_name(gwi->gwion->env, s, 1); - if(tl_name) { - if(!(td->types = str2tl(gwi, tl_name))) { - free_type_decl(gwi->gwion->mp, td); - return NULL; - } - } - if(ck.depth) { - td->array = new_array_sub(gwi->gwion->mp, ck.exp); - td->array->depth = ck.depth; - } - td->flag |= flag; - return td; -} - -ANN static void array_add_exp(struct array_checker *ck, const Exp exp) { - if(ck->exp) - ck->exp = (ck->exp->next = exp); - else - ck->base = ck->exp = exp; - ++ck->is_exp; -} - -ANN m_bool _array_check(const Gwi gwi, struct array_checker *ck) { - const m_str base = ck->str; - const size_t sz = strlen(ck->str); - char tmp[sz + 1]; - for(m_uint i = 0; i < sz; ++i) { - const char c = ck->str[i]; - if(c == ']') { - const m_bool is_end = ck->str[i + 1] == '\0'; - if(!is_end && ck->str[i + 1] != '[') - break; - ck->str += i + 2; - ck->sz += i + 2; - if(i) { - if(!ck->is_exp && ck->depth) - break; - tmp[i] = '\0'; - const m_uint num = strtol(tmp, NULL, 10);// migth use &endptr and check errno - const Exp exp = new_prim_int(gwi->gwion->mp, num, loc(gwi)); - array_add_exp(ck, exp); - } else { - if(ck->is_exp > 0) - break; - } - ++ck->depth; - return is_end ? GW_OK : _array_check(gwi, ck); - } - if(isdigit(c)) - tmp[i] = c; - else - GWI_ERR_B(_("invalid subscript '%c' in '%s'"), c, base) } - GWI_ERR_B(_("incoherent subscript '%s'"), base) -} - -ANN m_bool array_check(const Gwi gwi, struct array_checker *ck) { - ck->str = ck->str ? strchr(ck->str, '[') : NULL; - if(!ck->str) - return GW_OK; - ++ck->str; - return _array_check(gwi, ck); + tdc->str += 2; + return list; } ANN m_bool check_typename_def(const Gwi gwi, ImportCK *ck) { - const m_str base = ck->name; - char str[strlen(base) + 1]; - const m_str c = strchr(ck->name, '<'); - memcpy(str, base, strlen(base) - (c ? strlen(c) : 0)); - str[strlen(base) - (c ? strlen(c) : 0)] = '\0'; - ck->name = str; - CHECK_OB((ck->sym = str2sym(gwi, str))) - ID_List tmpl = NULL; - if(c && (tmpl = tmpl_valid(gwi, c)) == (ID_List)GW_ERROR) + struct td_checker tdc = { .str= ck->name }; + ID_List il = __tmpl_list(gwi, &tdc); + if(il == (ID_List)GW_ERROR) + return GW_ERROR; + if(!(ck->sym = _str2sym(gwi, &tdc, tdc.str))) { + if(il) + free_id_list(gwi->gwion->mp, il); return GW_ERROR; - ck->tmpl = tmpl; - ck->name = base; + } + ck->tmpl = il; + ck->name = s_name(ck->sym); return GW_OK; + } ANN m_bool ck_ini(const Gwi gwi, const enum importck_type t) { @@ -335,3 +177,145 @@ ANN void ck_clean(const Gwi gwi) { memset(gwi->ck, 0, sizeof(ImportCK)); } +ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc); +ANN Type_List __str2tl(const Gwi gwi, struct td_checker *tdc) { + Type_Decl *td = _str2decl(gwi, tdc); + if(!td) + GWI_ERR_O("invalid types"); + Type_List next = NULL; + if(*tdc->str == ',') { + ++tdc->str; + if(!(next = __str2tl(gwi, tdc))) { + free_type_decl(gwi->gwion->mp, td); + return NULL; + } + } + return new_type_list(gwi->gwion->mp, td, next); +} + +ANN Type_List td_tmpl(const Gwi gwi, struct td_checker *tdc) { + if(*tdc->str != '<') + return NULL; // GW_PASS + ++tdc->str; + if(*tdc->str != '~') { + GWI_ERR("invalid character"); + return (Type_List)GW_ERROR; + } + ++tdc->str; + Type_List tl = __str2tl(gwi, tdc); + if(!tl) + return (Type_List)GW_ERROR; + if(tdc->str[0] != '~' || tdc->str[1] != '>') { + free_type_list(gwi->gwion->mp, tl); + GWI_ERR("unfinished template"); + return (Type_List)GW_ERROR; + } + tdc->str += 2; + return tl; +} + +ANN static void ac_add_exp(struct AC *ac, const Exp exp) { + if(ac->exp) + ac->exp = (ac->exp->next = exp); + else + ac->base = ac->exp = exp; +} + + +ANN Type_Decl* _str2decl(const Gwi gwi, struct td_checker *tdc) { + Type_List tl = td_tmpl(gwi, tdc); + if(tl == (Type_List)GW_ERROR) + return NULL; + Type_Decl *next = NULL; + const Symbol sym = __str2sym(gwi, tdc); + if(!sym) { + if(tl) + free_type_list(gwi->gwion->mp, tl); + return NULL; + } + struct AC ac = { .str = tdc->str }; + if(ac_run(gwi, &ac) < 0) { + if(tl)free_type_list(gwi->gwion->mp, tl); + return NULL; + } + tdc->str = ac.str; + if(*tdc->str == '.') { + ++tdc->str; + if(!(next = _str2decl(gwi, tdc))) { + if(tl) + free_type_list(gwi->gwion->mp, tl); + if(ac.base) + free_exp(gwi->gwion->mp, ac.base); + return NULL; + } + } + Type_Decl *td = new_type_decl(gwi->gwion->mp, sym, loc(gwi)); + td->next = next; + if(ac.depth) + td->array = mk_array(gwi->gwion->mp, &ac); + return td; +} + +ANN Type_Decl* str2decl(const Gwi gwi, const m_str str) { + const ae_flag flag = strncmp(str, "nonnull ", 8) ? ae_flag_none : ae_flag_nonnull; + struct td_checker tdc = { .str=str }; + if(flag == ae_flag_nonnull) + tdc.str += 8; + DECL_OO(Type_Decl *, td, = _str2decl(gwi, &tdc)) + if(*tdc.str) { + free_type_decl(gwi->gwion->mp, td); + GWI_ERR_O("excedental character '%c'", *tdc.str); + } + td->flag |= flag; + return td; +} + +ANN static inline m_bool ac_finish(const Gwi gwi, struct AC *ac) { + if(*ac->str == ']') + return GW_OK; + GWI_ERR_B("unfinished array"); +} + +ANN static inline m_bool ac_num(const Gwi gwi, const m_int num) { + if(num >= 0) + return GW_OK; + GWI_ERR_B("negative array dimension") +} + +ANN static inline m_bool ac_exp(const Gwi gwi, struct AC *ac) { + if(!ac->depth || ac->base) + return GW_OK; + GWI_ERR_B("malformed array [][...]") +} + +ANN static inline m_bool ac_noexp(const Gwi gwi, struct AC *ac) { + if(!ac->exp) + return GW_OK; + GWI_ERR_B("malformed array [...][]") +} + +ANN static m_bool _ac_run(const Gwi gwi, struct AC *ac) { + const m_str str = ac->str; + const m_int num = strtol(str, &ac->str, 10); + CHECK_BB(ac_finish(gwi, ac)) + if(str != ac->str) { + CHECK_BB(ac_num(gwi, num)) + CHECK_BB(ac_exp(gwi, ac)) + const Exp exp = new_prim_int(gwi->gwion->mp, num, loc(gwi)); + ac_add_exp(ac, exp); + } else + CHECK_BB(ac_noexp(gwi, ac)) + ++ac->str; + return GW_OK; +} + +ANN static m_bool ac_run(const Gwi gwi, struct AC *ac) { + while(*ac->str) { + if(*ac->str != '[') + break; + ++ac->str; + CHECK_BB(_ac_run(gwi, ac)) + ++ac->depth; + } + return GW_OK; +} diff --git a/src/lib/array.c b/src/lib/array.c index 93ca7368..3d54713a 100644 --- a/src/lib/array.c +++ b/src/lib/array.c @@ -47,12 +47,16 @@ void free_m_vector(MemPool p, M_Vector a) { mp_free(p, M_Vector, a); } +ANN static inline int is_array(const Type *types, const Type type) { + const Type base = array_base(type); + return isa(base, types[et_object]) > 0; +} + static DTOR(array_dtor) { const Type t = !GET_FLAG(o->type_ref, nonnull) ? o->type_ref : o->type_ref->e->parent; - const Type base = array_base(t); struct M_Vector_* a = ARRAY(o); - if(t->array_depth > 1 || isa(base, shred->info->vm->gwion->type[et_object]) > 0) + if(t->array_depth > 1 || is_array(shred->info->vm->gwion->type, t)) for(m_uint i = 0; i < ARRAY_LEN(a); ++i) release(*(M_Object*)(ARRAY_PTR(a) + i * SZ_INT), shred); free_m_vector(shred->info->mp, a); diff --git a/src/lib/engine.c b/src/lib/engine.c index 2bc1d817..688f2721 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -153,7 +153,7 @@ ANN static m_bool import_core_libs(const Gwi gwi) { ANN m_bool type_engine_init(const Gwion gwion, const Vector plug_dirs) { gwion->env->name = "[builtin]"; - struct loc_t loc = {}; + struct loc_t_ loc = {}; OperCK oper = {}; struct Gwi_ gwi = { .gwion=gwion, .loc=&loc, .oper=&oper }; CHECK_BB(import_core_libs(&gwi)) diff --git a/src/lib/func.c b/src/lib/func.c index 78ad9eb0..23df474a 100644 --- a/src/lib/func.c +++ b/src/lib/func.c @@ -40,7 +40,6 @@ static OP_EMIT(opem_func_assign) { fptr_instr(emit, bin->lhs->info->type->e->d.func, 2); const Instr instr = emit_add_instr(emit, int_r_assign); if(!is_fptr(emit->gwion, bin->lhs->info->type) && GET_FLAG(bin->rhs->info->type->e->d.func, member)) { -//exit(3); const Instr pop = emit_add_instr(emit, LambdaAssign); pop->m_val = SZ_INT; } @@ -70,7 +69,7 @@ ANN static m_bool fptr_tmpl_push(const Env env, struct FptrInfo *info) { } -static m_bool td_match(const Env env, const Type_Decl *id[2]) { +static m_bool td_match(const Env env, Type_Decl *id[2]) { DECL_OB(const Type, t0, = known_type(env, id[0])) DECL_OB(const Type, t1, = known_type(env, id[1])) return isa(t0, t1); @@ -80,7 +79,7 @@ ANN static m_bool fptr_args(const Env env, Func_Base *base[2]) { Arg_List arg0 = base[0]->args, arg1 = base[1]->args; while(arg0) { CHECK_OB(arg1) - const Type_Decl* td[2] = { arg0->td, arg1->td }; + Type_Decl* td[2] = { arg0->td, arg1->td }; CHECK_BB(td_match(env, td)) arg0 = arg0->next; arg1 = arg1->next; @@ -109,7 +108,7 @@ ANN static m_bool fptr_check(const Env env, struct FptrInfo *info) { } ANN static inline m_bool fptr_rettype(const Env env, struct FptrInfo *info) { - const Type_Decl* td[2] = { info->lhs->def->base->td, + Type_Decl* td[2] = { info->lhs->def->base->td, info->rhs->def->base->td }; return td_match(env, td); } @@ -165,13 +164,16 @@ ANN static m_bool _check_lambda(const Env env, Exp_Lambda *l, const Func_Def def } return GW_OK; } + ANN2(1,3,4) m_bool check_lambda(const Env env, const Type owner, Exp_Lambda *l, const Func_Def def) { - const m_uint scope = ((l->owner = owner)) ? - env_push_type(env, owner) : env->scope->depth; + struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)check_cdef, + .scope=env->scope->depth, .flag=ae_flag_check }; + if((l->owner = owner)) + envset_push(&es, owner); const m_bool ret = _check_lambda(env, l, def); - if(owner) - env_pop(env, scope); + if(owner && es.run) + envset_pop(&es, owner); if(ret < 0) return GW_ERROR; exp_self(l)->info->type = l->def->base->func->value_ref->type; @@ -238,8 +240,6 @@ static OP_EMIT(opem_fptr_cast) { const Exp_Cast* cast = (Exp_Cast*)data; if(exp_self(cast)->info->type->e->d.func->def->base->tmpl) fptr_instr(emit, cast->exp->info->type->e->d.func, 1); -// if(GET_FLAG(cast->exp->info->type->e->d.func, member) && -// !(GET_FLAG(cast->exp->info->type, nonnull) || GET_FLAG(exp_self(cast)->info->type, nonnull))) if(is_member(cast->exp->info->type, exp_self(cast)->info->type)) member_fptr(emit); return (Instr)GW_OK; @@ -256,8 +256,6 @@ static OP_CHECK(opck_fptr_impl) { static OP_EMIT(opem_fptr_impl) { struct Implicit *impl = (struct Implicit*)data; if(is_member(impl->e->info->type, impl->t)) -// if(GET_FLAG(impl->e->info->type->e->d.func, member) && -// !(GET_FLAG(impl->e->info->type, nonnull) || GET_FLAG(impl->t, nonnull))) member_fptr(emit); if(impl->t->e->d.func->def->base->tmpl) fptr_instr(emit, ((Exp)impl->e)->info->type->e->d.func, 1); @@ -284,7 +282,11 @@ static OP_CHECK(opck_spork) { static OP_EMIT(opem_spork) { const Exp_Unary* unary = (Exp_Unary*)data; - return emit_exp_spork(emit, unary); + const Env env = emit->env; + const Instr ret = emit_exp_spork(emit, unary); + if(unary->op == insert_symbol("fork")) + emit_add_instr(emit, GcAdd); + return ret; } static FREEARG(freearg_xork) { diff --git a/src/lib/instr.c b/src/lib/instr.c index 6ed0c88b..de018cf1 100644 --- a/src/lib/instr.c +++ b/src/lib/instr.c @@ -44,7 +44,6 @@ ANN static Func_Def from_base(const Env env, struct dottmpl_ *const dt, const Ns SET_FLAG(def, template); return def; } - ANN static Func_Def traverse_tmpl(const Emitter emit, struct dottmpl_ *const dt, const Nspc nspc) { DECL_OO(const Func_Def, def, = from_base(emit->env, dt, nspc)) CHECK_BO(traverse_dot_tmpl(emit, dt)) diff --git a/src/lib/object.c b/src/lib/object.c index a5db437c..8d958d49 100644 --- a/src/lib/object.c +++ b/src/lib/object.c @@ -113,8 +113,8 @@ static ID_CHECK(opck_this) { if(env->func && !GET_FLAG(env->func, member)) ERR_O(exp_self(prim)->pos, _("keyword 'this' cannot be used inside static functions...")) if(env->func && !strcmp(s_name(env->func->def->base->xid), "@gack") && -GET_FLAG(env->class_def, struct)) - ERR_O(exp_self(prim)->pos, _("can't use 'this' in struct @gack")) + GET_FLAG(env->class_def, struct)) + ERR_O(exp_self(prim)->pos, _("can't use 'this' in struct @gack")) return env->class_def; } diff --git a/src/lib/object_op.c b/src/lib/object_op.c index d33a54d1..90ab1d1e 100644 --- a/src/lib/object_op.c +++ b/src/lib/object_op.c @@ -222,8 +222,6 @@ ANN static inline void emit_struct_data(const Emitter emit, const Value v, const push->m_val = v->type->size - v->from->owner_class->size; if(v->from->offset) emit_struct_var(emit, v); -// const Instr push = emit_add_instr(emit, RegPush); -// push->m_val = v->type->size - SZ_INT; } ANN m_bool not_from_owner_class(const Env env, const Type t, const Value v, const loc_t pos); @@ -271,8 +269,8 @@ OP_EMIT(opem_object_dot) { if(!is_class(emit->gwion, member->t_base) && (GET_FLAG(value, member) || (isa(exp_self(member)->info->type, emit->gwion->type[et_function]) > 0 && !is_fptr(emit->gwion, exp_self(member)->info->type)))) { - if(!GET_FLAG(t_base, struct)) - CHECK_BO(emit_exp(emit, member->base)) + if(!GET_FLAG(t_base, struct)) + CHECK_BO(emit_exp(emit, member->base)) if(isa(member->t_base, emit->env->gwion->type[et_object]) > 0) emit_except(emit, member->t_base); } @@ -374,13 +372,9 @@ ANN static Class_Def template_class(const Env env, const Class_Def def, const Ty } -extern ANN m_bool scan0_class_def(const Env, const Class_Def); -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 static m_bool class2udef(const Env env, const Class_Def a, const Type t) { - a->union_def = new_union_def(env->gwion->mp, a->list, +puts("\033[35mhere\033[0m"); + a->union_def = new_union_def(env->gwion->mp, cpy_decl_list(env->gwion->mp, a->list), loc_cpy(env->gwion->mp, t->e->def->pos)); a->union_def->type_xid = a->base.xid; if(GET_FLAG(t, global)) @@ -395,7 +389,7 @@ ANN static m_bool class2udef(const Env env, const Class_Def a, const Type t) { ANN static Type scan_class(const Env env, const Type t, const Type_Decl* td) { if(template_match(t->e->def->base.tmpl->list, td->types) < 0) - ERR_O(td->xid->pos, _("invalid template types number")) + ERR_O(td->pos, _("invalid template types number")) DECL_OO(const Class_Def, a, = template_class(env, t->e->def, td->types)) if(a->base.type) return a->base.type; diff --git a/src/lib/ptr.c b/src/lib/ptr.c index a3483dec..c3e78c55 100644 --- a/src/lib/ptr.c +++ b/src/lib/ptr.c @@ -52,6 +52,8 @@ static OP_CHECK(opck_ptr_deref) { static OP_CHECK(opck_ptr_cast) { const Exp_Cast* cast = (Exp_Cast*)data; + if(!cast->td->types->td) + ERR_N(exp_self(cast)->pos, "'Ptr' needs types to cast") DECL_ON(const Type, t, = type_decl_resolve(env, cast->td)) if(!GET_FLAG(t, check)) CHECK_BN(traverse_class_def(env, t->e->def)) @@ -64,6 +66,7 @@ static OP_CHECK(opck_ptr_cast) { static OP_CHECK(opck_ptr_implicit) { const struct Implicit* imp = (struct Implicit*)data; const Exp e = imp->e; + DECL_OO(const m_str, name, = get_type_name(env, imp->t->name, 1)) if(!strcmp(get_type_name(env, imp->t->name, 1), e->info->type->name)) { const m_str access = exp_access(e); if(access) @@ -118,7 +121,7 @@ static OP_EMIT(opem_ptr_deref) { } GWION_IMPORT(ptr) { - const Type t_ptr = gwi_class_ini(gwi, "Ptr<~A~>", NULL); + const Type t_ptr = gwi_class_ini(gwi, "<~A~>Ptr", NULL); gwi->gwion->type[et_ptr] = t_ptr; GWI_BB(gwi_item_ini(gwi, "@internal", "@val")) GWI_BB(gwi_item_end(gwi, 0, NULL)) diff --git a/src/lib/shred.c b/src/lib/shred.c index a54c1af0..6a7b428d 100644 --- a/src/lib/shred.c +++ b/src/lib/shred.c @@ -13,9 +13,11 @@ #include "specialid.h" #include "gwi.h" -static m_int o_fork_thread, o_shred_cancel, o_fork_done, o_fork_ev, o_fork_retsize; +static m_int o_fork_thread, o_fork_cond, o_fork_mutex, o_shred_cancel, o_fork_done, o_fork_ev, o_fork_retsize; #define FORK_THREAD(o) *(THREAD_TYPE*)(o->data + o_fork_thread) +#define FORK_COND(o) *(THREAD_COND_TYPE*)(o->data + o_fork_cond) +#define FORK_MUTEX(o) *(MUTEX_TYPE*)(o->data + o_fork_mutex) #define FORK_RETSIZE(o) *(m_int*)(o->data + o_fork_retsize) VM_Shred new_shred_base(const VM_Shred shred, const VM_Code code) { @@ -132,8 +134,12 @@ describe_path_and_dir(, s->info->name) describe_path_and_dir(_code, s->code->name) static DTOR(shred_dtor) { - if(ME(o)) + if(ME(o)) { + MUTEX_TYPE mutex = ME(o)->tick->shreduler->mutex; + MUTEX_LOCK(mutex); free_vm_shred(ME(o)); + MUTEX_UNLOCK(mutex); + } } static MFUN(shred_lock) { @@ -147,42 +153,39 @@ static MFUN(shred_unlock) { static void stop(const M_Object o) { VM *vm = ME(o)->info->vm; MUTEX_LOCK(vm->shreduler->mutex); - MUTEX_LOCK(vm->parent->shreduler->mutex); vm->shreduler->bbq->is_running = 0; - MUTEX_UNLOCK(vm->parent->shreduler->mutex); + *(m_int*)(o->data + o_shred_cancel) = 1; MUTEX_UNLOCK(vm->shreduler->mutex); } static void join(const M_Object o) { - VM *vm = ME(o)->info->vm->parent; - MUTEX_LOCK(vm->shreduler->mutex); - THREAD_JOIN(FORK_THREAD(o)); - MUTEX_UNLOCK(vm->shreduler->mutex); + VM *vm = ME(o)->info->vm; + if(FORK_THREAD(o)) { + THREAD_JOIN(FORK_THREAD(o)); + FORK_THREAD(o) = 0; + } } static DTOR(fork_dtor) { + *(m_int*)(o->data + o_fork_done) = 1; stop(o); - VM *vm = ME(o)->info->vm->parent; - const m_int idx = vector_find(&vm->gwion->data->child, (vtype)o); - VPTR(&vm->gwion->data->child, idx) = 0; - if(!vm->gwion->data->child2.ptr) - vector_init(&vm->gwion->data->child2); - vector_add(&vm->gwion->data->child2, (vtype)ME(o)->info->vm->gwion); - gwion_end_child(shred, ME(o)->info->vm->gwion); - join(o); + VM *parent = ME(o)->info->vm->parent; + MUTEX_LOCK(parent->shreduler->mutex); + if(parent->gwion->data->child.ptr) { + const m_int idx = vector_find(&parent->gwion->data->child, (vtype)o); + if(idx > -1) + VPTR(&parent->gwion->data->child, idx) = 0; + } + if(!parent->gwion->data->child2.ptr) + vector_init(&parent->gwion->data->child2); + vector_add(&parent->gwion->data->child2, (vtype)ME(o)->info->vm->gwion); + REM_REF(ME(o)->code, ME(o)->info->vm->gwion); + MUTEX_UNLOCK(parent->shreduler->mutex); } static MFUN(fork_join) { - MUTEX_LOCK(ME(o)->tick->shreduler->mutex); - MUTEX_LOCK(shred->tick->shreduler->mutex); - release(o, shred); - if(*(m_int*)(o->data + o_fork_done)) { - MUTEX_UNLOCK(shred->tick->shreduler->mutex); - MUTEX_UNLOCK(ME(o)->tick->shreduler->mutex); + if(*(m_int*)(o->data + o_fork_done)) return; - } - MUTEX_UNLOCK(ME(o)->tick->shreduler->mutex); - MUTEX_UNLOCK(shred->tick->shreduler->mutex); shreduler_remove(shred->tick->shreduler, shred, 0); vector_add(EV_SHREDS(*(M_Object*)(o->data + o_fork_ev)), (vtype)shred); } @@ -194,45 +197,67 @@ static MFUN(shred_cancel) { } static MFUN(shred_test_cancel) { - MUTEX_LOCK(ME(o)->tick->shreduler->mutex); + if(*(m_int*)(o->data + o_shred_cancel)) + vm_shred_exit(ME(o)); +} + +static MFUN(fork_test_cancel) { if(*(m_int*)(o->data + o_shred_cancel)) { - const m_bool is_me = ME(o) == shred; - if(is_me) - MUTEX_UNLOCK(ME(o)->tick->shreduler->mutex); + stop(o); + join(o); + _release(o, ME(o)); vm_shred_exit(ME(o)); - if(is_me) - return; } - MUTEX_UNLOCK(ME(o)->tick->shreduler->mutex); +} + +struct ThreadLauncher { + MUTEX_TYPE mutex; + THREAD_COND_TYPE cond; + VM *vm; +}; + +static inline int fork_running(VM *vm, const M_Object o) { + MUTEX_LOCK(vm->shreduler->mutex); + const int ret = vm->bbq->is_running && !*(m_int*)(o->data + o_shred_cancel); + MUTEX_UNLOCK(vm->shreduler->mutex); + return ret; } static ANN THREAD_FUNC(fork_run) { - VM *vm = (VM*)data; - vm_lock(vm->parent); - const M_Object me = vm->bbq->is_running ? - vm->shreduler->list->self->info->me : NULL; - vm_unlock(vm->parent); - if(!me) - THREAD_RETURN(0); - while(vm->bbq->is_running) { +struct ThreadLauncher *tl = data; + VM *vm = tl->vm; + MUTEX_TYPE mutex = tl->mutex; + const M_Object me = vm->shreduler->list->self->info->me; + ++me->ref; + MUTEX_LOCK(mutex); + THREAD_COND_SIGNAL(FORK_COND(me)); + MUTEX_UNLOCK(mutex); + while(fork_running(vm, me)) { vm_run(vm); ++vm->bbq->pos; } - vm_lock(vm->parent); - if(vm_running(vm->parent)) { - *(m_int*)(me->data + o_fork_done) = 1; + gwion_end_child(ME(me), vm->gwion); + MUTEX_LOCK(vm->parent->shreduler->mutex); + if(!*(m_int*)(me->data + o_shred_cancel)) broadcast(*(M_Object*)(me->data + o_fork_ev)); - } else if(me->ref > 1) - release(me, ME(me)); - vm_unlock(vm->parent); + MUTEX_UNLOCK(vm->parent->shreduler->mutex); + *(m_int*)(me->data + o_fork_done) = 1; +// if(!*(m_int*)(me->data + o_shred_cancel)) +// _release(me, ME(me)); THREAD_RETURN(0); } ANN void fork_launch(VM const* vm, const M_Object o, const m_uint sz) { - if(vm_running(vm)) { - FORK_RETSIZE(o) = sz; - THREAD_CREATE(FORK_THREAD(o), fork_run, ME(o)->info->vm); - } else release(o, ME(o)); + FORK_RETSIZE(o) = sz; + MUTEX_SETUP(FORK_MUTEX(o)); + THREAD_COND_SETUP(FORK_COND(o)); + struct ThreadLauncher tl = { .mutex=FORK_MUTEX(o), .cond=FORK_COND(o), .vm=ME(o)->info->vm }; + MUTEX_LOCK(tl.mutex); + THREAD_CREATE(FORK_THREAD(o), fork_run, &tl); + THREAD_COND_WAIT(FORK_COND(o), tl.mutex); + MUTEX_UNLOCK(tl.mutex); + THREAD_COND_CLEANUP(FORK_COND(o)); + MUTEX_CLEANUP(FORK_MUTEX(o)); } ANN void fork_clean(const VM_Shred shred, const Vector v) { @@ -241,9 +266,19 @@ ANN void fork_clean(const VM_Shred shred, const Vector v) { if(!o) continue; stop(o); - THREAD_JOIN(FORK_THREAD(o)); - _release(o, shred); } + for(m_uint i = 0; i < vector_size(v); ++i) { + const M_Object o = (M_Object)vector_at(v, i); + if(!o) + continue; + join(o); + } + for(m_uint i = 0; i < vector_size(v); ++i) { + const M_Object o = (M_Object)vector_at(v, i); + if(!o) + continue; + _release(o, shred); + } vector_release(v); v->ptr = NULL; } @@ -325,6 +360,10 @@ GWION_IMPORT(shred) { gwi_item_ini(gwi, "@internal", "@thread"); GWI_BB((o_fork_thread = gwi_item_end(gwi, ae_flag_const, NULL))) + gwi_item_ini(gwi, "@internal", "@cond"); + GWI_BB((o_fork_cond = gwi_item_end(gwi, ae_flag_const, NULL))) + gwi_item_ini(gwi, "@internal", "@mutex"); + GWI_BB((o_fork_mutex = gwi_item_end(gwi, ae_flag_const, NULL))) gwi_item_ini(gwi, "int", "is_done"); GWI_BB((o_fork_done = gwi_item_end(gwi, ae_flag_const, NULL))) gwi_item_ini(gwi, "Event", "ev"); @@ -333,6 +372,8 @@ GWION_IMPORT(shred) { GWI_BB((o_fork_retsize = gwi_item_end(gwi, ae_flag_const, NULL))) gwi_func_ini(gwi, "void", "join"); GWI_BB(gwi_func_end(gwi, fork_join, ae_flag_none)) + gwi_func_ini(gwi, "void", "test_cancel"); + GWI_BB(gwi_func_end(gwi, fork_test_cancel, ae_flag_none)) GWI_BB(gwi_class_end(gwi)) SET_FLAG((t_fork), abstract); return GW_OK; diff --git a/src/main.c b/src/main.c index c1461968..d08ae840 100644 --- a/src/main.c +++ b/src/main.c @@ -22,19 +22,24 @@ ANN static void gwion_reset(const Gwion gwion) { push_global(gwion, "[user]"); } -//#define BUFSIZE 1024 -#define BUFSIZE 256 +#define BUFSIZE 64 static void afl_run(const Gwion gwion) { char buf[BUFSIZE]; - __AFL_INIT(); - while (__AFL_LOOP(1000)) { + struct GwText_ text = { .mp=gwion->mp }; + while (__AFL_LOOP(5)) { + ssize_t sz; memset(buf, 0, BUFSIZE); - read(0, buf, BUFSIZE); - if(compile_string(gwion, "afl", buf)) + while((sz = read(0, buf, BUFSIZE)) > 0) { + buf[sz] = '\0'; + text_add(&text, buf); + } + if(compile_string(gwion, "afl", text.str)) gwion_run(gwion); + text_reset(&text); gwion_reset(gwion); } + text_release(&text); } #define gwion_run(a) afl_run(a) #endif diff --git a/src/parse/check.c b/src/parse/check.c index c4bf2db2..34e2beeb 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -73,14 +73,10 @@ ANN static m_bool check_fptr_decl(const Env env, const Var_Decl var) { t = t->e->parent; if(!t->e->d.func) return GW_ERROR; + if(!env->class_def) + return GW_OK; const Func func = t->e->d.func; const Type type = func->value_ref->from->owner_class; - if(!env->class_def) { - if(!type || GET_FLAG(func, global)) - return GW_OK; -return GW_OK; -// ERR_B(var->pos, _("can't use non public typedef at global scope.")) - } if(type && isa(type, env->class_def) < 0 && !GET_FLAG(func, global)) ERR_B(var->pos, _("can't use non global fptr of other class.")) if(GET_FLAG(func, member) && GET_FLAG(v, static)) @@ -96,8 +92,7 @@ ANN Type check_td(const Env env, Type_Decl *td) { assert(t); if(GET_FLAG(t, template) && !GET_FLAG(t, ref)) ERR_O(td_pos(td), _("type '%s' needs template types"), t->name) - td->xid = new_id_list(env->gwion->mp, insert_symbol("@resolved"), - loc_cpy(env->gwion->mp, td->exp->pos)); + td->xid = insert_symbol("@resolved"); if(t->array_depth) SET_FLAG(td, force); return t; @@ -130,7 +125,7 @@ ANN static m_bool check_var_td(const Env env, const Var_Decl var, Type_Decl *con if(GET_FLAG(td, member)) { decl_member(env, v); if(env->class_def->e->tuple) - tuple_info(env, td, var); + tuple_info(env, v); } else if(GET_FLAG(td, static)) decl_static(env, v); } else if(GET_FLAG(td, global) || (env->func && GET_FLAG(env->func->def, global))) @@ -152,10 +147,16 @@ ANN static m_bool check_decl(const Env env, const Exp_Decl *decl) { return GW_OK; } +ANN static inline m_bool ensure_check(const Env env, const Type t) { + struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)check_cdef, + .scope=env->scope->depth, .flag=ae_flag_check }; + return envset_run(&es, t); +} + ANN Type check_exp_decl(const Env env, const Exp_Decl* decl) { if(!decl->td->xid) return no_xid(env, decl); - if(decl->td->xid->xid == insert_symbol("auto")) { // should be better + if(decl->td->xid == insert_symbol("auto")) { // should be better clear_decl(env, decl); CHECK_BO(scan1_exp(env, exp_self(decl))) CHECK_BO(scan2_exp(env, exp_self(decl))) @@ -165,11 +166,11 @@ ANN Type check_exp_decl(const Env env, const Exp_Decl* decl) { } if(!decl->type) ERR_O(td_pos(decl->td), _("can't find type")); -{ - const Type t = get_type(decl->type); - if(GET_FLAG(t, template) && !GET_FLAG(t, check)) - CHECK_BO(check_cdef(env, t->e->def)) -} + { + const Type t = get_type(decl->type); + if(!GET_FLAG(t, check) && t->e->def) + CHECK_BO(ensure_check(env, t)) + } const m_bool global = GET_FLAG(decl->td, global); const m_uint scope = !global ? env->scope->depth : env_push_global(env); const m_bool ret = check_decl(env, decl); @@ -360,28 +361,25 @@ static ANN Type check_exp_slice(const Env env, const Exp_Slice* range) { return op_check(env, &opi); } -ANN static void fill_tl_vector(const Env env, Nspc nspc, const Vector v) { - while(nspc->parent) { - const Type t = nspc_lookup_type0(nspc->parent, insert_symbol(nspc->name)); - if(!t) - break; - vector_add(v, (vtype)insert_symbol(t->name)); - nspc = nspc->parent; - } +ANN static Type_Decl* prepend_type_decl(MemPool mp, const Symbol xid, Type_Decl* td, const loc_t pos) { + Type_Decl *a = new_type_decl(mp, xid, loc_cpy(mp, pos)); + a->next = td; + return a; } ANN static Type_List mk_type_list(const Env env, const Type type, const loc_t pos) { struct Vector_ v; vector_init(&v); vector_add(&v, (vtype)insert_symbol(type->name)); - if(type->e->owner) - fill_tl_vector(env, type->e->owner, &v); - ID_List id = NULL; + Type owner = type->e->owner_class; + while(owner) { + vector_add(&v, (vtype)insert_symbol(owner->name)); + owner = owner->e->owner_class; + } + Type_Decl *td = NULL; for(m_uint i = 0 ; i < vector_size(&v); ++i) - id = prepend_id_list(env->gwion->mp, (Symbol)vector_at(&v, i), id, loc_cpy(env->gwion->mp, pos)); + td = prepend_type_decl(env->gwion->mp, (Symbol)vector_at(&v, i), td, pos); vector_release(&v); - assert(id); - Type_Decl* td = new_type_decl(env->gwion->mp, id); return new_type_list(env->gwion->mp, td, NULL); } @@ -392,9 +390,7 @@ ANN static m_bool func_match_inner(const Env env, const Exp e, const Type t, array_base(e->info->type) == array_base(t); if(!match) { if(e->info->type == env->gwion->type[et_lambda] && is_fptr(env->gwion, t)) { - const Type owner = nspc_lookup_type1(t->e->owner->parent, - insert_symbol(t->e->owner->name)); - const m_bool ret = check_lambda(env, owner, &e->d.exp_lambda, t->e->d.func->def); + const m_bool ret = check_lambda(env, t->e->owner_class, &e->d.exp_lambda, t->e->d.func->def); exp_setvar(e, 1); return ret; } @@ -418,10 +414,11 @@ ANN2(1,2) static Func find_func_match_actual(const Env env, Func func, const Exp } if(e1->type == env->gwion->type[et_undefined] || (func->def->base->tmpl && is_fptr(env->gwion, func->value_ref->type) > 0)) { - if(SAFE_FLAG(func->value_ref->from->owner_class, template)) - CHECK_BO(template_push_types(env, func->value_ref->from->owner_class->e->def->base.tmpl)) - e1->type = known_type(env, e1->td); - if(SAFE_FLAG(func->value_ref->from->owner_class, template)) + const Type owner = func->value_ref->from->owner_class; + if(owner) + CHECK_BO(template_push(env, owner)) + e1->type = known_type(env, e1->td); + if(owner) nspc_pop_type(env->gwion->mp, env->curr); CHECK_OO(e1->type) } @@ -499,7 +496,12 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal const Type_List types = exp->tmpl->call; Func m_func = NULL, former = env->func; DECL_OO(const m_str, tmpl_name, = tl2str(env, types)) - const m_uint scope = env_push(env, v->from->owner_class, v->from->owner); + const m_uint scope = env->scope->depth; + struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)check_cdef, + .scope=scope, .flag=ae_flag_check }; + if(v->from->owner_class) + envset_push(&es, v->from->owner_class); + (void)env_push(env, v->from->owner_class, v->from->owner); if(is_fptr(env->gwion, v->type)) { const Symbol sym = func_symbol(env, v->from->owner->name, v->name, tmpl_name, 0); const Type exists = nspc_lookup_type0(v->from->owner, sym); @@ -521,7 +523,7 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal if(m_func) nspc_add_type_front(v->from->owner, sym, actual_type(env->gwion, m_func->value_ref->type)); } - free_fptr_def(env->gwion->mp, fptr); // ???? related + free_fptr_def(env->gwion->mp, fptr); } } } else { @@ -555,6 +557,8 @@ ANN static Func _find_template_match(const Env env, const Value v, const Exp_Cal } } free_mstr(env->gwion->mp, tmpl_name); + if(v->from->owner_class && v->from->owner_class->e->owner_class && es.run) + envset_pop(&es, v->from->owner_class->e->owner_class); env_pop(env, scope); env->func = former; return m_func; @@ -650,11 +654,18 @@ ANN static Func predefined_func(const Env env, const Value v, return v->d.func_ref = func; } -ANN static Type check_predefined(const Env env, Exp_Call *exp, const Value value, const Tmpl *tm, const Func_Def fdef) { - DECL_OO(const Func, func, = value->d.func_ref ?: predefined_func(env, value, exp, tm)) +ANN static Type check_predefined(const Env env, Exp_Call *exp, const Value v, const Tmpl *tm, const Func_Def fdef) { + DECL_OO(const Func, func, = v->d.func_ref ?: predefined_func(env, v, exp, tm)) if(!fdef->base->ret_type) { // template fptr - const m_uint scope = env_push(env, value->from->owner_class, value->from->owner); + const m_uint scope = env->scope->depth; + struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)check_cdef, + .scope=scope, .flag=ae_flag_check }; + if(v->from->owner_class) + envset_push(&es, v->from->owner_class); + (void)env_push(env, v->from->owner_class, v->from->owner); const m_bool ret = traverse_func_def(env, func->def); + if(v->from->owner_class && v->from->owner_class->e->owner_class && es.run) + envset_push(&es, v->from->owner_class); env_pop(env, scope); CHECK_BO(ret) } @@ -672,9 +683,7 @@ ANN static Type_List check_template_args(const Env env, Exp_Call *exp, const Tmp Arg_List arg = fdef->base->args; Exp template_arg = exp->args; while(arg && template_arg) { - char path[id_list_len(arg->td->xid)]; - type_path(path, arg->td->xid); - if(!strcmp(s_name(list->xid), path)) { + if(list->xid == arg->td->xid) { tl[args_number] = mk_type_list(env, template_arg->info->type, fdef->pos); if(args_number) tl[args_number - 1]->next = tl[args_number]; @@ -963,21 +972,19 @@ ANN static m_bool do_stmt_auto(const Env env, const Stmt_Auto stmt) { memset(&array, 0, sizeof(struct Array_Sub_)); memset(&td0, 0, sizeof(Type_Decl)); memset(&td, 0, sizeof(Type_Decl)); - id.xid = insert_symbol("Ptr"); - id0.xid = insert_symbol(ptr->name); - td0.xid = &id0; - td.xid = &id; + td.xid = insert_symbol("Ptr"); + td0.xid = insert_symbol(ptr->name); tl.td = &td0; td.types = &tl; - td0.xid->pos = stmt->exp->pos; - td.xid->pos = stmt->exp->pos; + td0.pos = stmt->exp->pos; + td.pos = stmt->exp->pos; if(depth) { array.depth = depth; td.array = &array; } ptr = known_type(env, &td); if(!GET_FLAG(ptr, checked) && ptr->e->def) - CHECK_BB(traverse_cdef(env, ptr->e->def)) + CHECK_BB(ensure_check(env, ptr)) } t = depth ? array_type(env, ptr, depth) : ptr; stmt->v = new_value(env->gwion->mp, t, s_name(stmt->sym)); @@ -1028,9 +1035,8 @@ ANN static m_bool check_stmt_return(const Env env, const Stmt_Exp stmt) { if(stmt->val) { if(env->func->def->base->xid == insert_symbol("@implicit") && ret_type == env->func->def->base->args->type) ERR_B(stmt_self(stmt)->pos, _("can't use implicit casting while defining it")) - const m_bool ret = check_implicit(env, stmt->val, env->func->def->base->ret_type); - if(ret > 0) - return ret; + if(check_implicit(env, stmt->val, env->func->def->base->ret_type) > 0) + return GW_OK; ERR_B(stmt_self(stmt)->pos, _("invalid return type: got '%s', expected '%s'"), ret_type->name, env->func->def->base->ret_type->name) } @@ -1351,18 +1357,19 @@ ANN static m_bool cdef_parent(const Env env, const Class_Def cdef) { ANN m_bool check_class_def(const Env env, const Class_Def c) { if(tmpl_base(c->base.tmpl)) return GW_OK; - const Class_Def cdef = c->base.type->e->def; - if(GET_FLAG(cdef->base.type, checked))return GW_OK; - const Type type = cdef->base.type; - SET_FLAG(type, check); + const Type t = c->base.type; + const Class_Def cdef = t->e->def; + if(t->e->owner_class && !GET_FLAG(t->e->owner_class, check)) + CHECK_BB(check_class_def(env, t->e->owner_class->e->def)) + if(GET_FLAG(t, checked))return GW_OK; + SET_FLAG(t, check); if(cdef->base.ext) CHECK_BB(cdef_parent(env, cdef)) - assert(type->e->parent || GET_FLAG(cdef, struct)); if(!GET_FLAG(cdef, struct)) - inherit(type); + inherit(t); if(cdef->body) CHECK_BB(env_body(env, cdef, check_section)) - SET_FLAG(type, checked); + SET_FLAG(t, checked); return GW_OK; } diff --git a/src/parse/scan0.c b/src/parse/scan0.c index 6d4cb056..ce645987 100644 --- a/src/parse/scan0.c +++ b/src/parse/scan0.c @@ -77,29 +77,31 @@ ANN static m_bool check_tmpl_args(const Env env, const Func_Base *base) { return GW_OK; } +ANN static m_bool scan0_fptr_args(const Env env, const Fptr_Def fptr) { + nspc_push_type(env->gwion->mp, env->curr); + const m_bool ret = check_tmpl_args(env, fptr->base); + nspc_pop_type(env->gwion->mp, env->curr); + return ret; +} + ANN m_bool scan0_fptr_def(const Env env, const Fptr_Def fptr) { CHECK_BB(env_access(env, fptr->base->td->flag, td_pos(fptr->base->td))) CHECK_OB(known_type(env, fptr->base->td)) CHECK_BB(scan0_defined(env, fptr->base->xid, td_pos(fptr->base->td))); const m_str name = s_name(fptr->base->xid); -if(fptr->base->tmpl && fptr->base->args) { - nspc_push_type(env->gwion->mp, env->curr); - const m_bool ret = check_tmpl_args(env, fptr->base); - nspc_pop_type(env->gwion->mp, env->curr); - CHECK_BB(ret); -} + if(fptr->base->tmpl && fptr->base->args) + CHECK_BB(scan0_fptr_args(env, fptr)) const Type t = scan0_type(env, env->gwion->type[et_fptr]->xid, name, env->gwion->type[et_fptr]); t->e->owner = !(!env->class_def && GET_FLAG(fptr->base->td, global)) ? env->curr : env->global_nspc; + t->e->owner_class = env->class_def; if(GET_FLAG(fptr->base->td, global)) context_global(env); t->nspc = new_nspc(env->gwion->mp, name); t->flag = fptr->base->td->flag; fptr->type = t; fptr->value = mk_class(env, t); -// set owner ? - fptr->value->from->owner = env->curr; - fptr->value->from->owner_class = env->class_def; + valuefrom(env, fptr->value->from); fptr_def(env, fptr); if(env->class_def) fptr_assign(env, fptr); @@ -139,6 +141,7 @@ ANN static void typedef_simple(const Env env, const Type_Def tdef, const Type ba context_global(env); add_type(env, nspc, t); t->e->owner = nspc; + t->e->owner_class = env->class_def; tdef->type = t; if(base->nspc) ADD_REF((t->nspc = base->nspc)); @@ -171,7 +174,7 @@ ANN static void typedef_fptr(const Env env, const Type_Def tdef, const Type base ANN m_bool scan0_type_def(const Env env, const Type_Def tdef) { CHECK_BB(env_access(env, tdef->ext->flag, td_pos(tdef->ext))) - DECL_OB(const Type, base, = tdef->tmpl ? find_type(env, tdef->ext->xid) : known_type(env, tdef->ext)) + DECL_OB(const Type, base, = tdef->tmpl ? find_type(env, tdef->ext) : known_type(env, tdef->ext)) CHECK_BB(scan0_defined(env, tdef->xid, td_pos(tdef->ext))) if(isa(base, env->gwion->type[et_function]) < 0) { if(!tdef->ext->types && (!tdef->ext->array || !tdef->ext->array->exp)) @@ -201,6 +204,7 @@ ANN static Type enum_type(const Env env, const Enum_Def edef) { t->e->parent = env->gwion->type[et_int]; const Nspc nspc = GET_FLAG(edef, global) ? env->global_nspc : env->curr; t->e->owner = nspc; + t->e->owner_class = env->class_def; add_type(env, nspc, t); mk_class(env, t); scan0_implicit_similar(env, t, env->gwion->type[et_int]); @@ -223,6 +227,7 @@ ANN static Type union_type(const Env env, const Symbol s, const m_bool add) { t->name = name; t->nspc = new_nspc(env->gwion->mp, name); t->e->owner = t->nspc->parent = env->curr; + t->e->owner_class = env->class_def; t->e->parent = env->gwion->type[et_union]; add_type(env, env->curr, t); if(add) { @@ -236,11 +241,11 @@ ANN static void union_tmpl(const Env env, const Union_Def udef) { if(tmpl_base(udef->tmpl)) { assert(udef->type_xid); const Class_Def cdef = new_class_def(env->gwion->mp, udef->flag, udef->type_xid, - NULL, (Ast)udef->l, loc_cpy(env->gwion->mp, udef->pos)); + NULL, (Ast)cpy_decl_list(env->gwion->mp, udef->l), loc_cpy(env->gwion->mp, udef->pos)); udef->type->e->def = cdef; cdef->base.tmpl = cpy_tmpl(env->gwion->mp, udef->tmpl); cdef->base.type = udef->type; - cdef->list = cpy_decl_list(env->gwion->mp, udef->l); +// cdef->list = cpy_decl_list(env->gwion->mp, udef->l); SET_FLAG(cdef, union); SET_FLAG(udef->type, pure); SET_FLAG(udef, template); @@ -299,19 +304,13 @@ ANN static m_bool scan0_class_def_pre(const Env env, const Class_Def cdef) { return GW_OK; } -ANN static void set_template(const Type t, const Class_Def cdef) { - SET_FLAG(t, template); - SET_FLAG(cdef, template); -} - - -ANN static void inherit_tmpl(const Env env, const Class_Def cdef) { - const ID_List list = env->class_def->e->def->base.tmpl->list; - const ID_List prev_list = cpy_id_list(env->gwion->mp, list); - ID_List il = prev_list; - while(il->next && (il = il->next)); - il->next = cdef->base.tmpl->list; - cdef->base.tmpl->list = prev_list; +ANN static void cdef_flag(const Class_Def cdef, const Type t) { + if(cdef->base.tmpl) { + SET_FLAG(t, template); + SET_FLAG(cdef, template); + } + if(cdef->base.ext && cdef->base.ext->array) + SET_FLAG(t, typedef); } ANN static Type scan0_class_def_init(const Env env, const Class_Def cdef) { @@ -324,20 +323,13 @@ ANN static Type scan0_class_def_init(const Env env, const Class_Def cdef) { } t->e->tuple = new_tupleform(env->gwion->mp, parent); t->e->owner = env->curr; + t->e->owner_class = env->class_def; t->nspc = new_nspc(env->gwion->mp, t->name); t->nspc->parent = env->curr; t->e->def = cdef; t->flag = cdef->flag; add_type(env, t->e->owner, t); - if(cdef->base.tmpl) { - if(SAFE_FLAG(env->class_def, template) && env->class_def->e->def->base.tmpl->call == (Type_List)1) - inherit_tmpl(env, cdef); - set_template(t, cdef); - } else if(SAFE_FLAG(env->class_def, template)) { - cdef->base.tmpl = new_tmpl_base(env->gwion->mp, cpy_id_list(env->gwion->mp, env->class_def->e->def->base.tmpl->list)); -// cdef->base.tmpl = cpy_tmpl(env->gwion->mp, env->class_def->e->def->base.tmpl); - set_template(t, cdef); - } + cdef_flag(cdef, t); if(cdef->base.ext && cdef->base.ext->array) SET_FLAG(t, typedef); return t; @@ -360,18 +352,15 @@ ANN static m_bool scan0_section(const Env env, const Section* section) { ANN static m_bool scan0_class_def_inner(const Env env, const Class_Def cdef) { CHECK_OB((cdef->base.type = scan0_class_def_init(env, cdef))) SET_FLAG(cdef->base.type, scan0); - if(cdef->body) { - int call = cdef->base.tmpl && !cdef->base.tmpl->call; - if(call)cdef->base.tmpl->call = (Type_List)1; - const m_bool ret = env_body(env, cdef, scan0_section); - if(call)cdef->base.tmpl->call = NULL; - CHECK_BB(ret); - } + if(cdef->body) + CHECK_BB(env_body(env, cdef, scan0_section)) (void)mk_class(env, cdef->base.type); return GW_OK; } -ANN m_bool scan0_class_def(const Env env, const Class_Def cdef) { +ANN m_bool scan0_class_def(const Env env, const Class_Def c) { + const Class_Def cdef = !(GET_FLAG(c, global) || (c->base.tmpl && !c->base.tmpl->call)) ? + c : cpy_class_def(env->gwion->mp, c); if(GET_FLAG(cdef, global)) { vector_add(&env->scope->nspc_stack, (vtype)env->curr); env->curr = env->global_nspc; @@ -382,11 +371,8 @@ ANN m_bool scan0_class_def(const Env env, const Class_Def cdef) { if(GET_FLAG(cdef, global)) env->curr = (Nspc)vector_pop(&env->scope->nspc_stack); CHECK_BB(ret) - if(GET_FLAG(cdef, global) || (cdef->base.tmpl && !cdef->base.tmpl->call)) { - const Class_Def c = cpy_class_def(env->gwion->mp, cdef); + if(GET_FLAG(cdef, global) || (cdef->base.tmpl && !cdef->base.tmpl->call)) c->base.type = cdef->base.type; - c->base.type->e->def = c; - } return GW_OK; } diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 265f339e..b00d0d75 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -9,32 +9,17 @@ ANN static m_bool scan1_stmt_list(const Env env, Stmt_List list); ANN static m_bool scan1_stmt(const Env env, Stmt stmt); -ANN static inline void type_contains(const Type base, const Type t) { - const Vector v = &base->e->contains; - if(!v->ptr) - vector_init(v); - if(vector_find(v, (vtype)t) == GW_ERROR) { - vector_add(v, (vtype)t); - if(base != t) - ADD_REF(t); - } -} - ANN static m_bool type_recursive(const Env env, const Type_Decl *td, const Type t) { if(env->class_def && !env->scope->depth) { - type_contains(env->class_def, t); - if(t->e->contains.ptr) { - for(m_uint i = 0; i < vector_size(&t->e->contains); ++i) { - if(env->class_def == (Type)vector_at(&t->e->contains, i) && !GET_FLAG(td, ref)) - ERR_B(td_pos(td), _("%s declared inside %s\n. (make it a ref ?)"), - t->name, t == env->class_def ? "itself" : env->class_def->name); - } - } + const m_int idx = vector_find(&env->scope->class_stack, (vtype)t); + if(idx > -1 || t == env->class_def) + ERR_B(td_pos(td), _("%s declared inside %s\n. (make it a ref ?)"), + t->name, t == env->class_def ? "itself" : env->class_def->name); } return GW_OK; } -ANN static Type void_type(const Env env, const Type_Decl* td) { +ANN static Type void_type(const Env env, Type_Decl* td) { DECL_OO(const Type, type, = known_type(env, td)) const Type t = get_type(type); if(isa(t, env->gwion->type[et_object]) > 0 || GET_FLAG(t, struct)) @@ -48,7 +33,7 @@ ANN static Type scan1_exp_decl_type(const Env env, Exp_Decl* decl) { if(decl->type) return decl->type; DECL_OO(const Type ,t, = void_type(env, decl->td)) - if(decl->td->xid && decl->td->xid->xid == insert_symbol("auto") && decl->type) + if(decl->td->xid == insert_symbol("auto") && decl->type) return decl->type; if(!env->scope->depth && env->class_def && !GET_FLAG(decl->td, static)) SET_FLAG(decl->td, member); @@ -78,13 +63,11 @@ ANN static m_bool scan1_decl(const Env env, const Exp_Decl* decl) { } t = array_type(env, decl->type, var->array->depth); } else if(GET_FLAG(t, abstract) && !GET_FLAG(decl->td, ref)) { - if(decl->td->xid && decl->td->xid->xid == insert_symbol("auto")) + if(decl->td->xid == insert_symbol("auto")) SET_FLAG(decl->td, ref); else ERR_B(exp_self(decl)->pos, _("Type '%s' is abstract, declare as ref. (use @)"), t->name) } - if(env->class_def) - type_contains(env->class_def, t); const Value v = var->value = former ?: new_value(env->gwion->mp, t, s_name(var->xid)); if(SAFE_FLAG(env->class_def, struct) && !GET_FLAG(decl->td, static)) { v->from->offset = env->class_def->size; @@ -310,12 +293,18 @@ ANN static m_bool scan1_args(const Env env, Arg_List list) { ANN m_bool scan1_fptr_def(const Env env, const Fptr_Def fptr) { if(tmpl_base(fptr->base->tmpl)) return GW_OK; + if(!fptr->base->func) { + fptr->base->func = nspc_lookup_value0(env->curr, fptr->base->xid)->d.func_ref; + fptr->type = nspc_lookup_type0(env->curr, fptr->base->xid); + } const Func_Def fdef = fptr->base->func->def; CHECK_OB((fdef->base->ret_type = known_type(env, fdef->base->td))) return fdef->base->args ? scan1_args(env, fdef->base->args) : GW_OK; } ANN m_bool scan1_type_def(const Env env, const Type_Def tdef) { + if(!tdef->type) + tdef->type = nspc_lookup_type0(env->curr, tdef->xid); if(!tdef->type->e->def)return GW_OK; return !is_fptr(env->gwion, tdef->type) ? scan1_cdef(env, tdef->type->e->def) : GW_OK; } @@ -368,7 +357,7 @@ ANN m_bool scan1_union_def(const Env env, const Union_Def udef) { } const m_bool ret = scan1_union_def_inner(env, udef); union_pop(env, udef, scope); - const Type type = udef->xid || udef->type_xid ? udef->value->type : udef->type; + const Type type = udef->xid || !udef->type_xid ? udef->value->type : udef->type; SET_FLAG(type, scan1); return ret; } @@ -516,8 +505,11 @@ ANN static m_bool cdef_parent(const Env env, const Class_Def cdef) { ANN m_bool scan1_class_def(const Env env, const Class_Def c) { if(tmpl_base(c->base.tmpl)) return GW_OK; - const Class_Def cdef = c->base.type->e->def; - if(GET_FLAG(cdef->base.type, scan1))return GW_OK; + const Type t = c->base.type; + const Class_Def cdef = t->e->def; + if(GET_FLAG(t, scan1))return GW_OK; + if(t->e->owner_class && !GET_FLAG(t->e->owner_class, scan1)) + CHECK_BB(scan1_class_def(env, t->e->owner_class->e->def)) SET_FLAG(cdef->base.type, scan1); if(cdef->base.ext) CHECK_BB(cdef_parent(env, cdef)) diff --git a/src/parse/scan2.c b/src/parse/scan2.c index 6dd4cdb7..8f38e935 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -13,10 +13,16 @@ ANN static m_bool scan2_stmt(const Env, const Stmt); ANN static m_bool scan2_stmt_list(const Env, Stmt_List); +ANN static inline m_bool ensure_scan2(const Env env, const Type t) { + struct EnvSet es = { .env=env, .data=env, .func=(_exp_func)scan2_cdef, + .scope=env->scope->depth, .flag=ae_flag_scan2 }; + return envset_run(&es, t); +} + ANN static m_bool scan2_decl(const Env env, const Exp_Decl* decl) { const Type t = get_type(decl->type); - if(GET_FLAG(t, template) && !GET_FLAG(t, scan2)) - CHECK_BB(scan2_cdef(env, t->e->def)) + if(!GET_FLAG(t, scan2) && t->e->def) + CHECK_BB(ensure_scan2(env, t)) Var_Decl_List list = decl->list; do { const Var_Decl var = list->self; @@ -37,7 +43,7 @@ ANN m_bool scan2_exp_decl(const Env env, const Exp_Decl* decl) { return ret; } -ANN static m_bool scan2_args(const Env env, const Func_Def f) { +ANN static m_bool scan2_args(const Func_Def f) { Arg_List list = f->base->args; do { const Value v = list->var_decl->value; @@ -64,11 +70,11 @@ ANN static Value scan2_func_assign(const Env env, const Func_Def d, } -ANN m_bool scan2_fptr_def(const Env env, const Fptr_Def fptr) { +ANN m_bool scan2_fptr_def(const Env env NUSED, const Fptr_Def fptr) { if(!tmpl_base(fptr->base->tmpl)) { const Func_Def def = fptr->type->e->d.func->def; if(def->base->args) - CHECK_BB(scan2_args(env, def)) + CHECK_BB(scan2_args(def)) } else SET_FLAG(fptr->type, func); return GW_OK; @@ -259,6 +265,7 @@ ANN static m_bool scan2_stmt_jump(const Env env, const Stmt_Jump stmt) { ANN static m_bool scan2_union_decl(const Env env, const Decl_List list) { Decl_List l = list; do CHECK_BB(scan2_exp_decl(env, &l->self->d.exp_decl)) +// do CHECK_BB(scan2_exp(env, l->self)) while((l = l->next)); return GW_OK; } @@ -323,6 +330,7 @@ ANN static Type func_type(const Env env, const Func func) { t->e->parent = env->gwion->type[func->def->base->td ? et_function : et_lambda]; t->name = func->name; t->e->owner = env->curr; + t->e->owner_class = env->class_def; if(GET_FLAG(func, member)) t->size += SZ_INT; t->e->d.func = func; @@ -391,7 +399,6 @@ ANN2(1, 2) static m_bool scan2_fdef_tmpl(const Env env, const Func_Def f, const const Symbol sym = func_symbol(env, env->curr->name, name, "template", i); nspc_add_value(env->curr, sym, value); if(!overload) { -// func->vt_index = i; // ????? ADD_REF(value) nspc_add_value(env->curr, f->base->xid, value); nspc_add_func(env->curr, f->base->xid, func); @@ -445,7 +452,6 @@ ANN static m_str func_tmpl_name(const Env env, const Func_Def f) { do { const Type t = nspc_lookup_type0(env->curr, id->xid); if(!t)return NULL; -// assert(t); vector_add(&v, (vtype)t); tlen += strlen(t->name); } while((id = id->next) && ++tlen); @@ -495,7 +501,7 @@ ANN2(1,2) m_bool scan2_fdef_std(const Env env, const Func_Def f, const Value ove else f->base->func = base; if(f->base->args) - CHECK_BB(scan2_args(env, f)) + CHECK_BB(scan2_args(f)) if(!GET_FLAG(f, builtin) && f->d.code) CHECK_BB(scan2_func_def_code(env, f)) if(!base) { @@ -573,9 +579,12 @@ ANN static m_bool cdef_parent(const Env env, const Class_Def cdef) { ANN m_bool scan2_class_def(const Env env, const Class_Def c) { if(tmpl_base(c->base.tmpl)) return GW_OK; - const Class_Def cdef = c->base.type->e->def; - if(GET_FLAG(cdef->base.type, scan2))return GW_OK; - SET_FLAG(cdef->base.type, scan2); + const Type t = c->base.type; + const Class_Def cdef = t->e->def; + if(GET_FLAG(t, scan2))return GW_OK; + if(t->e->owner_class && !GET_FLAG(t->e->owner_class, scan2)) + CHECK_BB(scan2_class_def(env, t->e->owner_class->e->def)) + SET_FLAG(t, scan2); if(cdef->base.ext) CHECK_BB(cdef_parent(env, cdef)) if(cdef->body) diff --git a/src/parse/template.c b/src/parse/template.c index cd5beb76..8e47c8cb 100644 --- a/src/parse/template.c +++ b/src/parse/template.c @@ -17,22 +17,39 @@ struct tmpl_info { uint8_t index; }; -ANN m_bool template_push_types(const Env env, const Tmpl *tmpl) { +ANN static m_bool push_types(const Env env, const Tmpl *tmpl) { ID_List list = tmpl->list; Type_List call = tmpl->call; - nspc_push_type(env->gwion->mp, env->curr); do { if(!call) break; const Type t = known_type(env, call->td); if(!t) - return GW_ERROR; + return 1; nspc_add_type(env->curr, list->xid, t); call = call->next; } while((list = list->next)); - if(!call) + return !call; +} + +ANN static m_bool _template_push(const Env env, const Type t) { + if(t->e->owner_class) + CHECK_BB(template_push(env, t->e->owner_class)) + if(GET_FLAG(t, template)) + return push_types(env, t->e->def->base.tmpl); + return GW_OK; +} + +ANN m_bool template_push(const Env env, const Type t) { + nspc_push_type(env->gwion->mp, env->curr); + return _template_push(env, t); +} + +ANN m_bool template_push_types(const Env env, const Tmpl *tmpl) { + nspc_push_type(env->gwion->mp, env->curr); + if(push_types(env, tmpl)) return GW_OK; - POP_RET(-1); + POP_RET(GW_ERROR); } ANN Tmpl* mk_tmpl(const Env env, const Tmpl *tm, const Type_List types) { @@ -60,7 +77,7 @@ static ANN Type scan_func(const Env env, const Type t, const Type_Decl* td) { func->flag = def->flag; value->d.func_ref = func; value->from->owner = t->e->owner; - value->from->owner_class = t->e->d.func->value_ref->from->owner_class; + value->from->owner_class = t->e->owner_class; func->value_ref = value; func->def->base->tmpl = mk_tmpl(env, t->e->d.func->def->base->tmpl, td->types); def->base->func = func; @@ -71,11 +88,11 @@ static ANN Type scan_func(const Env env, const Type t, const Type_Decl* td) { static ANN Type maybe_func(const Env env, const Type t, const Type_Decl* td) { if(isa(t, env->gwion->type[et_function]) > 0 && t->e->d.func->def->base->tmpl) return scan_func(env, t, td); - ERR_O(td->xid->pos, - _("type '%s' is not template. You should not provide template types"), t->name) + ERR_O(td->pos, + _("type '%s' is not template. You should not provide template types"), t->name) } -ANN Type scan_type(const Env env, const Type t, const Type_Decl* td) { +ANN Type _scan_type(const Env env, const Type t, const Type_Decl* td) { if(GET_FLAG(t, template)) { if(GET_FLAG(t, ref)) return t; @@ -84,5 +101,29 @@ ANN Type scan_type(const Env env, const Type t, const Type_Decl* td) { return op_check(env, &opi); } else if(td->types) return maybe_func(env, t, td); - return t; + return td->xid ? nspc_lookup_type1(env->curr, td->xid) : t; } + +ANN Type scan_type(const Env env, const Type t, Type_Decl* td) { + if(td->next) { + Type_Decl *next = td->next; + td->next = NULL; + const Type owner = known_type(env, td); + td->next = next; + CHECK_OO(owner) + if(!owner->nspc) + ERR_O(td_pos(td), "type '%s' has no namespace", owner->name) + const Tmpl *tmpl = GET_FLAG(owner, template) ? + owner->e->def->base.tmpl : NULL; + if(tmpl) + CHECK_BO(template_push_types(env, tmpl)) + const m_uint scope = env_push(env, owner, owner->nspc); + const Type ret = scan_type(env, t, td->next); + env_pop(env, scope); + if(tmpl) + nspc_pop_type(env->gwion->mp, env->curr); + return ret; + } + return _scan_type(env, t, td); +} + diff --git a/src/parse/type_decl.c b/src/parse/type_decl.c index c03cc6e1..ea9746d0 100644 --- a/src/parse/type_decl.c +++ b/src/parse/type_decl.c @@ -27,8 +27,8 @@ ANN Type type_nonnull(const Env env, const Type base) { return t; } -ANN Type type_decl_resolve(const Env env, const Type_Decl* td) { - DECL_OO(const Type, base, = find_type(env, td->xid)) +ANN Type type_decl_resolve(const Env env, Type_Decl* td) { + DECL_OO(const Type, base, = find_type(env, td)) if(base->e->ctx && base->e->ctx->error) ERR_O(td_pos(td), _("type '%s' is invalid"), base->name) DECL_OO(const Type, t, = scan_type(env, base, td)) @@ -65,16 +65,13 @@ ANEW ANN m_str tl2str(const Env env, Type_List tl) { return info.text.str; } -ANN static inline void* type_unknown(const Env env, const ID_List id) { - char path[id_list_len(id)]; - type_path(path, id); - env_err(env, id->pos, _("unknown type '%s'"), path); - did_you_mean_nspc(env->curr, s_name(id->xid)); +ANN static inline void* type_unknown(const Env env, const Type_Decl* td) { + env_err(env, td->pos, _("unknown type '%s'"), s_name(td->xid)); return NULL; } -ANN Type known_type(const Env env, const Type_Decl* td) { +ANN Type known_type(const Env env, Type_Decl* td) { if(!td->xid) return env->gwion->type[et_undefined]; - return type_decl_resolve(env, td) ?:type_unknown(env, td->xid); + return type_decl_resolve(env, td) ?:type_unknown(env, td); } diff --git a/src/vm/shreduler.c b/src/vm/shreduler.c index 95967a3b..0822589e 100644 --- a/src/vm/shreduler.c +++ b/src/vm/shreduler.c @@ -54,9 +54,8 @@ ANN static void shreduler_erase(const Shreduler s, struct ShredTick_ *tk) { } ANN void shreduler_remove(const Shreduler s, const VM_Shred out, const m_bool erase) { - struct ShredTick_ *tk = out->tick; - assert(tk); MUTEX_LOCK(s->mutex); + struct ShredTick_ *tk = out->tick; if(tk == s->curr) s->curr = NULL; else if(tk == s->list) diff --git a/src/vm/vm.c b/src/vm/vm.c index 2cb7dd0f..13b0d0ba 100644 --- a/src/vm/vm.c +++ b/src/vm/vm.c @@ -75,8 +75,9 @@ ANN void vm_ini_shred(const VM* vm, const VM_Shred shred) { } ANN void vm_lock(VM const *vm) { - do MUTEX_LOCK(vm->shreduler->mutex); - while((vm = vm->parent)); + if(vm->parent) + vm_lock(vm->parent); + MUTEX_LOCK(vm->shreduler->mutex); } ANN void vm_unlock(VM const *vm) { @@ -92,17 +93,6 @@ ANN m_bool vm_running(VM const *vm) { return vm->shreduler->bbq->is_running = vm_running(vm->parent); } -ANN static void vm_fork(VM* src, const VM_Shred shred) { - VM* vm = (shred->info->vm = gwion_cpy(src)); - vm->parent = src; - const M_Object o = shred->info->me = new_shred(shred, 0); - ++shred->info->me->ref; - if(!src->gwion->data->child.ptr) - vector_init(&src->gwion->data->child); - vector_add(&src->gwion->data->child, (vtype)o); - shreduler_add(vm->shreduler, shred); -} - __attribute__((hot)) ANN static inline void vm_ugen_init(const VM* vm) { const Vector v = (Vector)&vm->ugen; @@ -145,17 +135,18 @@ ANN static inline VM_Shred init_spork_shred(const VM_Shred shred, const VM_Code return sh; } -ANN static inline VM_Shred fork_shred(const VM_Shred shred, const VM_Code code) { +ANN static VM_Shred init_fork_shred(const VM_Shred shred, const VM_Code code, const m_uint retsz) { + VM* parent = shred->info->vm; const VM_Shred sh = new_shred_base(shred, code); - vm_fork(shred->info->vm, sh); - return sh; -} - -ANN static inline VM_Shred init_fork_shred(const VM_Shred shred, const VM_Code code) { - VM *vm = shred->info->vm; - vm_lock(vm); - const VM_Shred sh = vm_running(vm) ? fork_shred(shred, code) : NULL; - vm_unlock(vm); + VM* vm = (sh->info->vm = gwion_cpy(parent)); + vm->parent = parent; + const M_Object o = sh->info->me = new_shred(sh, 0); + ++sh->info->me->ref; + if(!parent->gwion->data->child.ptr) + vector_init(&parent->gwion->data->child); + vector_add(&parent->gwion->data->child, (vtype)o); + shreduler_add(vm->shreduler, sh); + fork_launch(parent, sh->info->me, retsz); return sh; } @@ -333,7 +324,7 @@ ANN void vm_run(const VM* vm) { // lgtm [cpp/use-of-goto] &&timeadv, &&setcode, &®pop, &®push, &®tomem, &®tomemother, &&overflow, &&funcusrend, &&funcmemberend, - &&sporkini, &&sporkfunc, &&sporkmemberfptr, &&sporkexp, &&forkend, &&sporkend, + &&sporkini, &&forkini, &&sporkfunc, &&sporkmemberfptr, &&sporkexp, &&sporkend, &&brancheqint, &&branchneint, &&brancheqfloat, &&branchnefloat, &&arrayappend, &&autoloop, &&autoloopptr, &&autoloopcount, &&arraytop, &&arrayaccess, &&arrayget, &&arrayaddr, &&arrayvalid, &&newobj, &&addref, &&addrefaddr, &&objassign, &&assign, &&remref, @@ -672,10 +663,10 @@ funcmemberend: } PC_DISPATCH(shred->pc) sporkini: - if(!(child = (VAL2 ? init_spork_shred : init_fork_shred)(shred, (VM_Code)VAL))) { - exception(shred, "[SporkAbortedException]"); - continue; - } + child = init_spork_shred(shred, (VM_Code)VAL); + DISPATCH() +forkini: + child = init_fork_shred(shred, (VM_Code)VAL, VAL2), DISPATCH() sporkfunc: // LOOP_OPTIM @@ -697,8 +688,6 @@ sporkexp: for(m_uint i = 0; i < VAL; i+= SZ_INT) *(m_uint*)(child->mem + i) = *(m_uint*)(mem+i); DISPATCH() -forkend: - fork_launch(vm, child->info->me, VAL2); sporkend: assert(!VAL); // spork are not mutable *(M_Object*)(reg-SZ_INT) = child->info->me; @@ -916,6 +905,10 @@ VM* new_vm(MemPool p, const m_bool audio) { vector_init(&vm->shreduler->shreds); MUTEX_SETUP(vm->shreduler->mutex); vm->shreduler->bbq = vm->bbq; +#ifndef __AFL_COMPILER gw_seed(vm->rand, (uint64_t)time(NULL)); +#else + gw_seed(vm->rand, 0); +#endif return vm; } diff --git a/tests/error/no_namespace.gw b/tests/error/no_namespace.gw new file mode 100644 index 00000000..e2dd9440 --- /dev/null +++ b/tests/error/no_namespace.gw @@ -0,0 +1,5 @@ +#! [contains] has no namespace +class C{ + class private D{} +} +int->D d; diff --git a/tests/tree/fork_clean.gw b/tests/tree/fork_clean.gw deleted file mode 100644 index 4e6877b3..00000000 --- a/tests/tree/fork_clean.gw +++ /dev/null @@ -1 +0,0 @@ -fork { <<< __func__ >>>; second => now; }; diff --git a/tests/tree/fork_in_fork.gw b/tests/tree/fork_in_fork.gw deleted file mode 100644 index 395710bd..00000000 --- a/tests/tree/fork_in_fork.gw +++ /dev/null @@ -1,8 +0,0 @@ -fork { - fork { - <<< __func__ >>>; - second => now; - }; - <<< __func__ >>>; - second => now; -}; diff --git a/tests/tree/fork_join.gw b/tests/tree/fork_join.gw deleted file mode 100644 index e0b85d7e..00000000 --- a/tests/tree/fork_join.gw +++ /dev/null @@ -1,3 +0,0 @@ -fork { <<< __func__ >>>; } @=> Fork ref f; -second => now; -f.join(); diff --git a/tests/tree/fork_join2.gw b/tests/tree/fork_join2.gw deleted file mode 100644 index dd8d58f0..00000000 --- a/tests/tree/fork_join2.gw +++ /dev/null @@ -1,2 +0,0 @@ -fork { <<< __func__ >>>; minute => now; } @=> Fork ref f; -f.join(); diff --git a/util b/util index 8054afd4..b83174c4 160000 --- a/util +++ b/util @@ -1 +1 @@ -Subproject commit 8054afd48c0b7c13a6e0d53e044df5812dc99ca5 +Subproject commit b83174c4c45a7f372d317cd6cb1b0c357fba7afb