Commit 242b5c07ebf8642a2fb90ef8d6aba29ae782e3b9

Thomas de Grivel 2024-08-02T15:04:32

frame_replace

diff --git a/libkc3/env.c b/libkc3/env.c
index de4c878..2364634 100644
--- a/libkc3/env.c
+++ b/libkc3/env.c
@@ -998,7 +998,7 @@ bool env_eval_equal_tag (s_env *env, bool macro, const s_tag *a,
       tag_init_copy(dest, b);
     else
       env_eval_tag(env, b, dest);
-    frame_binding_new_copy(env->frame->next, a->data.ident.sym, dest);
+    frame_replace(env->frame->next, a->data.ident.sym, dest);
     return true;
   }
   if (is_unbound_b) {
@@ -1006,7 +1006,7 @@ bool env_eval_equal_tag (s_env *env, bool macro, const s_tag *a,
       tag_init_copy(dest, a);
     else
       env_eval_tag(env, a, dest);
-    frame_binding_new_copy(env->frame->next, b->data.ident.sym, dest);
+    frame_replace(env->frame->next, b->data.ident.sym, dest);
     return true;
   }
   if (! macro &&
@@ -2169,8 +2169,9 @@ s_tag * env_let (s_env *env, const s_tag *tag, const s_block *block,
       assert(! "env_let: binding key is not a symbol");
       return NULL;
     }
-    if (! frame_binding_new_copy(env->frame, map->key[i].data.sym,
-                            map->value + i)) {
+    if (! frame_binding_new_copy(env->frame,
+                                 map->key[i].data.sym,
+                                 map->value + i)) {
       tag_clean(&tmp);
       return NULL;
     }
diff --git a/libkc3/frame.c b/libkc3/frame.c
index 7da3b5f..373a6ea 100644
--- a/libkc3/frame.c
+++ b/libkc3/frame.c
@@ -27,7 +27,8 @@ s_tag * frame_binding_new (s_frame *frame, const s_sym *name)
   return &b->value;
 }
 
-s_frame * frame_binding_new_copy (s_frame *frame, const s_sym *name, const s_tag *value)
+s_frame * frame_binding_new_copy (s_frame *frame, const s_sym *name,
+                                  const s_tag *value)
 {
   s_tag *tag;
   frame_binding_new(frame, name);
@@ -54,6 +55,36 @@ s_frame * frame_binding_delete (s_frame *frame, const s_sym *name)
   return frame;
 }
 
+s_frame * frame_binding_replace (s_frame *frame, const s_sym *name,
+                                 const s_tag *value)
+{
+  s_tag *tag;
+  tag = binding_get_w(frame->bindings, name);
+  if (tag) {
+    tag_clean(tag);
+    if (! tag_init_copy(tag, value)) {
+      err_puts("frame_binding_new_copy: tag_init_copy 1");
+      assert(! "frame_binding_new_copy: tag_init_copy 1");
+      return NULL;
+    }
+    return frame;
+  }
+  frame_binding_new(frame, name);
+  tag = binding_get_w(frame->bindings, name);
+  if (! tag) {
+    err_puts("frame_binding_new_copy: binding new");
+    assert(! "frame_binding_new_copy: binding new");
+    return NULL;
+  }
+  if (! tag_init_copy(tag, value)) {
+    err_puts("frame_binding_new_copy: tag_init_copy 2");
+    assert(! "frame_binding_new_copy: tag_init_copy 2");
+    frame = frame_binding_delete(frame, name);
+    return NULL;
+  }
+  return frame;
+}
+
 s_frame * frame_clean (s_frame *frame)
 {
   s_frame *next;
@@ -132,3 +163,22 @@ s_frame * frame_new (s_frame *next)
   }
   return frame;
 }
+
+s_frame * frame_replace (s_frame *frame, const s_sym *sym,
+                         const s_tag *value)
+{
+  s_frame *f;
+  s_tag *result;
+  assert(sym);
+  f = frame;
+  while (f) {
+    result = binding_get_w(f->bindings, sym);
+    if (result) {
+      tag_clean(result);
+      tag_init_copy(result, value);
+      return frame;
+    }
+    f = f->next;
+  }
+  return frame_binding_new_copy(frame, sym, value);
+}
diff --git a/libkc3/frame.h b/libkc3/frame.h
index 9702c0f..5a97cac 100644
--- a/libkc3/frame.h
+++ b/libkc3/frame.h
@@ -28,9 +28,14 @@ void      frame_delete_all (s_frame *frame);
 
 /* Operators. */
 s_tag *   frame_binding_new (s_frame *frame, const s_sym *name);
-s_frame * frame_binding_new_copy (s_frame *frame, const s_sym *name, const s_tag *value);
+s_frame * frame_binding_new_copy (s_frame *frame, const s_sym *name,
+                                  const s_tag *value);
 s_frame * frame_binding_delete (s_frame *frame, const s_sym *name);
+s_frame * frame_binding_replace (s_frame *frame, const s_sym *name,
+                                 const s_tag *value);
 s_tag *   frame_get_w (s_frame *frame, const s_sym *sym);
+s_frame * frame_replace (s_frame *frame, const s_sym *sym,
+                         const s_tag *value);
 
 /* Observers. */
 const s_tag * frame_get (const s_frame *frame, const s_sym *sym);