From: fennecdjay Date: Fri, 1 Mar 2019 09:02:35 +0000 (+0100) Subject: :art: clean plug X-Git-Tag: nightly~2758 X-Git-Url: http://10.11.0.4:5575/?a=commitdiff_plain;h=7f85679ee48440a20a66a2e730c4700caddd45b0;p=gwion.git :art: clean plug --- diff --git a/include/plug.h b/include/plug.h index 4ee5e4ca..23d2d195 100644 --- a/include/plug.h +++ b/include/plug.h @@ -9,7 +9,7 @@ enum plug_t { }; typedef struct Vector_ PlugInfo[GWPLUG_LAST]; -void plug_ini(PlugInfo, Vector); +void plug_discover(PlugInfo, Vector); void plug_end(const Gwion gwion); #define GWMODNAME_NAME "gwmodname" @@ -25,5 +25,5 @@ void plug_end(const Gwion gwion); //typedef void* (*f_gwmodname)(void); typedef void* (*f_gwmodini)(const Gwion, const Vector); typedef void* (*f_gwmodend)(const Gwion, void*); -void module_ini(const Gwion gwion, Vector); +void plug_ini(const Gwion gwion, const Vector); #endif diff --git a/src/emit/emit.c.save b/src/emit/emit.c.save new file mode 100644 index 00000000..d97cd598 --- /dev/null +++ b/src/emit/emit.c.save @@ -0,0 +1,1715 @@ +#include +#include +#include "gwion_util.h" +#include "gwion_ast.h" +#include "oo.h" +#include "vm.h" +#include "env.h" +#include "type.h" +#include "nspc.h" +#include "value.h" +#include "instr.h" +#include "emit.h" +#include "object.h" +#include "array.h" +#include "func.h" +#include "traverse.h" +#include "template.h" +#include "escape.h" +#include "parse.h" +#include "memoize.h" +#include "operator.h" +#include "import.h" +#include "switch.h" + +typedef struct Local_ { + m_uint size; + m_uint offset; + m_bool is_obj; +} Local; + +static inline void emit_pop_type(const Emitter emit) { nspc_pop_type(emit->env->curr); } +static inline void emit_pop(const Emitter emit, const m_uint scope) { env_pop(emit->env, scope); } +static inline m_uint emit_push(const Emitter emit, const Type type, const Nspc nspc) { + return env_push(emit->env, type, nspc); +} +static inline m_uint emit_push_type(const Emitter emit, const Type type) { + return env_push_type(emit->env, type); +} +static inline m_uint emit_push_global(const Emitter emit) { + return env_push_global(emit->env); +} + +ANEW static Frame* new_frame() { + Frame* frame = mp_alloc(Frame); + vector_init(&frame->stack); + vector_add(&frame->stack, (vtype)NULL); + return frame; +} + +ANN static void free_frame(Frame* a) { + LOOP_OPTIM + for(vtype i = vector_size(&a->stack) + 1; --i;) + if(vector_at(&a->stack, i - 1)) + mp_free(Local, (Local*)vector_at(&a->stack, i - 1)); + vector_release(&a->stack); + mp_free(Frame, a); +} + +ANN static Local* new_local(const m_uint size, const m_bool is_obj) { + Local* local = mp_alloc(Local); + local->size = size; + local->is_obj = is_obj; + return local; +} + +ANN static m_uint frame_local(Frame* frame, const m_uint size, const m_bool is_obj) { + Local* local = new_local(size, is_obj); + local->offset = frame->curr_offset; + frame->curr_offset += size; + vector_add(&frame->stack, (vtype)local); + return local->offset; +} + +ANN static inline void frame_push(Frame* frame) { + vector_add(&frame->stack, (vtype)NULL); +} + +ANN static m_int frame_pop(Frame* frame) { + const Local* l = (Local*)vector_pop(&frame->stack); + CHECK_OB(l) + frame->curr_offset -= l->size; + return l->is_obj ? (m_int)l->offset : frame_pop(frame); +} + +ANN static m_bool emit_exp(const Emitter emit, Exp exp, const m_bool add_ref); +ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop); +ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List list); +ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member); +ANN static m_bool emit_func_def(const Emitter emit, const Func_Def func_def); + +ANEW static Code* new_code(const Emitter emit, const m_str name) { + Code* code = mp_alloc(Code); + code->name = code_name_set(name, emit->env->name); + vector_init(&code->instr); + vector_init(&code->stack_break); + vector_init(&code->stack_cont); + vector_init(&code->stack_return); + code->frame = new_frame(); + return code; +} + +ANN static void free_code(Code* code) { + vector_release(&code->instr); + vector_release(&code->stack_break); + vector_release(&code->stack_cont); + vector_release(&code->stack_return); + free_frame(code->frame); + free(code->name); + mp_free(Code, code); +} + +ANN static void emit_pop_scope(const Emitter emit) { GWDEBUG_EXE + m_int offset; + while((offset = frame_pop(emit->code->frame)) > -1) { + Instr instr = emit_add_instr(emit, ObjectRelease); + instr->m_val = (m_uint)offset; + } +} + +ANN static inline void emit_push_code(const Emitter emit, const m_str name) { + vector_add(&emit->stack, (vtype)emit->code); + emit->code = new_code(emit, name); +} + +ANN static inline void emit_pop_code(const Emitter emit) { + emit->code = (Code*)vector_pop(&emit->stack); +} + +ANN static inline void emit_push_scope(const Emitter emit) { + frame_push(emit->code->frame); +} + +ANN static inline m_uint emit_code_size(const Emitter emit) { + return vector_size(&emit->code->instr); +} + +ANN static inline m_uint emit_code_offset(const Emitter emit) { + return emit->code->frame->curr_offset; +} + +ANN static inline m_uint emit_local(const Emitter emit, const m_uint size, const m_bool is_obj) { GWDEBUG_EXE + return frame_local(emit->code->frame, size, is_obj); +} + +ANN static void emit_pre_ctor(const Emitter emit, const Type type) { GWDEBUG_EXE + if(type->parent) + emit_pre_ctor(emit, type->parent); + if(type->nspc->pre_ctor) + emit_ext_ctor(emit, type->nspc->pre_ctor); + if(GET_FLAG(type, template) && GET_FLAG(type, builtin)) { + const Type t = template_parent(type); + if(t->nspc->pre_ctor) + emit_ext_ctor(emit, t->nspc->pre_ctor); + } +} + +ANN static void emit_pre_constructor_array(const Emitter emit, const Type type) { + const m_uint start_index = emit_code_size(emit); + const Instr top = emit_add_instr(emit, ArrayTop); + top->m_val2 = (m_uint)type; + emit_pre_ctor(emit, type); + const Instr bottom = emit_add_instr(emit, ArrayBottom); + top->m_val = emit_code_size(emit); + bottom->m_val = start_index; + emit_add_instr(emit, ArrayPost); +} + +ANN ArrayInfo* emit_array_extend_inner(const Emitter emit, const Type t, const Exp e) { GWDEBUG_EXE + CHECK_BO(emit_exp(emit, e, 0)) + const Type base = array_base(t); + ArrayInfo* info = mp_alloc(ArrayInfo); + vector_init(&info->type); + for(m_uint i = 1; i < t->array_depth; ++i) + vector_add(&info->type, (vtype)array_type(base, i)); + vector_add(&info->type, (vtype)t); + info->depth = (m_int)t->array_depth; + info->base = base; + const Instr alloc = emit_add_instr(emit, ArrayAlloc); + alloc->m_val = (m_uint)info; + if(isa(base, t_object) > 0) { + emit_pre_constructor_array(emit, base); + info->is_obj = 1; + } + return info; +} + +ANN void emit_ext_ctor(const Emitter emit, const VM_Code code) { GWDEBUG_EXE + emit_add_instr(emit, RegDup); + const Instr push_f = emit_add_instr(emit, RegPushImm); + push_f->m_val = (m_uint)code; + const Instr offset = emit_add_instr(emit, RegSetImm); + offset->m_val = emit_code_offset(emit); + emit_add_instr(emit, !GET_FLAG(code, builtin) ? FuncUsr : FuncMember); +} + +ANN m_bool emit_array_extend(const Emitter emit, const Type t, const Exp e) { GWDEBUG_EXE + CHECK_OB(emit_array_extend_inner(emit, t, e)) + emit_add_instr(emit, PopArrayClass); + return 1; +} + +ANN2(1,2) m_bool emit_instantiate_object(const Emitter emit, const Type type, + const Array_Sub array, const uint is_ref) { + if(type->array_depth) { + assert(array); + assert(array->exp); + ArrayInfo* info = emit_array_extend_inner(emit, type, array->exp); + CHECK_OB(info) + info->is_ref = !!is_ref; + } else if(!is_ref) { + const Instr instr = emit_add_instr(emit, ObjectInstantiate); + instr->m_val = (m_uint)type; + emit_pre_ctor(emit, type); + } + return GW_OK; +} + +static inline enum Kind kindof(const m_uint size, const uint emit_var) { + if(emit_var) + return KIND_ADDR; + return size == SZ_INT ? KIND_INT : size == SZ_FLOAT ? KIND_FLOAT : KIND_OTHER; +} + +ANN static Instr emit_kind(Emitter emit, const m_uint size, const uint addr, const f_instr func[]) { + const enum Kind kind = kindof(size, addr); + const Instr instr = emit_add_instr(emit, func[kind]); + instr->m_val2 = size; + return instr; +} + +static const f_instr regpushimm[] = { RegPushImm, RegPushImm2, RegPushImm3, RegPushImm4 }; +static const f_instr regpushmem[] = { RegPushMem, RegPushMem2, RegPushMem3, RegPushMem4 }; +static const f_instr regpushbase[] = { RegPushBase, RegPushBase2, RegPushBase3, RegPushBase4 }; +static const f_instr dotstatic[] = { DotStatic, DotStatic2, DotStatic3, RegPushImm }; +static const f_instr dotmember[] = { DotMember, DotMember2, DotMember3, DotMember4 }; +static const f_instr allocmember[] = { RegPushImm, RegPushImm2, RegPushImm3, AllocMember4 }; +static const f_instr allocword[] = { AllocWord, AllocWord2, AllocWord3, AllocWord4 }; + +ANN static m_bool emit_symbol_owned(const Emitter emit, const Exp_Primary* prim) { GWDEBUG_EXE + const Value v = prim->value; + const Exp exp = new_exp_prim_id(insert_symbol("this"), prim->self->pos); + const Exp dot = new_exp_dot(exp, prim->d.var); + exp->type = v->owner_class; + dot->d.exp_dot.t_base = v->owner_class; + dot->type = v->type; + dot->emit_var = prim->self->emit_var; + const m_bool ret = emit_exp_dot(emit, &dot->d.exp_dot); + free_exp(exp); + return ret; +} + +ANN static m_bool emit_symbol_builtin(const Emitter emit, const Exp_Primary* prim) { GWDEBUG_EXE + const Value v = prim->value; + if(GET_FLAG(v, func)) { + const Instr instr = emit_add_instr(emit, RegPushImm); + instr->m_val = (m_uint)v->d.func_ref; + return GW_OK; + } + if(GET_FLAG(v, union)) { + const m_uint size = v->type->size; + const Instr instr = emit_kind(emit, size, prim->self->emit_var, dotstatic); + instr->m_val = (m_uint)v->d.ptr; + } else { + const m_uint size = v->type->size; + const Instr instr = emit_kind(emit, size, prim->self->emit_var, regpushimm); + if(!prim->self->emit_var && size == SZ_INT) { + if(isa(v->type, t_object) > 0) { + instr->execute = RegPushImm; + instr->m_val = (m_uint)v->d.ptr; + } else if(v->d.ptr) + instr->m_val = *(m_uint*)v->d.ptr; + } else if(v->d.ptr) + memcpy(&instr->m_val, v->d.ptr, v->type->size); + else + instr->m_val = (m_uint)v->d.ptr; + instr->m_val2 = size; + } + return GW_OK; +} + +ANN static m_bool emit_symbol(const Emitter emit, const Exp_Primary* prim) { GWDEBUG_EXE + const Value v = prim->value; + if(v->owner_class) + return emit_symbol_owned(emit, prim); + if(GET_FLAG(v, builtin) || GET_FLAG(v, union)) + return emit_symbol_builtin(emit, prim); + const m_uint size = v->type->size; + const Instr instr = emit_kind(emit, size, prim->self->emit_var, !GET_FLAG(v, global) ? regpushmem : regpushbase); + instr->m_val = v->offset; + return GW_OK; +} + +ANEW ANN VM_Code emit_code(const Emitter emit) { GWDEBUG_EXE + Code* c = emit->code; + const VM_Code code = new_vm_code(&c->instr, c->stack_depth, + c->flag, c->name); + free_code(c); + return code; +} + +ANN static VM_Code finalyze(const Emitter emit) { + emit_add_instr(emit, EOC); + const VM_Code code = emit_code(emit); + emit_pop_code(emit); + return code; +} + +ANN static m_bool prim_array(const Emitter emit, const Exp_Primary * primary) { + const Array_Sub array = primary->d.array; + Exp e = array->exp; + CHECK_BB(emit_exp(emit, e, 0)) + m_uint count = 0; + do ++count; + while((e = e->next)); + const Type type = array->type; + const Type base = array_base(type); + const Instr push = emit_add_instr(emit, RegSetImm); + push->m_val = count; + const Instr instr = emit_add_instr(emit, ArrayInit); + instr->m_val = (m_uint)type; + instr->m_val2 = base->size; + emit_add_instr(emit, GcAdd); + return GW_OK; +} + +ANN static m_uint get_depth(Type t) { + m_uint depth = 0; + do depth += t->array_depth; + while((t = t->parent)); + return depth; +} + +ANN static m_bool emit_exp_array(const Emitter emit, const Exp_Array* array) { GWDEBUG_EXE + const m_uint is_var = array->self->emit_var; + const m_uint depth = get_depth(array->base->type) - array->self->type->array_depth; + CHECK_BB(emit_exp(emit, array->base, 0)) + CHECK_BB(emit_exp(emit, array->array->exp, 0)) + if(depth == 1) { + const Instr instr = emit_add_instr(emit, ArrayAccess); + instr->m_val = is_var; + instr->m_val2 = is_var ? SZ_INT : array->self->type->size; + } else { + const Instr push = emit_add_instr(emit, RegSetImm); + push->m_val = depth; + const Instr instr = emit_add_instr(emit, ArrayAccessMulti); + instr->m_val = is_var || array->self->type->array_depth; + instr->m_val2 = (is_var || array->self->type->array_depth) ? + SZ_INT : array_base(array->base->type)->size; + } + return GW_OK; +} + +ANN static m_bool prim_vec(const Emitter emit, const Exp_Primary * primary) { GWDEBUG_EXE + const Vec * vec = &primary->d.vec; + const ae_prim_t t = primary->primary_type; + CHECK_BB(emit_exp(emit, vec->exp, 0)); + m_int n = (m_int)((t == ae_primary_vec ? 3 : 2) - vec->dim + 1); + while(--n > 0) + emit_add_instr(emit, RegPushImm2); + if(primary->self->emit_var) { + emit_local(emit, primary->self->type->size, 0); + const m_uint offset = emit_local(emit, SZ_INT, 0); + const Instr cpy = emit_add_instr(emit, VecCpy); + cpy->m_val = offset; + cpy->m_val2 = primary->self->type->size; + const Instr instr = emit_add_instr(emit, RegPushMem); + instr->m_val = offset; + } + return GW_OK; +} + +ANN static m_bool prim_id(const Emitter emit, const Exp_Primary* prim) { + if(prim->d.var == insert_symbol("this")) + emit_add_instr(emit, RegPushMem); + else if(prim->d.var == insert_symbol("me")) + emit_add_instr(emit, RegPushMe); + else if(prim->d.var == insert_symbol("now")) + emit_add_instr(emit, RegPushNow); + else if(prim->d.var == insert_symbol("maybe")) + emit_add_instr(emit, RegPushMaybe); + else if(prim->d.var == insert_symbol("__func__")) { + const Instr instr = emit_add_instr(emit, RegPushStr); + instr->m_val = (m_uint)s_name(insert_symbol(emit->env->func ? + emit->env->func->name : emit->env->class_def ? + emit->env->class_def->name : emit->env->name)); + } else + emit_symbol(emit, prim); + return GW_OK; +} + +ANN static m_bool prim_num(const Emitter emit, const Exp_Primary * primary) { + const Instr instr = emit_add_instr(emit, RegPushImm); + instr->m_val = primary->d.num; + return GW_OK; +} + +ANN static m_bool prim_float(const Emitter emit, const Exp_Primary* primary) { + const Instr instr = emit_add_instr(emit, RegPushImm2); + instr->f = primary->d.fnum; + return GW_OK; +} + +ANN static m_bool prim_char(const Emitter emit, const Exp_Primary* prim) { + const m_int c = str2char(prim->d.chr, prim->self->pos); + CHECK_BB(c); + const Instr instr = emit_add_instr(emit, RegPushImm); + instr->m_val = (m_uint)c; + return GW_OK; +} + +ANN static m_bool prim_str(const Emitter emit, const Exp_Primary* prim) { GWDEBUG_EXE + char c[strlen(prim->d.str)]; + strcpy(c, prim->d.str); + CHECK_BB(escape_str(c, prim->self->pos)); + const Instr instr = emit_add_instr(emit, RegPushStr); + instr->m_val = (m_uint)s_name(insert_symbol(c)); + return GW_OK; +} + +ANN static m_bool prim_gack(const Emitter emit, const Exp_Primary* primary) { + const Exp exp = primary->d.exp; + const Vector v = new_vector(); + m_uint offset = 0; + Exp e = exp; + do { + vector_add(v, (vtype)e->type); + offset += e->type->size; + if(e->type != emit->env->class_def) + ADD_REF(e->type); + } while((e = e->next)); + if(emit_exp(emit, exp, 0) < 0) { + free_vector(v); + ERR_B(exp->pos, "\t... in 'gack' expression.") + } + const Instr instr = emit_add_instr(emit, Gack); + instr->m_val = offset; + instr->m_val2 = (m_uint)v; + return GW_OK; +} + +static const _exp_func prim_func[] = { + (_exp_func)prim_id, (_exp_func)prim_num, (_exp_func)prim_float, (_exp_func)prim_str, + (_exp_func)prim_array, (_exp_func)prim_gack, (_exp_func)prim_vec, (_exp_func)prim_vec, + (_exp_func)prim_vec, (_exp_func)prim_char, (_exp_func)dummy_func, +}; + +ANN static m_bool emit_exp_primary(const Emitter emit, const Exp_Primary* prim) { GWDEBUG_EXE + return prim_func[prim->primary_type](emit, prim); +} + +ANN static m_bool emit_dot_static_data(const Emitter emit, const Value v, const uint emit_var) { GWDEBUG_EXE + const m_uint size = v->type->size; + const Instr instr = emit_kind(emit, size, emit_var, dotstatic); + instr->m_val = (m_uint)(v->owner_class->nspc->class_data + v->offset); + instr->m_val2 = size; + return GW_OK; +} + +ANN static m_bool decl_static(const Emitter emit, const Var_Decl var_decl, const uint is_ref) { + const Value v = var_decl->value; + Code* code = emit->code; + emit->code = (Code*)vector_back(&emit->stack); + CHECK_BB(emit_instantiate_object(emit, v->type, var_decl->array, is_ref)) + CHECK_BB(emit_dot_static_data(emit, v, 1)) + emit_add_instr(emit, ObjectAssign); + emit->code = code; + return GW_OK; +} + +ANN static m_bool emit_exp_decl_static(const Emitter emit, const Var_Decl var_decl, const uint is_ref) { GWDEBUG_EXE + const Value value = var_decl->value; + if(isa(value->type, t_object) > 0 && !is_ref) + CHECK_BB(decl_static(emit, var_decl, 0)) + return emit_dot_static_data(emit, value, 1); +} + +ANN static m_bool emit_exp_decl_non_static(const Emitter emit, const Var_Decl var_decl, + const uint is_ref, const uint emit_var) { GWDEBUG_EXE + const Value v = var_decl->value; + const Type type = v->type; + const Array_Sub array = var_decl->array; + const m_bool is_array = array && array->exp; + const m_bool is_obj = isa(type, t_object) > 0; + const uint emit_addr = ((is_ref && !array) || isa(type, t_object) < 0) ? + emit_var : 1; + if(is_obj && (is_array || !is_ref)) + CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) + f_instr *exec = (f_instr*)allocmember; + if(!GET_FLAG(v, member)) { + v->offset = emit_local(emit, v->type->size, is_obj); + exec = (f_instr*)(allocword); + } + const Instr instr = emit_kind(emit, v->type->size, emit_addr, exec); + instr->m_val = v->offset; + instr->m_val2 = v->type->size; + if(is_obj && (is_array || !is_ref)) { + const Instr assign = emit_add_instr(emit, ObjectAssign); + assign->m_val = (m_uint)emit_var; + if(is_array && !emit->env->scope) + ADD_REF(type) + } + return GW_OK; +} + +ANN static m_bool emit_exp_decl_global(const Emitter emit, const Var_Decl var_decl, + const uint is_ref, const uint emit_var) { GWDEBUG_EXE + const Value v = var_decl->value; + const Type type = v->type; + const Array_Sub array = var_decl->array; + const m_bool is_array = array && array->exp; + const m_bool is_obj = isa(type, t_object) > 0; + const uint emit_addr = ((is_ref && !array) || isa(type, t_object) < 0) ? + emit_var : 1; + if(is_obj && (is_array || !is_ref)) + CHECK_BB(emit_instantiate_object(emit, type, array, is_ref)) + f_instr *exec = (f_instr*)dotstatic; + const Instr instr = emit_kind(emit, v->type->size, emit_addr, exec); + v->d.ptr = _mp_alloc(v->type->size); + SET_FLAG(v, union); + instr->m_val = (m_uint)v->d.ptr; + instr->m_val2 = v->type->size; + if(is_obj && (is_array || !is_ref)) { + const Instr assign = emit_add_instr(emit, ObjectAssign); + assign->m_val = (m_uint)emit_var; + if(is_array && !emit->env->scope) + ADD_REF(type) + const Instr instr = emit_add_instr(emit, RegAddRef); + instr->m_val = emit_var; + } + return GW_OK; +} + +ANN static m_bool emit_class_def(const Emitter, const Class_Def); + +ANN static m_bool emit_exp_decl_template(const Emitter emit, const Exp_Decl* decl) { GWDEBUG_EXE + const Type t = typedef_base(decl->type); + if(!GET_FLAG(t, emit)) { + CHECK_BB(template_push_types(emit->env, t->def->tmpl->list.list, t->def->tmpl->base)) + CHECK_BB(emit_class_def(emit, t->def)) + emit_pop_type(emit); + } + return GW_OK; +} + +ANN static m_bool emit_exp_decl(const Emitter emit, const Exp_Decl* decl) { GWDEBUG_EXE + Var_Decl_List list = decl->list; + const uint ref = GET_FLAG(decl->td, ref) || type_ref(decl->type); + const uint var = decl->self->emit_var; + + if(GET_FLAG(decl->type, template)) + CHECK_BB(emit_exp_decl_template(emit, decl)) + m_uint scope; + const m_bool global = GET_FLAG(decl->td, global); + if(global) + scope = emit_push_global(emit); + do { + const uint r = (uint)(GET_FLAG(list->self->value, ref) + ref); + if(!GET_FLAG(list->self->value, used)) + continue; + if(GET_FLAG(decl->td, static)) + CHECK_BB(emit_exp_decl_static(emit, list->self, r)) + else if(!global) + CHECK_BB(emit_exp_decl_non_static(emit, list->self, r, var)) +else + CHECK_BB(emit_exp_decl_global(emit, list->self, r, var)) + } while((list = list->next)); + if(global) + emit_pop(emit, scope); + return GW_OK; +} + +ANN static m_uint vararg_size(const Exp_Call* exp_call, const Vector kinds) { + Exp e = exp_call->args; + Arg_List l = exp_call->m_func->def->arg_list; + m_uint size = 0; + while(e) { + if(!l) { + size += e->type->size; + vector_add(kinds, e->type->size); + } else + l = l->next; + e = e->next; + } + return size; +} + +ANN static void emit_func_arg_vararg(const Emitter emit, const Exp_Call* exp_call) { GWDEBUG_EXE + const Instr instr = emit_add_instr(emit, VarargIni); + const Vector kinds = new_vector(); + if((instr->m_val = vararg_size(exp_call, kinds))) + instr->m_val2 = (m_uint)kinds; + else { + instr->execute = VarargEmpty; + free_vector(kinds); + } +} + +ANN static m_bool emit_func_args(const Emitter emit, const Exp_Call* exp_call) { GWDEBUG_EXE + if(exp_call->args) + CHECK_BB(emit_exp(emit, exp_call->args, 1)) + if(GET_FLAG(exp_call->m_func->def, variadic)) + emit_func_arg_vararg(emit, exp_call); + return GW_OK; +} + +ANN static m_bool prepare_call(const Emitter emit, const Exp_Call* exp_call) { GWDEBUG_EXE + CHECK_BB(emit_func_args(emit, exp_call)) + return emit_exp(emit, exp_call->func, 0); +} + +ANN static inline m_int push_tmpl_func(const Emitter emit, const Func f, + const Type_List types) { + const Value v = f->value_ref; + const m_uint scope = emit_push(emit, v->owner_class, v->owner); + CHECK_BB(traverse_func_template(emit->env, f->def, types)) + return (m_int)scope; +} + +ANN static m_bool emit_exp_call_template(const Emitter emit, const Exp_Call* exp_call) { + if(emit->env->func && emit->env->func == exp_call->m_func) + return prepare_call(emit, exp_call); + const m_int scope = push_tmpl_func(emit, exp_call->m_func, exp_call->tmpl->types); + CHECK_BB(scope); + CHECK_BB(prepare_call(emit, exp_call)) + emit_pop_type(emit); + emit_pop(emit, (m_uint)scope); + UNSET_FLAG(exp_call->m_func, checked); + return GW_OK; +} + +ANN static m_bool emit_exp_call(const Emitter emit, const Exp_Call* exp_call) { GWDEBUG_EXE + if(!exp_call->tmpl) + CHECK_BB(prepare_call(emit, exp_call)) + else + CHECK_BB(emit_exp_call_template(emit, exp_call)) + return emit_exp_call1(emit, exp_call->m_func); +} + +ANN static m_bool emit_binary_func(const Emitter emit, const Exp_Binary* bin) { GWDEBUG_EXE + const Exp_Call exp = { .func=bin->rhs, .args=bin->lhs, .m_func=bin->func, .tmpl=bin->tmpl, .self=bin->self }; + return emit_exp_call(emit, &exp); +} + +ANN static m_bool emit_exp_binary(const Emitter emit, const Exp_Binary* bin) { GWDEBUG_EXE + const Exp lhs = bin->lhs; + const Exp rhs = bin->rhs; + struct Op_Import opi = { .op=bin->op, .lhs=lhs->type, .rhs=rhs->type, .data = (uintptr_t)bin }; + if(bin->op == op_chuck && isa(rhs->type, t_function) > 0) + return emit_binary_func(emit, bin); + CHECK_BB(emit_exp(emit, lhs, 1)) + CHECK_BB(emit_exp(emit, rhs, 1)) + return op_emit(emit, &opi); +} + +ANN static m_bool emit_exp_cast(const Emitter emit, const Exp_Cast* cast) { + struct Op_Import opi = { .op=op_cast, .lhs=cast->exp->type, .rhs=cast->self->type, .data=(uintptr_t)cast}; + CHECK_BB(emit_exp(emit, cast->exp, 0)) + (void)op_emit(emit, &opi); + return GW_OK; +} + +ANN static m_bool emit_exp_post(const Emitter emit, const Exp_Postfix* post) { GWDEBUG_EXE + struct Op_Import opi = { .op=post->op, .lhs=post->exp->type, .data=(uintptr_t)post }; + CHECK_BB(emit_exp(emit, post->exp, 1)) + return op_emit(emit, &opi); +} + +ANN static m_bool emit_exp_dur(const Emitter emit, const Exp_Dur* dur) { GWDEBUG_EXE + CHECK_BB(emit_exp(emit, dur->base, 0)) + CHECK_BB(emit_exp(emit, dur->unit, 0)) + emit_add_instr(emit, FloatTimes); + return GW_OK; +} + +ANN static m_bool is_special(const Type t) { + if(isa(t, t_complex) > 0 || isa(t, t_polar) > 0 || + isa(t, t_vec3) > 0 || isa(t, t_vec4) > 0 || + isa(t, t_vararg) > 0) + return GW_OK; + return GW_ERROR; +} + +ANN static Type_List tmpl_tl(const Env env, const m_str name) { + const m_str start = strchr(name, '<'); + const m_str end = strchr(name, '@'); + char c[strlen(name)]; + strcpy(c, start + 1); + c[strlen(start) - strlen(end) - 2] = '\0'; + m_uint depth; + return str2tl(env, c, &depth); +} + +ANN m_bool traverse_dot_tmpl(const Emitter emit, const struct dottmpl_ *dt) { + const m_uint scope = env_push_type(emit->env, dt->owner); + m_bool ret = GW_ERROR; + if(traverse_func_template(emit->env, dt->def, dt->tl) > 0) { + ret = emit_func_def(emit, dt->def); + nspc_pop_type(emit->env->curr); + } + env_pop(emit->env, scope); + return ret; +} + +static inline m_bool push_func_code(const Emitter emit, const Func f) { + if(GET_FLAG(f, template) && f->value_ref->owner_class) { + const Instr _instr = (Instr)vector_back(&emit->code->instr); + assert(_instr->execute == DotTmpl); + size_t len = strlen(f->name); + size_t sz = len - strlen(f->value_ref->owner_class->name); + char c[sz + 1]; + strncpy(c, f->name, sz); + c[sz] = '\0'; + struct dottmpl_ *dt = mp_alloc(dottmpl); + dt->name = s_name(insert_symbol(c)); + dt->overload = f->def->tmpl->base; + dt->tl = tmpl_tl(emit->env, c); + dt->base = f->def; + _instr->m_val = (m_uint)dt; + _instr->m_val2 = strlen(c); + return GW_OK; + } + const Instr _instr = (Instr)vector_back(&emit->code->instr); + if(_instr->opcode == (m_bit)(m_uint)RegPushImm) + return !!(_instr->m_val = (m_uint)f->code); + assert(_instr->opcode == (m_bit)(m_uint)RegPushBase); + _instr->m_val = (m_uint)f->code; + _instr->opcode = (m_bit)(m_uint)RegPushImm; + return GW_OK; +} + +static m_bool emit_template_code(const Emitter emit, const Func f) { + if(GET_FLAG(f, ref)) + CHECK_BB(traverse_template(emit->env, f->value_ref->owner_class->def)) + const Value v = f->value_ref; + size_t scope = emit_push(emit, v->owner_class, v->owner); + CHECK_BB(emit_func_def(emit, f->def)) // orig + emit_pop(emit, scope); + return push_func_code(emit, f); +} + + ANN static Instr emit_call(const Emitter emit, const Func f) { + MEMOIZE_CALL + const Type t = actual_type(f->value_ref->type); + if(isa(t, t_fptr) < 0) { + const f_instr exec = GET_FLAG(f->def, builtin) ? GET_FLAG(f, member) ? + FuncMember : FuncStatic : FuncUsr; + return emit_add_instr(emit, exec); + } + /*const Instr ex = */emit_add_instr(emit, GWOP_EXCEPT); +// ex->m_val = -SZ_INT; + return emit_add_instr(emit, FuncPtr); +} + +ANN m_bool emit_exp_call1(const Emitter emit, const Func f) { GWDEBUG_EXE + if(!f->code || (GET_FLAG(f, ref) && !GET_FLAG(f, builtin))) { + if(GET_FLAG(f, template) && emit->env->func != f) + CHECK_BB(emit_template_code(emit, f)) + } else if((f->value_ref->owner_class && is_special(f->value_ref->owner_class) > 0) || + !f->value_ref->owner_class || GET_FLAG(f, template)) + push_func_code(emit, f); + else { + const Instr back = (Instr)vector_back(&emit->code->instr); + if((f_instr)(m_uint)back->opcode == DotFunc) + back->m_val = f->vt_index; + } + if(GET_FLAG(f, member) && isa(actual_type(f->value_ref->type), t_fptr) > 0) { + const Instr back = (Instr)vector_back(&emit->code->instr); + m_bit exec = back->opcode; + m_uint val = back->m_val; + m_uint val2 = back->m_val2; + back->opcode = (m_bit)(m_uint)RegDup2; + back->m_val = f->def->stack_depth; + const Instr instr = emit_add_instr(emit, (f_instr)(m_uint)exec); + instr->m_val = val; + instr->m_val2 = val2; + } + const Instr offset = emit_add_instr(emit, RegSetImm); + offset->m_val = emit_code_offset(emit); + const Instr instr = emit_call(emit, f); + const m_uint size = instr->m_val = f->def->ret_type->size; + return (m_bool)(instr->m_val2 = kindof(size, !size)); +} + +ANN2(1,2) static m_bool emit_exp_spork_finish(const Emitter emit, const VM_Code code, + const m_uint depth, const m_bool f) { + const Instr ini = emit_add_instr(emit, SporkIni); + ini->m_val = (m_uint)code; + if(!f) { + const m_uint member = GET_FLAG(code, member) ? SZ_INT : 0; + const Instr pop = emit_add_instr(emit, RegPop); + pop->m_val = depth + member; + if(depth) { + const Instr spork = emit_add_instr(emit, SporkFunc); + spork->m_val = depth; + } + if(member) { + const Instr m = emit_add_instr(emit, SporkThis); + m->m_val = depth; + } + } else { + const Instr spork = emit_add_instr(emit, SporkExp); + spork->m_val = depth; + } + emit_add_instr(emit, SporkEnd); + return GW_OK; +} + +static inline void stack_alloc(const Emitter emit) { + emit_local(emit, SZ_INT, 0); + emit->code->stack_depth += SZ_INT; +} + +static inline void stack_alloc_this(const Emitter emit) { + SET_FLAG(emit->code, member); + stack_alloc(emit); +} + +static m_bool scoped_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { + ++emit->env->scope; + emit_push_scope(emit); + const m_bool pure = SAFE_FLAG(emit->env->func, pure); + if(!pure) + emit_add_instr(emit, GcIni); + CHECK_BB(emit_stmt(emit, stmt, pop)) + if(!pure) + emit_add_instr(emit, GcEnd); + emit_pop_scope(emit); + --emit->env->scope; + return GW_OK; +} + +#define SPORK_FUNC_PREFIX "spork~func:%i" +#define SPORK_CODE_PREFIX "spork~code:%i" + +static void push_spork_code(const Emitter emit, const m_str prefix, const int pos) { + char c[strlen(SPORK_FUNC_PREFIX) + num_digit(pos) + 1]; + sprintf(c, prefix, pos); + emit_push_code(emit, c); +} + +ANN static m_bool spork_func(const Emitter emit, const Exp_Call* exp) { GWDEBUG_EXE + CHECK_BB(prepare_call(emit, exp)) + push_spork_code(emit, SPORK_FUNC_PREFIX, exp->self->pos); + if(GET_FLAG(exp->m_func, member)) + SET_FLAG(emit->code, member); + const Instr p = emit_add_instr(emit, RegPushImm); + p->m_val = (m_uint)exp->m_func->code; + CHECK_BB(emit_exp_call1(emit, exp->m_func)) + const VM_Code code = finalyze(emit); + const m_uint size = exp->m_func->def->stack_depth - (GET_FLAG(exp->m_func, + member) ? SZ_INT : 0); + return emit_exp_spork_finish(emit, code, size, 0); +} + +ANN static m_bool spork_code(const Emitter emit, const Stmt stmt) { GWDEBUG_EXE + emit_add_instr(emit, RegPushImm); + push_spork_code(emit, SPORK_CODE_PREFIX, stmt->pos); + if(!SAFE_FLAG(emit->env->func, member)) + stack_alloc_this(emit); + CHECK_BB(scoped_stmt(emit, stmt, 0)) + const VM_Code code = finalyze(emit); + return emit_exp_spork_finish(emit, code, emit->code->stack_depth, 1); +} + +ANN m_bool emit_exp_spork(const Emitter emit, const Exp_Unary* unary) { + return unary->code ? spork_code(emit, unary->code) : + spork_func(emit, &unary->exp->d.exp_call); +} + +ANN static m_bool emit_exp_unary(const Emitter emit, const Exp_Unary* unary) { GWDEBUG_EXE + struct Op_Import opi = { .op=unary->op, .data=(uintptr_t)unary }; + if(unary->op != op_spork && unary->exp) { + CHECK_BB(emit_exp(emit, unary->exp, 1)) + opi.rhs = unary->exp->type; + } + return op_emit(emit, &opi); +} + +ANN static m_bool emit_implicit_cast(const Emitter emit, + const restrict Type from, const restrict Type to) { GWDEBUG_EXE + struct Op_Import opi = { .op=op_impl, .lhs=from, .rhs=to, .data=(m_uint)from }; + return op_emit(emit, &opi); +} + +ANN static Instr emit_flow(const Emitter emit, const Type type, + const f_instr f1, const f_instr f2) { GWDEBUG_EXE + if(isa(type, t_float) > 0) { + return emit_add_instr(emit, f2); + } + return emit_add_instr(emit, f1); +} + +ANN static m_bool emit_exp_if(const Emitter emit, const Exp_If* exp_if) { GWDEBUG_EXE + CHECK_BB(emit_exp(emit, exp_if->cond, 0)) + const Instr op = emit_flow(emit, exp_if->cond->type, BranchEqInt, BranchEqFloat); + CHECK_BB(emit_exp(emit, exp_if->if_exp, 0)) + const Instr op2 = emit_add_instr(emit, Goto); + op->m_val = emit_code_size(emit); + const m_bool ret = emit_exp(emit, exp_if->else_exp, 0); + op2->m_val = emit_code_size(emit); + return ret; +} + +ANN static m_bool emit_exp_lambda(const Emitter emit, const Exp_Lambda * lambda) { GWDEBUG_EXE + if(lambda->def) { + const m_uint scope = !lambda->owner ? + emit->env->scope : emit_push_type(emit, lambda->owner); + CHECK_BB(emit_func_def(emit, lambda->def)) + const Instr instr = emit_add_instr(emit, RegPushImm); + instr->m_val = (m_uint)lambda->def->func->code; + if(lambda->owner) + emit_pop(emit, scope); + } else + emit_add_instr(emit, RegPushImm); + return GW_OK; +} + +DECL_EXP_FUNC(emit) + +ANN2(1) static m_bool emit_exp(const Emitter emit, Exp exp, const m_bool ref) { GWDEBUG_EXE + do { + CHECK_BB(exp_func[exp->exp_type](emit, &exp->d)) + if(exp->cast_to) + CHECK_BB(emit_implicit_cast(emit, exp->type, exp->cast_to)) + if(ref && isa(exp->type, t_object) > 0) { + const Instr instr = emit_add_instr(emit, RegAddRef); + instr->m_val = exp->emit_var; + } + if(emit->env->func && isa(exp->type, t_function) > 0 && + !GET_FLAG(exp->type->d.func->value_ref->d.func_ref, pure)) + UNSET_FLAG(emit->env->func, pure); + } while((exp = exp->next)); + return GW_OK; +} + +ANN static m_bool emit_stmt_if(const Emitter emit, const Stmt_If stmt) { GWDEBUG_EXE + emit_push_scope(emit); + CHECK_BB(emit_exp(emit, stmt->cond, 0)) + const Instr op = emit_flow(emit, isa(stmt->cond->type, t_object) > 0 ? + t_int : stmt->cond->type, BranchEqInt, BranchEqFloat); + CHECK_OB(op) + CHECK_BB(scoped_stmt(emit, stmt->if_body, 1)) + const Instr op2 = emit_add_instr(emit, Goto); + op->m_val = emit_code_size(emit); + if(stmt->else_body) + CHECK_BB(scoped_stmt(emit, stmt->else_body, 1)) + op2->m_val = emit_code_size(emit); + emit_pop_scope(emit); + return GW_OK; +} + +ANN static m_bool emit_stmt_code(const Emitter emit, const Stmt_Code stmt) { GWDEBUG_EXE + ++emit->env->scope; + const m_bool ret = stmt->stmt_list ? emit_stmt_list(emit, stmt->stmt_list) : 1; + --emit->env->scope; + return ret; +} + +#ifdef OPTIMIZE +ANN static m_bool optimize_taill_call(const Emitter emit, const Exp_Call* e) { + Exp arg = e->args; + if(arg) + CHECK_BB(emit_exp(emit, e->args, 0)) + const Instr instr = emit_add_instr(emit, PutArgsInMem); + while(arg) { + instr->m_val += arg->type->size; + arg = arg->next; + } + emit_add_instr(emit, Goto); + return GW_OK; +} +#define OPTIMIZE_TCO\ + if(stmt->val->exp_type == ae_exp_call && emit->env->func == stmt->val->d.exp_call.m_func)\ + return optimize_taill_call(emit, &stmt->val->d.exp_call); +#else +#define OPTIMIZE_TCO +#endif + + +ANN static m_bool emit_stmt_return(const Emitter emit, const Stmt_Exp stmt) { GWDEBUG_EXE + if(stmt->val) { + OPTIMIZE_TCO + CHECK_BB(emit_exp(emit, stmt->val, 0)) + if(isa(stmt->val->type, t_object) > 0) + emit_add_instr(emit, RegAddRef); + } + vector_add(&emit->code->stack_return, (vtype)emit_add_instr(emit, Goto)); + return GW_OK; +} + +ANN static inline m_bool emit_stmt_continue(const Emitter emit, const Stmt stmt __attribute__((unused))) { GWDEBUG_EXE + vector_add(&emit->code->stack_cont, (vtype)emit_add_instr(emit, Goto)); + return GW_OK; +} + +ANN static inline m_bool emit_stmt_break(const Emitter emit, const Stmt stmt __attribute__((unused))) { GWDEBUG_EXE + vector_add(&emit->code->stack_break, (vtype)emit_add_instr(emit, Goto)); + return GW_OK; +} + +ANN static inline void emit_push_stack(const Emitter emit) { + emit_push_scope(emit); + vector_add(&emit->code->stack_cont, (vtype)NULL); + vector_add(&emit->code->stack_break, (vtype)NULL); +} + +ANN static void pop_vector(Vector v, const m_uint pc) { + Instr instr; + while((instr = (Instr)vector_pop(v))) + instr->m_val = pc; +} + +ANN static void emit_pop_stack(const Emitter emit, const m_uint index) { + pop_vector(&emit->code->stack_cont, index); + pop_vector(&emit->code->stack_break, emit_code_size(emit)); + emit_pop_scope(emit); +} + +ANN static Instr _flow(const Emitter emit, const Exp e, const m_bool b) { + CHECK_BO(emit_exp(emit, e, 0)) + const f_instr instr_i = b ? BranchEqInt : BranchNeqInt; + const f_instr instr_f = b ? BranchEqFloat : BranchNeqFloat; + return emit_flow(emit, e->type, instr_i, instr_f); +} + +ANN static m_bool emit_stmt_flow(const Emitter emit, const Stmt_Flow stmt) { GWDEBUG_EXE + const m_uint index = emit_code_size(emit); + Instr op = NULL; + emit_push_stack(emit); + if(!stmt->is_do) + op = _flow(emit, stmt->cond, stmt->self->stmt_type == ae_stmt_while); + CHECK_BB(scoped_stmt(emit, stmt->body, 1)) + if(stmt->is_do) { + CHECK_OB((op = _flow(emit, stmt->cond, stmt->self->stmt_type != ae_stmt_while))) + op->m_val = index; + } else { + const Instr goto_ = emit_add_instr(emit, Goto); + goto_->m_val = index; + op->m_val = emit_code_size(emit); + } + emit_pop_stack(emit, index); + return GW_OK; +} + +ANN static m_uint get_decl_size(Var_Decl_List a) { + m_uint size = 0; + do if(GET_FLAG(a->self->value, used)) + size += a->self->value->type->size; + while((a = a->next)); + return size; +} + +ANN static m_uint pop_exp_size(const Emitter emit, Exp e) { + m_uint size = 0; + do { + if(e->exp_type == ae_exp_primary && + e->d.exp_primary.primary_type == ae_primary_hack) { + size += pop_exp_size(emit, e->d.exp_primary.d.exp); + continue; + } + size += (e->exp_type == ae_exp_decl ? + get_decl_size(e->d.exp_decl.list) : e->type->size); + } while((e = e->next)); + return size; +} + +ANN static void pop_exp(const Emitter emit, Exp e) { + const m_uint size = pop_exp_size(emit, e); + if(size) { + const Instr instr = emit_add_instr(emit, RegPop); + instr->m_val = size; + } +} + +ANN static m_bool emit_stmt_for(const Emitter emit, const Stmt_For stmt) { GWDEBUG_EXE + emit_push_stack(emit); + CHECK_BB(emit_stmt(emit, stmt->c1, 1)) + const m_uint index = emit_code_size(emit); + CHECK_BB(emit_stmt(emit, stmt->c2, 0)) + const Instr op = emit_flow(emit, stmt->c2->d.stmt_exp.val->type, + BranchEqInt, BranchEqFloat); + CHECK_BB(scoped_stmt(emit, stmt->body, 1)) + const m_uint action_index = emit_code_size(emit); + if(stmt->c3) { + CHECK_BB(emit_exp(emit, stmt->c3, 0)) + pop_exp(emit, stmt->c3); + } + 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_auto(const Emitter emit, const Stmt_Auto stmt) { GWDEBUG_EXE + CHECK_BB(emit_exp(emit, stmt->exp, 0)) + const Instr s1 = emit_add_instr(emit, MemSetImm); + const Instr s2 = emit_add_instr(emit, MemSetImm); + const m_uint ini_pc = emit_code_size(emit); + emit_push_stack(emit); + const Instr loop = emit_add_instr(emit, AutoLoopStart); + const m_uint offset = emit_local(emit, 2*SZ_INT, 0); + s2->m_val = stmt->v->offset = offset + SZ_INT; + CHECK_BB(emit_stmt(emit, stmt->body, 1)) + const m_uint end_pc = emit_code_size(emit); + if(stmt->is_ptr) { + const Instr release = emit_add_instr(emit, ObjectRelease); + release->m_val = offset + SZ_INT; + } + const Instr end = emit_add_instr(emit, AutoLoopEnd); + const Instr tgt = emit_add_instr(emit, Goto); + end->m_val2 = emit_code_size(emit); + tgt->m_val = ini_pc; + s1->m_val = end->m_val = loop->m_val = offset; + if(stmt->is_ptr) + loop->m_val2 = (m_uint)stmt->v->type; + emit_pop_stack(emit, end_pc); + return GW_OK; +} + +ANN static m_bool emit_stmt_loop(const Emitter emit, const Stmt_Loop stmt) { GWDEBUG_EXE + emit_push_stack(emit); + CHECK_BB(emit_exp(emit, stmt->cond, 0)) + m_int* counter = (m_int*)xcalloc(1, SZ_INT); + const Instr init = emit_add_instr(emit, InitLoopCounter); + init->m_val = (m_uint)counter; + const m_uint index = emit_code_size(emit); + const Instr deref = emit_add_instr(emit, DotStatic); + deref->m_val = (m_uint)counter; + deref->m_val2 = SZ_INT; + const Instr op = emit_add_instr(emit, BranchEqInt); + const Instr dec = emit_add_instr(emit, DecIntAddr); + dec->m_val = (m_uint)counter; + CHECK_BB(scoped_stmt(emit, stmt->body, 1)) + const Instr _goto = emit_add_instr(emit, Goto); + _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_jump(const Emitter emit, const Stmt_Jump stmt) { GWDEBUG_EXE + if(!stmt->is_label) + stmt->data.instr = emit_add_instr(emit, Goto); + else { + if(switch_inside(emit->env, stmt->self->pos) && !strcmp(s_name(stmt->name), "default")) { + if(!strcmp(s_name(stmt->name), "default")) + vector_release(&stmt->data.v); + return switch_default(emit->env, emit_code_size(emit), stmt->self->pos); + } + if(!stmt->data.v.ptr) + ERR_B(stmt->self->pos, "illegal case") + const m_uint size = vector_size(&stmt->data.v); + if(!size) { + vector_release(&stmt->data.v); + ERR_B(stmt->self->pos, "label '%s' defined but not used.", s_name(stmt->name)) + } + LOOP_OPTIM + for(m_uint i = size + 1; --i;) { + const Stmt_Jump label = (Stmt_Jump)vector_at(&stmt->data.v, i - 1); + if(!label->data.instr) { + vector_release(&stmt->data.v); + ERR_B(label->self->pos, "you are trying to use a upper label.") + } + label->data.instr->m_val = emit_code_size(emit); + } + vector_release(&stmt->data.v); + } + return GW_OK; +} + +ANN static m_bool emit_switch_instr(const Emitter emit, Instr *instr) { + const m_uint dyn = switch_dyn(emit->env); + if(dyn) { + Exp e; + while((e = switch_expget(emit->env))) + CHECK_BB(emit_exp(emit, e, 0)) + *instr = emit_add_instr(emit, SwitchIni); + } else { + const Instr instr = emit_add_instr(emit, RegSetImm); + instr->m_val = (m_uint)switch_map(emit->env); + } + return GW_OK; +} + +ANN static void emit_switch_map(const Instr instr, const Map map) { + const Map m = new_map(); + for(m_uint i = map_size(map) + 1; --i;) + map_set(m, VKEY(map, i-1), VVAL(map, i -1)); + instr->m_val2 = (m_uint)m; +} + +ANN static m_bool emit_stmt_switch(const Emitter emit, const Stmt_Switch stmt) { GWDEBUG_EXE + switch_get(emit->env, stmt); + Instr push = NULL; + CHECK_BB(emit_exp(emit, stmt->val, 0)) + CHECK_BB(emit_switch_instr(emit, &push)) + vector_add(&emit->code->stack_break, (vtype)NULL); + const Instr instr = emit_add_instr(emit, BranchSwitch); + instr->m_val2 = (m_uint)switch_map(emit->env); + CHECK_BB(emit_stmt(emit, stmt->stmt, 1)) + instr->m_val = switch_idx(emit->env) ?: emit_code_size(emit); + if(push) { + emit_switch_map(push, (Map)instr->m_val2); + (push)->m_val = (m_uint)switch_vec(emit->env); + } + switch_end(emit->env); + pop_vector(&emit->code->stack_break, emit_code_size(emit)); + return GW_OK; +} + +ANN m_bool value_value(const Value v, m_int *value) { + if((!GET_FLAG(v, builtin) && !GET_FLAG(v, enum)) || GET_FLAG(v, member)) + return 0; + *value = v->d.ptr ? *(m_int*)v->d.ptr : v->owner->class_data[v->offset]; + return GW_OK; +} + +ANN Value case_value(const Exp exp) { + if(exp->exp_type == ae_exp_primary) { + const Exp_Primary* prim = &exp->d.exp_primary; + if(prim->primary_type == ae_primary_num) + return NULL; + return prim->value; + } + const Exp_Dot* dot = &exp->d.exp_dot; + return find_value(actual_type(dot->t_base), dot->xid); +} + +ANN static m_bool prim_value(const Exp exp, m_int *value) { + *value = (m_int)exp->d.exp_primary.d.num; + return GW_OK; +} + +ANN static m_bool emit_stmt_case(const Emitter emit, const Stmt_Exp stmt) { GWDEBUG_EXE + CHECK_BB(switch_inside(emit->env, stmt->self->pos)) + m_int value = 0; + const Value v = case_value(stmt->val); + if((!v && prim_value(stmt->val, &value)) || value_value(v, &value)) { + CHECK_BB(switch_dup(emit->env, value, stmt->val->pos)) + switch_dynpc(emit->env, value, emit_code_size(emit)); + } else + switch_pc(emit->env, emit_code_size(emit)); + return GW_OK; +} + +ANN static m_bool emit_stmt_type(const Emitter emit, const Stmt_Type stmt) { GWDEBUG_EXE + return stmt->type->def ? emit_class_def(emit, stmt->type->def) : 1; +} + +ANN static m_bool emit_stmt_enum(const Emitter emit, const Stmt_Enum stmt) { GWDEBUG_EXE + LOOP_OPTIM + for(m_uint i = 0; i < vector_size(&stmt->values); ++i) { + const Value v = (Value)vector_at(&stmt->values, i); + if(!emit->env->class_def) { + ALLOC_PTR(addr, m_uint, i); + v->offset = emit_local(emit, SZ_INT, 0); + v->d.ptr = addr; + } else + *(m_uint*)(emit->env->class_def->nspc->class_data + v->offset) = i; + } + return GW_OK; +} + +ANN void emit_union_offset(Decl_List l, const m_uint o) { GWDEBUG_EXE + do { + Var_Decl_List v = l->self->d.exp_decl.list; + do v->self->value->offset = o; + while((v = v->next)); + } while((l = l->next)); +} + +ANN static m_bool emit_stmt_union(const Emitter emit, const Stmt_Union stmt) { GWDEBUG_EXE + Decl_List l = stmt->l; + m_uint scope = emit->env->scope; + const m_bool global = GET_FLAG(stmt, global); + if(stmt->xid) { + if(stmt->value->type->nspc->class_data_size && !stmt->value->type->nspc->class_data) + stmt->value->type->nspc->class_data = + (m_bit*)xcalloc(1, stmt->value->type->nspc->class_data_size); + stmt->value->type->nspc->offset = stmt->s; + if(!stmt->value->type->p) + stmt->value->type->p = mp_ini((uint32_t)stmt->value->type->size); + Type_Decl *type_decl = new_type_decl(new_id_list(stmt->xid, stmt->self->pos), + emit->env->class_def ? ae_flag_member : 0); // or zero ? + type_decl->flag = stmt->flag; + const Var_Decl var_decl = new_var_decl(stmt->xid, NULL, 0); + const Var_Decl_List var_decl_list = new_var_decl_list(var_decl, NULL); + const Exp exp = new_exp_decl(type_decl, var_decl_list); + exp->d.exp_decl.type = stmt->value->type; + var_decl->value = stmt->value; + CHECK_BB(emit_exp_decl(emit, &exp->d.exp_decl)) + free_exp(exp); + if(global) { + const M_Object o = new_object(NULL, stmt->value->type); + stmt->value->d.ptr = (m_uint*)o; + SET_FLAG(stmt->value, builtin); + SET_FLAG(stmt->value, global); + } + scope = emit_push_type(emit, stmt->value->type); + } else if(stmt->type_xid) { + if(stmt->type->nspc->class_data_size && !stmt->type->nspc->class_data) + stmt->type->nspc->class_data = + (m_bit*)xcalloc(1, stmt->type->nspc->class_data_size); + stmt->type->nspc->offset = stmt->s; + if(!stmt->type->p) + stmt->type->p = mp_ini((uint32_t)stmt->type->size); + scope = emit_push_type(emit, stmt->type); + } else if(emit->env->class_def) { + if(!GET_FLAG(l->self->d.exp_decl.list->self->value, member)) + stmt->o = emit_local(emit, stmt->s, 0); + } else if(global) { + void* ptr = (void*)xcalloc(1, stmt->s); + l = stmt->l; + do { + Var_Decl_List list = l->self->d.exp_decl.list; + list->self->value->d.ptr = ptr; + SET_FLAG(list->self->value, union); + } while((l = l->next)); + SET_FLAG(stmt->l->self->d.exp_decl.list->self->value, enum); + } + emit_union_offset(stmt->l, stmt->o); + if(stmt->xid) { + const Instr instr = emit_add_instr(emit, RegPop); + instr->m_val = SZ_INT; + } + if(stmt->xid || stmt->type_xid || global) + emit_pop(emit, scope); + return GW_OK; +} + +ANN static m_bool emit_stmt_exp(const Emitter emit, const struct Stmt_Exp_* exp) { + return exp->val ? emit_exp(emit, exp->val, 0) : 1; +} + +static const _exp_func stmt_func[] = { + (_exp_func)emit_stmt_exp, (_exp_func)emit_stmt_flow, (_exp_func)emit_stmt_flow, + (_exp_func)emit_stmt_for, (_exp_func)emit_stmt_auto, (_exp_func)emit_stmt_loop, + (_exp_func)emit_stmt_if, (_exp_func)emit_stmt_code, (_exp_func)emit_stmt_switch, + (_exp_func)emit_stmt_break, (_exp_func)emit_stmt_continue, (_exp_func)emit_stmt_return, + (_exp_func)emit_stmt_case, (_exp_func)emit_stmt_jump, (_exp_func)emit_stmt_enum, + (_exp_func)dummy_func, (_exp_func)emit_stmt_type, (_exp_func)emit_stmt_union, +}; + +ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { GWDEBUG_EXE + CHECK_BB(stmt_func[stmt->stmt_type](emit, &stmt->d)) + if(pop && stmt->stmt_type == ae_stmt_exp && stmt->d.stmt_exp.val) + pop_exp(emit, stmt->d.stmt_exp.val); + return GW_OK; +} + +ANN static m_bool emit_stmt_list(const Emitter emit, Stmt_List l) { GWDEBUG_EXE + do CHECK_BB(emit_stmt(emit, l->stmt, 1)) + while((l = l->next)); + return GW_OK; +} + +ANN static m_bool emit_dot_static_import_data(const Emitter emit, const Value v, const uint emit_addr) { GWDEBUG_EXE + if(v->d.ptr && GET_FLAG(v, builtin)) { // from C + if(GET_FLAG(v, enum)) { + const Instr func_i = emit_add_instr(emit, RegPushImm); + func_i->m_val = (m_uint)v->d.ptr; + } else { + const m_uint size = v->type->size; + const Instr instr = emit_kind(emit, size, emit_addr, regpushimm); + instr->m_val = (isa(v->type, t_object) > 0 ? + (m_uint)&v->d.ptr : (m_uint)v->d.ptr); + instr->m_val2 = size; + } + return GW_OK; + } + return emit_dot_static_data(emit, v, emit_addr); +} + +ANN static m_bool emit_complex_member(const Emitter emit, const Exp_Dot* member) { GWDEBUG_EXE + const Exp base = member->base; + base->emit_var = 1; + CHECK_BB(emit_exp(emit, base, 0)) + const m_bool is_complex = !strcmp((isa(base->type, t_complex) > 0 ? "re" : "phase") , + s_name(member->xid)); + if(is_complex && member->self->emit_var) // skip + return GW_OK; + const Instr instr = emit_add_instr(emit, is_complex ? ComplexReal : ComplexImag); + instr->m_val = member->self->emit_var; + return GW_OK; +} + +ANN static inline void emit_vec_func(const Emitter emit, const Value v) { + const Instr instr = emit_add_instr(emit, RegPushImm); + instr->m_val = (m_uint)v->d.func_ref->code; +} + +ANN static m_bool emit_VecMember(const Emitter emit, const Exp_Dot* member) { + member->base->emit_var = 1; + CHECK_BB(emit_exp(emit, member->base, 0)) + const Value v = find_value(member->base->type, member->xid); + if(GET_FLAG(v, func)) { + emit_vec_func(emit, v); + return GW_OK; + } + if(!v->offset && member->self->emit_var) // skip + return GW_OK; + const Instr instr = emit_add_instr(emit, VecMember); + instr->m_val2 = v->offset; + instr->m_val = member->self->emit_var; + return GW_OK; +} + +ANN static m_bool emit_vararg_start(const Emitter emit, const m_uint offset) { GWDEBUG_EXE + if(emit->env->func->variadic) + ERR_B(0, "vararg.start already used. this is an error") + emit->env->func->variadic = emit_add_instr(emit, VarargTop); + emit->env->func->variadic->m_val = offset; + emit->env->func->variadic->m_val2 = emit_code_size(emit); + return GW_OK; +} + +ANN static m_bool emit_vararg_end(const Emitter emit, const m_uint offset) { GWDEBUG_EXE + if(!emit->env->func->variadic) + ERR_B(0, "vararg.start not used before vararg.end. this is an error") + const Instr instr = emit_add_instr(emit, VarargEnd); + instr->m_val = offset; + instr->m_val2 = emit->env->func->variadic->m_val2; + emit->env->func->variadic->m_val2 = emit_code_size(emit); + return GW_OK; +} + +ANN static m_bool emit_vararg(const Emitter emit, const Exp_Dot* member) { GWDEBUG_EXE + m_uint offset = emit->env->class_def ? SZ_INT : 0; + Arg_List l = emit->env->func->def->arg_list; + const m_str str = s_name(member->xid); + while(l) { + offset += l->type->size; + l = l->next; + } + if(!strcmp(str, "start")) + return emit_vararg_start(emit, offset); + if(!strcmp(str, "end")) + return emit_vararg_end(emit, offset); + const Instr instr = emit_add_instr(emit, VarargMember); + instr->m_val = offset; + instr->m_val2 = member->self->type->size; + return GW_OK; +} + +ANN static m_bool emit_exp_dot_special(const Emitter emit, const Exp_Dot* member) { GWDEBUG_EXE + const Type t = member->t_base; + if(isa(t, t_complex) > 0 || isa(t, t_polar) > 0) + return emit_complex_member(emit, member); + else if(isa(t, t_vec3) > 0 || isa(t, t_vec4) > 0) + return emit_VecMember(emit, member); + return emit_vararg(emit, member); +} + +ANN static m_bool emit_dot_static_func(const Emitter emit, const Func func) { GWDEBUG_EXE +// if(func->code) { +// const Instr func_i = emit_add_instr(emit, RegPushImm); +// func_i->m_val = (m_uint)func->code; +// } else { + // TODO: improve me + const Instr func_i = emit_add_instr(emit, PushStaticCode); + func_i->m_val = (m_uint)func; +// } + return GW_OK; +} + +ANN static m_bool emit_member_func(const Emitter emit, const Exp_Dot* member, const Func func) { GWDEBUG_EXE + if(emit_exp(emit, member->base, 0) < 0) + ERR_B(member->self->pos, "... in member function") // LCOV_EXCL_LINE + /*const Instr ex = */emit_add_instr(emit, GWOP_EXCEPT); + //ex->m_val = -SZ_INT; + if(GET_FLAG(member->base->type, force)) { + const Instr func_i = emit_add_instr(emit, RegPushImm); + func_i->m_val = (m_uint)func->code; + return GW_OK; + } + if(!func->def->tmpl) { + const Instr func_i = emit_add_instr(emit, DotFunc); + func_i->m_val = func->vt_index; + return GW_OK; + } + emit_add_instr(emit, DotTmpl); + return GW_OK; +} + +ANN static inline void emit_member(const Emitter emit, const Value v, const uint emit_addr) { + /*const Instr ex = */emit_add_instr(emit, GWOP_EXCEPT); + //ex->m_val = -SZ_INT; + const m_uint size = v->type->size; + const Instr instr = emit_kind(emit, size, emit_addr, dotmember); + instr->m_val = v->offset; + instr->m_val2 = size; +} + +ANN static m_bool emit_exp_dot_instance(const Emitter emit, const Exp_Dot* member) { GWDEBUG_EXE + const Type t_base = member->t_base; + const Value value = find_value(t_base, member->xid); + const uint emit_addr = member->self->emit_var; + if(isa(member->self->type, t_fptr) > 0) { // function pointer + if(GET_FLAG(value, member)) { // member + if(emit_exp(emit, member->base, 0) < 0) + ERR_B(member->self->pos, "... in member function") // LCOV_EXCL_LINE + emit_member(emit, value, emit_addr); + return GW_OK; + } else + return emit_dot_static_data(emit, value, emit_addr); + } else if(isa(member->self->type, t_function) > 0) + return emit_member_func(emit, member, value->d.func_ref); + else { // variable + if(GET_FLAG(value, member)) { // member + CHECK_BB(emit_exp(emit, member->base, 0)) + emit_member(emit, value, emit_addr); + return GW_OK; + } else // static + CHECK_BB(emit_dot_static_import_data(emit, value, emit_addr)) + } + return GW_OK; +} + +ANN static m_bool emit_exp_dot_static(const Emitter emit, const Exp_Dot* member) { GWDEBUG_EXE + const Type t_base = member->t_base->d.base_type; + const Value value = find_value(t_base, member->xid); + if(isa(member->self->type, t_function) > 0 && isa(member->self->type, t_fptr) < 0) + return emit_dot_static_func(emit, value->d.func_ref); + return emit_dot_static_import_data(emit, value, member->self->emit_var); +} + +ANN static m_bool emit_exp_dot(const Emitter emit, const Exp_Dot* member) { GWDEBUG_EXE + if(is_special(member->t_base) > 0) + return emit_exp_dot_special(emit, member); + if(isa(member->t_base, t_class) > 0) + return emit_exp_dot_static(emit, member); + return emit_exp_dot_instance(emit, member); +} + +ANN static inline void emit_func_def_global(const Emitter emit, const Value value) { GWDEBUG_EXE + const Instr set_mem = emit_add_instr(emit, MemSetImm); + set_mem->m_val = value->offset = emit_local(emit, SZ_INT, 0); + set_mem->m_val2 = (m_uint)value->d.func_ref->code; +} + +ANN static void emit_func_def_init(const Emitter emit, const Func func) { GWDEBUG_EXE + const Type t = emit->env->class_def; + char c[(t ? strlen(t->name) + 1 : 0) + strlen(func->name) + 6]; + sprintf(c, "%s%s%s(...)", t ? t->name : "", t ? "." : "", func->name); + emit_push_code(emit, c); +} + +ANN static void emit_func_def_args(const Emitter emit, Arg_List a) { GWDEBUG_EXE + do { + const Value value = a->var_decl->value; + const m_uint size = value->type->size; + const m_bool obj = isa(value->type, t_object) > 0; + emit->code->stack_depth += size; + value->offset = emit_local(emit, size, obj); + } while((a = a->next)); +} + +ANN static void emit_func_def_ensure(const Emitter emit, const Func_Def func_def) { GWDEBUG_EXE + const m_uint size = func_def->ret_type->size; + if(size) { + const Instr instr = emit_kind(emit, size, 0, regpushimm); + instr->m_val2 = size; + } + vector_add(&emit->code->stack_return, (vtype)emit_add_instr(emit, Goto)); +} + +ANN static void emit_func_def_return(const Emitter emit) { GWDEBUG_EXE + const m_uint val = emit_code_size(emit); + LOOP_OPTIM + for(m_uint i = vector_size(&emit->code->stack_return) + 1; --i; ) { + const Instr instr = (Instr)vector_at(&emit->code->stack_return, i-1); + instr->m_val = val; + } + vector_clear(&emit->code->stack_return); + emit_pop_scope(emit); + MEMOIZE_STORE + emit_add_instr(emit, FuncReturn); +} + +ANN static void emit_func_def_code(const Emitter emit, const Func func) { GWDEBUG_EXE + func->code = emit_code(emit); + if(GET_FLAG(func->def, dtor)) { + emit->env->class_def->nspc->dtor = func->code; + Instr instr = (Instr)vector_back(func->code->instr); + instr->execute = DTOR_EOC; + ADD_REF(func->code) + } +} + +ANN static m_bool emit_func_def_body(const Emitter emit, const Func_Def func_def) { GWDEBUG_EXE + if(func_def->arg_list) + emit_func_def_args(emit, func_def->arg_list); + if(GET_FLAG(func_def, variadic)) + stack_alloc(emit); + if(func_def->d.code->d.stmt_code.stmt_list) + CHECK_BB(emit_stmt_code(emit, &func_def->d.code->d.stmt_code)) + emit_func_def_ensure(emit, func_def); + return GW_OK; +} + +ANN static m_bool emit_func_def(const Emitter emit, const Func_Def func_def) { GWDEBUG_EXE + const Func func = get_func(emit->env, func_def); + if(func->code)return GW_OK; + if(tmpl_list_base(func_def->tmpl)) { // don't check template definition + UNSET_FLAG(func_def, template); + return GW_OK; + } + if(SAFE_FLAG(emit->env->class_def, builtin) && GET_FLAG(emit->env->class_def, template)) + return GW_OK; + emit_func_def_init(emit, func); + if(GET_FLAG(func, member)) + stack_alloc_this(emit); + emit_push_scope(emit); + const Func former = emit->env->func; + emit->env->func = func; + CHECK_BB(emit_func_def_body(emit, func_def)) + if(GET_FLAG(func_def, variadic) && !emit->env->func->variadic) + ERR_B(func_def->td->xid->pos, "invalid variadic use") + emit_func_def_return(emit); + emit_func_def_code(emit, func); + emit->env->func = former; + emit_pop_code(emit); + if(!emit->env->class_def && !GET_FLAG(func_def, global) && !func_def->tmpl) + emit_func_def_global(emit, func->value_ref); + MEMOIZE_INI + return GW_OK; +} + +DECL_SECTION_FUNC(emit) + +ANN Code* emit_class_code(const Emitter emit, const m_str name) { GWDEBUG_EXE + const m_uint len = strlen(name) + 7; + char c[len]; + snprintf(c, len, "class %s", name); + emit_push_code(emit, c); + stack_alloc_this(emit); + return emit->code; +} + +ANN inline void emit_class_finish(const Emitter emit, const Nspc nspc) { GWDEBUG_EXE + emit_add_instr(emit, FuncReturn); + nspc->pre_ctor = emit_code(emit); +} + +ANN static inline void emit_class_push(const Emitter emit, const Type type) { GWDEBUG_EXE + vector_add(&emit->env->class_stack, (vtype)emit->env->class_def); + emit->env->class_def = type; +} + +ANN static inline void emit_class_pop(const Emitter emit) { GWDEBUG_EXE + emit->env->class_def = (Type)vector_pop(&emit->env->class_stack); + emit_pop_code(emit); +} + +ANN static m_bool emit_class_def(const Emitter emit, const Class_Def class_def) { GWDEBUG_EXE + const Type type = class_def->type; + const Nspc nspc = type->nspc; + if(tmpl_class_base(class_def->tmpl)) + return GW_OK; + if(class_def->ext && ((/*!GET_FLAG(type->parent, emit) &&*/ + GET_FLAG(class_def->ext, typedef)) || class_def->ext->types)) { + const Type base = class_def->ext->array ? + array_base(type->parent) : type->parent; + if(!base->nspc->pre_ctor) + CHECK_BB(emit_class_def(emit, base->def)) + } + if(nspc->class_data_size) + nspc->class_data = (m_bit*)xcalloc(1, nspc->class_data_size); + emit_class_push(emit, type); + emit_class_code(emit, type->name); + if(class_def->ext && class_def->ext->array) + CHECK_BB(emit_array_extend(emit, type->parent, class_def->ext->array->exp)) + if(class_def->body) { + Class_Body body = class_def->body; + do CHECK_BB(emit_section(emit, body->section)) + while((body = body->next)); + } + emit_class_finish(emit, nspc); + emit_class_pop(emit); + SET_FLAG(type, emit); + return GW_OK; +} + +ANN static void emit_free_code(Code* code) { + LOOP_OPTIM + for(m_uint j = vector_size(&code->instr) + 1; --j;) + mp_free(Instr, (Instr)vector_at(&code->instr, j - 1)); + free_code(code); +} + +ANN static void emit_free_stack(const Emitter emit) { GWDEBUG_EXE + LOOP_OPTIM + for(m_uint i = vector_size(&emit->stack) + 1; --i;) + emit_free_code((Code*)vector_at(&emit->stack, i - 1)); + vector_clear(&emit->stack); + emit_free_code(emit->code); +} + +ANN static inline m_bool emit_ast_inner(const Emitter emit, Ast ast) { GWDEBUG_EXE + do CHECK_BB(emit_section(emit, ast->section)) + while((ast = ast->next)); + return GW_OK; +} + +ANN VM_Code emit_ast(const Emitter emit, Ast ast) { GWDEBUG_EXE + emit->code = new_code(emit, emit->env->name); + emit_push_scope(emit); + const m_bool ret = emit_ast_inner(emit, ast); + emit_pop_scope(emit); + if(ret > 0) + return finalyze(emit); + emit_free_stack(emit); + return NULL; +} diff --git a/src/gwion.c b/src/gwion.c index 3a149cfd..bac64f3d 100644 --- a/src/gwion.c +++ b/src/gwion.c @@ -31,7 +31,7 @@ ANN void gwion_init(const Gwion gwion, const Vector args) { gwion->vm->gwion = gwion; gwion->env->gwion = gwion; gwion->driver = (Driver*)xcalloc(1, sizeof(Driver)); - plug_ini(gwion->plug, args); + plug_discover(gwion->plug, args); } ANN m_bool gwion_audio(const Gwion gwion, DriverInfo* di) { diff --git a/src/lib/float.c b/src/lib/float.c index 74a0b27a..71a13c72 100644 --- a/src/lib/float.c +++ b/src/lib/float.c @@ -110,6 +110,8 @@ GWION_IMPORT(float) { CHECK_OP(not, unary_meta, not) CHECK_BB(gwi_oper_ini(gwi, NULL, "dur", "int")) CHECK_OP(not, unary_meta, not) + + CHECK_BB(gwi_oper_ini(gwi, "int", "float", "int")) CHECK_BB(gwi_oper_end(gwi, op_and, int_float_and)) CHECK_BB(gwi_oper_end(gwi, op_or, int_float_or)) @@ -132,6 +134,8 @@ GWION_IMPORT(float) { CHECK_BB(gwi_oper_emi(gwi, opem_i2f)) _CHECK_OP(cast, basic_cast, CastI2F) _CHECK_OP(impl, implicit_i2f, CastI2F) + + CHECK_BB(gwi_oper_ini(gwi, "float", "int", "float")) CHECK_BB(gwi_oper_end(gwi, op_add, float_int_plus)) CHECK_BB(gwi_oper_end(gwi, op_sub, float_int_minus)) @@ -154,6 +158,8 @@ GWION_IMPORT(float) { CHECK_BB(gwi_oper_emi(gwi, opem_f2i)) _CHECK_OP(cast, basic_cast, CastF2I) _CHECK_OP(impl, implicit_f2i, CastF2I) + + CHECK_BB(gwi_oper_ini(gwi, "dur", "dur", "dur")) CHECK_OP(chuck, rassign, r_assign) CHECK_BB(gwi_oper_end(gwi, op_add, FloatPlus)) @@ -162,6 +168,7 @@ GWION_IMPORT(float) { CHECK_BB(gwi_oper_ini(gwi, "dur", "dur", "float")) CHECK_BB(gwi_oper_end(gwi, op_div, FloatDivide)) + CHECK_BB(gwi_oper_ini(gwi, "dur", "dur", "int")) CHECK_BB(gwi_oper_end(gwi, op_gt, float_gt)) CHECK_BB(gwi_oper_end(gwi, op_ge, float_ge)) diff --git a/src/main.c b/src/main.c index 973e95f7..a52b01c9 100644 --- a/src/main.c +++ b/src/main.c @@ -17,12 +17,8 @@ static void sig(int unused __attribute__((unused))) { int main(int argc, char** argv) { Arg arg = { .argc = argc, .argv=argv, .loop=-1 }; - DriverInfo di = { 2, 2, 2, - 48000, 256, 3, "default:CARD=CODEC", 0, 0, D_FUNC, vm_run, 0, 0}; -//#define BUFSZ 10000 -//char outbuf[BUFSZ], errbuf[BUFSZ]; -//setvbuf(stdout, outbuf, _IOFBF, BUFSZ); -//setvbuf(stderr, errbuf, _IOFBF, BUFSZ); + DriverInfo di = { .in=2, .out=2, .chan=2, .sr=48000, .bufsize=256, + .bufnum=3, .card="default:CARD=CODEC", .func=D_FUNC, .run=vm_run }; if(parse_args(&arg, &di)) { arg_release(&arg); return 0; @@ -31,13 +27,13 @@ int main(int argc, char** argv) { signal(SIGINT, sig); signal(SIGTERM, sig); if(gwion_audio(&gwion, &di) && gwion_engine(&gwion)) { - module_ini(&gwion, &arg.mod); + plug_ini(&gwion, &arg.mod); for(m_uint i = 0; i < vector_size(&arg.add); i++) compile_filename(&gwion, (m_str)vector_at(&arg.add, i)); shreduler_set_loop(gwion.vm->shreduler, arg.loop); gwion_run(&gwion, &di); } - arg_release(&arg); gwion_release(&gwion, &di); + arg_release(&arg); return 0; } diff --git a/src/plug.c b/src/plug.c index 2593bd8c..b36129a6 100644 --- a/src/plug.c +++ b/src/plug.c @@ -24,7 +24,7 @@ struct Plug_ { void* self; }; -ANN static void handle_plug(PlugInfo v, const m_str c) { +ANN static void plug_get(PlugInfo v, const m_str c) { void* handler = dlopen(c, RTLD_LAZY); if(handler) { vector_add(&v[GWPLUG_DL], (vtype)handler); @@ -44,27 +44,27 @@ ANN static void handle_plug(PlugInfo v, const m_str c) { err_msg(0, "error in %s.", dlerror()); } -void plug_ini(PlugInfo v, Vector list) { +void plug_discover(PlugInfo v, Vector list) { for(m_uint i = 0; i < GWPLUG_LAST; ++i) vector_init(&v[i]); for(m_uint i = 0; i < vector_size(list); i++) { - const m_str dirname = (m_str)vector_at(list, i); - struct dirent **namelist; - int n = scandir(dirname, &namelist, so_filter, alphasort); + const m_str dir = (m_str)vector_at(list, i); + struct dirent **file; + int n = scandir(dir, &file, so_filter, alphasort); if(n > 0) { while(n--) { - char c[strlen(dirname) + strlen(namelist[n]->d_name) + 2]; - sprintf(c, "%s/%s", dirname, namelist[n]->d_name); - handle_plug(v, c); - free(namelist[n]); + char c[strlen(dir) + strlen(file[n]->d_name) + 2]; + sprintf(c, "%s/%s", dir, file[n]->d_name); + plug_get(v, c); + free(file[n]); } - free(namelist); + free(file); } } } void plug_end(const Gwion gwion) { - struct Vector_ *v = gwion->plug; + struct Vector_ * const v = gwion->plug; for(m_uint i = 0; i < vector_size(&v[GWPLUG_MODULE]); ++i) { struct Plug_ *plug = (struct Plug_*)vector_at(&v[GWPLUG_MODULE], i); if(plug->end) @@ -97,8 +97,8 @@ ANN static Vector get_arg(const m_str name, const Vector v) { return NULL; } -void module_ini(const Gwion gwion, Vector args) { - Vector v = &gwion->plug[GWPLUG_MODULE]; +void plug_ini(const Gwion gwion, const Vector args) { + const Vector v = &gwion->plug[GWPLUG_MODULE]; for(m_uint i = 0; i < vector_size(v); ++i) { struct Plug_ *plug = (struct Plug_*)vector_at(v, i); const Vector arg = get_arg(plug->name, args);