about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-04-14 19:06:57 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-04-14 19:08:38 -0700
commit82ac0b7ecbc145ed8c8ecd8309166f654af1ee75 (patch)
treefb24d253bec1b3a24bf9d3e6d746111dbf4b856f
parent0edf822f996c5def4588cc207d1977cffc3e9a0c (diff)
downloadmu-82ac0b7ecbc145ed8c8ecd8309166f654af1ee75.tar.gz
1063 - variable names for surrounding spaces now work
This was a pain to debug.
-rw-r--r--cpp/.traces/closure120
-rw-r--r--cpp/.traces/convert_names_warns1
-rw-r--r--cpp/.traces/new2
-rw-r--r--cpp/.traces/new_array2
-rw-r--r--cpp/.traces/string-equal-common-lengths-but-distinct2
-rw-r--r--cpp/.traces/string-equal-distinct-lengths2
-rw-r--r--cpp/.traces/string-equal-identical2
-rw-r--r--cpp/.traces/string-equal-reflexive2
-rw-r--r--cpp/.traces/string-equal-with-empty2
-rw-r--r--cpp/.traces/surrounding_space3
-rw-r--r--cpp/010vm4
-rw-r--r--cpp/013run1
-rw-r--r--cpp/023call_reply1
-rw-r--r--cpp/025name18
-rw-r--r--cpp/026new1
-rw-r--r--cpp/027space9
-rw-r--r--cpp/028space_surround20
-rw-r--r--cpp/036closure_name142
-rw-r--r--cpp/090debug2
-rw-r--r--mu.arc12
20 files changed, 326 insertions, 22 deletions
diff --git a/cpp/.traces/closure b/cpp/.traces/closure
new file mode 100644
index 00000000..152df47e
--- /dev/null
+++ b/cpp/.traces/closure
@@ -0,0 +1,120 @@
+parse/0: instruction: 30
+parse/0:   ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]}
+parse/0:   ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]}
+parse/0:   product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]}
+parse/0: instruction: 1001
+parse/0:   product: {name: "1", value: 0, type: 2-0, properties: ["1": "address":"space", "names": "init-counter"]}
+parse/0: instruction: 1002
+parse/0:   ingredient: {name: "1", value: 0, type: 2-0, properties: ["1": "address":"space", "names": "init-counter"]}
+parse/0:   product: {name: "2", value: 0, type: 1, properties: ["2": "integer", "raw": ]}
+parse/0: instruction: 1002
+parse/0:   ingredient: {name: "1", value: 0, type: 2-0, properties: ["1": "address":"space", "names": "init-counter"]}
+parse/0:   product: {name: "3", value: 0, type: 1, properties: ["3": "integer", "raw": ]}
+parse/0: instruction: 30
+parse/0:   ingredient: {name: "location", value: 0, type: 0, properties: ["location": "type"]}
+parse/0:   ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]}
+parse/0:   product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]}
+parse/0: instruction: 1
+parse/0:   ingredient: {name: "23", value: 0, type: 0, properties: ["23": "literal"]}
+parse/0:   product: {name: "x", value: 0, type: 1, properties: ["x": "integer"]}
+parse/0: instruction: 1
+parse/0:   ingredient: {name: "3", value: 0, type: 0, properties: ["3": "literal"]}
+parse/0:   product: {name: "y", value: 0, type: 1, properties: ["y": "integer"]}
+parse/0: instruction: 23
+parse/0:   ingredient: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]}
+parse/0: instruction: 30
+parse/0:   ingredient: {name: "space", value: 0, type: 0, properties: ["space": "literal"]}
+parse/0:   ingredient: {name: "30", value: 0, type: 0, properties: ["30": "literal"]}
+parse/0:   product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]}
+parse/0: instruction: 22
+parse/0:   product: {name: "0", value: 0, type: 2-0, properties: ["0": "address":"space", "names": "init-counter"]}
+parse/0: instruction: 2
+parse/0:   ingredient: {name: "y", value: 0, type: 1, properties: ["y": "integer", "space": "1"]}
+parse/0:   ingredient: {name: "1", value: 0, type: 0, properties: ["1": "literal"]}
+parse/0:   product: {name: "y", value: 0, type: 1, properties: ["y": "integer", "space": "1"]}
+parse/0: instruction: 1
+parse/0:   ingredient: {name: "234", value: 0, type: 0, properties: ["234": "literal"]}
+parse/0:   product: {name: "y", value: 0, type: 1, properties: ["y": "integer"]}
+parse/0: instruction: 23
+parse/0:   ingredient: {name: "y", value: 0, type: 1, properties: ["y": "integer", "space": "1"]}
+name/0: recipe increment-counter is surrounded by init-counter
+new/0: location -> 1
+name/0: assign x 1
+name/0: assign y 2
+new/0: space -> 0
+name/0: assign y 1
+new/0: location -> 1
+after-brace/0: recipe init-counter
+after-brace/0: new ...
+after-brace/0: copy ...
+after-brace/0: copy ...
+after-brace/0: reply ...
+after-brace/0: recipe increment-counter
+after-brace/0: new ...
+after-brace/0: next-ingredient ...
+after-brace/0: add ...
+after-brace/0: copy ...
+after-brace/0: reply ...
+after-brace/0: recipe main
+after-brace/0: new ...
+after-brace/0: init-counter ...
+after-brace/0: increment-counter ...
+after-brace/0: increment-counter ...
+run/0: instruction main/0
+mem/0: new alloc: 1000
+mem/0: array size is 30
+run/0: instruction main/1
+run/0: instruction init-counter/0
+mem/0: new alloc: 1030
+mem/0: array size is 30
+run/0: instruction init-counter/1
+run/0: ingredient 0 is 23
+mem/0: storing 23 in location 1032
+run/0: instruction init-counter/2
+run/0: ingredient 0 is 3
+mem/0: storing 3 in location 1033
+run/0: instruction init-counter/3
+run/0: result 0 is 1030
+mem/0: storing 1030 in location 1002
+run/0: instruction main/2
+mem/0: location 1002 is 1030
+run/0: instruction increment-counter/0
+mem/0: new alloc: 1060
+mem/0: array size is 30
+run/0: instruction increment-counter/1
+run/0: product 0 is 1030
+mem/0: storing 1030 in location 1061
+run/0: instruction increment-counter/2
+run/0: ingredient 0 is y
+mem/0: location 1033 is 3
+run/0: ingredient 1 is 1
+run/0: product 0 is 4
+mem/0: storing 4 in location 1033
+run/0: instruction increment-counter/3
+run/0: ingredient 0 is 234
+mem/0: storing 234 in location 1062
+run/0: instruction increment-counter/4
+mem/0: location 1033 is 4
+run/0: result 0 is 4
+mem/0: storing 4 in location 2
+run/0: instruction main/3
+mem/0: location 1002 is 1030
+run/0: instruction increment-counter/0
+mem/0: new alloc: 1090
+mem/0: array size is 30
+run/0: instruction increment-counter/1
+run/0: product 0 is 1030
+mem/0: storing 1030 in location 1091
+run/0: instruction increment-counter/2
+run/0: ingredient 0 is y
+mem/0: location 1033 is 4
+run/0: ingredient 1 is 1
+run/0: product 0 is 5
+mem/0: storing 5 in location 1033
+run/0: instruction increment-counter/3
+run/0: ingredient 0 is 234
+mem/0: storing 234 in location 1092
+run/0: instruction increment-counter/4
+mem/0: location 1033 is 5
+run/0: result 0 is 5
+mem/0: storing 5 in location 3
diff --git a/cpp/.traces/convert_names_warns b/cpp/.traces/convert_names_warns
index 837f83df..11614845 100644
--- a/cpp/.traces/convert_names_warns
+++ b/cpp/.traces/convert_names_warns
@@ -2,6 +2,7 @@ parse/0: instruction: 1
 parse/0:   ingredient: {name: "y", value: 0, type: 1, properties: ["y": "integer"]}
 parse/0:   product: {name: "x", value: 0, type: 1, properties: ["x": "integer"]}
 warn/0: use before set: y in main
+warn/0: name not found: y
 name/0: assign x 1
 after-brace/0: recipe main
 after-brace/0: copy ...
diff --git a/cpp/.traces/new b/cpp/.traces/new
index e9be5862..4c3d8001 100644
--- a/cpp/.traces/new
+++ b/cpp/.traces/new
@@ -15,8 +15,10 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: equal ...
 run/0: instruction main/0
+mem/0: new alloc: 1000
 mem/0: storing 1000 in location 1
 run/0: instruction main/1
+mem/0: new alloc: 1001
 mem/0: storing 1001 in location 2
 run/0: instruction main/2
 run/0: ingredient 0 is 1
diff --git a/cpp/.traces/new_array b/cpp/.traces/new_array
index 8a44bcf8..d2e846bb 100644
--- a/cpp/.traces/new_array
+++ b/cpp/.traces/new_array
@@ -16,9 +16,11 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: subtract ...
 run/0: instruction main/0
+mem/0: new alloc: 1000
 mem/0: storing 1000 in location 1
 mem/0: array size is 5
 run/0: instruction main/1
+mem/0: new alloc: 1005
 mem/0: storing 1005 in location 2
 run/0: instruction main/2
 run/0: ingredient 0 is 2
diff --git a/cpp/.traces/string-equal-common-lengths-but-distinct b/cpp/.traces/string-equal-common-lengths-but-distinct
index 58112874..e5e99282 100644
--- a/cpp/.traces/string-equal-common-lengths-but-distinct
+++ b/cpp/.traces/string-equal-common-lengths-but-distinct
@@ -23,6 +23,7 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: string-equal ...
 run/0: instruction test-string-equal-common-lengths-but-distinct/0
+mem/0: new alloc: 1000
 mem/0: array size is 30
 run/0: instruction test-string-equal-common-lengths-but-distinct/1
 mem/0: storing 1030 in location 1002
@@ -32,6 +33,7 @@ run/0: instruction test-string-equal-common-lengths-but-distinct/3
 mem/0: location 1002 is 1030
 mem/0: location 1003 is 1034
 run/0: instruction string-equal/0
+mem/0: new alloc: 1038
 mem/0: array size is 30
 run/0: instruction string-equal/1
 run/0: product 0 is 1030
diff --git a/cpp/.traces/string-equal-distinct-lengths b/cpp/.traces/string-equal-distinct-lengths
index 6008eaf4..4af8113c 100644
--- a/cpp/.traces/string-equal-distinct-lengths
+++ b/cpp/.traces/string-equal-distinct-lengths
@@ -23,6 +23,7 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: string-equal ...
 run/0: instruction test-string-equal-distinct-lengths/0
+mem/0: new alloc: 1000
 mem/0: array size is 30
 run/0: instruction test-string-equal-distinct-lengths/1
 mem/0: storing 1030 in location 1002
@@ -32,6 +33,7 @@ run/0: instruction test-string-equal-distinct-lengths/3
 mem/0: location 1002 is 1030
 mem/0: location 1003 is 1034
 run/0: instruction string-equal/0
+mem/0: new alloc: 1039
 mem/0: array size is 30
 run/0: instruction string-equal/1
 run/0: product 0 is 1030
diff --git a/cpp/.traces/string-equal-identical b/cpp/.traces/string-equal-identical
index ad2db713..7d25443e 100644
--- a/cpp/.traces/string-equal-identical
+++ b/cpp/.traces/string-equal-identical
@@ -23,6 +23,7 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: string-equal ...
 run/0: instruction test-string-equal-identical/0
+mem/0: new alloc: 1000
 mem/0: array size is 30
 run/0: instruction test-string-equal-identical/1
 mem/0: storing 1030 in location 1002
@@ -32,6 +33,7 @@ run/0: instruction test-string-equal-identical/3
 mem/0: location 1002 is 1030
 mem/0: location 1003 is 1034
 run/0: instruction string-equal/0
+mem/0: new alloc: 1038
 mem/0: array size is 30
 run/0: instruction string-equal/1
 run/0: product 0 is 1030
diff --git a/cpp/.traces/string-equal-reflexive b/cpp/.traces/string-equal-reflexive
index be1548bb..ab94aa39 100644
--- a/cpp/.traces/string-equal-reflexive
+++ b/cpp/.traces/string-equal-reflexive
@@ -17,6 +17,7 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: string-equal ...
 run/0: instruction test-string-equal-reflexive/0
+mem/0: new alloc: 1000
 mem/0: array size is 30
 run/0: instruction test-string-equal-reflexive/1
 mem/0: storing 1030 in location 1002
@@ -24,6 +25,7 @@ run/0: instruction test-string-equal-reflexive/2
 mem/0: location 1002 is 1030
 mem/0: location 1002 is 1030
 run/0: instruction string-equal/0
+mem/0: new alloc: 1034
 mem/0: array size is 30
 run/0: instruction string-equal/1
 run/0: product 0 is 1030
diff --git a/cpp/.traces/string-equal-with-empty b/cpp/.traces/string-equal-with-empty
index 13f64aac..22a9d4a9 100644
--- a/cpp/.traces/string-equal-with-empty
+++ b/cpp/.traces/string-equal-with-empty
@@ -23,6 +23,7 @@ after-brace/0: new ...
 after-brace/0: new ...
 after-brace/0: string-equal ...
 run/0: instruction test-string-equal-with-empty/0
+mem/0: new alloc: 1000
 mem/0: array size is 30
 run/0: instruction test-string-equal-with-empty/1
 mem/0: storing 1030 in location 1002
@@ -32,6 +33,7 @@ run/0: instruction test-string-equal-with-empty/3
 mem/0: location 1002 is 1030
 mem/0: location 1003 is 1031
 run/0: instruction string-equal/0
+mem/0: new alloc: 1036
 mem/0: array size is 30
 run/0: instruction string-equal/1
 run/0: product 0 is 1030
diff --git a/cpp/.traces/surrounding_space b/cpp/.traces/surrounding_space
index 0f1371d5..f4bc55fe 100644
--- a/cpp/.traces/surrounding_space
+++ b/cpp/.traces/surrounding_space
@@ -9,13 +9,14 @@ parse/0:   ingredient: {name: "10", value: 0, type: 0, properties: ["10": "liter
 parse/0:   product: {name: "default-space", value: 0, type: 2-0, properties: ["default-space": "address":"space"]}
 parse/0: instruction: 1
 parse/0:   ingredient: {name: "20", value: 0, type: 0, properties: ["20": "literal"]}
-parse/0:   product: {name: "0", value: 0, type: 2-0, properties: ["0": "address":"space"]}
+parse/0:   product: {name: "0", value: 0, type: 2-0, properties: ["0": "address":"space", "names": "dummy"]}
 parse/0: instruction: 1
 parse/0:   ingredient: {name: "32", value: 0, type: 0, properties: ["32": "literal"]}
 parse/0:   product: {name: "1", value: 0, type: 1, properties: ["1": "integer"]}
 parse/0: instruction: 1
 parse/0:   ingredient: {name: "33", value: 0, type: 0, properties: ["33": "literal"]}
 parse/0:   product: {name: "1", value: 0, type: 1, properties: ["1": "integer", "space": "1"]}
+name/0: recipe main is surrounded by dummy
 after-brace/0: recipe main
 after-brace/0: copy ...
 after-brace/0: copy ...
diff --git a/cpp/010vm b/cpp/010vm
index 54fc8906..2c230c10 100644
--- a/cpp/010vm
+++ b/cpp/010vm
@@ -46,7 +46,7 @@ struct reagent {
   reagent(string s);
   reagent();
   void set_value(int v) { value = v; initialized = true; }
-  string to_string();
+  string to_string() const;
 };
 
 :(before "struct reagent")
@@ -192,7 +192,7 @@ Next_recipe_number = 1000;  // consistent new numbers for each test
     // assigned to.
     properties.push_back(pair<string, vector<string> >("", vector<string>()));
   }
-  string reagent::to_string() {
+  string reagent::to_string() const {
     ostringstream out;
     out << "{name: \"" << name << "\", value: " << value << ", type: ";
     for (size_t i = 0; i < types.size(); ++i) {
diff --git a/cpp/013run b/cpp/013run
index 1606a82d..91e242a7 100644
--- a/cpp/013run
+++ b/cpp/013run
@@ -44,6 +44,7 @@ void run(routine rr) {
 //?     cout << "AAA " << Trace_stream << " ^" << Trace_stream->dump_layer << "$\n"; //? 1
     trace("run") << "instruction " << recipe_name(rr) << '/' << pc;
 //?     cout << "operation " << instructions[pc].operation << '\n'; //? 3
+//?     if (!instructions[pc].products.empty()) trace("foo") << "AAA product 0 is " << instructions[pc].products[0].to_string(); //? 1
     switch (instructions[pc].operation) {
       // Primitive Recipe Implementations
       case COPY: {
diff --git a/cpp/023call_reply b/cpp/023call_reply
index 476875ab..4c9fe34c 100644
--- a/cpp/023call_reply
+++ b/cpp/023call_reply
@@ -27,6 +27,7 @@ case REPLY: {
     callee_results.push_back(read_memory(instructions[pc].ingredients[i]));
   }
   rr.calls.pop();
+  assert(!rr.calls.empty());
   size_t& caller_pc = rr.calls.top().pc;
   instruction& caller_instruction = Recipe[rr.calls.top().running_recipe].steps[caller_pc];
   assert(caller_instruction.products.size() <= callee_results.size());
diff --git a/cpp/025name b/cpp/025name
index 81ab0cc9..45fdece2 100644
--- a/cpp/025name
+++ b/cpp/025name
@@ -40,6 +40,7 @@ void transform_names(const recipe_number r) {
     // Per-recipe Transforms
     // map names to addresses
     for (size_t in = 0; in < inst.ingredients.size(); ++in) {
+//?       cout << "ingredients\n"; //? 1
       if (is_raw(inst.ingredients[in])) continue;
 //?       cout << "ingredient " << inst.ingredients[in].name << '\n'; //? 1
       if (inst.ingredients[in].name == "default-space")
@@ -47,13 +48,15 @@ void transform_names(const recipe_number r) {
       if (inst.ingredients[in].types[0]  // not a literal
           && !inst.ingredients[in].initialized
           && inst.ingredients[in].name.find_first_not_of("0123456789-.") != string::npos) {
-        if (names.find(inst.ingredients[in].name) == names.end()) {
+        if (!already_transformed(inst.ingredients[in], names)) {
           raise << "use before set: " << inst.ingredients[in].name << " in " << Recipe[r].name << '\n';
         }
-        inst.ingredients[in].set_value(names[inst.ingredients[in].name]);
+        inst.ingredients[in].set_value(lookup_name(inst.ingredients[in], r));
+//?         cout << "lookup ingredient " << Recipe[r].name << "/" << i << ": " << inst.ingredients[in].to_string() << '\n'; //? 1
       }
     }
     for (size_t out = 0; out < inst.products.size(); ++out) {
+//?       cout << "products\n"; //? 1
       if (is_raw(inst.products[out])) continue;
 //?       cout << "product " << out << '/' << inst.products.size() << " " << inst.products[out].name << '\n'; //? 4
 //?       cout << inst.products[out].types[0] << '\n'; //? 1
@@ -67,12 +70,21 @@ void transform_names(const recipe_number r) {
           names[inst.products[out].name] = curr_idx;
           curr_idx += size_of(inst.products[out]);
         }
-        inst.products[out].set_value(names[inst.products[out].name]);
+        inst.products[out].set_value(lookup_name(inst.products[out], r));
+//?         cout << "lookup product " << Recipe[r].name << "/" << i << ": " << inst.products[out].to_string() << '\n'; //? 1
       }
     }
   }
 }
 
+bool already_transformed(const reagent& r, const unordered_map<string, int>& names) {
+  return names.find(r.name) != names.end();
+}
+
+size_t lookup_name(const reagent& r, const recipe_number default_recipe) {
+  return Name[default_recipe][r.name];
+}
+
 type_number skip_addresses(const vector<type_number>& types) {
   for (size_t i = 0; i < types.size(); ++i) {
     if (types[i] != Type_number["address"]) return types[i];
diff --git a/cpp/026new b/cpp/026new
index 02196c49..e75d4148 100644
--- a/cpp/026new
+++ b/cpp/026new
@@ -45,6 +45,7 @@ Next_recipe_number++;
 :(before "End Primitive Recipe Implementations")
 case NEW: {
   vector<int> result;
+  trace("mem") << "new alloc: " << Current_routine->alloc;
   result.push_back(Current_routine->alloc);
   write_memory(instructions[pc].products[0], result);
   vector<int> types;
diff --git a/cpp/027space b/cpp/027space
index 2a845015..1bb91b8e 100644
--- a/cpp/027space
+++ b/cpp/027space
@@ -35,13 +35,15 @@ call(recipe_number r) :running_recipe(r), pc(0), next_ingredient_to_process(0),
 reagent r = absolutize(x);
 :(code)
 reagent absolutize(reagent x) {
-//?   cout << "absolutize " << x.to_string() << '\n'; //? 2
+//?   if (Recipe_number.find("increment-counter") != Recipe_number.end()) //? 1
+//?     cout << "AAA " << "increment-counter/2: " << Recipe[Recipe_number["increment-counter"]].steps[2].products[0].to_string() << '\n'; //? 1
+//?   cout << "absolutize " << x.to_string() << '\n'; //? 3
 //?   cout << is_raw(x) << '\n'; //? 1
   if (is_raw(x) || is_dummy(x)) return x;
 //?   cout << "not raw: " << x.to_string() << '\n'; //? 1
   assert(x.initialized);
   reagent r = x;
-  r.set_value(address(r.value, space(r)));
+  r.set_value(address(r.value, space_base(r)));
 //?   cout << "after absolutize: " << r.value << '\n'; //? 1
   r.properties.push_back(pair<string, vector<string> >("raw", vector<string>()));
   assert(is_raw(r));
@@ -51,12 +53,13 @@ reagent absolutize(reagent x) {
 result.properties.push_back(pair<string, vector<string> >("raw", vector<string>()));
 
 :(code)
-int space(const reagent& x) {
+int space_base(const reagent& x) {
   return Current_routine->calls.top().default_space;
 }
 
 int address(int offset, int base) {
   if (base == 0) return offset;  // raw
+//?   cout << base << '\n'; //? 1
   if (offset >= Memory[base]) {
     // todo: test
     raise << "location " << offset << " is out of bounds " << Memory[base] << '\n';
diff --git a/cpp/028space_surround b/cpp/028space_surround
index dd4fb44f..76cd5807 100644
--- a/cpp/028space_surround
+++ b/cpp/028space_surround
@@ -10,7 +10,7 @@ recipe main [
   10:integer <- copy 5:literal  # pretend array
   20:integer <- copy 5:literal  # pretend array
   default-space:address:space <- copy 10:literal
-  0:address:space <- copy 20:literal
+  0:address:space/names:dummy <- copy 20:literal  # later layers will explain the /names: property
   1:integer <- copy 32:literal
   1:integer/space:1 <- copy 33:literal
 ]
@@ -25,14 +25,20 @@ recipe main [
 //: lifetime, surrounding allows managing shorter lifetimes inside a longer
 //: one.
 
-:(replace{} "int space(const reagent& x)")
-int space(const reagent& x) {
-  return space(x, space_index(x), Current_routine->calls.top().default_space);
+:(replace{} "int space_base(const reagent& x)")
+int space_base(const reagent& x) {
+  return space_base(x, space_index(x), Current_routine->calls.top().default_space);
 }
 
-int space(const reagent& x, int space_index, int base) {
-  if (space_index == 0) return base;
-  return space(x, space_index-1, Memory[base+1]);
+int space_base(const reagent& x, int space_index, int base) {
+//?   trace("foo") << "base of space " << space_index << '\n'; //? 1
+  if (space_index == 0) {
+//?     trace("foo") << "base of space " << space_index << " is " << base << '\n'; //? 1
+    return base;
+  }
+//?   trace("foo") << "base of space " << space_index << " is " << Memory[base+1] << '\n'; //? 1
+  int result = space_base(x, space_index-1, Memory[base+1]);
+  return result;
 }
 
 int space_index(const reagent& x) {
diff --git a/cpp/036closure_name b/cpp/036closure_name
new file mode 100644
index 00000000..76a1bdd7
--- /dev/null
+++ b/cpp/036closure_name
@@ -0,0 +1,142 @@
+//: Writing to a literal (not computed) address of 0 in a recipe chains two
+//: spaces together. When a variable has a property of /space:1, it looks up
+//: the variable in the chained/surrounding space. /space:2 looks up the
+//: surrounding space of the surrounding space, etc.
+:(scenario "closure")
+recipe main [
+  default-space:address:space <- new location:type, 30:literal
+  1:address:space/names:init-counter <- init-counter
+#?   $print [AAAAAAAAAAAAAAAA]
+#?   $print 1:address:space
+  2:integer/raw <- increment-counter 1:address:space/names:init-counter
+  3:integer/raw <- increment-counter 1:address:space/names:init-counter
+]
+
+recipe init-counter [
+  default-space:address:space <- new location:type, 30:literal
+  x:integer <- copy 23:literal
+  y:integer <- copy 3:literal  # variable that will be incremented
+  reply default-space:address:space
+]
+
+recipe increment-counter [
+  default-space:address:space <- new space:literal, 30:literal
+  0:address:space/names:init-counter <- next-ingredient  # outer space must be created by 'init-counter' above
+  y:integer/space:1 <- add y:integer/space:1, 1:literal  # increment
+  y:integer <- copy 234:literal  # dummy
+  reply y:integer/space:1
+]
+
++name: recipe increment-counter is surrounded by init-counter
++mem: storing 5 in location 3
+
+//: To make this work, compute the recipe that provides names for the
+//: surrounding space of each recipe. This must happen before transform_names.
+:(before "End Globals")
+unordered_map<recipe_number, recipe_number> Surrounding_space;
+
+:(after "int main")
+  Transform.push_back(collect_surrounding_spaces);
+
+:(code)
+void collect_surrounding_spaces(const recipe_number r) {
+  for (size_t i = 0; i < Recipe[r].steps.size(); ++i) {
+    const instruction& inst = Recipe[r].steps[i];
+    if (inst.is_label) continue;
+    for (size_t j = 0; j < inst.products.size(); ++j) {
+      if (isa_literal(inst.products[j])) continue;
+      if (inst.products[j].name != "0") continue;
+      if (inst.products[j].types.size() != 2
+          || inst.products[j].types[0] != Type_number["address"]
+          || inst.products[j].types[1] != Type_number["space"]) {
+        raise << "slot 0 should always have type address:space, but is " << inst.products[j].to_string() << '\n';
+        continue;
+      }
+      vector<string> s = property(inst.products[j], "names");
+      if (s.empty())
+        raise << "slot 0 requires a /names property in recipe " << Recipe[r].name << die();
+      if (s.size() > 1) raise << "slot 0 should have a single value in /names, got " << inst.products[j].to_string() << '\n';
+      string surrounding_recipe_name = s[0];
+      if (Surrounding_space.find(r) != Surrounding_space.end()
+          && Surrounding_space[r] != Recipe_number[surrounding_recipe_name]) {
+        raise << "recipe " << Recipe[r].name << " can have only one 'surrounding' recipe but has " << Recipe[Surrounding_space[r]].name << " and " << surrounding_recipe_name << '\n';
+        continue;
+      }
+      trace("name") << "recipe " << Recipe[r].name << " is surrounded by " << surrounding_recipe_name;
+      Surrounding_space[r] = Recipe_number[surrounding_recipe_name];
+    }
+  }
+}
+
+vector<string> property(const reagent& r, const string& name) {
+  for (size_t p = 0; p != r.properties.size(); ++p) {
+    if (r.properties[p].first == name)
+      return r.properties[p].second;
+  }
+  return vector<string>();
+}
+
+//: Once surrounding spaces are available, transform_names uses them to handle
+//: /space properties.
+
+:(replace{} "size_t lookup_name(const reagent& r, const recipe_number default_recipe)")
+size_t lookup_name(const reagent& x, const recipe_number default_recipe) {
+//?   cout << "AAA " << default_recipe << " " << Recipe[default_recipe].name << '\n'; //? 2
+//?   cout << "AAA " << x.to_string() << '\n'; //? 1
+  if (!has_property(x, "space")) {
+    if (Name[default_recipe].empty()) raise << "name not found: " << x.name << '\n' << die();
+    return Name[default_recipe][x.name];
+  }
+  vector<string> p = property(x, "space");
+  if (p.size() != 1) raise << "/space property should have exactly one (non-negative integer) value\n";
+  int n = to_int(p[0]);
+  assert(n >= 0);
+  recipe_number surrounding_recipe = lookup_surrounding_recipe(default_recipe, n);
+  set<recipe_number> done;
+  vector<recipe_number> path;
+  return lookup_name(x, surrounding_recipe, done, path);
+}
+
+// If the recipe we need to lookup this name in doesn't have names done yet,
+// recursively call transform_names on it.
+size_t lookup_name(const reagent& x, const recipe_number r, set<recipe_number>& done, vector<recipe_number>& path) {
+  if (!Name[r].empty()) return Name[r][x.name];
+  if (done.find(r) != done.end()) {
+    raise << "can't compute address of " << x.to_string() << " because ";
+    for (size_t i = 1; i < path.size(); ++i) {
+      raise << path[i-1] << " requires computing names of " << path[i] << '\n';
+    }
+    raise << path[path.size()-1] << " requires computing names of " << r << "..ad infinitum\n" << die();
+    return 0;
+  }
+  done.insert(r);
+  path.push_back(r);
+  transform_names(r);  // Not passing 'done' through. Might this somehow cause an infinite loop?
+  assert(!Name[r].empty());
+  return Name[r][x.name];
+}
+
+recipe_number lookup_surrounding_recipe(const recipe_number r, size_t n) {
+  if (n == 0) return r;
+  if (Surrounding_space.find(r) == Surrounding_space.end()) {
+    raise << "don't know surrounding recipe of " << Recipe[r].name << '\n';
+    return 0;
+  }
+  assert(Surrounding_space[r]);
+  return lookup_surrounding_recipe(Surrounding_space[r], n-1);
+}
+
+//: weaken use-before-set warnings just a tad
+:(replace{} "bool already_transformed(const reagent& r, const unordered_map<string, int>& names)")
+bool already_transformed(const reagent& r, const unordered_map<string, int>& names) {
+  if (has_property(r, "space")) {
+    vector<string> p = property(r, "space");
+    assert(p.size() == 1);
+    if (p[0] != "0") return true;
+  }
+  return names.find(r.name) != names.end();
+}
+
+:(before "End Includes")
+#include<set>
+using std::set;
diff --git a/cpp/090debug b/cpp/090debug
index 08373a49..b6acae9d 100644
--- a/cpp/090debug
+++ b/cpp/090debug
@@ -7,11 +7,13 @@ assert(Next_recipe_number < _PRINT);
 :(before "End Primitive Recipe Implementations")
 case _PRINT: {
   if (isa_literal(instructions[pc].ingredients[0])) {
+    trace("run") << "$print: " << instructions[pc].ingredients[0].name;
     cout << instructions[pc].ingredients[0].name << '\n';
     break;
   }
   vector<int> result(read_memory(instructions[pc].ingredients[0]));
   for (size_t i = 0; i < result.size(); ++i) {
+    trace("run") << "$print: " << result[i];
     cout << result[i] << " ";
   }
   cout << '\n';
diff --git a/mu.arc b/mu.arc
index 283f056f..292126b3 100644
--- a/mu.arc
+++ b/mu.arc
@@ -1134,12 +1134,12 @@
           (die "routine has no globals: @operand"))
       :else
         (iflet base rep.routine*!call-stack.0!default-space
-          (lookup-space (rem [caris _ 'space] operand)
-                        base
-                        space.operand)
+          (space-base (rem [caris _ 'space] operand)
+                      base
+                      space.operand)
           operand)))
 
-(def lookup-space (operand base space)
+(def space-base (operand base space)
 ;?   (prn operand " " base) ;? 1
   (if (is 0 space)
     ; base case
@@ -1149,8 +1149,8 @@
         (raw))
       (die "no room for var @operand in routine of size @memory*.base"))
     ; recursive case
-    (lookup-space operand (memory* (+ base 1))  ; location 0 points to next space
-                  (- space 1))))
+    (space-base operand (memory* (+ base 1))  ; location 0 points to next space
+                (- space 1))))
 
 (def space (operand)
   (or (alref metadata.operand 'space)
a4ac05d28db2'>f9d069b5 ^
dc1323e9 ^
b24eb476 ^
dc1323e9 ^
7fd01071 ^
dc1323e9 ^
596490f4 ^
dc1323e9 ^
0012c703 ^





795f5244 ^
166e3c0d ^



0012c703 ^

f9d069b5 ^
dc1323e9 ^
7fd01071 ^
dc1323e9 ^
596490f4 ^
dc1323e9 ^
0012c703 ^





795f5244 ^
166e3c0d ^



0012c703 ^

f9d069b5 ^
dc1323e9 ^
b24eb476 ^
dc1323e9 ^
7fd01071 ^
dc1323e9 ^
596490f4 ^
dc1323e9 ^
0012c703 ^





795f5244 ^
166e3c0d ^



0012c703 ^

f9d069b5 ^
dc1323e9 ^
7fd01071 ^
dc1323e9 ^
596490f4 ^
dc1323e9 ^
0012c703 ^


cf3ac87f ^






7fd01071 ^
15fdc5d9 ^
cf3ac87f ^




9fae6657 ^


795f5244 ^
166e3c0d ^



9fae6657 ^

f9d069b5 ^
9fae6657 ^







795f5244 ^
166e3c0d ^



9fae6657 ^

f9d069b5 ^
9fae6657 ^




48bb8627 ^


795f5244 ^
166e3c0d ^



48bb8627 ^

f9d069b5 ^
48bb8627 ^






795f5244 ^
166e3c0d ^



48bb8627 ^

f9d069b5 ^
48bb8627 ^



596490f4 ^


795f5244 ^
166e3c0d ^



596490f4 ^

f9d069b5 ^
596490f4 ^






795f5244 ^
166e3c0d ^



596490f4 ^

f9d069b5 ^
596490f4 ^




45c08fea ^
12d73ee8 ^

45c08fea ^
54d48b25 ^
795f5244 ^
166e3c0d ^



54d48b25 ^
45c08fea ^
f9d069b5 ^
e02d7e98 ^
45c08fea ^
bbff2a35 ^



45c08fea ^
bbff2a35 ^
795f5244 ^
166e3c0d ^



bbff2a35 ^
45c08fea ^
f9d069b5 ^
45c08fea ^
e02d7e98 ^
bbff2a35 ^
45c08fea ^










601ff75b ^

601ff75b ^

45c08fea ^








0487a30e ^
45c08fea ^





bbff2a35 ^
45c08fea ^
e766fd13 ^
45c08fea ^





6fef33fd ^








45c08fea ^




54d48b25 ^

5e9eff8c ^



795f5244 ^
166e3c0d ^



5e9eff8c ^

f9d069b5 ^
5e9eff8c ^



fec4d874 ^





795f5244 ^
166e3c0d ^



fec4d874 ^

f9d069b5 ^
fec4d874 ^





6c96a437 ^

fec4d874 ^





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556