Эх сурвалжийг харах

ncd: Reverse the immediate effect logic of backtrack_point::rgo().

Turns out we want the backtrack triggering effects to have priority. Consider the following test case.

process main {
    backtrack_point() pointA;
    println("A");
    sleep("1");
    If ("true") {
        backtrack_point() pointB;
        println("B");
        pointA->rgo();
        pointB->go();
    };
}

The result of this would originally have been "A B B B B...". The reason is that the If process would be caught in an infinite loop, and the main process would never get a chance to backtrack past the If statement. With this change, the result is "A B A B...", since the rgo() deinitialization immediately causes backtracking in main.

This is actually a nice example about a design bug regarding the subtle ways in which a process call (If, in this case) is not equivalent to embedding the statements in place. Without the If, there would not be an infinite loop in any case.
Ambroz Bizjak 11 жил өмнө
parent
commit
f20999da62

+ 10 - 5
ncd/modules/backtrack.c

@@ -40,8 +40,8 @@
  *   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().
+ *   the immediate effects of triggering backtracking in the backtrack_point() have
+ *   priority over the immediate effects of rgo() deinitialization completion.
  */
 
 #include <ncd/module_common.h>
@@ -121,11 +121,11 @@ static void rgo_func_die (void *vo)
 {
     struct rgo_instance *o = vo;
     
-    // toggle backtrack point
+    // deref backtrack_point
+    NCDModuleInst *backtrack_point_inst = NULL;
     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);
+        backtrack_point_inst = NCDObject_MethodUser(&rgo_obj);
     }
     
     // free object reference
@@ -133,6 +133,11 @@ static void rgo_func_die (void *vo)
     
     // die
     NCDModuleInst_Backend_Dead(o->i);
+    
+    // toggle backtrack_point
+    if (backtrack_point_inst) {
+        NCDModuleInst_Backend_DownUp(backtrack_point_inst);
+    }
 }
 
 static struct NCDModule modules[] = {

+ 4 - 2
ncd/tests/backtracking.ncd

@@ -52,10 +52,12 @@ template helper1 {
 }
 
 template helper2 {
-    _caller._caller.flag->set("true");
+    val_equal(_caller._caller.flag, "true") a;
+    assert(a);
 }
 
 template helper3 {
-    val_equal(_caller.flag, "true") a;
+    val_equal(_caller.flag, "false") a;
     assert(a);
+    _caller.flag->set("true");
 }