Procházet zdrojové kódy

ncd: modules: value: add value::replace_this() and value::replace_this_undo()

ambrop7 před 13 roky
rodič
revize
0e2f69fcf0
3 změnil soubory, kde provedl 193 přidání a 0 odebrání
  1. 4 0
      ChangeLog
  2. 133 0
      ncd/modules/value.c
  3. 56 0
      ncd/tests/value.ncd

+ 4 - 0
ChangeLog

@@ -1,3 +1,7 @@
+- NCD: add value::replace_this() and value::replace_this_undo()
+
+- NCD: add value::replace() and value::replace_undo()
+
 - Port to compile with MSVC for Windows.
 
 - NCD: add Foreach clause

+ 133 - 0
ncd/modules/value.c

@@ -35,8 +35,10 @@
  *   value value::getpath(list path)
  *   value value::insert(where, what)
  *   value value::replace(where, what)
+ *   value value::replace_this(value)
  *   value value::insert_undo(where, what)
  *   value value::replace_undo(where, what)
+ *   value value::replace_this_undo(value)
  * 
  * Description:
  *   Value objects allow examining and manipulating values.
@@ -1259,6 +1261,123 @@ static void func_new_replace_undo (void *vo, NCDModuleInst *i)
     func_new_insert_replace_undo_common(vo, i, 1);
 }
 
+static void func_new_replace_this (void *vo, NCDModuleInst *i)
+{
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    
+    struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
+    struct value *mov = valref_val(&mo->ref);
+    
+    if (!mov) {
+        ModuleLog(i, BLOG_ERROR, "value was deleted");
+        goto fail0;
+    }
+    
+    struct value *v = value_init_fromvalue(i, value_arg);
+    if (!v) {
+        goto fail0;
+    }
+    
+    if (mov->parent) {
+        struct value *parent = mov->parent;
+        
+        switch (parent->type) {
+            case NCDVAL_LIST: {
+                size_t index = value_list_indexof(parent, mov);
+                value_list_remove(parent, mov);
+                int res = value_list_insert(i, parent, v, index);
+                ASSERT(res)
+            } break;
+            
+            case NCDVAL_MAP: {
+                NCDValMem key_mem;
+                NCDValSafeRef key;
+                value_map_remove2(parent, mov, &key_mem, &key);
+                int res = value_map_insert(parent, v, key_mem, key, i);
+                ASSERT(res)
+            } break;
+            
+            default: ASSERT(0);
+        }
+        
+        value_cleanup(mov);
+    }
+    
+    func_new_common(vo, i, v, NULL, NULL);
+    return;
+    
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Dead(i);
+}
+
+static void func_new_replace_this_undo (void *vo, NCDModuleInst *i)
+{
+    NCDValRef value_arg;
+    if (!NCDVal_ListRead(i->args, 1, &value_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    
+    struct instance *mo = NCDModuleInst_Backend_GetUser((NCDModuleInst *)i->method_user);
+    struct value *mov = valref_val(&mo->ref);
+    
+    if (!mov) {
+        ModuleLog(i, BLOG_ERROR, "value was deleted");
+        goto fail0;
+    }
+    
+    struct value *v = value_init_fromvalue(i, value_arg);
+    if (!v) {
+        goto fail0;
+    }
+    
+    struct insert_undo_deinit_data *data = malloc(sizeof(*data));
+    if (!data) {
+        ModuleLog(i, BLOG_ERROR, "malloc failed");
+        goto fail1;
+    }
+    
+    valref_init(&data->val_ref, v);
+    valref_init(&data->oldval_ref, mov);
+    
+    if (mov->parent) {
+        struct value *parent = mov->parent;
+        
+        switch (parent->type) {
+            case NCDVAL_LIST: {
+                size_t index = value_list_indexof(parent, mov);
+                value_list_remove(parent, mov);
+                int res = value_list_insert(i, parent, v, index);
+                ASSERT(res)
+            } break;
+            
+            case NCDVAL_MAP: {
+                NCDValMem key_mem;
+                NCDValSafeRef key;
+                value_map_remove2(parent, mov, &key_mem, &key);
+                int res = value_map_insert(parent, v, key_mem, key, i);
+                ASSERT(res)
+            } break;
+            
+            default: ASSERT(0);
+        }
+    }
+    
+    func_new_common(vo, i, v, (value_deinit_func)undo_deinit_func, data);
+    return;
+    
+fail1:
+    value_cleanup(v);
+fail0:
+    NCDModuleInst_Backend_SetError(i);
+    NCDModuleInst_Backend_Dead(i);
+}
+
 static void func_new_substr (void *vo, NCDModuleInst *i)
 {
     NCDValRef start_arg;
@@ -1452,6 +1571,13 @@ static const struct NCDModule modules[] = {
         .func_die = func_die,
         .func_getvar = func_getvar,
         .alloc_size = sizeof(struct instance)
+    }, {
+        .type = "value::replace_this",
+        .base_type = "value",
+        .func_new2 = func_new_replace_this,
+        .func_die = func_die,
+        .func_getvar = func_getvar,
+        .alloc_size = sizeof(struct instance)
     }, {
         .type = "value::insert_undo",
         .base_type = "value",
@@ -1466,6 +1592,13 @@ static const struct NCDModule modules[] = {
         .func_die = func_die,
         .func_getvar = func_getvar,
         .alloc_size = sizeof(struct instance)
+    }, {
+        .type = "value::replace_this_undo",
+        .base_type = "value",
+        .func_new2 = func_new_replace_this_undo,
+        .func_die = func_die,
+        .func_getvar = func_getvar,
+        .alloc_size = sizeof(struct instance)
     }, {
         .type = "value::remove",
         .func_new = remove_func_new

+ 56 - 0
ncd/tests/value.ncd

@@ -121,6 +121,52 @@ process main {
     val_equal(vb, "B") a;
     assert(a);
 
+    value({"a", "b", "c"}) v;
+    v->get("1") vb;
+    vb->replace_this("B") vB;
+    val_equal(vb, "b") a;
+    assert(a);
+    val_equal(vB, "B") a;
+    assert(a);
+    v->get("1") vB2;
+    val_equal(vB2, "B") a;
+    assert(a);
+
+    value(["a":"va", "b":"vb", "c":"vc"]) v;
+    v->get("b") vb;
+    vb->replace_this("vB") vB;
+    val_equal(vB, "vB") a;
+    assert(a);
+    val_equal(vb, "vb") a;
+    assert(a);
+    v->get("b") vB2;
+    val_equal(vB2, "vB") a;
+    assert(a);
+
+    value({"a", "b", "c"}) v;
+    v->get("1") vb;
+    imperative("<none>", {}, "check3", {}, "10000");
+    vb->replace_this_undo("B") vB;
+    val_equal(vb, "b") a;
+    assert(a);
+    val_equal(vB, "B") a;
+    assert(a);
+    v->get("1") vB2;
+    val_equal(vB2, "B") a;
+    assert(a);
+
+    value(["a":"va", "b":"vb", "c":"vc"]) v;
+    v->get("b") vb;
+    imperative("<none>", {}, "check4", {}, "10000");
+    vb->replace_this_undo("vB") vB;
+    val_equal(vB, "vB") a;
+    assert(a);
+    val_equal(vb, "vb") a;
+    assert(a);
+    v->get("b") vB2;
+    val_equal(vB2, "vB") a;
+    assert(a);
+
     println("succeeded");
     exit("0");
 }
@@ -134,3 +180,13 @@ template check2 {
     val_equal(_caller.v, {"a", "b", "c"}) a;
     assert(a);
 }
+
+template check3 {
+    val_equal(_caller.v, {"a", "b", "c"}) a;
+    assert(a);
+}
+
+template check4 {
+    val_equal(_caller.v, ["a":"va", "b":"vb", "c":"vc"]) a;
+    assert(a);
+}