From 17b352cdc8ef3c7b74980d95fa5d2b95347cb108 Mon Sep 17 00:00:00 2001 From: fennecdjay Date: Thu, 19 Sep 2019 01:59:16 +0200 Subject: [PATCH] :art: Initial match commit --- include/env.h | 14 +--- include/instr.h | 5 -- include/match.h | 35 ++++++++ include/switch.h | 22 ----- src/emit/emit.c | 193 +++++++++++++++++++++++++------------------- src/lib/engine.c | 13 --- src/lib/instr.c | 14 ---- src/oo/env.c | 8 -- src/oo/switch.c | 185 ------------------------------------------ src/parse/check.c | 105 ++++++++++++++++++------ src/parse/cpy_ast.c | 12 +-- src/parse/scan1.c | 36 ++++++--- src/parse/scan2.c | 36 +++++++-- 13 files changed, 288 insertions(+), 390 deletions(-) create mode 100644 include/match.h delete mode 100644 include/switch.h delete mode 100644 src/oo/switch.c diff --git a/include/env.h b/include/env.h index d0a1a1a8..3bba04b3 100644 --- a/include/env.h +++ b/include/env.h @@ -4,25 +4,13 @@ #define SCOPE(a) { ++env->scope; a ;--env->scope; } #define NSPC(a) { nspc_push_value(env->curr); SCOPE(a); nspc_pop_value(env->curr); } -typedef struct Switch_ * Switch; -struct Switch_ { - struct Vector_ exp; - Map cases; - Vector vec; - vtype iter; - size_t default_case_index; - size_t depth; - struct SwInfo_ *info; - uint ok; -}; - struct Env_Scope_ { struct Vector_ nspc_stack; struct Vector_ class_stack; struct Vector_ breaks; struct Vector_ conts; struct Vector_ known_ctx; - Scope swi; + struct Match_ *match; size_t depth; size_t type_xid; }; diff --git a/include/instr.h b/include/instr.h index 1f97a27d..9a545cbe 100644 --- a/include/instr.h +++ b/include/instr.h @@ -34,11 +34,6 @@ INSTR(EOC); INSTR(DTOR_EOC); INSTR(DtorReturn); -/* branching */ -INSTR(SwitchBranch); -INSTR(SwitchIni); -INSTR(SwitchEnd); - INSTR(ComplexReal); INSTR(ComplexImag); diff --git a/include/match.h b/include/match.h new file mode 100644 index 00000000..dbdb6a2f --- /dev/null +++ b/include/match.h @@ -0,0 +1,35 @@ +#ifndef __MATCH +#define __MATCH +struct Match_ { + struct Map_ map; + struct Vector_ vec; +}; + +ANN static inline void match_map(struct Match_ * const match, Exp e) { + const Map map = &match->map; + map_init(map); + do { + e->next = NULL; + map_set(map, (vtype)e, 0); + } while((e = e->next)); +} + +ANN static inline void match_unmap(struct Match_ * const match) { + const Map map = &match->map; + for(m_uint i = 0; i < map_size(map) - 1; ++i) { + const Exp e = (Exp)VKEY(map, i), next = (Exp)VKEY(map, i + 1); + e->next = next; + } + map_release(map); +} + +#define MATCH_INI(scope) \ + struct Match_ *former = scope->match, m = {}; \ + scope->match = &m; \ + match_map(&m, stmt->cond); + +#define MATCH_END(scope) \ + match_unmap(scope->match); \ + scope->match = former; + +#endif diff --git a/include/switch.h b/include/switch.h deleted file mode 100644 index b6080cb8..00000000 --- a/include/switch.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __SWITCH -#define __SWITCH -ANN Map switch_map(const Env env); -ANN Vector switch_vec(const Env env); -ANN void switch_expset(const Env env, const Exp); -ANN Exp switch_expget(const Env env); -ANN void switch_pc(const Env env, const m_uint pc); -ANN void switch_dynpc(const Env env, const m_int val, const m_uint pc); -ANN m_bool switch_dup(const Env env, const m_int value, const loc_t pos); -ANN m_bool switch_pop(const Env env); -ANN m_bool switch_end(const Env env, const loc_t pos); -ANN m_uint switch_idx(const Env); -ANN Vector switch_vec(const Env); -ANN m_bool switch_add(const Env env, const Stmt_Switch stmt); -ANN m_bool switch_default(const Env env, const m_uint pc, const loc_t pos); -ANN m_bool switch_inside(const Env env, const loc_t pos); -ANN m_bool switch_dyn(const Env env); -ANN m_bool switch_decl(const Env env, const loc_t pos); -ANN void switch_reset(const Env env); -ANN void switch_release(const Scope); -ANN void switch_get(const Env env, const Stmt_Switch stmt); -#endif diff --git a/src/emit/emit.c b/src/emit/emit.c index ca8dd7b6..ed6808c7 100644 --- a/src/emit/emit.c +++ b/src/emit/emit.c @@ -21,7 +21,7 @@ #include "memoize.h" #include "operator.h" #include "import.h" -#include "switch.h" +#include "match.h" #include "parser.h" #include "tuple.h" @@ -1341,8 +1341,6 @@ 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); else { - if(!strcmp(s_name(stmt->name), "default") && switch_inside(emit->env, stmt_self(stmt)->pos) > 0) - return switch_default(emit->env, emit_code_size(emit), stmt_self(stmt)->pos); if(!stmt->data.v.ptr) ERR_B(stmt_self(stmt)->pos, _("illegal case")) const m_uint size = vector_size(&stmt->data.v); @@ -1359,82 +1357,6 @@ ANN static m_bool emit_stmt_jump(const Emitter emit, const Stmt_Jump stmt) { 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[0] = emit_add_instr(emit, RegPop); - instr[1] = emit_add_instr(emit, SwitchIni); - instr[2] = emit_add_instr(emit, RegSetImm); - } else - regseti(emit, (m_uint)switch_map(emit->env)); - return GW_OK; -} - -ANN static Map emit_switch_map(MemPool p, const Map map) { - const Map m = new_map(p); - for(m_uint i = map_size(map) + 1; --i;) - map_set(m, VKEY(map, i-1), VVAL(map, i -1)); - return m; -} - -ANN static m_bool emit_stmt_switch(const Emitter emit, const Stmt_Switch stmt) { - switch_get(emit->env, stmt); - Instr push[3] = { NULL, NULL, 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, SwitchBranch); - 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[0]) { - push[2]->m_val = push[1]->m_val2 = (m_uint) emit_switch_map(emit->gwion->mp, (Map)instr->m_val2); - Vector v = (Vector)(push[1]->m_val = (m_uint)switch_vec(emit->env)); - push[0]->m_val = vector_size(v) * SZ_INT; - } - CHECK_BB(switch_end(emit->env, stmt->stmt->pos)) - 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->info->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) { - CHECK_BB(switch_inside(emit->env, stmt_self(stmt)->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_self(stmt)->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_type_def(const Emitter emit, const Type_Def tdef) { return tdef->type->e->def ? emit_class_def(emit, tdef->type->e->def) : 1; } @@ -1522,12 +1444,121 @@ 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; } +ANN static Instr emit_when(const Emitter emit, const Exp when) { + CHECK_BO(emit_exp(emit, when, 1)) + return emit_add_instr(emit, BranchEqInt); +} + +ANN static m_bool emit_case_head(const Emitter emit, const Exp base, const Exp e, const Symbol op) { + CHECK_BB(emit_exp(emit, base, 1)) + CHECK_BB(emit_exp(emit, e, 1)) + Exp_Binary bin = { .lhs=base, .rhs=e, .op=op, .nspc=emit->env->curr }; + struct Op_Import opi = { .op=op, .lhs=base->type, .rhs=e->type, .data=(uintptr_t)&bin, .pos=e->pos }; + CHECK_BB(op_emit(emit, &opi)) + regpop(emit, base->type->size); + return GW_OK; +} + +ANN static m_bool emit_case_body(const Emitter emit, const struct Stmt_Match_* stmt) { + const Instr when = stmt->when ? emit_when(emit, stmt->when) : NULL; + if(stmt->when) + CHECK_OB(when) + CHECK_BB(emit_stmt_list(emit, stmt->list)) + const Instr instr = emit_add_instr(emit, Goto); + vector_add(&emit->env->scope->match->vec, (vtype)instr); + if(when) + when->m_val = emit_code_size(emit); + return GW_OK; +} + +ANN static m_bool case_value(const Emitter emit, const Exp base, const Exp e) { + const Value v = e->d.exp_primary.value; + v->offset = emit_local(emit, base->type->size, isa(base->type, t_object) > 0); + CHECK_BB(emit_exp(emit, base, 1)) + regpop(emit, base->type->size); + const Instr instr = emit_add_instr(emit, Reg2Mem4); + instr->m_val = v->offset; + instr->m_val2 = base->type->size; + return GW_OK; +} + + +#define CASE_PASS (Symbol)1 +ANN static Symbol case_op(const Emitter emit, const Exp base, const Exp e) { + if(e->exp_type == ae_exp_primary) { + if(e->d.exp_primary.primary_type == ae_primary_unpack) + return insert_symbol("@=>"); + if(e->d.exp_primary.primary_type == ae_primary_id) { + if(e->d.exp_primary.d.var == insert_symbol("_")) + return CASE_PASS; + if(!nspc_lookup_value1(emit->env->curr, e->d.exp_primary.d.var)) { + CHECK_BO(case_value(emit, base, e)) + return CASE_PASS; + } + } + } + return insert_symbol("=="); +} + +ANN static m_bool _emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt) { + Exp e = stmt->cond; + const Map map = &emit->env->scope->match->map; + for(m_uint i = 0; i < map_size(map); e = e->next, ++i) { + const Exp base = (Exp)VKEY(map, i); + const Symbol op = case_op(emit, base, e); + if(op != CASE_PASS) + CHECK_BB(emit_case_head(emit, base, e, op)) + } + return emit_case_body(emit, stmt); +} + +ANN static m_bool emit_stmt_match_case(const Emitter emit, const struct Stmt_Match_* stmt) { + emit_push_scope(emit); + const m_bool ret = _emit_stmt_match_case(emit, stmt); + emit_pop_scope(emit); + return ret; +} + +ANN static inline void match_unvec(struct Match_ *const match , const m_uint pc) { + const Vector vec = &match->vec; + for(m_uint i = 0; i < vector_size(vec); ++i) { + const Instr instr = (Instr)VPTR(vec, i); + instr->m_val = pc; + } + vector_release(vec); +} + +ANN static m_bool emit_stmt_cases(const Emitter emit, Stmt_List list) { + do CHECK_BB(emit_stmt_match_case(emit, &list->stmt->d.stmt_match)) // beware push + 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 + MATCH_INI(emit->env->scope) + vector_init(&m.vec); + const m_bool ret = emit_stmt_cases(emit, stmt->list); + match_unvec(&m, emit_code_size(emit)); + MATCH_END(emit->env->scope) + return ret; +} + +ANN static m_bool emit_stmt_match(const Emitter emit, const struct Stmt_Match_* stmt) { + emit_push_scope(emit); + const m_bool ret = emit_match(emit, stmt); + emit_pop_scope(emit); + return ret; +} + 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_if, (_exp_func)emit_stmt_code, (_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_match, (_exp_func)emit_stmt_match_case, + (_exp_func)emit_stmt_jump, }; ANN static m_bool emit_stmt(const Emitter emit, const Stmt stmt, const m_bool pop) { diff --git a/src/lib/engine.c b/src/lib/engine.c index 4b128d24..03e67e03 100644 --- a/src/lib/engine.c +++ b/src/lib/engine.c @@ -19,17 +19,6 @@ #include "parser.h" #include "lang_private.h" -static FREEARG(freearg_switchini) { - if(instr->m_val) - free_vector(((Gwion)gwion)->mp, (Vector)instr->m_val); - if(instr->m_val2) - free_map(((Gwion)gwion)->mp, (Map)instr->m_val2); -} - -static FREEARG(freearg_switchbranch) { - free_map(((Gwion)gwion)->mp, (Map)instr->m_val2); -} - static FREEARG(freearg_gack) { free_vector(((Gwion)gwion)->mp, (Vector)instr->m_val2); } @@ -112,8 +101,6 @@ ANN static m_bool import_core_libs(const Gwi gwi) { GWI_BB(gwi_oper_end(gwi, "<=", instr_class_le)) GWI_BB(gwi_oper_end(gwi, "<", instr_class_lt)) - register_freearg(gwi, SwitchIni, freearg_switchini); - register_freearg(gwi, SwitchBranch, freearg_switchbranch); register_freearg(gwi, Gack, freearg_gack); return GW_OK; } diff --git a/src/lib/instr.c b/src/lib/instr.c index 634a7868..0da50fc5 100644 --- a/src/lib/instr.c +++ b/src/lib/instr.c @@ -25,20 +25,6 @@ INSTR(DTOR_EOC) { vm_shred_exit(shred); } -/* branching */ -INSTR(SwitchIni) { - const Vector v = (Vector)instr->m_val; - const m_uint size = vector_size(v); - for(m_uint i = 0; i < size; ++i) - map_set((Map)instr->m_val2, *(vtype*)REG((i) * SZ_INT), vector_at(v, i)); -} - -INSTR(SwitchBranch) { - POP_REG(shred, SZ_INT); - const Map map = *(Map*)REG(SZ_INT); - shred->pc = map_get(map, *(m_uint*)REG(0)) ?: instr->m_val; -} - #include "gwion.h" #include "emit.h" #include "value.h" diff --git a/src/oo/env.c b/src/oo/env.c index 5e0532b5..0dda4c35 100644 --- a/src/oo/env.c +++ b/src/oo/env.c @@ -12,7 +12,6 @@ #include "context.h" #include "nspc.h" #include "mpool.h" -#include "switch.h" #include "vm.h" #include "parse.h" @@ -23,9 +22,6 @@ ANN static struct Env_Scope_ *new_envscope(MemPool p) { vector_init(&a->class_stack); vector_init(&a->nspc_stack); vector_init(&a->known_ctx); - a->swi = mp_calloc(p, Scope); - _scope_init(a->swi); - map_init(&a->swi->map); return a; } @@ -49,7 +45,6 @@ ANN void env_reset(const Env env) { env->class_def = NULL; env->func = NULL; env->scope->depth = 0; - switch_reset(env); } ANN static void free_env_scope(struct Env_Scope_ *a, Gwion gwion) { @@ -61,13 +56,10 @@ ANN static void free_env_scope(struct Env_Scope_ *a, Gwion gwion) { vector_release(&a->class_stack); vector_release(&a->breaks); vector_release(&a->conts); - switch_release(a->swi); - mp_free(gwion->mp, Scope, a->swi); mp_free(gwion->mp, Env_Scope, a); } ANN void free_env(const Env a) { - switch_reset(a); free_env_scope(a->scope, a->gwion); REM_REF(a->global_nspc, a->gwion); free(a); diff --git a/src/oo/switch.c b/src/oo/switch.c deleted file mode 100644 index 3d8dc38e..00000000 --- a/src/oo/switch.c +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include "gwion_util.h" -#include "gwion_ast.h" -#include "oo.h" -#include "env.h" -#include "vm.h" -#include "env.h" -#include "gwion.h" -#include "operator.h" -#include "value.h" -#include "type.h" -#include "context.h" -#include "nspc.h" -#include "traverse.h" -#include "parse.h" -#include "switch.h" - -static inline void _scope_add(Scope s, Switch sw) { vector_add((Vector)(void*)s, (vtype)sw); } -static inline vtype _scope_pop(Scope s) { return vector_pop((Vector)(void*)s); } -static inline vtype _scope_back(Scope s) { return vector_back((Vector)(void*)s); } -static inline void _scope_clear(Scope s) { vector_clear((Vector)(void*)s); } - -static Switch new_switch(MemPool p) { - Switch sw = mp_calloc(p, Switch); - sw->cases = new_map(p); // could be struct ? - vector_init(&sw->exp); - sw->vec = new_vector(p); - return sw; -} - -struct SwInfo_ { - Stmt_Switch s; - Type t; - Func f; -}; - -ANN static void free_switch(MemPool p, const Switch sw) { - if(!sw->ok) - free_map(p, sw->cases); - free_vector(p, sw->vec); // only for dynamic - vector_release(&sw->exp); - mp_free(p, SwInfo, sw->info); - mp_free(p, Switch, sw); -} - -ANN static Switch new_swinfo(const Env env, const Stmt_Switch stmt) { - struct SwInfo_ *info = mp_calloc(env->gwion->mp, SwInfo); - info->s = stmt; - info->t = env->class_def; - info->f = env->func; - const Switch sw = new_switch(env->gwion->mp); - map_set(&env->scope->swi->map, (vtype)info, (vtype)sw); - sw->depth = env->scope->depth + 2; - sw->info = info; - return sw; -} - -ANN static inline m_bool swinfo_cmp(const struct SwInfo_ *i1, const struct SwInfo_ *i2) { - return i1->s == i2->s && i1->t == i2->t && i1->f == i2->f; -} - -ANN Switch swinfo_get(const Env env, const struct SwInfo_ *info) { - for(m_uint i = 0; i < VLEN(&env->scope->swi->map); ++i) { - const struct SwInfo_ *key = (const struct SwInfo_*)VKEY(&env->scope->swi->map, i); - if(swinfo_cmp(key, info)) { - return (Switch)VVAL(&env->scope->swi->map, i); - } - } - return NULL; -} - -ANN m_bool switch_add(const Env env, const Stmt_Switch stmt) { - const struct SwInfo_ info = { stmt, env->class_def, env->func }; - Switch sw = (Switch)swinfo_get(env, &info) ?: new_swinfo(env, stmt); - _scope_add(env->scope->swi, sw); - return GW_OK; -} - -ANN m_bool switch_decl(const Env env, const loc_t pos) { - const Switch sw = (Switch)(VLEN(&env->scope->swi->map) ? - VVAL(&env->scope->swi->map, VLEN(&env->scope->swi->map) - 1): 0); - if(sw && sw->depth == env->scope->depth) - ERR_B(pos, _("Declaration in switch is prohibited.")) - return GW_OK; -} - -ANN void switch_get(const Env env, const Stmt_Switch stmt) { - const struct SwInfo_ info = { stmt, env->class_def, env->func }; - const Switch sw = swinfo_get(env, &info); - _scope_add(env->scope->swi, sw); -} - -void switch_reset(const Env env) { - for(m_uint i = VLEN(&env->scope->swi->map) + 1; --i;) { - const Switch sw = (Switch)VVAL(&env->scope->swi->map, i - 1); - free_switch(env->gwion->mp, sw); - } - _scope_clear(env->scope->swi); - map_clear(&env->scope->swi->map); -} - -ANN void switch_release(const Scope sw) { - vector_release((Vector)sw); - map_release(&sw->map); -} - -ANN void switch_expset(const Env env, const Exp e) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - vector_add(&sw->exp, (vtype)e); -} - -ANN Exp switch_expget(const Env env) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - return (Exp)vector_at(&sw->exp, sw->iter++); -} - -ANN m_bool switch_inside(const Env env, const loc_t pos) { - if(!VLEN(env->scope->swi)) - ERR_B(pos, _("case found outside switch statement.")) - return GW_OK; -} - -ANN m_bool switch_dup(const Env env, const m_int value, const loc_t pos) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - if(map_get(sw->cases, (vtype)value)) - ERR_B(pos, _("duplicated cases value %i"), value) - sw->ok = 1; - return GW_OK; -} - -ANN void switch_pc(const Env env, const m_uint pc) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - vector_add(sw->vec, pc); -} - -ANN void switch_dynpc(const Env env, const m_int val, const m_uint pc) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - map_set(sw->cases, val, pc); -} - -ANN m_bool switch_dyn(const Env env) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - return vector_size(&sw->exp); -} - -ANN m_bool switch_default(const Env env, const m_uint pc, const loc_t pos) { - if(!VLEN(env->scope->swi)) - ERR_B(pos, _("'default'case found outside switch statement.")) - const Switch sw = (Switch)_scope_back(env->scope->swi); - if(sw->default_case_index) - ERR_B(pos, _("default case already defined")) - sw->default_case_index = pc; - return GW_OK; -} - -ANN Map switch_map(const Env env) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - return sw->cases; -} - -ANN Vector switch_vec(const Env env) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - return vector_copy(env->gwion->mp, sw->vec); // new_vector(); // dyn only -} - -ANN m_uint switch_idx(const Env env) { - const Switch sw = (Switch)_scope_back(env->scope->swi); - return sw->default_case_index; -} - -ANN m_bool switch_pop(const Env env) { - const Switch sw = (Switch)_scope_pop(env->scope->swi); - sw->ok = 1; - return GW_OK; -} - -ANN m_bool switch_end(const Env env, const loc_t pos) { - const Switch sw = (Switch)_scope_pop(env->scope->swi); - map_remove(&env->scope->swi->map, (vtype)sw->info); - const m_bool empty = !VLEN(sw->cases) && !VLEN(&sw->exp); - free_switch(env->gwion->mp, sw); - if(empty) - ERR_B(pos, _("switch statement with no cases.")) - return GW_OK; -} diff --git a/src/parse/check.c b/src/parse/check.c index fc3fc8f2..8a488a39 100644 --- a/src/parse/check.c +++ b/src/parse/check.c @@ -17,7 +17,7 @@ #include "import.h" #include "parse.h" #include "nspc.h" -#include "switch.h" +#include "match.h" #include "cpy_ast.h" #include "tuple.h" @@ -106,7 +106,6 @@ ANN static Type no_xid(const Env env, const Exp_Decl *decl) { ANN Type check_exp_decl(const Env env, const Exp_Decl* decl) { Var_Decl_List list = decl->list; - CHECK_BO(switch_decl(env, exp_self(decl)->pos)) if(!decl->td->xid) return no_xid(env, decl); if(decl->td->xid->xid == insert_symbol("auto")) { // should be better @@ -1069,9 +1068,6 @@ stmt_func_xxx(for, Stmt_For,, !( stmt_func_xxx(loop, Stmt_Loop,, !(!check_exp(env, stmt->cond) || cond_type(env, stmt->cond) < 0 || check_conts(env, stmt_self(stmt), stmt->body) < 0) ? 1 : -1) -stmt_func_xxx(switch, Stmt_Switch,, !(!check_exp(env, stmt->val) || - cond_type(env, stmt->val) < 0 || !switch_add(env, stmt) || - check_breaks(env, stmt_self(stmt), stmt->stmt) < 0 || switch_pop(env) < 0) ? 1 : -1) stmt_func_xxx(auto, Stmt_Auto,, do_stmt_auto(env, stmt)) ANN static m_bool check_stmt_return(const Env env, const Stmt_Exp stmt) { @@ -1102,22 +1098,6 @@ ANN static m_bool check_stmt_##name(const Env env, const Stmt stmt) {\ describe_check_stmt_stack(conts, continue) describe_check_stmt_stack(breaks, break) -ANN Value case_value(const Exp exp); -ANN static m_bool check_stmt_case(const Env env, const Stmt_Exp stmt) { - CHECK_BB(switch_inside(env, stmt_self(stmt)->pos)); - DECL_OB(const Type, t, = check_exp(env, stmt->val)) - if(isa(t, t_int) < 0) - ERR_B(stmt_self(stmt)->pos, _("invalid type '%s' case expression. should be 'int'"), t->name) - const Value v = case_value(stmt->val); - if(!v) - return GW_OK; - if(!GET_FLAG(v, const)) - ERR_B(stmt->val->pos, _("'%s' is not constant."), v->name) - if(!GET_FLAG(v, builtin) && !GET_FLAG(v, enum)) - switch_expset(env, stmt->val); - return GW_OK; -} - ANN static m_bool check_stmt_jump(const Env env, const Stmt_Jump stmt) { if(stmt->is_label) return GW_OK; @@ -1168,15 +1148,92 @@ ANN m_bool check_union_def(const Env env, const Union_Def udef) { } ANN static m_bool check_stmt_exp(const Env env, const Stmt_Exp stmt) { - return stmt->val ? check_exp(env, stmt->val) ? 1 : -1 : 1; + return stmt->val ? check_exp(env, stmt->val) ? 1 : -1 : 1; +} + +ANN static Value match_value(const Env env, const Exp_Primary* prim, const m_uint i) { + const Symbol sym = prim->d.var; + const Value v = new_value(env->gwion->mp, + ((Exp)VKEY(&env->scope->match->map, i))->type, s_name(sym)); + SET_FLAG(v, checked); + nspc_add_value(env->curr, sym, v); + VVAL(&env->scope->match->map, i) = (vtype)v; + return v; +} + +ANN static Symbol case_op(const Env env, const Exp e, const m_uint i) { + if(e->exp_type == ae_exp_primary) { + if(e->d.exp_primary.primary_type == ae_primary_unpack) + return insert_symbol("@=>"); + else if(e->d.exp_primary.primary_type == ae_primary_id) { + if(e->d.exp_primary.d.var == insert_symbol("_")) + return NULL; + if(!nspc_lookup_value1(env->curr, e->d.exp_primary.d.var)) { + e->d.exp_primary.value = match_value(env, &e->d.exp_primary, i); + return NULL; + } + } + } + return insert_symbol("=="); +} + +ANN static m_bool match_case_exp(const Env env, Exp e) { + for(m_uint i = 0; i < map_size(&env->scope->match->map); e = e->next, ++i) { + const Symbol op = case_op(env, e, i); + if(op) { + const Exp base = (Exp)VKEY(&env->scope->match->map, i); + CHECK_OB(check_exp(env, e)) + Exp_Binary bin = { .lhs=base, .rhs=e, .op=op }; + struct Op_Import opi = { .op=op, .lhs=base->type, .rhs=e->type, .data=(uintptr_t)&bin, .pos=e->pos }; + CHECK_OB(op_check(env, &opi)) + } + } + return GW_OK; +} + +ANN static m_bool _check_stmt_case(const Env env, const Stmt_Match stmt) { + CHECK_BB(match_case_exp(env, stmt->cond)) + if(stmt->when) + CHECK_OB(check_exp(env, stmt->when)) + return check_stmt_list(env, stmt->list); +} + +ANN static m_bool check_stmt_case(const Env env, const Stmt_Match stmt) { + RET_NSPC(_check_stmt_case(env, stmt)) +} + +ANN static m_bool case_loop(const Env env, const Stmt_Match stmt) { + Stmt_List list = stmt->list; + do CHECK_BB(check_stmt_case(env, &list->stmt->d.stmt_match)) + while((list = list->next)); + return GW_OK; +} + +ANN static m_bool check_match(const Env env, const Stmt_Match stmt) { + CHECK_OB(check_exp(env, stmt->cond)) + return case_loop(env, stmt); +} + +ANN static m_bool _check_stmt_match(const Env env, const Stmt_Match stmt) { + if(stmt->where) + CHECK_BB(check_stmt(env, stmt->where)) + MATCH_INI(env->scope) + const m_bool ret = check_match(env, stmt); + MATCH_END(env->scope) + return ret; +} + +ANN static m_bool check_stmt_match(const Env env, const Stmt_Match stmt) { + RET_NSPC(_check_stmt_match(env, stmt)) } static const _exp_func stmt_func[] = { (_exp_func)check_stmt_exp, (_exp_func)check_stmt_flow, (_exp_func)check_stmt_flow, (_exp_func)check_stmt_for, (_exp_func)check_stmt_auto, (_exp_func)check_stmt_loop, - (_exp_func)check_stmt_if, (_exp_func)check_stmt_code, (_exp_func)check_stmt_switch, + (_exp_func)check_stmt_if, (_exp_func)check_stmt_code, (_exp_func)check_stmt_break, (_exp_func)check_stmt_continue, (_exp_func)check_stmt_return, - (_exp_func)check_stmt_case, (_exp_func)check_stmt_jump, + (_exp_func)check_stmt_match, (_exp_func)check_stmt_case, + (_exp_func)check_stmt_jump, }; ANN m_bool check_stmt(const Env env, const Stmt stmt) { diff --git a/src/parse/cpy_ast.c b/src/parse/cpy_ast.c index ef9c993d..6bd29333 100644 --- a/src/parse/cpy_ast.c +++ b/src/parse/cpy_ast.c @@ -310,9 +310,9 @@ ANN static void cpy_stmt_jump(MemPool p NUSED, const Stmt_Jump a,const Stmt_Jump a->name = src->name; } -ANN static void cpy_stmt_switch(MemPool p, Stmt_Switch a, const Stmt_Switch src) { - a->val = cpy_exp(p, src->val); - a->stmt = cpy_stmt(p, src->stmt); +ANN static void cpy_stmt_match(MemPool p, Stmt_Match a, const Stmt_Match src) { + a->cond = cpy_exp(p, src->cond); + a->list = cpy_stmt_list(p, src->list); } ANN static Enum_Def cpy_enum_def(MemPool p, const Enum_Def src) { @@ -372,7 +372,6 @@ ANN static Union_Def cpy_union_def(MemPool p, const Union_Def src) { ANN static Stmt cpy_stmt(MemPool p, const Stmt src) { Stmt a = mp_calloc(p, Stmt); switch(src->stmt_type) { - case ae_stmt_case: case ae_stmt_exp: case ae_stmt_return: cpy_stmt_exp(p, &a->d.stmt_exp, &src->d.stmt_exp); @@ -399,8 +398,9 @@ ANN static Stmt cpy_stmt(MemPool p, const Stmt src) { case ae_stmt_jump: cpy_stmt_jump(p, &a->d.stmt_jump, &src->d.stmt_jump); break; - case ae_stmt_switch: - cpy_stmt_switch(p, &a->d.stmt_switch, &src->d.stmt_switch); + case ae_stmt_match_case: + case ae_stmt_match: + cpy_stmt_match(p, &a->d.stmt_match, &src->d.stmt_match); break; case ae_stmt_break: case ae_stmt_continue: diff --git a/src/parse/scan1.c b/src/parse/scan1.c index 4fa3d3c4..0bb580b4 100644 --- a/src/parse/scan1.c +++ b/src/parse/scan1.c @@ -179,12 +179,31 @@ ANN static inline m_bool scan1_exp_typeof(const restrict Env env, const Exp_Type #define scan1_exp_lambda dummy_func HANDLE_EXP_FUNC(scan1, m_bool, 1) -ANN static inline m_bool scan1_stmt_switch(const restrict Env env, const Stmt_Switch stmt) { - CHECK_BB(scan1_exp(env, stmt->val)) - CHECK_BB(scan1_stmt(env, stmt->stmt)) +ANN static inline m_bool _scan1_stmt_match_case(const restrict Env env, const Stmt_Match stmt) { + CHECK_BB(scan1_exp(env, stmt->cond)) + if(stmt->when) + CHECK_BB(scan1_exp(env, stmt->when)) + return scan1_stmt_list(env, stmt->list); +} + +ANN static inline m_bool scan1_stmt_match_case(const restrict Env env, const Stmt_Match stmt) { + RET_NSPC(_scan1_stmt_match_case(env, stmt)) +} + +ANN static inline m_bool _scan1_stmt_match(const restrict Env env, const Stmt_Match stmt) { + if(stmt->where) + CHECK_BB(scan1_stmt(env, stmt->where)) + Stmt_List list = stmt->list; + do CHECK_BB(scan1_stmt_match_case(env, &list->stmt->d.stmt_match)) + while((list = list->next)); return GW_OK; } +ANN static inline m_bool scan1_stmt_match(const restrict Env env, const Stmt_Match stmt) { + CHECK_BB(scan1_exp(env, stmt->cond)) + RET_NSPC(_scan1_stmt_match(env, stmt)) +} + #define describe_ret_nspc(name, type, prolog, exp) describe_stmt_func(scan1, name, type, prolog, exp) describe_ret_nspc(flow, Stmt_Flow,, !(scan1_exp(env, stmt->cond) < 0 || scan1_stmt(env, stmt->body) < 0) ? 1 : -1) @@ -196,8 +215,6 @@ describe_ret_nspc(auto, Stmt_Auto,, !(scan1_exp(env, stmt->exp) < 0 || scan1_stmt(env, stmt->body) < 0) ? 1 : -1) describe_ret_nspc(loop, Stmt_Loop,, !(scan1_exp(env, stmt->cond) < 0 || scan1_stmt(env, stmt->body) < 0) ? 1 : -1) -//describe_ret_nspc(switch, Stmt_Switch,, !(scan1_exp(env, stmt->val) < 0 || -// scan1_stmt(env, stmt->stmt) < 0) ? 1 : -1) describe_ret_nspc(if, Stmt_If,, !(scan1_exp(env, stmt->cond) < 0 || scan1_stmt(env, stmt->if_body) < 0 || (stmt->else_body && scan1_stmt(env, stmt->else_body) < 0)) ? 1 : -1) @@ -212,10 +229,6 @@ ANN static inline m_bool scan1_stmt_exp(const Env env, const Stmt_Exp stmt) { return stmt->val ? scan1_exp(env, stmt->val) : 1; } -ANN static inline m_bool scan1_stmt_case(const Env env, const Stmt_Exp stmt) { - return scan1_exp(env, stmt->val); -} - ANN m_bool scan1_enum_def(const Env env, const Enum_Def edef) { ID_List list = edef->list; do { @@ -299,9 +312,10 @@ ANN m_bool scan1_union_def(const Env env, const Union_Def udef) { static const _exp_func stmt_func[] = { (_exp_func)scan1_stmt_exp, (_exp_func)scan1_stmt_flow, (_exp_func)scan1_stmt_flow, (_exp_func)scan1_stmt_for, (_exp_func)scan1_stmt_auto, (_exp_func)scan1_stmt_loop, - (_exp_func)scan1_stmt_if, (_exp_func)scan1_stmt_code, (_exp_func)scan1_stmt_switch, + (_exp_func)scan1_stmt_if, (_exp_func)scan1_stmt_code, (_exp_func)dummy_func, (_exp_func)dummy_func, (_exp_func)scan1_stmt_exp, - (_exp_func)scan1_stmt_case, (_exp_func)dummy_func + (_exp_func)scan1_stmt_match, (_exp_func)scan1_stmt_match_case, + (_exp_func)dummy_func }; ANN static inline m_bool scan1_stmt(const Env env, const Stmt stmt) { diff --git a/src/parse/scan2.c b/src/parse/scan2.c index b64bc2bb..c04a6a1f 100644 --- a/src/parse/scan2.c +++ b/src/parse/scan2.c @@ -189,6 +189,31 @@ ANN static inline m_bool scan2_exp_typeof(const restrict Env env, const Exp_Type return scan2_exp(env, exp->exp); } +ANN static inline m_bool _scan2_stmt_match_case(const restrict Env env, const Stmt_Match stmt) { + CHECK_BB(scan2_exp(env, stmt->cond)) + if(stmt->when) + CHECK_BB(scan2_exp(env, stmt->when)) + return scan2_stmt_list(env, stmt->list); +} + +ANN static inline m_bool scan2_stmt_match_case(const restrict Env env, const Stmt_Match stmt) { + RET_NSPC(_scan2_stmt_match_case(env, stmt)) +} + +ANN static inline m_bool _scan2_stmt_match(const restrict Env env, const Stmt_Match stmt) { + if(stmt->where) + CHECK_BB(scan2_stmt(env, stmt->where)) + Stmt_List list = stmt->list; + do CHECK_BB(scan2_stmt_match_case(env, &list->stmt->d.stmt_match)) + while((list = list->next)); + return GW_OK; +} + +ANN static inline m_bool scan2_stmt_match(const restrict Env env, const Stmt_Match stmt) { + CHECK_BB(scan2_exp(env, stmt->cond)) + RET_NSPC(_scan2_stmt_match(env, stmt)) +} + #define scan2_exp_lambda dummy_func HANDLE_EXP_FUNC(scan2, m_bool, 1) @@ -203,8 +228,6 @@ scan2_stmt_func(auto, Stmt_Auto,, !(scan2_exp(env, stmt->exp) < 0 || scan2_stmt(env, stmt->body) < 0) ? 1 : -1) scan2_stmt_func(loop, Stmt_Loop,, !(scan2_exp(env, stmt->cond) < 0 || scan2_stmt(env, stmt->body) < 0) ? 1 : -1) -scan2_stmt_func(switch, Stmt_Switch,, !(scan2_exp(env, stmt->val) < 0 || - scan2_stmt(env, stmt->stmt) < 0) ? 1 : -1) scan2_stmt_func(if, Stmt_If,, !(scan2_exp(env, stmt->cond) < 0 || scan2_stmt(env, stmt->if_body) < 0 || (stmt->else_body && scan2_stmt(env, stmt->else_body) < 0)) ? 1 : -1) @@ -219,10 +242,6 @@ ANN static inline m_bool scan2_stmt_exp(const Env env, const Stmt_Exp stmt) { return stmt->val ? scan2_exp(env, stmt->val) : 1; } -ANN static inline m_bool scan2_stmt_case(const Env env, const Stmt_Exp stmt) { - return scan2_exp(env, stmt->val); -} - __attribute__((returns_nonnull)) ANN static Map scan2_label_map(const Env env) { Map m, label = env_label(env); @@ -262,9 +281,10 @@ ANN m_bool scan2_union_def(const Env env, const Union_Def udef) { static const _exp_func stmt_func[] = { (_exp_func)scan2_stmt_exp, (_exp_func)scan2_stmt_flow, (_exp_func)scan2_stmt_flow, (_exp_func)scan2_stmt_for, (_exp_func)scan2_stmt_auto, (_exp_func)scan2_stmt_loop, - (_exp_func)scan2_stmt_if, (_exp_func)scan2_stmt_code, (_exp_func)scan2_stmt_switch, + (_exp_func)scan2_stmt_if, (_exp_func)scan2_stmt_code, (_exp_func)dummy_func, (_exp_func)dummy_func, (_exp_func)scan2_stmt_exp, - (_exp_func)scan2_stmt_case, (_exp_func)scan2_stmt_jump + (_exp_func)scan2_stmt_match, (_exp_func)scan2_stmt_match, + (_exp_func)scan2_stmt_jump }; ANN static m_bool scan2_stmt(const Env env, const Stmt stmt) { -- 2.43.0