about summary refs log tree commit diff stats
path: root/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp')
-rw-r--r--cpp/.traces/keyboard_in_scenario465
-rw-r--r--cpp/.traces/read-key-in-mu465
-rw-r--r--cpp/074keyboard.mu53
-rw-r--r--cpp/075scenario_keyboard.cc55
-rw-r--r--cpp/076scenario_keyboard_test.mu23
5 files changed, 1061 insertions, 0 deletions
diff --git a/cpp/.traces/keyboard_in_scenario b/cpp/.traces/keyboard_in_scenario
new file mode 100644
index 00000000..a6bc5f3b
--- /dev/null
+++ b/cpp/.traces/keyboard_in_scenario
@@ -0,0 +1,465 @@
+parse/0: instruction: assume-keyboard
+parse/0:   ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]}
+parse/0: instruction: run
+parse/0:   ingredient: {name: "
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ", value: 0, type: 0, properties: ["
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ": "literal-string"]}
+parse/0: instruction: memory-should-contain
+parse/0:   ingredient: {name: "
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ", value: 0, type: 0, properties: ["
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ": "literal-string"]}
+new/0: abc -> 0
+after-brace/0: recipe keyboard-in-scenario
+after-brace/0: assume-keyboard ...
+after-brace/0: assume-keyboard ...
+after-brace/0: run ...
+after-brace/0: memory-should-contain ...
+new/0: routine allocated memory from 1000 to 101000
+schedule/0: keyboard-in-scenario
+run/0: instruction keyboard-in-scenario/0
+run/0: {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- assume-keyboard/42 {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]}
+mem/0: storing 1000 in location 901
+run/0: instruction keyboard-in-scenario/1
+run/0: {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- assume-keyboard/125 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1000
+run/0: instruction init-fake-keyboard/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1004
+run/0: instruction init-fake-keyboard/1
+run/0: {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard"]} <- new/42 {name: "keyboard", value: 12, type: 0, properties: ["keyboard": "type"]}
+mem/0: new alloc: 1035
+mem/0: storing 1035 in location 1006
+run/0: instruction init-fake-keyboard/2
+run/0: {name: "buf", value: 2, type: 2-2-5-4, properties: ["buf": "address":"address":"array":"character"]} <- get-address/25 {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is result
+mem/0: location 1006 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: product 0 is 1036
+mem/0: storing 1036 in location 1007
+run/0: instruction init-fake-keyboard/3
+run/0: {name: "buf", value: 2, type: 2-2-5-4, properties: ["buf": "address":"address":"array":"character", "deref": ]} <- next-ingredient/30 
+run/0: product 0 is 1000
+mem/0: location 1007 is 1036
+mem/0: storing 1000 in location 1036
+run/0: instruction init-fake-keyboard/4
+run/0: {name: "idx", value: 3, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is result
+mem/0: location 1006 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1008
+run/0: instruction init-fake-keyboard/5
+run/0: {name: "idx", value: 3, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- copy/1 {name: "0", value: 0, type: 0, properties: ["0": "literal"]}
+run/0: ingredient 0 is 0
+mem/0: location 1008 is 1035
+mem/0: storing 0 in location 1035
+run/0: instruction init-fake-keyboard/6
+run/0: reply/33 {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard"]}
+mem/0: location 1006 is 1035
+run/0: result 0 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction keyboard-in-scenario/2
+run/0: run/43 {name: "
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ", value: 0, type: 0, properties: ["
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ": "literal-string"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "1", value: 0, type: 4, properties: ["1": "character"]}
+parse/0:   product: {name: "2", value: 0, type: 3, properties: ["2": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "3", value: 0, type: 4, properties: ["3": "character"]}
+parse/0:   product: {name: "4", value: 0, type: 3, properties: ["4": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "5", value: 0, type: 4, properties: ["5": "character"]}
+parse/0:   product: {name: "6", value: 0, type: 3, properties: ["6": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "7", value: 0, type: 4, properties: ["7": "character"]}
+parse/0:   product: {name: "8", value: 0, type: 3, properties: ["8": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+after-brace/0: recipe run1002
+after-brace/0: read-key ...
+after-brace/0: read-key ...
+after-brace/0: read-key ...
+after-brace/0: read-key ...
+run/0: instruction run1002/0
+run/0: {name: "1", value: 1, type: 4, properties: ["1": "character"]}, {name: "2", value: 2, type: 3, properties: ["2": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1037
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1039
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1039 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1039 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1040
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1039 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1041
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1041 is 1000
+mem/0: storing 3 in location 1042
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1040 is 1035
+mem/0: location 1035 is 0
+run/0: ingredient 1 is max
+mem/0: location 1042 is 3
+run/0: product 0 is 0
+mem/0: storing 0 in location 1043
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1043 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 11
+run/0: instruction read-key/12
+run/0: {name: "c", value: 6, type: 4, properties: ["c": "character"]} <- index/26 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}, {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+run/0: ingredient 0 is {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1041 is 1000
+run/0: ingredient 1 is {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+mem/0: location 1040 is 1035
+mem/0: location 1035 is 0
+run/0: address to copy is 1001
+run/0: its type is 4
+mem/0: location 1001 is 97
+run/0: product 0 is 97
+mem/0: storing 97 in location 1044
+run/0: instruction read-key/13
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- add/2 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "1", value: 1, type: 0, properties: ["1": "literal"]}
+run/0: ingredient 0 is idx
+mem/0: location 1040 is 1035
+mem/0: location 1035 is 0
+run/0: ingredient 1 is 1
+run/0: product 0 is 1
+mem/0: location 1040 is 1035
+mem/0: storing 1 in location 1035
+run/0: instruction read-key/14
+run/0: reply/33 {name: "c", value: 6, type: 4, properties: ["c": "character"]}, {name: "1", value: 1, type: 0, properties: ["1": "literal", "found": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1044 is 97
+mem/0: location 1039 is 1035
+run/0: result 0 is 97
+mem/0: storing 97 in location 1
+run/0: result 1 is 1
+mem/0: storing 1 in location 2
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction run1002/1
+run/0: {name: "3", value: 3, type: 4, properties: ["3": "character"]}, {name: "4", value: 4, type: 3, properties: ["4": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1068
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1070
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1070 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1070 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1071
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1070 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1072
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1072 is 1000
+mem/0: storing 3 in location 1073
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1071 is 1035
+mem/0: location 1035 is 1
+run/0: ingredient 1 is max
+mem/0: location 1073 is 3
+run/0: product 0 is 0
+mem/0: storing 0 in location 1074
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1074 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 11
+run/0: instruction read-key/12
+run/0: {name: "c", value: 6, type: 4, properties: ["c": "character"]} <- index/26 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}, {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+run/0: ingredient 0 is {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1072 is 1000
+run/0: ingredient 1 is {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+mem/0: location 1071 is 1035
+mem/0: location 1035 is 1
+run/0: address to copy is 1002
+run/0: its type is 4
+mem/0: location 1002 is 98
+run/0: product 0 is 98
+mem/0: storing 98 in location 1075
+run/0: instruction read-key/13
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- add/2 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "1", value: 1, type: 0, properties: ["1": "literal"]}
+run/0: ingredient 0 is idx
+mem/0: location 1071 is 1035
+mem/0: location 1035 is 1
+run/0: ingredient 1 is 1
+run/0: product 0 is 2
+mem/0: location 1071 is 1035
+mem/0: storing 2 in location 1035
+run/0: instruction read-key/14
+run/0: reply/33 {name: "c", value: 6, type: 4, properties: ["c": "character"]}, {name: "1", value: 1, type: 0, properties: ["1": "literal", "found": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1075 is 98
+mem/0: location 1070 is 1035
+run/0: result 0 is 98
+mem/0: storing 98 in location 3
+run/0: result 1 is 1
+mem/0: storing 1 in location 4
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction run1002/2
+run/0: {name: "5", value: 5, type: 4, properties: ["5": "character"]}, {name: "6", value: 6, type: 3, properties: ["6": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1099
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1101
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1101 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1101 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1102
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1101 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1103
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1103 is 1000
+mem/0: storing 3 in location 1104
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1102 is 1035
+mem/0: location 1035 is 2
+run/0: ingredient 1 is max
+mem/0: location 1104 is 3
+run/0: product 0 is 0
+mem/0: storing 0 in location 1105
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1105 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 11
+run/0: instruction read-key/12
+run/0: {name: "c", value: 6, type: 4, properties: ["c": "character"]} <- index/26 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}, {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+run/0: ingredient 0 is {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1103 is 1000
+run/0: ingredient 1 is {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+mem/0: location 1102 is 1035
+mem/0: location 1035 is 2
+run/0: address to copy is 1003
+run/0: its type is 4
+mem/0: location 1003 is 99
+run/0: product 0 is 99
+mem/0: storing 99 in location 1106
+run/0: instruction read-key/13
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- add/2 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "1", value: 1, type: 0, properties: ["1": "literal"]}
+run/0: ingredient 0 is idx
+mem/0: location 1102 is 1035
+mem/0: location 1035 is 2
+run/0: ingredient 1 is 1
+run/0: product 0 is 3
+mem/0: location 1102 is 1035
+mem/0: storing 3 in location 1035
+run/0: instruction read-key/14
+run/0: reply/33 {name: "c", value: 6, type: 4, properties: ["c": "character"]}, {name: "1", value: 1, type: 0, properties: ["1": "literal", "found": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1106 is 99
+mem/0: location 1101 is 1035
+run/0: result 0 is 99
+mem/0: storing 99 in location 5
+run/0: result 1 is 1
+mem/0: storing 1 in location 6
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction run1002/3
+run/0: {name: "7", value: 7, type: 4, properties: ["7": "character"]}, {name: "8", value: 8, type: 3, properties: ["8": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1130
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1132
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1132 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1132 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1133
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1132 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1134
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1134 is 1000
+mem/0: storing 3 in location 1135
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1133 is 1035
+mem/0: location 1035 is 3
+run/0: ingredient 1 is max
+mem/0: location 1135 is 3
+run/0: product 0 is 1
+mem/0: storing 1 in location 1136
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1136 is 1
+run/0: ingredient 0 is 1
+run/0: jump-unless fell through
+run/0: instruction read-key/10
+run/0: reply/33 {name: "0", value: 0, type: 0, properties: ["0": "literal"]}, {name: "0", value: 0, type: 0, properties: ["0": "literal", "done": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1132 is 1035
+run/0: result 0 is 0
+mem/0: storing 0 in location 7
+run/0: result 1 is 0
+mem/0: storing 0 in location 8
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction keyboard-in-scenario/3
+run/0: memory-should-contain/44 {name: "
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ", value: 0, type: 0, properties: ["
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ": "literal-string"]}
+run/0: checking location 1
+run/0: checking location 2
+run/0: checking location 3
+run/0: checking location 4
+run/0: checking location 5
+run/0: checking location 6
+run/0: checking location 7
+run/0: checking location 8
diff --git a/cpp/.traces/read-key-in-mu b/cpp/.traces/read-key-in-mu
new file mode 100644
index 00000000..e07f5a5f
--- /dev/null
+++ b/cpp/.traces/read-key-in-mu
@@ -0,0 +1,465 @@
+parse/0: instruction: assume-keyboard
+parse/0:   ingredient: {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]}
+parse/0: instruction: run
+parse/0:   ingredient: {name: "
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ", value: 0, type: 0, properties: ["
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ": "literal-string"]}
+parse/0: instruction: memory-should-contain
+parse/0:   ingredient: {name: "
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ", value: 0, type: 0, properties: ["
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ": "literal-string"]}
+new/0: abc -> 0
+after-brace/0: recipe read-key-in-mu
+after-brace/0: assume-keyboard ...
+after-brace/0: assume-keyboard ...
+after-brace/0: run ...
+after-brace/0: memory-should-contain ...
+new/0: routine allocated memory from 1000 to 101000
+schedule/0: read-key-in-mu
+run/0: instruction read-key-in-mu/0
+run/0: {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- assume-keyboard/42 {name: "abc", value: 0, type: 0, properties: ["abc": "literal-string"]}
+mem/0: storing 1000 in location 901
+run/0: instruction read-key-in-mu/1
+run/0: {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- assume-keyboard/125 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1000
+run/0: instruction init-fake-keyboard/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1004
+run/0: instruction init-fake-keyboard/1
+run/0: {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard"]} <- new/42 {name: "keyboard", value: 12, type: 0, properties: ["keyboard": "type"]}
+mem/0: new alloc: 1035
+mem/0: storing 1035 in location 1006
+run/0: instruction init-fake-keyboard/2
+run/0: {name: "buf", value: 2, type: 2-2-5-4, properties: ["buf": "address":"address":"array":"character"]} <- get-address/25 {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is result
+mem/0: location 1006 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: product 0 is 1036
+mem/0: storing 1036 in location 1007
+run/0: instruction init-fake-keyboard/3
+run/0: {name: "buf", value: 2, type: 2-2-5-4, properties: ["buf": "address":"address":"array":"character", "deref": ]} <- next-ingredient/30 
+run/0: product 0 is 1000
+mem/0: location 1007 is 1036
+mem/0: storing 1000 in location 1036
+run/0: instruction init-fake-keyboard/4
+run/0: {name: "idx", value: 3, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is result
+mem/0: location 1006 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1008
+run/0: instruction init-fake-keyboard/5
+run/0: {name: "idx", value: 3, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- copy/1 {name: "0", value: 0, type: 0, properties: ["0": "literal"]}
+run/0: ingredient 0 is 0
+mem/0: location 1008 is 1035
+mem/0: storing 0 in location 1035
+run/0: instruction init-fake-keyboard/6
+run/0: reply/33 {name: "result", value: 1, type: 2-12, properties: ["result": "address":"keyboard"]}
+mem/0: location 1006 is 1035
+run/0: result 0 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction read-key-in-mu/2
+run/0: run/43 {name: "
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ", value: 0, type: 0, properties: ["
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ": "literal-string"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "1", value: 0, type: 4, properties: ["1": "character"]}
+parse/0:   product: {name: "2", value: 0, type: 3, properties: ["2": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "3", value: 0, type: 4, properties: ["3": "character"]}
+parse/0:   product: {name: "4", value: 0, type: 3, properties: ["4": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "5", value: 0, type: 4, properties: ["5": "character"]}
+parse/0:   product: {name: "6", value: 0, type: 3, properties: ["6": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0: instruction: read-key
+parse/0:   ingredient: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+parse/0:   product: {name: "7", value: 0, type: 4, properties: ["7": "character"]}
+parse/0:   product: {name: "8", value: 0, type: 3, properties: ["8": "boolean"]}
+parse/0:   product: {name: "keyboard", value: 0, type: 2, properties: ["keyboard": "address"]}
+after-brace/0: recipe run1001
+after-brace/0: read-key ...
+after-brace/0: read-key ...
+after-brace/0: read-key ...
+after-brace/0: read-key ...
+run/0: instruction run1001/0
+run/0: {name: "1", value: 1, type: 4, properties: ["1": "character"]}, {name: "2", value: 2, type: 3, properties: ["2": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1037
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1039
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1039 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1039 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1040
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1039 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1041
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1041 is 1000
+mem/0: storing 3 in location 1042
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1040 is 1035
+mem/0: location 1035 is 0
+run/0: ingredient 1 is max
+mem/0: location 1042 is 3
+run/0: product 0 is 0
+mem/0: storing 0 in location 1043
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1043 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 11
+run/0: instruction read-key/12
+run/0: {name: "c", value: 6, type: 4, properties: ["c": "character"]} <- index/26 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}, {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+run/0: ingredient 0 is {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1041 is 1000
+run/0: ingredient 1 is {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+mem/0: location 1040 is 1035
+mem/0: location 1035 is 0
+run/0: address to copy is 1001
+run/0: its type is 4
+mem/0: location 1001 is 97
+run/0: product 0 is 97
+mem/0: storing 97 in location 1044
+run/0: instruction read-key/13
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- add/2 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "1", value: 1, type: 0, properties: ["1": "literal"]}
+run/0: ingredient 0 is idx
+mem/0: location 1040 is 1035
+mem/0: location 1035 is 0
+run/0: ingredient 1 is 1
+run/0: product 0 is 1
+mem/0: location 1040 is 1035
+mem/0: storing 1 in location 1035
+run/0: instruction read-key/14
+run/0: reply/33 {name: "c", value: 6, type: 4, properties: ["c": "character"]}, {name: "1", value: 1, type: 0, properties: ["1": "literal", "found": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1044 is 97
+mem/0: location 1039 is 1035
+run/0: result 0 is 97
+mem/0: storing 97 in location 1
+run/0: result 1 is 1
+mem/0: storing 1 in location 2
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction run1001/1
+run/0: {name: "3", value: 3, type: 4, properties: ["3": "character"]}, {name: "4", value: 4, type: 3, properties: ["4": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1068
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1070
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1070 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1070 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1071
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1070 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1072
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1072 is 1000
+mem/0: storing 3 in location 1073
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1071 is 1035
+mem/0: location 1035 is 1
+run/0: ingredient 1 is max
+mem/0: location 1073 is 3
+run/0: product 0 is 0
+mem/0: storing 0 in location 1074
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1074 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 11
+run/0: instruction read-key/12
+run/0: {name: "c", value: 6, type: 4, properties: ["c": "character"]} <- index/26 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}, {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+run/0: ingredient 0 is {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1072 is 1000
+run/0: ingredient 1 is {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+mem/0: location 1071 is 1035
+mem/0: location 1035 is 1
+run/0: address to copy is 1002
+run/0: its type is 4
+mem/0: location 1002 is 98
+run/0: product 0 is 98
+mem/0: storing 98 in location 1075
+run/0: instruction read-key/13
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- add/2 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "1", value: 1, type: 0, properties: ["1": "literal"]}
+run/0: ingredient 0 is idx
+mem/0: location 1071 is 1035
+mem/0: location 1035 is 1
+run/0: ingredient 1 is 1
+run/0: product 0 is 2
+mem/0: location 1071 is 1035
+mem/0: storing 2 in location 1035
+run/0: instruction read-key/14
+run/0: reply/33 {name: "c", value: 6, type: 4, properties: ["c": "character"]}, {name: "1", value: 1, type: 0, properties: ["1": "literal", "found": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1075 is 98
+mem/0: location 1070 is 1035
+run/0: result 0 is 98
+mem/0: storing 98 in location 3
+run/0: result 1 is 1
+mem/0: storing 1 in location 4
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction run1001/2
+run/0: {name: "5", value: 5, type: 4, properties: ["5": "character"]}, {name: "6", value: 6, type: 3, properties: ["6": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1099
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1101
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1101 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1101 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1102
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1101 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1103
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1103 is 1000
+mem/0: storing 3 in location 1104
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1102 is 1035
+mem/0: location 1035 is 2
+run/0: ingredient 1 is max
+mem/0: location 1104 is 3
+run/0: product 0 is 0
+mem/0: storing 0 in location 1105
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1105 is 0
+run/0: ingredient 0 is 0
+run/0: ingredient 1 is 
+run/0: jumping to instruction 11
+run/0: instruction read-key/12
+run/0: {name: "c", value: 6, type: 4, properties: ["c": "character"]} <- index/26 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}, {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+run/0: ingredient 0 is {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1103 is 1000
+run/0: ingredient 1 is {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}
+mem/0: location 1102 is 1035
+mem/0: location 1035 is 2
+run/0: address to copy is 1003
+run/0: its type is 4
+mem/0: location 1003 is 99
+run/0: product 0 is 99
+mem/0: storing 99 in location 1106
+run/0: instruction read-key/13
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]} <- add/2 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "1", value: 1, type: 0, properties: ["1": "literal"]}
+run/0: ingredient 0 is idx
+mem/0: location 1102 is 1035
+mem/0: location 1035 is 2
+run/0: ingredient 1 is 1
+run/0: product 0 is 3
+mem/0: location 1102 is 1035
+mem/0: storing 3 in location 1035
+run/0: instruction read-key/14
+run/0: reply/33 {name: "c", value: 6, type: 4, properties: ["c": "character"]}, {name: "1", value: 1, type: 0, properties: ["1": "literal", "found": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1106 is 99
+mem/0: location 1101 is 1035
+run/0: result 0 is 99
+mem/0: storing 99 in location 5
+run/0: result 1 is 1
+mem/0: storing 1 in location 6
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction run1001/3
+run/0: {name: "7", value: 7, type: 4, properties: ["7": "character"]}, {name: "8", value: 8, type: 3, properties: ["8": "boolean"]}, {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]} <- read-key/126 {name: "keyboard", value: 901, type: 2, properties: ["keyboard": "address"]}
+mem/0: location 901 is 1035
+run/0: instruction read-key/0
+run/0: {name: "default-space", value: 0, type: 2-5-1, properties: ["default-space": "address":"array":"location"]} <- new/42 {name: "location", value: 1, type: 0, properties: ["location": "type"]}, {name: "30", value: 30, type: 0, properties: ["30": "literal"]}
+mem/0: array size is 30
+mem/0: new alloc: 1130
+run/0: instruction read-key/1
+run/0: {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]} <- next-ingredient/30 
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1132
+run/0: instruction read-key/3
+run/0: break-unless/12 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard"]}, {name: "", value: 11, type: , properties: ["": ]}
+mem/0: location 1132 is 1035
+run/0: ingredient 0 is 1035
+run/0: jump-unless fell through
+run/0: instruction read-key/4
+run/0: {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer"]} <- get-address/25 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "index", value: 0, type: 0, properties: ["index": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1132 is 1035
+run/0: ingredient 1 is index
+run/0: address to copy is 1035
+run/0: product 0 is 1035
+mem/0: storing 1035 in location 1133
+run/0: instruction read-key/5
+run/0: {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character"]} <- get/24 {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "deref": ]}, {name: "data", value: 1, type: 0, properties: ["data": "offset"]}
+run/0: ingredient 0 is x
+mem/0: location 1132 is 1035
+run/0: ingredient 1 is data
+run/0: address to copy is 1036
+run/0: its type is 2
+mem/0: location 1036 is 1000
+run/0: product 0 is 1000
+mem/0: storing 1000 in location 1134
+run/0: instruction read-key/6
+run/0: {name: "max", value: 4, type: 1, properties: ["max": "integer"]} <- length/28 {name: "buf", value: 3, type: 2-5-4, properties: ["buf": "address":"array":"character", "deref": ]}
+mem/0: location 1134 is 1000
+mem/0: storing 3 in location 1135
+run/0: instruction read-key/8
+run/0: {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]} <- greater-or-equal/16 {name: "idx", value: 2, type: 2-1, properties: ["idx": "address":"integer", "deref": ]}, {name: "max", value: 4, type: 1, properties: ["max": "integer"]}
+run/0: ingredient 0 is idx
+mem/0: location 1133 is 1035
+mem/0: location 1035 is 3
+run/0: ingredient 1 is max
+mem/0: location 1135 is 3
+run/0: product 0 is 1
+mem/0: storing 1 in location 1136
+run/0: instruction read-key/9
+run/0: break-unless/12 {name: "done?", value: 5, type: 3, properties: ["done?": "boolean"]}, {name: "", value: 1, type: , properties: ["": ]}
+mem/0: location 1136 is 1
+run/0: ingredient 0 is 1
+run/0: jump-unless fell through
+run/0: instruction read-key/10
+run/0: reply/33 {name: "0", value: 0, type: 0, properties: ["0": "literal"]}, {name: "0", value: 0, type: 0, properties: ["0": "literal", "done": ]}, {name: "x", value: 1, type: 2-12, properties: ["x": "address":"keyboard", "same-as-ingredient": "0"]}
+mem/0: location 1132 is 1035
+run/0: result 0 is 0
+mem/0: storing 0 in location 7
+run/0: result 1 is 0
+mem/0: storing 0 in location 8
+run/0: result 2 is 1035
+mem/0: storing 1035 in location 901
+run/0: instruction read-key-in-mu/3
+run/0: memory-should-contain/44 {name: "
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ", value: 0, type: 0, properties: ["
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ": "literal-string"]}
+run/0: checking location 1
+run/0: checking location 2
+run/0: checking location 3
+run/0: checking location 4
+run/0: checking location 5
+run/0: checking location 6
+run/0: checking location 7
+run/0: checking location 8
diff --git a/cpp/074keyboard.mu b/cpp/074keyboard.mu
new file mode 100644
index 00000000..9cea3d1f
--- /dev/null
+++ b/cpp/074keyboard.mu
@@ -0,0 +1,53 @@
+# Wrappers around keyboard primitives that take a 'keyboard' object and are thus
+# easier to test.
+
+container keyboard [  # can't think of another word like screen/display, so real and fake keyboards use the same name
+  index:integer
+  data:address:array:character
+]
+
+recipe init-fake-keyboard [
+  default-space:address:array:location <- new location:type, 30:literal
+  result:address:keyboard <- new keyboard:type
+  buf:address:address:array:character <- get-address result:address:keyboard/deref data:offset
+#?   $start-tracing #? 1
+  buf:address:address:array:character/deref <- next-ingredient
+#?   $stop-tracing #? 1
+  idx:address:integer <- get-address result:address:keyboard/deref index:offset
+  idx:address:integer/deref <- copy 0:literal
+  reply result:address:keyboard
+]
+
+recipe read-key [
+  default-space:address:array:location <- new location:type, 30:literal
+  x:address:keyboard <- next-ingredient
+  {
+    break-unless x:address:keyboard
+    idx:address:integer <- get-address x:address:keyboard/deref, index:offset
+    buf:address:array:character <- get x:address:keyboard/deref, data:offset
+    max:integer <- length buf:address:array:character/deref
+    {
+      done?:boolean <- greater-or-equal idx:address:integer/deref, max:integer
+      break-unless done?:boolean
+      reply 0:literal, 0:literal/done, x:address:keyboard/same-as-ingredient:0
+    }
+    c:character <- index buf:address:array:character/deref, idx:address:integer/deref
+    idx:address:integer/deref <- add idx:address:integer/deref, 1:literal
+    reply c:character, 1:literal/found, x:address:keyboard/same-as-ingredient:0
+  }
+  c:character, found?:boolean <- read-key-from-keyboard
+  reply c:character, found?:boolean, x:address:keyboard/same-as-ingredient:0
+]
+
+recipe wait-for-key [
+  default-space:address:array:location <- new location:type, 30:literal
+  x:address:keyboard <- next-ingredient
+  {
+    break-unless x:address:keyboard
+    # on fake keyboards 'wait-for-key' behaves just like 'read-key'
+    c:character, x:address:keyboard <- read-key x:address:keyboard
+    reply c:character, x:address:keyboard/same-as-ingredient:0
+  }
+  c:character <- wait-for-key-from-keyboard
+  reply c:character, x:address:keyboard/same-as-ingredient:0
+]
diff --git a/cpp/075scenario_keyboard.cc b/cpp/075scenario_keyboard.cc
new file mode 100644
index 00000000..d14e4de7
--- /dev/null
+++ b/cpp/075scenario_keyboard.cc
@@ -0,0 +1,55 @@
+//: Clean syntax to manipulate and check the keyboard in scenarios.
+//: Instruction 'assume-keyboard' implicitly creates a variable called
+//: 'keyboard' that is accessible inside other 'run' instructions in the
+//: scenario.
+
+:(scenarios run_mu_scenario)
+:(scenario keyboard_in_scenario)
+scenario keyboard-in-scenario [
+  assume-keyboard [abc]
+  run [
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ]
+  memory-should-contain [
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ]
+]
+
+:(before "End Scenario Globals")
+const size_t KEYBOARD = Next_predefined_global_for_scenarios++;
+:(before "End Predefined Scenario Locals In Run")
+Name[tmp_recipe[0]]["keyboard"] = KEYBOARD;
+
+:(before "End Rewrite Instruction(curr)")
+// rewrite `assume-keyboard string` to
+//   ```
+//   keyboard:address <- new string  # hacky reuse of location
+//   keyboard:address <- init-fake-keyboard keyboard:address
+//   ```
+if (curr.name == "assume-keyboard") {
+  // insert first instruction
+  curr.operation = Recipe_number["new"];
+  assert(curr.products.empty());
+  curr.products.push_back(reagent("keyboard:address"));
+  curr.products[0].set_value(KEYBOARD);
+  Recipe[r].steps.push_back(curr);  // hacky that "Rewrite Instruction" is converting to multiple instructions
+  // leave second instruction in curr
+  curr.clear();
+  curr.operation = Recipe_number["init-fake-keyboard"];
+  assert(curr.ingredients.empty());
+  curr.ingredients.push_back(reagent("keyboard:address"));
+  curr.ingredients[0].set_value(KEYBOARD);
+  assert(curr.products.empty());
+  curr.products.push_back(reagent("keyboard:address"));
+  curr.products[0].set_value(KEYBOARD);
+}
diff --git a/cpp/076scenario_keyboard_test.mu b/cpp/076scenario_keyboard_test.mu
new file mode 100644
index 00000000..67a965b1
--- /dev/null
+++ b/cpp/076scenario_keyboard_test.mu
@@ -0,0 +1,23 @@
+# To check our support for keyboards in scenarios, rewrite tests from
+# scenario_keyboard.mu
+# Tests for keyboard interface.
+
+scenario read-key-in-mu [
+  assume-keyboard [abc]
+  run [
+    1:character, 2:boolean, keyboard:address <- read-key keyboard:address
+    3:character, 4:boolean, keyboard:address <- read-key keyboard:address
+    5:character, 6:boolean, keyboard:address <- read-key keyboard:address
+    7:character, 8:boolean, keyboard:address <- read-key keyboard:address
+  ]
+  memory-should-contain [
+    1 <- 97  # 'a'
+    2 <- 1  # first read-key call found a character
+    3 <- 98  # 'b'
+    4 <- 1  # second read-key call found a character
+    5 <- 99  # 'c'
+    6 <- 1  # third read-key call found a character
+    7 <- 0
+    8 <- 0  # fourth read-key call didn't find a character
+  ]
+]
9
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