From: Jérémie Astor Date: Wed, 20 Apr 2022 00:45:55 +0000 (+0200) Subject: :art: Locales :smile: X-Git-Tag: nightly~297 X-Git-Url: http://10.10.0.4:5575/?a=commitdiff_plain;h=7b9a92ff631f76e71338f6a9bb9018580a24cbe5;p=gwion.git :art: Locales :smile: --- diff --git a/ast b/ast index c13d5da0..04b44ae1 160000 --- a/ast +++ b/ast @@ -1 +1 @@ -Subproject commit c13d5da0476a1409d2f501e7e014a58f55be9fd8 +Subproject commit 04b44ae194ffa5b2d20c963c92971f1acbab8ea0 diff --git a/highlighters/gwion.kak b/highlighters/gwion.kak index c342e51f..e79652f9 100644 --- a/highlighters/gwion.kak +++ b/highlighters/gwion.kak @@ -22,10 +22,10 @@ provide-module -override gwion %{ where when case varloop defer try perform handle retry fun function typedef distinct funptr - new spork fork' + new spork fork locale' attributes='const var static private public protect variadic template samp ms second minute delay' - types='auto int float bool dur void Object Shred Event' + types='auto int float bool dur time void Object Shred Event' values='true false none this now me adc dac maybe' builtins='__file__ __line__ __func__' entities='class struct trait union enum' diff --git a/highlighters/gwion.nanorc b/highlighters/gwion.nanorc index b6ed677b..52729fa1 100644 --- a/highlighters/gwion.nanorc +++ b/highlighters/gwion.nanorc @@ -37,14 +37,14 @@ color mauve "\" color mauve "\" comment "#!" -color italic,red start="#\<(pragma|include|define|ifdef|ifndef|undef|endif|import)\>" end="$" - color brightred "\<(typeof|spork|fork)\>" color lightred "\<(second|ms|day|samp|minute|hour)\>" color brightcyan "\<(maybe)\>" color cyan "\<(adc|blackhole)\>" -color brightgreen "\<(try|handle|perform|retry|class|struct|trait|union|enum|fun|operator|funptr|typedef|distinct|new)\>" +color brightgreen "\<(try|handle|perform|retry|class|struct|trait|union|enum|fun|locale|operator|funptr|typedef|distinct|new)\>" +color italic,red start="#\<(pragma|include|define|ifdef|ifndef|undef|endif|import|locale)\>" end="$" +color italic,red "#locale" color italic,yellow "extends" color italic,brightgreen "\<(final|abstract)\>" color lightgreen "@[a-zA-Z]+[a-zA-Z0-9_]*|&[a-zA-Z]+[a-zA-Z0-9_]*" diff --git a/include/curry.h b/include/curry.h new file mode 100644 index 00000000..7bf95f96 --- /dev/null +++ b/include/curry.h @@ -0,0 +1,4 @@ +#ifndef __CURRY +#define __CURRY +ANN2(1,2,3) Type curry_type(const Env env, const Exp exp, const Exp func, const Exp args, const bool lambda); +#endif diff --git a/include/emit.h b/include/emit.h index 808879e1..a5928716 100644 --- a/include/emit.h +++ b/include/emit.h @@ -52,6 +52,7 @@ struct Emitter_ { struct Gwion_ * gwion; struct EmitterInfo_ *info; struct Vector_ stack; + Func locale; uint16_t this_offset; // reset uint16_t vararg_offset; // reset }; diff --git a/include/env/context.h b/include/env/context.h index 77b4bb2e..af191283 100644 --- a/include/env/context.h +++ b/include/env/context.h @@ -5,7 +5,6 @@ struct Context_ { Nspc nspc; m_str name; Ast tree; - Func locale; uint16_t ref; uint16_t weight; bool error; diff --git a/plug b/plug index 49a4be94..52469434 160000 --- a/plug +++ b/plug @@ -1 +1 @@ -Subproject commit 49a4be94f9c4042f854dc82c8c6e598ec9d4df29 +Subproject commit 524694345a2e9ed7b257bf6ff8a3d70940e5aa61 diff --git a/src/compile.c b/src/compile.c index 5a0e380d..2974fdef 100644 --- a/src/compile.c +++ b/src/compile.c @@ -103,7 +103,6 @@ ANN static inline m_bool _passes(struct Gwion_ *gwion, struct Compiler *c) { ANN static inline m_bool passes(struct Gwion_ *gwion, struct Compiler *c) { const Env env = gwion->env; const Context ctx = new_context(env->gwion->mp, c->ast, env->name); -//ctx->locale = nspc_lookup_value1(gwion->env->global_nspc, insert_symbol(gwion->st, "@DefaultLocale"))->d.func_ref; env_reset(env); load_context(ctx, env); const m_bool ret = _passes(gwion, c); diff --git a/src/emit/emit.c b/src/emit/emit.c index 0b6acd14..0c5787d8 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -18,6 +18,7 @@ #include "specialid.h" #include "vararg.h" #include "looper.h" +#include "shreduler_private.h" #undef insert_symbol #define insert_symbol(a) insert_symbol(emit->gwion->st, (a)) @@ -912,7 +913,7 @@ ANN static m_bool emit_prim_interp(const Emitter emit, const Exp *exp) { emit_localx(emit, emit->gwion->type[et_string]); return GW_OK; } -#include "shreduler_private.h" + ANN static m_bool emit_ensure_func(const Emitter emit, const Func f) { const struct ValueFrom_ *from = f->value_ref->from; if(from->owner_class) @@ -925,32 +926,26 @@ ANN static m_bool emit_ensure_func(const Emitter emit, const Func f) { } ANN static m_bool emit_prim_locale(const Emitter emit, const Symbol *id) { - CHECK_BB(emit_ensure_func(emit, emit->env->context->locale)); + if(emit->locale->def->d.code) { + const Stmt stmt = mp_vector_at((emit->locale->def->d.code->d.stmt_code.stmt_list), struct Stmt_, 0); + const Func f = stmt->d.stmt_exp.val->d.exp_call.func->type->info->func; + CHECK_OB(emit_ensure_func(emit, f)); + } + CHECK_OB(emit_ensure_func(emit, emit->locale)); emit_push_code(emit, "locale"); // new code { - - // push args const M_Object string = new_string(emit->gwion, s_name(*id)); regpushi(emit, (m_uint)string); - - regpushi(emit, (m_uint)emit->env->context->locale->code); - emit_exp_call1(emit, emit->env->context->locale, true); - - regpop(emit, emit->env->context->locale->def->base->ret_type->size); + regpushi(emit, (m_uint)emit->locale->code); + emit_exp_call1(emit, emit->locale, true); + regpop(emit, emit->locale->def->base->ret_type->size); const VM_Code code = finalyze(emit, EOC); const VM_Shred shred = new_vm_shred(emit->gwion->mp, code); vm_add_shred(emit->gwion->vm, shred); shred->info->me->ref++; vm_run(emit->gwion->vm); emit->gwion->vm->bbq->is_running = true; - if(tflag(emit->env->context->locale->def->base->ret_type, tflag_float)) { - const Instr instr = emit_add_instr(emit, RegPushImm2); - instr->f = *(m_float*)shred->reg; - } else if(emit->env->context->locale->def->base->ret_type->size == SZ_INT) - regpushi(emit, *(m_uint*)shred->reg); - else { - // here we would need to deallocate - ERR_B(prim_pos(id), "not implemented atm"); - } + const Instr instr = emit_add_instr(emit, RegPushImm2); + instr->f = *(m_float*)shred->reg; return GW_OK; } @@ -2837,11 +2832,14 @@ ANN static m_bool emit_stmt_match(const Emitter emit, ANN static m_bool emit_stmt_pp(const Emitter emit, const struct Stmt_PP_ *stmt) { - if (stmt->pp_type == ae_pp_pragma) { + if (stmt->pp_type == ae_pp_include) + emit->env->name = stmt->data; + else if (stmt->pp_type == ae_pp_locale) + emit->locale = stmt->exp->d.exp_lambda.def->base->func; + else if (stmt->pp_type == ae_pp_pragma) { if (!strncmp(stmt->data, "unroll", strlen("unroll"))) emit->info->unroll = strtol(stmt->data + 6, NULL, 10); - } else if (stmt->pp_type == ae_pp_include) - emit->env->name = stmt->data; + } return GW_OK; } @@ -3078,7 +3076,9 @@ ANN m_bool _emit_func_def(const Emitter emit, const Func_Def f) { ANN m_bool emit_func_def(const Emitter emit, const Func_Def fdef) { const uint16_t depth = emit->env->scope->depth; emit->env->scope->depth = 0; + const Func locale = emit->locale; const m_bool ret = _emit_func_def(emit, fdef); + emit->locale = locale; emit->env->scope->depth = depth; return ret; } @@ -3131,10 +3131,8 @@ ANN static m_bool cdef_parent(const Emitter emit, const Class_Def cdef) { return ret; } -ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { - if (tmpl_base(cdef->base.tmpl)) return GW_OK; +ANN static m_bool _emit_class_def(const Emitter emit, const Class_Def cdef) { const Type t = cdef->base.type; - if (tflag(t, tflag_emit)) return GW_OK; set_tflag(t, tflag_emit); const Class_Def c = t->info->cdef; if (c->base.ext && t->info->parent->info->cdef && @@ -3153,6 +3151,15 @@ ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { return GW_OK; } +ANN static m_bool emit_class_def(const Emitter emit, const Class_Def cdef) { + if (tmpl_base(cdef->base.tmpl)) return GW_OK; + if (tflag(cdef->base.type, tflag_emit)) return GW_OK; + const Func locale = emit->locale; + const m_bool ret = _emit_class_def(emit, cdef); + emit->locale = locale; + return ret; +} + ANN static inline void emit_free_code(const Emitter emit, Code *code) { if (vector_size(&code->instr)) free_code_instr(&code->instr, emit->gwion); free_code(emit->gwion->mp, code); @@ -3177,6 +3184,7 @@ ANN static inline void emit_clear(const Emitter emit) { ANN m_bool emit_ast(const Env env, Ast *ast) { const Emitter emit = env->gwion->emit; + const Func locale = emit->locale; emit_clear(emit); emit->code = new_code(emit, emit->env->name); emit_push_scope(emit); @@ -3187,5 +3195,6 @@ ANN m_bool emit_ast(const Env env, Ast *ast) { else emit_free_stack(emit); emit_clear(emit); + emit->locale = locale; return ret; } diff --git a/src/gwion.c b/src/gwion.c index 9fca9311..0f7f94e8 100644 --- a/src/gwion.c +++ b/src/gwion.c @@ -68,6 +68,14 @@ ANN static void gwion_core(const Gwion gwion) { gwion->vm->gwion = gwion->emit->gwion = gwion->env->gwion = gwion; } + +ANN static Func gwion_locale(const Gwion gwion) { + const Nspc nspc = gwion->env->curr; + const Symbol sym = insert_symbol(gwion->st, "BasicLocale"); + const Value v = nspc_lookup_value1(nspc, sym); + return v->d.func_ref; +} + ANN static m_bool gwion_ok(const Gwion gwion, CliArg *arg) { CHECK_BB(plug_ini(gwion, &arg->lib)); shreduler_set_loop(gwion->vm->shreduler, arg->loop); @@ -75,6 +83,7 @@ ANN static m_bool gwion_ok(const Gwion gwion, CliArg *arg) { plug_run(gwion, &arg->mod); if (type_engine_init(gwion)) { gwion->vm->cleaner_shred = gwion_cleaner(gwion); + gwion->emit->locale = gwion_locale(gwion); (void)arg_compile(gwion, arg); return GW_OK; } diff --git a/src/lib/curry.c b/src/lib/curry.c index 75e84fda..4b60862f 100644 --- a/src/lib/curry.c +++ b/src/lib/curry.c @@ -11,6 +11,7 @@ #include "gwi.h" #include "traverse.h" #include "parse.h" +#include "curry.h" ANN static Arg_List curry_arg_list(const Env env, const Arg_List base, const Exp e) { Arg_List args = new_mp_vector(env->gwion->mp, sizeof(Arg), 0); @@ -30,10 +31,9 @@ ANN static Arg_List curry_arg_list(const Env env, const Arg_List base, const Exp return args; } -ANN2(1) static Func_Base *curry_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) { +ANN2(1, 2) static inline Func_Base *curry_base(const Env env, const Func_Base *base, Exp earg, const loc_t loc) { Arg_List args = earg ? curry_arg_list(env, base->args, earg) : NULL; Func_Base *fb = new_func_base(env->gwion->mp, cpy_type_decl(env->gwion->mp, base->td), lambda_name(env->gwion->st, loc.first), args, ae_flag_none, loc); - fb->fbflag |= fbflag_lambda; return fb; } @@ -67,9 +67,10 @@ ANN static Stmt curry_code(const Env env, const Exp efun, const Exp earg) { return new_stmt_code(env->gwion->mp, slist, efun->pos); } -ANN static Type curry_type(const Env env, const Exp exp, const Exp efun, const Exp earg) { - Func_Base *base = curry_base(env, efun->type->info->func->def->base, earg, exp->pos); - Stmt code = curry_code(env, efun, earg); +ANN2(1,2,3) Type curry_type(const Env env, const Exp exp, const Exp func, const Exp args, const bool lambda) { + Func_Base *const base = curry_base(env, func->type->info->func->def->base, args, exp->pos); + const Stmt code = curry_code(env, func, args); + if(lambda)base->fbflag |= fbflag_lambda; // rewritem exp->d.exp_lambda.def = new_func_def(env->gwion->mp, base, code); exp->exp_type = ae_exp_lambda; return check_exp(env, exp); @@ -83,7 +84,7 @@ static OP_CHECK(opck_curry) { const Exp earg = efun->next; efun->next = NULL; const Type ret = check_exp(env, efun) - ? curry_type(env, exp_self(call), efun, earg) + ? curry_type(env, exp_self(call), efun, earg, true) : env->gwion->type[et_error]; mp_free(env->gwion->mp, Exp, earg); return ret; @@ -104,4 +105,3 @@ GWION_IMPORT(curry) { CHECK_BB(add_op(gwi->gwion, &opi)); return GW_OK; } - diff --git a/src/lib/engine.c b/src/lib/engine.c index c4a607fa..dc2cfa91 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -56,6 +56,28 @@ static FREEARG(freearg_release) { vector_release(&v); } +ANN static m_float basic_locale(m_str str) { + const char base = str[0]; + str++; + if(base < 'A' || base > 'G') return -1; + m_int bnote = base - 'A'; + if(*str == '#') { bnote++; str++; } + else if(*str == 'b') { bnote--; str++; } + char *remainder; + const long octave = strtol(str, &remainder, 10); + if(*remainder != '\0') return -1; + const int note = bnote + 12 * octave + 21; + return (pow(2, (note - 69) / 12.0) * 440.0); +} + +static SFUN(BasicLocale) { + const M_Object arg = *(M_Object*)MEM(0); + const m_float ret = basic_locale(STRING(arg)); + if(ret == -1.0) + handle(shred, "invalid value for locale"); + *(m_float*)RETURN = ret; +} + ANN static m_bool import_core_libs(const Gwi gwi) { gwidoc(gwi, "one type to rule them all."); const Type t_class = gwi_mk_type(gwi, "Class", SZ_INT, NULL); @@ -189,6 +211,10 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_BB(import_curry(gwi)); +gwi_func_ini(gwi, "float", "BasicLocale"); +gwi_func_arg(gwi, "string", "str"); +gwi_func_end(gwi, BasicLocale, ae_flag_none); + // seemed need at a point to ease liking gwi_enum_ini(gwi, "@hidden_enum"); gwi_enum_add(gwi, "@hidden_enum", 0); diff --git a/src/lib/lib_func.c b/src/lib/lib_func.c index d4c29a92..0a827f5e 100644 --- a/src/lib/lib_func.c +++ b/src/lib/lib_func.c @@ -358,6 +358,7 @@ ANN static Type curry2auto(const Env env, const Exp_Binary *bin) { const Func_Def fdef = bin->lhs->d.exp_lambda.def; unset_fbflag(fdef->base, fbflag_lambda); CHECK_BN(traverse_func_def(env, fdef)); + set_fbflag(fdef->base, fbflag_lambda); const Type actual = fdef->base->func->value_ref->type; set_fbflag(fdef->base, fbflag_lambda); Var_Decl vd = mp_vector_at(bin->rhs->d.exp_decl.list, struct Var_Decl_, 0); diff --git a/src/parse/check.c b/src/parse/check.c index 76697b57..7289fed6 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -14,6 +14,7 @@ #include "match.h" #include "specialid.h" #include "tmp_resolve.h" +#include "curry.h" ANN static m_bool check_stmt_list(const Env env, Stmt_List list); ANN m_bool check_class_def(const Env env, const Class_Def class_def); @@ -310,6 +311,9 @@ ANN static Value check_non_res_value(const Env env, const Symbol *data) { ERR_O(prim_pos(data), _("non-global variable '%s' used from global function/class."), s_name(var)) + } else if(env->func && fbflag(env->func->def->base, fbflag_locale)) { + if(!is_func(env->gwion, value->type) && value->from->owner && !from_global_nspc(env, value->from->owner)) + ERR_O(prim_pos(data), _("invalid variable access from locale definition")); } return value; } @@ -422,7 +426,7 @@ ANN static Type check_prim_hack(const Env env, const Exp *data) { } ANN static Type check_prim_locale(const Env env, const Symbol *data NUSED) { - return env->context->locale->def->base->ret_type; + return env->gwion->type[et_float]; } #define describe_prim_xxx(name, type) \ @@ -765,17 +769,6 @@ ANN static Type check_lambda_call(const Env env, const Exp_Call *exp) { } if(e) ERR_O(exp_self(exp)->pos, _("argument number does not match for lambda")) -/* - while (arg && e) { - arg->type = e->type; - if(is_class(env->gwion, arg->type)) - type_addref(arg->type); - arg = arg->next; - e = e->next; - } - if (arg || e) - ERR_O(exp_self(exp)->pos, _("argument number does not match for lambda")) -*/ l->def->base->values = env->curr->info->value; const m_bool ret = traverse_func_def(env, l->def); if (l->def->base->func) { @@ -1500,9 +1493,20 @@ ANN static m_bool check_stmt_match(const Env env, const Stmt_Match stmt) { ANN static m_bool check_stmt_pp(const Env env, const Stmt_PP stmt) { if (stmt->pp_type == ae_pp_include) env->name = stmt->data; // check for memoization - if (env->func && stmt->pp_type == ae_pp_pragma && + else if (env->func && stmt->pp_type == ae_pp_pragma && !strncmp(stmt->data, "memoize", strlen("memoize"))) env->func->memoize = strtol(stmt->data + 7, NULL, 10); + else if(stmt->pp_type == ae_pp_locale) { + const loc_t loc = stmt_self(stmt)->pos; + const Exp id = new_prim_id(env->gwion->mp, stmt->xid, loc); + const Exp arg = new_prim_id(env->gwion->mp, insert_symbol("_"), loc); + arg->next = stmt->exp; + const Exp call = new_exp_call(env->gwion->mp, id, arg, loc); + stmt->exp = call; + CHECK_BB(traverse_exp(env, id)); + CHECK_OB(curry_type(env, call, id, call->d.exp_call.args, false)); + CHECK_OB(traverse_func_def(env, call->d.exp_lambda.def)); + } return GW_OK; } diff --git a/tests/curry/curry.gw b/tests/curry/curry.gw new file mode 100644 index 00000000..c167e841 --- /dev/null +++ b/tests/curry/curry.gw @@ -0,0 +1,15 @@ +#! [contains] 42 + +fun void test(int i, int j) { + <<< "The answer: ${ i + j}" >>>; +} + +curry(test, 40, _)(2); + +curry(test, _, 2) @=> const (void(int)) func0; + +curry(test, 40, _) @=> const auto func1; + +func0(40); + +func1(2); diff --git a/tests/locale/locale.basic.gw b/tests/locale/locale.basic.gw new file mode 100644 index 00000000..4d4b4ee5 --- /dev/null +++ b/tests/locale/locale.basic.gw @@ -0,0 +1,3 @@ +#! [contains] 440 + +<<< `A4` >>>; diff --git a/tests/locale/locale_default_args.gw b/tests/locale/locale_default_args.gw new file mode 100644 index 00000000..2272ce05 --- /dev/null +++ b/tests/locale/locale_default_args.gw @@ -0,0 +1,5 @@ +#! [contains] 432 +locale Test(float base : 432) { return base; } + +#locale Test +<<< `foo` >>>; diff --git a/tests/locale/locale_with_args.gw b/tests/locale/locale_with_args.gw new file mode 100644 index 00000000..3977e718 --- /dev/null +++ b/tests/locale/locale_with_args.gw @@ -0,0 +1,5 @@ +#! [contains] 440 +locale Test(float base : 432) { return base; } + +#locale Test 440 +<<< `foo` >>>;