#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;
};
INSTR(DTOR_EOC);
INSTR(DtorReturn);
-/* branching */
-INSTR(SwitchBranch);
-INSTR(SwitchIni);
-INSTR(SwitchEnd);
-
INSTR(ComplexReal);
INSTR(ComplexImag);
--- /dev/null
+#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
+++ /dev/null
-#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
#include "memoize.h"
#include "operator.h"
#include "import.h"
-#include "switch.h"
+#include "match.h"
#include "parser.h"
#include "tuple.h"
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);
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;
}
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) {
#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);
}
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;
}
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"
#include "context.h"
#include "nspc.h"
#include "mpool.h"
-#include "switch.h"
#include "vm.h"
#include "parse.h"
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;
}
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) {
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);
+++ /dev/null
-#include <stdlib.h>
-#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;
-}
#include "import.h"
#include "parse.h"
#include "nspc.h"
-#include "switch.h"
+#include "match.h"
#include "cpy_ast.h"
#include "tuple.h"
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
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) {
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;
}
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) {
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) {
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);
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:
#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)
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)
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 {
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) {
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)
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)
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);
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) {