about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-08-05 15:57:56 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-08-05 15:57:56 -0700
commitef49f4c6995281d0fc9caafa30defdd1120e54b3 (patch)
treee13a84947aefe38f90fbfd1c19126dbe83cf2594
parent310308ce45ec458c1038cfcf1c7d037160e7bddb (diff)
downloadmu-ef49f4c6995281d0fc9caafa30defdd1120e54b3.tar.gz
1939 - allow nested tangling
However, you can't have duplicate labels within a single recipe.
-rw-r--r--052tangle.cc79
1 files changed, 49 insertions, 30 deletions
diff --git a/052tangle.cc b/052tangle.cc
index dd317b42..3b0f75df 100644
--- a/052tangle.cc
+++ b/052tangle.cc
@@ -50,30 +50,41 @@ else if (command == "after") {
 :(code)
 void insert_fragments(const recipe_ordinal r) {
   // Copy into a new vector because insertions invalidate iterators.
-  // But this way we can't insert into labels created inside before/after.
   vector<instruction> result;
-  for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
-    const instruction inst = Recipe[r].steps.at(i);
-    if (!inst.is_label) {
-      result.push_back(inst);
-      continue;
-    }
-    if (Before_fragments.find(inst.label) != Before_fragments.end()) {
-//?       cerr << "loading code before " << inst.label << '\n'; //? 1
+  set<string /*label*/> fragments_inserted_this_recipe;
+  long long int fragments_originally_inserted = 0;
+  while (true) {  // repeat passes until convergence (inserted fragments might include more labels)
+    for (long long int i = 0; i < SIZE(Recipe[r].steps); ++i) {
+      const instruction inst = Recipe[r].steps.at(i);
+      if (!inst.is_label) {
+        result.push_back(inst);
+        continue;
+      }
+      if (fragments_inserted_this_recipe.find(inst.label) != fragments_inserted_this_recipe.end()) {
+        // already processed in a previous pass; ignore
+        result.push_back(inst);
+        continue;
+      }
       Fragments_used.insert(inst.label);
-      result.insert(result.end(), Before_fragments[inst.label].steps.begin(), Before_fragments[inst.label].steps.end());
+      fragments_inserted_this_recipe.insert(inst.label);
+      if (Before_fragments.find(inst.label) != Before_fragments.end()) {
+//?         cerr << "loading code before " << inst.label << '\n'; //? 1
+        result.insert(result.end(), Before_fragments[inst.label].steps.begin(), Before_fragments[inst.label].steps.end());
+      }
+      result.push_back(inst);
+      if (After_fragments.find(inst.label) != After_fragments.end()) {
+//?         cerr << "loading code after " << inst.label << '\n'; //? 1
+        result.insert(result.end(), After_fragments[inst.label].steps.begin(), After_fragments[inst.label].steps.end());
+      }
     }
-    result.push_back(inst);
-    if (After_fragments.find(inst.label) != After_fragments.end()) {
-//?       cerr << "loading code after " << inst.label << '\n'; //? 1
-      Fragments_used.insert(inst.label);
-      result.insert(result.end(), After_fragments[inst.label].steps.begin(), After_fragments[inst.label].steps.end());
+    Recipe[r].steps.swap(result);
+    if (fragments_originally_inserted == SIZE(fragments_inserted_this_recipe)) {
+      break;  // converged
     }
+    // not yet converged; prepare next pass
+    result.clear();
+    fragments_originally_inserted = SIZE(fragments_inserted_this_recipe);
   }
-//?   for (long long int i = 0; i < SIZE(result); ++i) { //? 1
-//?     cout << result.at(i).to_string() << '\n'; //? 1
-//?   } //? 1
-  Recipe[r].steps.swap(result);
 }
 
 //: warn about unapplied fragments
@@ -202,24 +213,32 @@ $mem: 6
 
 :(scenario tangle_tangles_into_all_labels_with_same_name)
 recipe main [
-  1:number <- copy 0
+  1:number <- copy 10
   +label1
+  4:number <- copy 10
+  recipe2
+]
+recipe recipe2 [
+  1:number <- copy 11
   +label1
-  4:number <- copy 0
+  4:number <- copy 11
 ]
 before +label1 [
-  2:number <- copy 0
+  2:number <- copy 12
 ]
 after +label1 [
-  3:number <- copy 0
+  3:number <- copy 12
 ]
-+mem: storing 0 in location 1
-+mem: storing 0 in location 2
++mem: storing 10 in location 1
++mem: storing 12 in location 2
 # label1
-+mem: storing 0 in location 3
-+mem: storing 0 in location 2
++mem: storing 12 in location 3
++mem: storing 10 in location 4
+# recipe2
++mem: storing 11 in location 1
++mem: storing 12 in location 2
 # label1
-+mem: storing 0 in location 3
-+mem: storing 0 in location 4
++mem: storing 12 in location 3
++mem: storing 11 in location 4
 # nothing else
-$mem: 6
+$mem: 8