Commit d25872410c724127a1ee74603398a120ec0aba5e

Thomas de Grivel 2023-11-19T15:21:58

map: pattern matching

diff --git a/libc3/env.c b/libc3/env.c
index 5e54ee0..2e9e7d8 100644
--- a/libc3/env.c
+++ b/libc3/env.c
@@ -332,6 +332,8 @@ bool env_eval_equal_list (s_env *env, const s_list *a, const s_list *b,
   s_list *b_next;
   s_list *tmp = NULL;
   s_list **t;
+  assert(env);
+  assert(dest);
   t = &tmp;
   while (1) {
     if (! a && ! b) {
@@ -343,18 +345,21 @@ bool env_eval_equal_list (s_env *env, const s_list *a, const s_list *b,
     if (! b)
       goto ko;
     *t = list_new(NULL, NULL);
-    if (! env_eval_equal_tag(env, &a->tag, &b->tag, &(*t)->tag))
+    if (! env_eval_equal_tag(env, &a->tag, &b->tag,
+                             &(*t)->tag))
       goto ko;
     a_next = list_next(a);
     b_next = list_next(b);
     if (! a_next || ! b_next) {
-      if (! env_eval_equal_tag(env, &a->next, &b->next, &(*t)->next))
+      if (! env_eval_equal_tag(env, &a->next, &b->next,
+                               &(*t)->next))
         goto ko;
       goto ok;
     }
     a = a_next;
     b = b_next;
-    t = &(*t)->next.data.list;
+    if (dest)
+      t = &(*t)->next.data.list;
   }
  ok:
   *dest = tmp;
@@ -364,6 +369,53 @@ bool env_eval_equal_list (s_env *env, const s_list *a, const s_list *b,
   return false;
 }
 
+bool env_eval_equal_map (s_env *env, const s_map *a,
+                         const s_map *b, s_map *dest)
+{
+  const s_map *c;
+  uw i;
+  uw j;
+  s_tag tmp;
+  assert(env);
+  assert(a);
+  assert(b);
+  assert(dest);
+  if (! a->count) {
+    map_copy(b, dest);
+    return true;
+  }
+  if (! b->count) {
+    map_copy(a, dest);
+    return true;
+  }
+  if (a->count > b->count) {
+    c = a;
+    a = b;
+    b = c;
+  }
+  i = 0;
+  while (i < a->count) {
+    j = 0;
+    while (j < b->count) {
+      if (! compare_tag(a->keys + i, b->keys + j)) {
+        if (! env_eval_equal_tag(env, a->values + i, b->values + j,
+                                 &tmp)) {
+          return false;
+        }
+        tag_clean(&tmp);
+        goto next;
+      }
+      j++;
+    }
+    return false;
+  next:
+    i++;
+  }
+  if (dest)
+    map_copy(b, dest);
+  return true;
+}
+
 bool env_eval_equal_tag (s_env *env, const s_tag *a, const s_tag *b,
                          s_tag *dest)
 {
@@ -445,6 +497,10 @@ bool env_eval_equal_tag (s_env *env, const s_tag *a, const s_tag *b,
     tag_init_list(dest, NULL);
     return env_eval_equal_list(env, a->data.list, b->data.list,
                                &dest->data.list);
+  case TAG_MAP:
+    dest->type = TAG_MAP;
+    return env_eval_equal_map(env, &a->data.map, &b->data.map,
+                              &dest->data.map);
   case TAG_TUPLE:
     dest->type = TAG_TUPLE;
     return env_eval_equal_tuple(env, &a->data.tuple, &b->data.tuple,
diff --git a/test/ic3/map.in b/test/ic3/map.in
index d47d159..6eb013e 100644
--- a/test/ic3/map.in
+++ b/test/ic3/map.in
@@ -40,3 +40,13 @@ quote %{a: 1, b: 2, c: 3}
 %{a: 1, b: 2, c: 3}
 quote %{c: 1, b: 2, a: 3}
 %{a: 3, b: 2, c: 1}
+quote %{} = %{a: 1, b: 2}
+%{} = %{a: 1, b: 2}
+quote %{a: a} = %{a: 1, b: 2}
+%{a: a} = %{a: 1, b: 2}
+quote a
+a
+quote %{b: b} = %{a: 1, b: 2}
+%{b: b} = %{a: 1, b: 2}
+quote b
+b
diff --git a/test/ic3/map.out.expected b/test/ic3/map.out.expected
index c769ec2..0cbf8ab 100644
--- a/test/ic3/map.out.expected
+++ b/test/ic3/map.out.expected
@@ -40,3 +40,13 @@
 %{a: 1, b: 2, c: 3}
 %{a: 3, b: 2, c: 1}
 %{a: 3, b: 2, c: 1}
+%{} = %{a: 1, b: 2}
+%{a: 1, b: 2}
+%{a: a} = %{a: 1, b: 2}
+%{a: 1, b: 2}
+a
+1
+%{b: b} = %{a: 1, b: 2}
+%{a: 1, b: 2}
+b
+2