]> Nishi Git Mirror - gwion.git/commitdiff
:art: Initial match commit
authorfennecdjay <astor.jeremie@wanadoo.fr>
Wed, 18 Sep 2019 23:59:16 +0000 (01:59 +0200)
committerfennecdjay <astor.jeremie@wanadoo.fr>
Thu, 19 Sep 2019 00:02:31 +0000 (02:02 +0200)
13 files changed:
include/env.h
include/instr.h
include/match.h [new file with mode: 0644]
include/switch.h [deleted file]
src/emit/emit.c
src/lib/engine.c
src/lib/instr.c
src/oo/env.c
src/oo/switch.c [deleted file]
src/parse/check.c
src/parse/cpy_ast.c
src/parse/scan1.c
src/parse/scan2.c

index d0a1a1a85a3960a6686e9cff5b9b5a6724336553..3bba04b3a4ff69f4e09854ef61a78b759527daac 100644 (file)
@@ -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;
 };
index 1f97a27dc2cf8c4e070ac677eafb6cf88ab35f36..9a545cbe797851197496548ad4f1551f58990386 100644 (file)
@@ -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 (file)
index 0000000..dbdb6a2
--- /dev/null
@@ -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 (file)
index b6080cb..0000000
+++ /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
index ca8dd7b64f6b92f6e047423e58614da4710bd082..ed6808c724451f836e107d97f3c1081403b6da4c 100644 (file)
@@ -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) {
index 4b128d24b97410d992dd48eb9aecad32fdc890fe..03e67e03b2c34290aea095d373e302231bd2cda9 100644 (file)
 #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;
 }
index 634a78685c1ea062fbda0cd6df31beeec5a17beb..0da50fc57453ccfddcd41937d58f32fa7a715888 100644 (file)
@@ -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"
index 5e0532b5d2cce536f571a967d9d9488b354ce4e2..0dda4c35fd928f7f763f60265265fe37f01efe01 100644 (file)
@@ -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 (file)
index 3d8dc38..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-#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;
-}
index fc3fc8f28b3922a922b4ce4653bd4b702a49fdd4..8a488a391e2434f8ae1fe38a28eacb84c2cdbc5f 100644 (file)
@@ -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) {
index ef9c993d676da6f4f71eb9e7174bc0fce5e08f67..6bd293333137b47ac7fa55899cae215474a445a2 100644 (file)
@@ -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:
index 4fa3d3c4fdda9de1e15d32c92c8c4f4371beebf7..0bb580b471c487d28c52a821e0f12dcd975c7751 100644 (file)
@@ -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) {
index b64bc2bbd6aab71fee7f55d4a9ee7b1583725cf7..c04a6a1ff9a2a08b729d1488084ef81f060765cc 100644 (file)
@@ -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) {