Kaynağa Gözat

ncd: Implement backtrack_point::rgo.

Ambroz Bizjak 11 yıl önce
ebeveyn
işleme
f662d54df7
2 değiştirilmiş dosya ile 88 ekleme ve 0 silme
  1. 58 0
      ncd/modules/backtrack.c
  2. 30 0
      ncd/tests/backtracking.ncd

+ 58 - 0
ncd/modules/backtrack.c

@@ -31,6 +31,7 @@
  * Synopsis:
  *   backtrack_point()
  *   backtrack_point::go()
+ *   backtrack_point::rgo()
  * 
  * Description:
  *   The backtrack_point() statement creates a backtrack point, going up immedietely.
@@ -38,12 +39,20 @@
  *   backtrack_point() statement go down and back up at atomically. The go() method
  *   itself goes up immedietely, but side effects of triggering backtracking have
  *   priority.
+ *   The rgo() method triggers backtracking when it deinitializes. In this case,
+ *   the immediate effects of rgo() deinitialization happen before the immediate
+ *   effects of triggering backtracking in the backtrack_point().
  */
 
 #include <ncd/module_common.h>
 
 #include <generated/blog_channel_ncd_backtrack.h>
 
+struct rgo_instance {
+    NCDModuleInst *i;
+    NCDObjRef bp_ref;
+};
+
 static void func_new (void *unused, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
 {
     // check arguments
@@ -82,6 +91,50 @@ fail0:
     NCDModuleInst_Backend_DeadError(i);
 }
 
+static void rgo_func_new (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
+{
+    struct rgo_instance *o = vo;
+    o->i = i;
+    
+    // check arguments
+    if (!NCDVal_ListRead(params->args, 0)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    
+    // get backtrack point
+    NCDModuleInst *backtrack_point_inst = params->method_user;
+    
+    // init object reference to the backtrack_point
+    NCDObject obj = NCDModuleInst_Object(backtrack_point_inst);
+    NCDObjRef_Init(&o->bp_ref, NCDObject_Pobj(&obj));
+    
+    // go up
+    NCDModuleInst_Backend_Up(i);
+    return;
+    
+fail0:
+    NCDModuleInst_Backend_DeadError(i);
+}
+
+static void rgo_func_die (void *vo)
+{
+    struct rgo_instance *o = vo;
+    
+    // toggle backtrack point
+    NCDObject rgo_obj;
+    if (NCDObjRef_Deref(&o->bp_ref, &rgo_obj)) {
+        NCDModuleInst *backtrack_point_inst = NCDObject_MethodUser(&rgo_obj);
+        NCDModuleInst_Backend_DownUp(backtrack_point_inst);
+    }
+    
+    // free object reference
+    NCDObjRef_Free(&o->bp_ref);
+    
+    // die
+    NCDModuleInst_Backend_Dead(o->i);
+}
+
 static struct NCDModule modules[] = {
     {
         .type = "backtrack_point",
@@ -89,6 +142,11 @@ static struct NCDModule modules[] = {
     }, {
         .type = "backtrack_point::go",
         .func_new2 = go_func_new
+    }, {
+        .type = "backtrack_point::rgo",
+        .func_new2 = rgo_func_new,
+        .func_die = rgo_func_die,
+        .alloc_size = sizeof(struct rgo_instance)
     }, {
         .type = NULL
     }

+ 30 - 0
ncd/tests/backtracking.ncd

@@ -27,5 +27,35 @@ process main {
     val_equal(list.length, "100") a;
     assert(a);
     
+    var("true") start;
+    var("false") flag;
+    backtrack_point() point;
+    If (start) {
+        blocker() blk;
+        blk->up();
+        spawn("helper1", {});
+        imperative("<none>", {}, "helper3", {}, "1000");
+        start->set("false");
+        blk->down();
+        if("false");
+    } Else {
+        assert(flag);
+    };
+    
     exit("0");
 }
+
+template helper1 {
+    _caller.blk->use();
+    imperative("<none>", {}, "helper2", {}, "1000");
+    _caller.point->rgo();
+}
+
+template helper2 {
+    _caller._caller.flag->set("true");
+}
+
+template helper3 {
+    val_equal(_caller.flag, "true") a;
+    assert(a);
+}