about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--060string.mu735
-rw-r--r--061channel.mu187
-rw-r--r--062array.mu22
-rw-r--r--063list.mu18
-rw-r--r--065duplex_list.mu94
-rw-r--r--066stream.mu38
-rw-r--r--071print.mu454
-rw-r--r--074console.mu75
-rw-r--r--edit.mu2
9 files changed, 792 insertions, 833 deletions
diff --git a/060string.mu b/060string.mu
index ddd50f04..a212b75b 100644
--- a/060string.mu
+++ b/060string.mu
@@ -3,30 +3,30 @@
 recipe string-equal [
   local-scope
   a:address:array:character <- next-ingredient
-  a-len:number <- length a:address:array:character/lookup
+  a-len:number <- length *a
   b:address:array:character <- next-ingredient
-  b-len:number <- length b:address:array:character/lookup
+  b-len:number <- length *b
   # compare lengths
   {
     trace [string-equal], [comparing lengths]
-    length-equal?:boolean <- equal a-len:number, b-len:number
-    break-if length-equal?:boolean
+    length-equal?:boolean <- equal a-len, b-len
+    break-if length-equal?
     reply 0
   }
   # compare each corresponding character
   trace [string-equal], [comparing characters]
   i:number <- copy 0
   {
-    done?:boolean <- greater-or-equal i:number, a-len:number
-    break-if done?:boolean
-    a2:character <- index a:address:array:character/lookup, i:number
-    b2:character <- index b:address:array:character/lookup, i:number
+    done?:boolean <- greater-or-equal i, a-len
+    break-if done?
+    a2:character <- index *a, i
+    b2:character <- index *b, i
     {
-      chars-match?:boolean <- equal a2:character, b2:character
-      break-if chars-match?:boolean
+      chars-match?:boolean <- equal a2, b2
+      break-if chars-match?
       reply 0
     }
-    i:number <- add i:number, 1
+    i <- add i, 1
     loop
   }
   reply 1
@@ -36,7 +36,7 @@ scenario string-equal-reflexive [
   run [
     default-space:address:array:location <- new location:type, 30
     x:address:array:character <- new [abc]
-    3:boolean/raw <- string-equal x:address:array:character, x:address:array:character
+    3:boolean/raw <- string-equal x, x
   ]
   memory-should-contain [
     3 <- 1  # x == x for all x
@@ -48,7 +48,7 @@ scenario string-equal-identical [
     default-space:address:array:location <- new location:type, 30
     x:address:array:character <- new [abc]
     y:address:array:character <- new [abc]
-    3:boolean/raw <- string-equal x:address:array:character, y:address:array:character
+    3:boolean/raw <- string-equal x, y
   ]
   memory-should-contain [
     3 <- 1  # abc == abc
@@ -60,7 +60,7 @@ scenario string-equal-distinct-lengths [
     default-space:address:array:location <- new location:type, 30
     x:address:array:character <- new [abc]
     y:address:array:character <- new [abcd]
-    3:boolean/raw <- string-equal x:address:array:character, y:address:array:character
+    3:boolean/raw <- string-equal x, y
   ]
   memory-should-contain [
     3 <- 0  # abc != abcd
@@ -78,7 +78,7 @@ scenario string-equal-with-empty [
     default-space:address:array:location <- new location:type, 30
     x:address:array:character <- new []
     y:address:array:character <- new [abcd]
-    3:boolean/raw <- string-equal x:address:array:character, y:address:array:character
+    3:boolean/raw <- string-equal x, y
   ]
   memory-should-contain [
     3 <- 0  # "" != abcd
@@ -90,7 +90,7 @@ scenario string-equal-common-lengths-but-distinct [
     default-space:address:array:location <- new location:type, 30
     x:address:array:character <- new [abc]
     y:address:array:character <- new [abd]
-    3:boolean/raw <- string-equal x:address:array:character, y:address:array:character
+    3:boolean/raw <- string-equal x, y
   ]
   memory-should-contain [
     3 <- 0  # abc != abd
@@ -107,47 +107,47 @@ recipe new-buffer [
   local-scope
 #?   $print default-space:address:array:location, 10/newline
   result:address:buffer <- new buffer:type
-  len:address:number <- get-address result:address:buffer/lookup, length:offset
-  len:address:number/lookup <- copy 0
-  s:address:address:array:character <- get-address result:address:buffer/lookup, data:offset
+  len:address:number <- get-address *result, length:offset
+  *len:address:number <- copy 0
+  s:address:address:array:character <- get-address *result, data:offset
   capacity:number, found?:boolean <- next-ingredient
-  assert found?:boolean, [new-buffer must get a capacity argument]
-  s:address:address:array:character/lookup <- new character:type, capacity:number
-#?   $print s:address:address:array:character/lookup, 10/newline
-  reply result:address:buffer
+  assert found?, [new-buffer must get a capacity argument]
+  *s <- new character:type, capacity
+#?   $print *s, 10/newline
+  reply result
 ]
 
 recipe grow-buffer [
   local-scope
   in:address:buffer <- next-ingredient
   # double buffer size
-  x:address:address:array:character <- get-address in:address:buffer/lookup, data:offset
-  oldlen:number <- length x:address:address:array:character/lookup/lookup
-  newlen:number <- multiply oldlen:number, 2
-  olddata:address:array:character <- copy x:address:address:array:character/lookup
-  x:address:address:array:character/lookup <- new character:type, newlen:number
+  x:address:address:array:character <- get-address *in, data:offset
+  oldlen:number <- length **x
+  newlen:number <- multiply oldlen, 2
+  olddata:address:array:character <- copy *x
+  *x <- new character:type, newlen
   # copy old contents
   i:number <- copy 0
   {
-    done?:boolean <- greater-or-equal i:number, oldlen:number
-    break-if done?:boolean
-    src:character <- index olddata:address:array:character/lookup, i:number
-    dest:address:character <- index-address x:address:address:array:character/lookup/lookup, i:number
-    dest:address:character/lookup <- copy src:character
-    i:number <- add i:number, 1
+    done?:boolean <- greater-or-equal i, oldlen
+    break-if done?
+    src:character <- index *olddata, i
+    dest:address:character <- index-address **x, i
+    *dest <- copy src
+    i <- add i, 1
     loop
   }
-  reply in:address:buffer
+  reply in
 ]
 
 recipe buffer-full? [
   local-scope
   in:address:buffer <- next-ingredient
-  len:number <- get in:address:buffer/lookup, length:offset
-  s:address:array:character <- get in:address:buffer/lookup, data:offset
-  capacity:number <- length s:address:array:character/lookup
-  result:boolean <- greater-or-equal len:number, capacity:number
-  reply result:boolean
+  len:number <- get *in, length:offset
+  s:address:array:character <- get *in, data:offset
+  capacity:number <- length *s
+  result:boolean <- greater-or-equal len, capacity
+  reply result
 ]
 
 # in:address:buffer <- buffer-append in:address:buffer, c:character
@@ -155,49 +155,49 @@ recipe buffer-append [
   local-scope
   in:address:buffer <- next-ingredient
   c:character <- next-ingredient
-  len:address:number <- get-address in:address:buffer/lookup, length:offset
+  len:address:number <- get-address *in, length:offset
   {
     # backspace? just drop last character if it exists and return
-    backspace?:boolean <- equal c:character, 8/backspace
-    break-unless backspace?:boolean
-    empty?:boolean <- lesser-or-equal len:address:number/lookup, 0
-    reply-if empty?:boolean, in:address:buffer/same-as-ingredient:0
-    len:address:number/lookup <- subtract len:address:number/lookup, 1
-    reply in:address:buffer/same-as-ingredient:0
+    backspace?:boolean <- equal c, 8/backspace
+    break-unless backspace?
+    empty?:boolean <- lesser-or-equal *len, 0
+    reply-if empty?, in/same-as-ingredient:0
+    *len <- subtract *len, 1
+    reply in/same-as-ingredient:0
   }
   {
     # grow buffer if necessary
-    full?:boolean <- buffer-full? in:address:buffer
-    break-unless full?:boolean
-    in:address:buffer <- grow-buffer in:address:buffer
+    full?:boolean <- buffer-full? in
+    break-unless full?
+    in <- grow-buffer in
   }
-  s:address:array:character <- get in:address:buffer/lookup, data:offset
-#?   $print [array underlying buf: ], s:address:array:character, 10/newline
-#?   $print [index: ], len:address:number/lookup, 10/newline
-  dest:address:character <- index-address s:address:array:character/lookup, len:address:number/lookup
-#?   $print [storing ], c:character, [ in ], dest:address:character, 10/newline
-  dest:address:character/lookup <- copy c:character
-  len:address:number/lookup <- add len:address:number/lookup, 1
-  reply in:address:buffer/same-as-ingredient:0
+  s:address:array:character <- get *in, data:offset
+#?   $print [array underlying buf: ], s, 10/newline
+#?   $print [index: ], *len, 10/newline
+  dest:address:character <- index-address *s, *len
+#?   $print [storing ], c, [ in ], dest, 10/newline
+  *dest <- copy c
+  *len <- add *len, 1
+  reply in/same-as-ingredient:0
 ]
 
 scenario buffer-append-works [
   run [
     local-scope
     x:address:buffer <- new-buffer 3
-    s1:address:array:character <- get x:address:buffer/lookup, data:offset
+    s1:address:array:character <- get *x:address:buffer, data:offset
     x:address:buffer <- buffer-append x:address:buffer, 97  # 'a'
     x:address:buffer <- buffer-append x:address:buffer, 98  # 'b'
     x:address:buffer <- buffer-append x:address:buffer, 99  # 'c'
-    s2:address:array:character <- get x:address:buffer/lookup, data:offset
+    s2:address:array:character <- get *x:address:buffer, data:offset
     1:boolean/raw <- equal s1:address:array:character, s2:address:array:character
-    2:array:character/raw <- copy s2:address:array:character/lookup
+    2:array:character/raw <- copy *s2:address:array:character
     +buffer-filled
     x:address:buffer <- buffer-append x:address:buffer, 100  # 'd'
-    s3:address:array:character <- get x:address:buffer/lookup, data:offset
+    s3:address:array:character <- get *x:address:buffer, data:offset
     10:boolean/raw <- equal s1:address:array:character, s3:address:array:character
-    11:number/raw <- get x:address:buffer/lookup, length:offset
-    12:array:character/raw <- copy s3:address:array:character/lookup
+    11:number/raw <- get *x:address:buffer, length:offset
+    12:array:character/raw <- copy *s3:address:array:character
   ]
   memory-should-contain [
     # before +buffer-filled
@@ -227,7 +227,7 @@ scenario buffer-append-handles-backspace [
     x:address:buffer <- buffer-append x:address:buffer, 98  # 'b'
     x:address:buffer <- buffer-append x:address:buffer, 8/backspace
     s:address:array:character <- buffer-to-array x:address:buffer
-    1:array:character/raw <- copy s:address:array:character/lookup
+    1:array:character/raw <- copy *s:address:array:character
   ]
   memory-should-contain [
     1 <- 1   # length
@@ -242,55 +242,53 @@ recipe integer-to-decimal-string [
   n:number <- next-ingredient
   # is it zero?
   {
-    break-if n:number
+    break-if n
     result:address:array:character <- new [0]
-    reply result:address:array:character
+    reply result
   }
   # save sign
   negate-result:boolean <- copy 0
   {
-    negative?:boolean <- lesser-than n:number, 0
-    break-unless negative?:boolean
-    negate-result:boolean <- copy 1
-    n:number <- multiply n:number, -1
+    negative?:boolean <- lesser-than n, 0
+    break-unless negative?
+    negate-result <- copy 1
+    n <- multiply n, -1
   }
   # add digits from right to left into intermediate buffer
   tmp:address:buffer <- new-buffer 30
   digit-base:number <- copy 48  # '0'
   {
-    done?:boolean <- equal n:number, 0
-    break-if done?:boolean
-    n:number, digit:number <- divide-with-remainder n:number, 10
-    c:character <- add digit-base:number, digit:number
-    tmp:address:buffer <- buffer-append tmp:address:buffer, c:character
+    done?:boolean <- equal n, 0
+    break-if done?
+    n, digit:number <- divide-with-remainder n, 10
+    c:character <- add digit-base, digit
+    tmp:address:buffer <- buffer-append tmp, c
     loop
   }
   # add sign
   {
     break-unless negate-result:boolean
-    tmp:address:buffer <- buffer-append tmp:address:buffer, 45  # '-'
+    tmp <- buffer-append tmp, 45  # '-'
   }
   # reverse buffer into string result
-  len:number <- get tmp:address:buffer/lookup, length:offset
-  buf:address:array:character <- get tmp:address:buffer/lookup, data:offset
-  result:address:array:character <- new character:type, len:number
-  i:number <- subtract len:number, 1
-  j:number <- copy 0
+  len:number <- get *tmp, length:offset
+  buf:address:array:character <- get *tmp, data:offset
+  result:address:array:character <- new character:type, len
+  i:number <- subtract len, 1  # source index, decreasing
+  j:number <- copy 0  # destination index, increasing
   {
     # while i >= 0
-    done?:boolean <- lesser-than i:number, 0
-    break-if done?:boolean
+    done?:boolean <- lesser-than i, 0
+    break-if done?
     # result[j] = tmp[i]
-    src:character <- index buf:address:array:character/lookup, i:number
-    dest:address:character <- index-address result:address:array:character/lookup, j:number
-    dest:address:character/lookup <- copy src:character
-    # ++i
-    i:number <- subtract i:number, 1
-    # --j
-    j:number <- add j:number, 1
+    src:character <- index *buf, i
+    dest:address:character <- index-address *result, j
+    *dest <- copy src
+    i <- subtract i, 1
+    j <- add j, 1
     loop
   }
-  reply result:address:array:character
+  reply result
 ]
 
 recipe buffer-to-array [
@@ -298,32 +296,32 @@ recipe buffer-to-array [
   in:address:buffer <- next-ingredient
   {
     # propagate null buffer
-    break-if in:address:buffer
+    break-if in
     reply 0
   }
-  len:number <- get in:address:buffer/lookup, length:offset
-#?   $print [size ], len:number, 10/newline
-  s:address:array:character <- get in:address:buffer/lookup, data:offset
+  len:number <- get *in, length:offset
+#?   $print [size ], len, 10/newline
+  s:address:array:character <- get *in, data:offset
   # we can't just return s because it is usually the wrong length
-  result:address:array:character <- new character:type, len:number
+  result:address:array:character <- new character:type, len
   i:number <- copy 0
   {
-#?     $print i:number #? 1
-    done?:boolean <- greater-or-equal i:number, len:number
-    break-if done?:boolean
-    src:character <- index s:address:array:character/lookup, i:number
-    dest:address:character <- index-address result:address:array:character/lookup, i:number
-    dest:address:character/lookup <- copy src:character
-    i:number <- add i:number, 1
+#?     $print i #? 1
+    done?:boolean <- greater-or-equal i, len
+    break-if done?
+    src:character <- index *s, i
+    dest:address:character <- index-address *result, i
+    *dest <- copy src
+    i <- add i, 1
     loop
   }
-  reply result:address:array:character
+  reply result
 ]
 
 scenario integer-to-decimal-digit-zero [
   run [
     1:address:array:character/raw <- integer-to-decimal-string 0
-    2:array:character/raw <- copy 1:address:array:character/lookup/raw
+    2:array:character/raw <- copy *1:address:array:character/raw
   ]
   memory-should-contain [
     2:string <- [0]
@@ -333,7 +331,7 @@ scenario integer-to-decimal-digit-zero [
 scenario integer-to-decimal-digit-positive [
   run [
     1:address:array:character/raw <- integer-to-decimal-string 234
-    2:array:character/raw <- copy 1:address:array:character/lookup/raw
+    2:array:character/raw <- copy *1:address:array:character/raw
   ]
   memory-should-contain [
     2:string <- [234]
@@ -343,7 +341,7 @@ scenario integer-to-decimal-digit-positive [
 scenario integer-to-decimal-digit-negative [
   run [
     1:address:array:character/raw <- integer-to-decimal-string -1
-    2:array:character/raw <- copy 1:address:array:character/lookup/raw
+    2:array:character/raw <- copy *1:address:array:character/raw
   ]
   memory-should-contain [
     2 <- 2
@@ -357,45 +355,41 @@ recipe string-append [
   local-scope
   # result = new character[a.length + b.length]
   a:address:array:character <- next-ingredient
-  a-len:number <- length a:address:array:character/lookup
+  a-len:number <- length *a
   b:address:array:character <- next-ingredient
-  b-len:number <- length b:address:array:character/lookup
-  result-len:number <- add a-len:number, b-len:number
-  result:address:array:character <- new character:type, result-len:number
+  b-len:number <- length *b
+  result-len:number <- add a-len, b-len
+  result:address:array:character <- new character:type, result-len
   # copy a into result
   result-idx:number <- copy 0
   i:number <- copy 0
   {
     # while i < a.length
-    a-done?:boolean <- greater-or-equal i:number, a-len:number
-    break-if a-done?:boolean
+    a-done?:boolean <- greater-or-equal i, a-len
+    break-if a-done?
     # result[result-idx] = a[i]
-    out:address:character <- index-address result:address:array:character/lookup, result-idx:number
-    in:character <- index a:address:array:character/lookup, i:number
-    out:address:character/lookup <- copy in:character
-    # ++i
-    i:number <- add i:number, 1
-    # ++result-idx
-    result-idx:number <- add result-idx:number, 1
+    out:address:character <- index-address *result, result-idx
+    in:character <- index *a, i
+    *out <- copy in
+    i <- add i, 1
+    result-idx <- add result-idx, 1
     loop
   }
   # copy b into result
-  i:number <- copy 0
+  i <- copy 0
   {
     # while i < b.length
-    b-done?:boolean <- greater-or-equal i:number, b-len:number
-    break-if b-done?:boolean
+    b-done?:boolean <- greater-or-equal i, b-len
+    break-if b-done?
     # result[result-idx] = a[i]
-    out:address:character <- index-address result:address:array:character/lookup, result-idx:number
-    in:character <- index b:address:array:character/lookup, i:number
-    out:address:character/lookup <- copy in:character
-    # ++i
-    i:number <- add i:number, 1
-    # ++result-idx
-    result-idx:number <- add result-idx:number, 1
+    out:address:character <- index-address *result, result-idx
+    in:character <- index *b, i
+    *out <- copy in
+    i <- add i, 1
+    result-idx <- add result-idx, 1
     loop
   }
-  reply result:address:array:character
+  reply result
 ]
 
 scenario string-append-1 [
@@ -403,7 +397,7 @@ scenario string-append-1 [
     1:address:array:character/raw <- new [hello,]
     2:address:array:character/raw <- new [ world!]
     3:address:array:character/raw <- string-append 1:address:array:character/raw, 2:address:array:character/raw
-    4:array:character/raw <- copy 3:address:array:character/raw/lookup
+    4:array:character/raw <- copy *3:address:array:character/raw
   ]
   memory-should-contain [
     4:string <- [hello, world!]
@@ -416,85 +410,78 @@ recipe interpolate [
   local-scope
   template:address:array:character <- next-ingredient
   # compute result-len, space to allocate for result
-  tem-len:number <- length template:address:array:character/lookup
-  result-len:number <- copy tem-len:number
+  tem-len:number <- length *template
+  result-len:number <- copy tem-len
   {
     # while arg received
     a:address:array:character, arg-received?:boolean <- next-ingredient
-    break-unless arg-received?:boolean
-    # result-len = result-len + arg.length - 1 for the 'underscore' being replaced
-    a-len:number <- length a:address:array:character/lookup
-    result-len:number <- add result-len:number, a-len:number
-    result-len:number <- subtract result-len:number, 1
+    break-unless arg-received?
+    # result-len = result-len + arg.length - 1 (for the 'underscore' being replaced)
+    a-len:number <- length *a
+    result-len <- add result-len, a-len
+    result-len <- subtract result-len, 1
     loop
   }
-#?   $print tem-len:number, [ ], $result-len:number, 10/newline
+#?   $print tem-len, [ ], $result-len, 10/newline
   rewind-ingredients
   _ <- next-ingredient  # skip template
-  # result = new array:character[result-len]
-  result:address:array:character <- new character:type, result-len:number
+  result:address:array:character <- new character:type, result-len
   # repeatedly copy sections of template and 'holes' into result
   result-idx:number <- copy 0
   i:number <- copy 0
   {
     # while arg received
     a:address:array:character, arg-received?:boolean <- next-ingredient
-    break-unless arg-received?:boolean
+    break-unless arg-received?
     # copy template into result until '_'
     {
       # while i < template.length
-      tem-done?:boolean <- greater-or-equal i:number, tem-len:number
-      break-if tem-done?:boolean, +done:label
+      tem-done?:boolean <- greater-or-equal i, tem-len
+      break-if tem-done?, +done:label
       # while template[i] != '_'
-      in:character <- index template:address:array:character/lookup, i:number
-      underscore?:boolean <- equal in:character, 95  # '_'
-      break-if underscore?:boolean
+      in:character <- index *template, i
+      underscore?:boolean <- equal in, 95/_
+      break-if underscore?
       # result[result-idx] = template[i]
-      out:address:character <- index-address result:address:array:character/lookup, result-idx:number
-      out:address:character/lookup <- copy in:character
-      # ++i
-      i:number <- add i:number, 1
-      # ++result-idx
-      result-idx:number <- add result-idx:number, 1
+      out:address:character <- index-address *result, result-idx
+      *out <- copy in
+      i <- add i, 1
+      result-idx <- add result-idx, 1
       loop
     }
     # copy 'a' into result
     j:number <- copy 0
     {
       # while j < a.length
-      arg-done?:boolean <- greater-or-equal j:number, a-len:number
-      break-if arg-done?:boolean
+      arg-done?:boolean <- greater-or-equal j, a-len
+      break-if arg-done?
       # result[result-idx] = a[j]
-      in:character <- index a:address:array:character/lookup, j:number
-      out:address:character <- index-address result:address:array:character/lookup, result-idx:number
-      out:address:character/lookup <- copy in:character
-      # ++j
-      j:number <- add j:number, 1
-      # ++result-idx
-      result-idx:number <- add result-idx:number, 1
+      in:character <- index *a, j
+      out:address:character <- index-address *result, result-idx
+      *out <- copy in
+      j <- add j, 1
+      result-idx <- add result-idx, 1
       loop
     }
     # skip '_' in template
-    i:number <- add i:number, 1
+    i <- add i, 1
     loop  # interpolate next arg
   }
   +done
   # done with holes; copy rest of template directly into result
   {
     # while i < template.length
-    tem-done?:boolean <- greater-or-equal i:number, tem-len:number
-    break-if tem-done?:boolean
+    tem-done?:boolean <- greater-or-equal i, tem-len
+    break-if tem-done?
     # result[result-idx] = template[i]
-    in:character <- index template:address:array:character/lookup, i:number
-    out:address:character <- index-address result:address:array:character/lookup, result-idx:number
-    out:address:character/lookup <- copy in:character
-    # ++i
-    i:number <- add i:number, 1
-    # ++result-idx
-    result-idx:number <- add result-idx:number, 1
+    in:character <- index *template, i
+    out:address:character <- index-address *result, result-idx:number
+    *out <- copy in
+    i <- add i, 1
+    result-idx <- add result-idx, 1
     loop
   }
-  reply result:address:array:character
+  reply result
 ]
 
 scenario interpolate-works [
@@ -503,7 +490,7 @@ scenario interpolate-works [
     1:address:array:character/raw <- new [abc _]
     2:address:array:character/raw <- new [def]
     3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw
-    4:array:character/raw <- copy 3:address:array:character/raw/lookup
+    4:array:character/raw <- copy *3:address:array:character/raw
   ]
   memory-should-contain [
     4:string <- [abc def]
@@ -515,7 +502,7 @@ scenario interpolate-at-start [
     1:address:array:character/raw <- new [_, hello!]
     2:address:array:character/raw <- new [abc]
     3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw
-    4:array:character/raw <- copy 3:address:array:character/raw/lookup
+    4:array:character/raw <- copy *3:address:array:character/raw
   ]
   memory-should-contain [
     4:string <- [abc, hello!]
@@ -528,7 +515,7 @@ scenario interpolate-at-end [
     1:address:array:character/raw <- new [hello, _]
     2:address:array:character/raw <- new [abc]
     3:address:array:character/raw <- interpolate 1:address:array:character/raw, 2:address:array:character/raw
-    4:array:character/raw <- copy 3:address:array:character/raw/lookup
+    4:array:character/raw <- copy *3:address:array:character/raw
   ]
   memory-should-contain [
     4:string <- [hello, abc]
@@ -540,124 +527,123 @@ recipe space? [
   local-scope
   c:character <- next-ingredient
   # most common case first
-  result:boolean <- equal c:character, 32/space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 10/newline
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 9/tab
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 13/carriage-return
+  result:boolean <- equal c, 32/space
+  jump-if result +reply:label
+  result <- equal c, 10/newline
+  jump-if result, +reply:label
+  result <- equal c, 9/tab
+  jump-if result, +reply:label
+  result <- equal c, 13/carriage-return
+  jump-if result, +reply:label
   # remaining uncommon cases in sorted order
   # http://unicode.org code-points in unicode-set Z and Pattern_White_Space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 11/ctrl-k
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 12/ctrl-l
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 133/ctrl-0085
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 160/no-break-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 5760/ogham-space-mark
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8192/en-quad
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8193/em-quad
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8194/en-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8195/em-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8196/three-per-em-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8197/four-per-em-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8198/six-per-em-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8199/figure-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8200/punctuation-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8201/thin-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8202/hair-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8206/left-to-right
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8207/right-to-left
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8232/line-separator
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8233/paragraph-separator
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8239/narrow-no-break-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 8287/medium-mathematical-space
-  jump-if result:boolean, +reply:label
-  result:boolean <- equal c:character, 12288/ideographic-space
-  jump-if result:boolean, +reply:label
+  result <- equal c, 11/ctrl-k
+  jump-if result, +reply:label
+  result <- equal c, 12/ctrl-l
+  jump-if result, +reply:label
+  result <- equal c, 133/ctrl-0085
+  jump-if result, +reply:label
+  result <- equal c, 160/no-break-space
+  jump-if result, +reply:label
+  result <- equal c, 5760/ogham-space-mark
+  jump-if result, +reply:label
+  result <- equal c, 8192/en-quad
+  jump-if result, +reply:label
+  result <- equal c, 8193/em-quad
+  jump-if result, +reply:label
+  result <- equal c, 8194/en-space
+  jump-if result, +reply:label
+  result <- equal c, 8195/em-space
+  jump-if result, +reply:label
+  result <- equal c, 8196/three-per-em-space
+  jump-if result, +reply:label
+  result <- equal c, 8197/four-per-em-space
+  jump-if result, +reply:label
+  result <- equal c, 8198/six-per-em-space
+  jump-if result, +reply:label
+  result <- equal c, 8199/figure-space
+  jump-if result, +reply:label
+  result <- equal c, 8200/punctuation-space
+  jump-if result, +reply:label
+  result <- equal c, 8201/thin-space
+  jump-if result, +reply:label
+  result <- equal c, 8202/hair-space
+  jump-if result, +reply:label
+  result <- equal c, 8206/left-to-right
+  jump-if result, +reply:label
+  result <- equal c, 8207/right-to-left
+  jump-if result, +reply:label
+  result <- equal c, 8232/line-separator
+  jump-if result, +reply:label
+  result <- equal c, 8233/paragraph-separator
+  jump-if result, +reply:label
+  result <- equal c, 8239/narrow-no-break-space
+  jump-if result, +reply:label
+  result <- equal c, 8287/medium-mathematical-space
+  jump-if result, +reply:label
+  result <- equal c, 12288/ideographic-space
+  jump-if result, +reply:label
   +reply
-  reply result:boolean
+  reply result
 ]
 
 # result:address:array:character <- trim s:address:array:character
 recipe trim [
   local-scope
   s:address:array:character <- next-ingredient
-  len:number <- length s:address:array:character/lookup
+  len:number <- length *s
   # left trim: compute start
   start:number <- copy 0
   {
     {
-      at-end?:boolean <- greater-or-equal start:number, len:number
-      break-unless at-end?:boolean
+      at-end?:boolean <- greater-or-equal start, len
+      break-unless at-end?
       result:address:array:character <- new character:type, 0
-      reply result:address:array:character
+      reply result
     }
-    curr:character <- index s:address:array:character/lookup, start:number
-    whitespace?:boolean <- space? curr:character
-    break-unless whitespace?:boolean
-    start:number <- add start:number, 1
+    curr:character <- index *s, start
+    whitespace?:boolean <- space? curr
+    break-unless whitespace?
+    start <- add start, 1
     loop
   }
   # right trim: compute end
-  end:number <- subtract len:number, 1
+  end:number <- subtract len, 1
   {
-    not-at-start?:boolean <- greater-than end:number, start:number
-    assert not-at-start?:boolean [end ran up against start]
-    curr:character <- index s:address:array:character/lookup, end:number
-    whitespace?:boolean <- space? curr:character
-    break-unless whitespace?:boolean
-    end:number <- subtract end:number, 1
+    not-at-start?:boolean <- greater-than end, start
+    assert not-at-start?, [end ran up against start]
+    curr:character <- index *s, end
+    whitespace?:boolean <- space? curr
+    break-unless whitespace?
+    end <- subtract end, 1
     loop
   }
   # result = new character[end+1 - start]
-  new-len:number <- subtract end:number, start:number, -1
-  result:address:array:character <- new character:type, new-len:number
+  new-len:number <- subtract end, start, -1
+  result:address:array:character <- new character:type, new-len
   # i = start, j = 0
-  i:number <- copy start:number
+  i:number <- copy start
   j:number <- copy 0
   {
     # while i <= end
-    done?:boolean <- greater-than i:number, end:number
-    break-if done?:boolean
+    done?:boolean <- greater-than i, end
+    break-if done?
     # result[j] = s[i]
-    src:character <- index s:address:array:character/lookup, i:number
-    dest:address:character <- index-address result:address:array:character/lookup, j:number
-    dest:address:character/lookup <- copy src:character
-    # ++i, ++j
-    i:number <- add i:number, 1
-    j:number <- add j:number, 1
+    src:character <- index *s, i
+    dest:address:character <- index-address *result, j
+    *dest <- copy src
+    i <- add i, 1
+    j <- add j, 1
     loop
   }
-  reply result:address:array:character
+  reply result
 ]
 
 scenario trim-unmodified [
   run [
     1:address:array:character <- new [abc]
     2:address:array:character <- trim 1:address:array:character
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [abc]
@@ -668,7 +654,7 @@ scenario trim-left [
   run [
     1:address:array:character <- new [  abc]
     2:address:array:character <- trim 1:address:array:character
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [abc]
@@ -679,7 +665,7 @@ scenario trim-right [
   run [
     1:address:array:character <- new [abc  ]
     2:address:array:character <- trim 1:address:array:character
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [abc]
@@ -690,7 +676,7 @@ scenario trim-left-right [
   run [
     1:address:array:character <- new [  abc   ]
     2:address:array:character <- trim 1:address:array:character
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [abc]
@@ -702,30 +688,30 @@ scenario trim-newline-tab [
     1:address:array:character <- new [	abc
 ]
     2:address:array:character <- trim 1:address:array:character
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [abc]
   ]
 ]
 
-# next-index:number <- find-next text:address:array:character, pattern:character
+# next-index:number <- find-next text:address:array:character, pattern:character, idx:number
 recipe find-next [
   local-scope
   text:address:array:character <- next-ingredient
   pattern:character <- next-ingredient
   idx:number <- next-ingredient
-  len:number <- length text:address:array:character/lookup
+  len:number <- length *text
   {
-    eof?:boolean <- greater-or-equal idx:number, len:number
-    break-if eof?:boolean
-    curr:character <- index text:address:array:character/lookup, idx:number
-    found?:boolean <- equal curr:character, pattern:character
-    break-if found?:boolean
-    idx:number <- add idx:number, 1
+    eof?:boolean <- greater-or-equal idx, len
+    break-if eof?
+    curr:character <- index *text, idx
+    found?:boolean <- equal curr, pattern
+    break-if found?
+    idx <- add idx, 1
     loop
   }
-  reply idx:number
+  reply idx
 ]
 
 scenario string-find-next [
@@ -808,6 +794,7 @@ scenario string-find-next-second [
   ]
 ]
 
+# idx:number <- find-substring text:address:array:character, pattern:address:array:character, idx:number
 # like find-next, but searches for multiple characters
 # fairly dumb algorithm
 recipe find-substring [
@@ -815,21 +802,21 @@ recipe find-substring [
   text:address:array:character <- next-ingredient
   pattern:address:array:character <- next-ingredient
   idx:number <- next-ingredient
-  first:character <- index pattern:address:array:character/lookup, 0
+  first:character <- index *pattern, 0
   # repeatedly check for match at current idx
-  len:number <- length text:address:array:character/lookup
+  len:number <- length *text
   {
     # does some unnecessary work checking for substrings even when there isn't enough of text left
-    done?:boolean <- greater-or-equal idx:number, len:number
-    break-if done?:boolean
-    found?:boolean <- match-at text:address:array:character pattern:address:array:character, idx:number
-    break-if found?:boolean
-    idx:number <- add idx:number, 1
+    done?:boolean <- greater-or-equal idx, len
+    break-if done?
+    found?:boolean <- match-at text, pattern, idx
+    break-if found?
+    idx <- add idx, 1
     # optimization: skip past indices that definitely won't match
-    idx:number <- find-next text:address:array:character, first:character, idx:number
+    idx <- find-next text, first, idx
     loop
   }
-  reply idx:number
+  reply idx
 ]
 
 scenario find-substring-1 [
@@ -894,29 +881,29 @@ recipe match-at [
   text:address:array:character <- next-ingredient
   pattern:address:array:character <- next-ingredient
   idx:number <- next-ingredient
-  pattern-len:number <- length pattern:address:array:character/lookup
+  pattern-len:number <- length *pattern
   # check that there's space left for the pattern
   {
-    x:number <- length text:address:array:character/lookup
-    x:number <- subtract x:number, pattern-len:number
-    enough-room?:boolean <- lesser-or-equal idx:number, x:number
-    break-if enough-room?:boolean
+    x:number <- length *text
+    x <- subtract x, pattern-len
+    enough-room?:boolean <- lesser-or-equal idx, x
+    break-if enough-room?
     reply 0/not-found
   }
   # check each character of pattern
   pattern-idx:number <- copy 0
   {
-    done?:boolean <- greater-or-equal pattern-idx:number, pattern-len:number
-    break-if done?:boolean
-    c:character <- index text:address:array:character/lookup, idx:number
-    exp:character <- index pattern:address:array:character/lookup, pattern-idx:number
+    done?:boolean <- greater-or-equal pattern-idx, pattern-len
+    break-if done?
+    c:character <- index *text, idx
+    exp:character <- index *pattern, pattern-idx
     {
-      match?:boolean <- equal c:character, exp:character
-      break-if match?:boolean
+      match?:boolean <- equal c, exp
+      break-if match?
       reply 0/not-found
     }
-    idx:number <- add idx:number, 1
-    pattern-idx:number <- add pattern-idx:number, 1
+    idx <- add idx, 1
+    pattern-idx <- add pattern-idx, 1
     loop
   }
   reply 1/found
@@ -1025,54 +1012,54 @@ recipe split [
   s:address:array:character <- next-ingredient
   delim:character <- next-ingredient
   # empty string? return empty array
-  len:number <- length s:address:array:character/lookup
+  len:number <- length *s
   {
-    empty?:boolean <- equal len:number, 0
-    break-unless empty?:boolean
+    empty?:boolean <- equal len, 0
+    break-unless empty?
     result:address:array:address:array:character <- new location:type, 0
-    reply result:address:array:address:array:character
+    reply result
   }
   # count #pieces we need room for
   count:number <- copy 1  # n delimiters = n+1 pieces
   idx:number <- copy 0
   {
-    idx:number <- find-next s:address:array:character, delim:character, idx:number
-    done?:boolean <- greater-or-equal idx:number, len:number
-    break-if done?:boolean
-    idx:number <- add idx:number, 1
-    count:number <- add count:number, 1
+    idx <- find-next s, delim, idx
+    done?:boolean <- greater-or-equal idx, len
+    break-if done?
+    idx <- add idx, 1
+    count <- add count, 1
     loop
   }
   # allocate space
-  result:address:array:address:array:character <- new location:type, count:number
+  result:address:array:address:array:character <- new location:type, count
   # repeatedly copy slices start..end until delimiter into result[curr-result]
   curr-result:number <- copy 0
   start:number <- copy 0
   {
     # while next delim exists
-    done?:boolean <- greater-or-equal start:number, len:number
-    break-if done?:boolean
-    end:number <- find-next s:address:array:character, delim:character, start:number
+    done?:boolean <- greater-or-equal start, len
+    break-if done?
+    end:number <- find-next s, delim, start
     # copy start..end into result[curr-result]
-    dest:address:address:array:character <- index-address result:address:array:address:array:character/lookup, curr-result:number
-    dest:address:address:array:character/lookup <- string-copy s:address:array:character, start:number, end:number
+    dest:address:address:array:character <- index-address *result, curr-result
+    *dest <- string-copy s, start, end
     # slide over to next slice
-    start:number <- add end:number, 1
-    curr-result:number <- add curr-result:number, 1
+    start <- add end, 1
+    curr-result <- add curr-result, 1
     loop
   }
-  reply result:address:array:address:array:character
+  reply result
 ]
 
 scenario string-split-1 [
   run [
     1:address:array:character <- new [a/b]
     2:address:array:address:array:character <- split 1:address:array:character, 47/slash
-    3:number <- length 2:address:array:address:array:character/lookup
-    4:address:array:character <- index 2:address:array:address:array:character/lookup, 0
-    5:address:array:character <- index 2:address:array:address:array:character/lookup, 1
-    10:array:character <- copy 4:address:array:character/lookup
-    20:array:character <- copy 5:address:array:character/lookup
+    3:number <- length *2:address:array:address:array:character
+    4:address:array:character <- index *2:address:array:address:array:character, 0
+    5:address:array:character <- index *2:address:array:address:array:character, 1
+    10:array:character <- copy *4:address:array:character
+    20:array:character <- copy *5:address:array:character
   ]
   memory-should-contain [
     3 <- 2  # length of result
@@ -1085,13 +1072,13 @@ scenario string-split-2 [
   run [
     1:address:array:character <- new [a/b/c]
     2:address:array:address:array:character <- split 1:address:array:character, 47/slash
-    3:number <- length 2:address:array:address:array:character/lookup
-    4:address:array:character <- index 2:address:array:address:array:character/lookup, 0
-    5:address:array:character <- index 2:address:array:address:array:character/lookup, 1
-    6:address:array:character <- index 2:address:array:address:array:character/lookup, 2
-    10:array:character <- copy 4:address:array:character/lookup
-    20:array:character <- copy 5:address:array:character/lookup
-    30:array:character <- copy 6:address:array:character/lookup
+    3:number <- length *2:address:array:address:array:character
+    4:address:array:character <- index *2:address:array:address:array:character, 0
+    5:address:array:character <- index *2:address:array:address:array:character, 1
+    6:address:array:character <- index *2:address:array:address:array:character, 2
+    10:array:character <- copy *4:address:array:character
+    20:array:character <- copy *5:address:array:character
+    30:array:character <- copy *6:address:array:character
   ]
   memory-should-contain [
     3 <- 3  # length of result
@@ -1105,9 +1092,9 @@ scenario string-split-missing [
   run [
     1:address:array:character <- new [abc]
     2:address:array:address:array:character <- split 1:address:array:character, 47/slash
-    3:number <- length 2:address:array:address:array:character/lookup
-    4:address:array:character <- index 2:address:array:address:array:character/lookup, 0
-    10:array:character <- copy 4:address:array:character/lookup
+    3:number <- length *2:address:array:address:array:character
+    4:address:array:character <- index *2:address:array:address:array:character, 0
+    10:array:character <- copy *4:address:array:character
   ]
   memory-should-contain [
     3 <- 1  # length of result
@@ -1119,7 +1106,7 @@ scenario string-split-empty [
   run [
     1:address:array:character <- new []
     2:address:array:address:array:character <- split 1:address:array:character, 47/slash
-    3:number <- length 2:address:array:address:array:character/lookup
+    3:number <- length *2:address:array:address:array:character
   ]
   memory-should-contain [
     3 <- 0  # empty result
@@ -1130,15 +1117,15 @@ scenario string-split-empty-piece [
   run [
     1:address:array:character <- new [a/b//c]
     2:address:array:address:array:character <- split 1:address:array:character, 47/slash
-    3:number <- length 2:address:array:address:array:character/lookup
-    4:address:array:character <- index 2:address:array:address:array:character/lookup, 0
-    5:address:array:character <- index 2:address:array:address:array:character/lookup, 1
-    6:address:array:character <- index 2:address:array:address:array:character/lookup, 2
-    7:address:array:character <- index 2:address:array:address:array:character/lookup, 3
-    10:array:character <- copy 4:address:array:character/lookup
-    20:array:character <- copy 5:address:array:character/lookup
-    30:array:character <- copy 6:address:array:character/lookup
-    40:array:character <- copy 7:address:array:character/lookup
+    3:number <- length *2:address:array:address:array:character
+    4:address:array:character <- index *2:address:array:address:array:character, 0
+    5:address:array:character <- index *2:address:array:address:array:character, 1
+    6:address:array:character <- index *2:address:array:address:array:character, 2
+    7:address:array:character <- index *2:address:array:address:array:character, 3
+    10:array:character <- copy *4:address:array:character
+    20:array:character <- copy *5:address:array:character
+    30:array:character <- copy *6:address:array:character
+    40:array:character <- copy *7:address:array:character
   ]
   memory-should-contain [
     3 <- 4  # length of result
@@ -1155,27 +1142,27 @@ recipe split-first [
   text:address:array:character <- next-ingredient
   delim:character <- next-ingredient
   # empty string? return empty strings
-  len:number <- length text:address:array:character/lookup
+  len:number <- length *text
   {
-    empty?:boolean <- equal len:number, 0
-    break-unless empty?:boolean
+    empty?:boolean <- equal len, 0
+    break-unless empty?
     x:address:array:character <- new []
     y:address:array:character <- new []
-    reply x:address:array:character, y:address:array:character
+    reply x, y
   }
-  idx:number <- find-next text:address:array:character, delim:character, 0
-  x:address:array:character <- string-copy text:address:array:character, 0, idx:number
-  idx:number <- add idx:number, 1
-  y:address:array:character <- string-copy text:address:array:character, idx:number, len:number
-  reply x:address:array:character, y:address:array:character
+  idx:number <- find-next text, delim, 0
+  x:address:array:character <- string-copy text, 0, idx
+  idx <- add idx, 1
+  y:address:array:character <- string-copy text, idx, len
+  reply x, y
 ]
 
 scenario string-split-first [
   run [
     1:address:array:character <- new [a/b]
     2:address:array:character, 3:address:array:character <- split-first 1:address:array:character, 47/slash
-    10:array:character <- copy 2:address:array:character/lookup
-    20:array:character <- copy 3:address:array:character/lookup
+    10:array:character <- copy *2:address:array:character
+    20:array:character <- copy *3:address:array:character
   ]
   memory-should-contain [
     10:string <- [a]
@@ -1191,32 +1178,32 @@ recipe string-copy [
   start:number <- next-ingredient
   end:number <- next-ingredient
   # if end is out of bounds, trim it
-  len:number <- length buf:address:array:character/lookup
-  end:number <- min len:number, end:number
+  len:number <- length *buf
+  end:number <- min len, end
   # allocate space for result
-  len:number <- subtract end:number, start:number
-  result:address:array:character <- new character:type, len:number
+  len <- subtract end, start
+  result:address:array:character <- new character:type, len
   # copy start..end into result[curr-result]
-  src-idx:number <- copy start:number
+  src-idx:number <- copy start
   dest-idx:number <- copy 0
   {
-    done?:boolean <- greater-or-equal src-idx:number, end:number
-    break-if done?:boolean
-    src:character <- index buf:address:array:character/lookup, src-idx:number
-    dest:address:character <- index-address result:address:array:character/lookup, dest-idx:number
-    dest:address:character/lookup <- copy src:character
-    src-idx:number <- add src-idx:number, 1
-    dest-idx:number <- add dest-idx:number, 1
+    done?:boolean <- greater-or-equal src-idx, end
+    break-if done?
+    src:character <- index *buf, src-idx
+    dest:address:character <- index-address *result, dest-idx
+    *dest <- copy src
+    src-idx <- add src-idx, 1
+    dest-idx <- add dest-idx, 1
     loop
   }
-  reply result:address:array:character
+  reply result
 ]
 
 scenario string-copy-copies-substring [
   run [
     1:address:array:character <- new [abc]
     2:address:array:character <- string-copy 1:address:array:character, 1, 3
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [bc]
@@ -1227,7 +1214,7 @@ scenario string-copy-out-of-bounds [
   run [
     1:address:array:character <- new [abc]
     2:address:array:character <- string-copy 1:address:array:character, 2, 4
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- [c]
@@ -1238,7 +1225,7 @@ scenario string-copy-out-of-bounds-2 [
   run [
     1:address:array:character <- new [abc]
     2:address:array:character <- string-copy 1:address:array:character, 3, 3
-    3:array:character <- copy 2:address:array:character/lookup
+    3:array:character <- copy *2:address:array:character
   ]
   memory-should-contain [
     3:string <- []
@@ -1250,11 +1237,11 @@ recipe min [
   x:number <- next-ingredient
   y:number <- next-ingredient
   {
-    return-x?:boolean <- lesser-than x:number, y:number
-    break-if return-x?:boolean
-    reply y:number
+    return-x?:boolean <- lesser-than x, y
+    break-if return-x?
+    reply y
   }
-  reply x:number
+  reply x
 ]
 
 recipe max [
@@ -1262,9 +1249,9 @@ recipe max [
   x:number <- next-ingredient
   y:number <- next-ingredient
   {
-    return-x?:boolean <- greater-than x:number, y:number
-    break-if return-x?:boolean
-    reply y:number
+    return-x?:boolean <- greater-than x, y
+    break-if return-x?
+    reply y
   }
-  reply x:number
+  reply x
 ]
diff --git a/061channel.mu b/061channel.mu
index 302e93c2..3470cc14 100644
--- a/061channel.mu
+++ b/061channel.mu
@@ -37,17 +37,17 @@ recipe new-channel [
   # result = new channel
   result:address:channel <- new channel:type
   # result.first-full = 0
-  full:address:number <- get-address result:address:channel/lookup, first-full:offset
-  full:address:number/lookup <- copy 0
+  full:address:number <- get-address *result, first-full:offset
+  *full <- copy 0
   # result.first-free = 0
-  free:address:number <- get-address result:address:channel/lookup, first-free:offset
-  free:address:number/lookup <- copy 0
+  free:address:number <- get-address *result, first-free:offset
+  *free <- copy 0
   # result.data = new location[ingredient+1]
   capacity:number <- next-ingredient
-  capacity:number <- add capacity:number, 1  # unused slot for 'full?' below
-  dest:address:address:array:location <- get-address result:address:channel/lookup, data:offset
-  dest:address:address:array:location/lookup <- new location:type, capacity:number
-  reply result:address:channel
+  capacity <- add capacity, 1  # unused slot for 'full?' below
+  dest:address:address:array:location <- get-address *result, data:offset
+  *dest <- new location:type, capacity
+  reply result
 ]
 
 # chan:address:channel <- write chan:address:channel, val:location
@@ -57,26 +57,26 @@ recipe write [
   val:location <- next-ingredient
   {
     # block if chan is full
-    full:boolean <- channel-full? chan:address:channel
-    break-unless full:boolean
-    full-address:address:number <- get-address chan:address:channel/lookup, first-full:offset
-    wait-for-location full-address:address:number/lookup
+    full:boolean <- channel-full? chan
+    break-unless full
+    full-address:address:number <- get-address *chan, first-full:offset
+    wait-for-location *full-address
   }
   # store val
-  circular-buffer:address:array:location <- get chan:address:channel/lookup, data:offset
-  free:address:number <- get-address chan:address:channel/lookup, first-free:offset
-  dest:address:location <- index-address circular-buffer:address:array:location/lookup, free:address:number/lookup
-  dest:address:location/lookup <- copy val:location
-  # increment free
-  free:address:number/lookup <- add free:address:number/lookup, 1
+  circular-buffer:address:array:location <- get *chan, data:offset
+  free:address:number <- get-address *chan, first-free:offset
+  dest:address:location <- index-address *circular-buffer, *free
+  *dest <- copy val
+  # mark its slot as filled
+  *free <- add *free, 1
   {
     # wrap free around to 0 if necessary
-    len:number <- length circular-buffer:address:array:location/lookup
-    at-end?:boolean <- greater-or-equal free:address:number/lookup, len:number
-    break-unless at-end?:boolean
-    free:address:number/lookup <- copy 0
+    len:number <- length *circular-buffer
+    at-end?:boolean <- greater-or-equal *free, len
+    break-unless at-end?
+    *free <- copy 0
   }
-  reply chan:address:channel/same-as-ingredient:0
+  reply chan/same-as-ingredient:0
 ]
 
 # result:location, chan:address:channel <- read chan:address:channel
@@ -85,43 +85,43 @@ recipe read [
   chan:address:channel <- next-ingredient
   {
     # block if chan is empty
-    empty:boolean <- channel-empty? chan:address:channel
-    break-unless empty:boolean
-    free-address:address:number <- get-address chan:address:channel/lookup, first-free:offset
-    wait-for-location free-address:address:number/lookup
+    empty?:boolean <- channel-empty? chan
+    break-unless empty?
+    free-address:address:number <- get-address *chan, first-free:offset
+    wait-for-location *free-address
   }
   # read result
-  full:address:number <- get-address chan:address:channel/lookup, first-full:offset
-  circular-buffer:address:array:location <- get chan:address:channel/lookup, data:offset
-  result:location <- index circular-buffer:address:array:location/lookup, full:address:number/lookup
+  full:address:number <- get-address *chan, first-full:offset
+  circular-buffer:address:array:location <- get *chan, data:offset
+  result:location <- index *circular-buffer, *full
   # increment full
-  full:address:number/lookup <- add full:address:number/lookup, 1
+  *full <- add *full, 1
   {
     # wrap full around to 0 if necessary
-    len:number <- length circular-buffer:address:array:location/lookup
-    at-end?:boolean <- greater-or-equal full:address:number/lookup, len:number
-    break-unless at-end?:boolean
-    full:address:number/lookup <- copy 0
+    len:number <- length *circular-buffer
+    at-end?:boolean <- greater-or-equal *full, len
+    break-unless at-end?
+    *full <- copy 0
   }
-  reply result:location, chan:address:channel/same-as-ingredient:0
+  reply result, chan/same-as-ingredient:0
 ]
 
 recipe clear-channel [
   local-scope
   chan:address:channel <- next-ingredient
   {
-    empty?:boolean <- channel-empty? chan:address:channel
-    break-if empty?:boolean
-    _, chan:address:channel <- read chan:address:channel
+    empty?:boolean <- channel-empty? chan
+    break-if empty?
+    _, chan <- read chan
   }
-  reply chan:address:channel/same-as-ingredient:0
+  reply chan/same-as-ingredient:0
 ]
 
 scenario channel-initialization [
   run [
     1:address:channel <- new-channel 3/capacity
-    2:number <- get 1:address:channel/lookup, first-full:offset
-    3:number <- get 1:address:channel/lookup, first-free:offset
+    2:number <- get *1:address:channel, first-full:offset
+    3:number <- get *1:address:channel, first-free:offset
   ]
   memory-should-contain [
     2 <- 0  # first-full
@@ -133,8 +133,8 @@ scenario channel-write-increments-free [
   run [
     1:address:channel <- new-channel 3/capacity
     1:address:channel <- write 1:address:channel, 34
-    2:number <- get 1:address:channel/lookup, first-full:offset
-    3:number <- get 1:address:channel/lookup, first-free:offset
+    2:number <- get *1:address:channel, first-full:offset
+    3:number <- get *1:address:channel, first-free:offset
   ]
   memory-should-contain [
     2 <- 0  # first-full
@@ -147,8 +147,8 @@ scenario channel-read-increments-full [
     1:address:channel <- new-channel 3/capacity
     1:address:channel <- write 1:address:channel, 34
     _, 1:address:channel <- read 1:address:channel
-    2:number <- get 1:address:channel/lookup, first-full:offset
-    3:number <- get 1:address:channel/lookup, first-free:offset
+    2:number <- get *1:address:channel, first-full:offset
+    3:number <- get *1:address:channel, first-free:offset
   ]
   memory-should-contain [
     2 <- 1  # first-full
@@ -164,14 +164,14 @@ scenario channel-wrap [
     1:address:channel <- write 1:address:channel, 34
     _, 1:address:channel <- read 1:address:channel
     # first-free will now be 1
-    2:number <- get 1:address:channel/lookup, first-free:offset
-    3:number <- get 1:address:channel/lookup, first-free:offset
+    2:number <- get *1:address:channel, first-free:offset
+    3:number <- get *1:address:channel, first-free:offset
     # write second value, verify that first-free wraps
     1:address:channel <- write 1:address:channel, 34
-    4:number <- get 1:address:channel/lookup, first-free:offset
+    4:number <- get *1:address:channel, first-free:offset
     # read second value, verify that first-full wraps
     _, 1:address:channel <- read 1:address:channel
-    5:number <- get 1:address:channel/lookup, first-full:offset
+    5:number <- get *1:address:channel, first-full:offset
   ]
   memory-should-contain [
     2 <- 1  # first-free after first write
@@ -188,10 +188,10 @@ recipe channel-empty? [
   local-scope
   chan:address:channel <- next-ingredient
   # return chan.first-full == chan.first-free
-  full:number <- get chan:address:channel/lookup, first-full:offset
-  free:number <- get chan:address:channel/lookup, first-free:offset
-  result:boolean <- equal full:number, free:number
-  reply result:boolean
+  full:number <- get *chan, first-full:offset
+  free:number <- get *chan, first-free:offset
+  result:boolean <- equal full, free
+  reply result
 ]
 
 # A full channel has first-empty just before first-full, wasting one slot.
@@ -200,28 +200,28 @@ recipe channel-full? [
   local-scope
   chan:address:channel <- next-ingredient
   # tmp = chan.first-free + 1
-  tmp:number <- get chan:address:channel/lookup, first-free:offset
-  tmp:number <- add tmp:number, 1
+  tmp:number <- get *chan, first-free:offset
+  tmp <- add tmp, 1
   {
     # if tmp == chan.capacity, tmp = 0
-    len:number <- channel-capacity chan:address:channel
-    at-end?:boolean <- greater-or-equal tmp:number, len:number
-    break-unless at-end?:boolean
-    tmp:number <- copy 0
+    len:number <- channel-capacity chan
+    at-end?:boolean <- greater-or-equal tmp, len
+    break-unless at-end?
+    tmp <- copy 0
   }
   # return chan.first-full == tmp
-  full:number <- get chan:address:channel/lookup, first-full:offset
-  result:boolean <- equal full:number, tmp:number
-  reply result:boolean
+  full:number <- get *chan, first-full:offset
+  result:boolean <- equal full, tmp
+  reply result
 ]
 
 # result:number <- channel-capacity chan:address:channel
 recipe channel-capacity [
   local-scope
   chan:address:channel <- next-ingredient
-  q:address:array:location <- get chan:address:channel/lookup, data:offset
-  result:number <- length q:address:array:location/lookup
-  reply result:number
+  q:address:array:location <- get *chan, data:offset
+  result:number <- length *q
+  reply result
 ]
 
 scenario channel-new-empty-not-full [
@@ -280,8 +280,6 @@ scenario channel-read-not-full [
 # out:address:channel <- buffer-lines in:address:channel, out:address:channel
 recipe buffer-lines [
   local-scope
-#?   $print [buffer-lines: aaa
-#? ]
   in:address:channel <- next-ingredient
   out:address:channel <- next-ingredient
   # repeat forever
@@ -290,59 +288,46 @@ recipe buffer-lines [
     # read characters from 'in' until newline, copy into line
     {
       +next-character
-      c:character, in:address:channel <- read in:address:channel
+      c:character, in <- read in
       # drop a character on backspace
       {
         # special-case: if it's a backspace
-        backspace?:boolean <- equal c:character, 8
-        break-unless backspace?:boolean
+        backspace?:boolean <- equal c, 8
+        break-unless backspace?
         # drop previous character
-#?         close-console #? 2
-#?         $print [backspace!
-#? ] #? 1
         {
-          buffer-length:address:number <- get-address line:address:buffer/lookup, length:offset
-          buffer-empty?:boolean <- equal buffer-length:address:number/lookup, 0
-          break-if buffer-empty?:boolean
-#?           $print [before: ], buffer-length:address:number/lookup, 10/newline
-          buffer-length:address:number/lookup <- subtract buffer-length:address:number/lookup, 1
-#?           $print [after: ], buffer-length:address:number/lookup, 10/newline
+          buffer-length:address:number <- get-address *line, length:offset
+          buffer-empty?:boolean <- equal *buffer-length, 0
+          break-if buffer-empty?
+          *buffer-length <- subtract *buffer-length, 1
         }
-#?         $exit #? 2
         # and don't append this one
         loop +next-character:label
       }
       # append anything else
-#?       $print [buffer-lines: appending ], c:character, 10/newline
-      line:address:buffer <- buffer-append line:address:buffer, c:character
-      line-done?:boolean <- equal c:character, 10/newline
-      break-if line-done?:boolean
+      line <- buffer-append line, c
+      line-done?:boolean <- equal c, 10/newline
+      break-if line-done?
       # stop buffering on eof (currently only generated by fake console)
-      eof?:boolean <- equal c:character, 0/eof
-      break-if eof?:boolean
+      eof?:boolean <- equal c, 0/eof
+      break-if eof?
       loop
     }
-#?     close-console #? 1
     # copy line into 'out'
-#?     $print [buffer-lines: emitting
-#? ]
     i:number <- copy 0
-    line-contents:address:array:character <- get line:address:buffer/lookup, data:offset
-    max:number <- get line:address:buffer/lookup, length:offset
+    line-contents:address:array:character <- get *line, data:offset
+    max:number <- get *line, length:offset
     {
-      done?:boolean <- greater-or-equal i:number, max:number
-      break-if done?:boolean
-      c:character <- index line-contents:address:array:character/lookup, i:number
-      out:address:channel <- write out:address:channel, c:character
-#?       $print [writing ], i:number, [: ], c:character, 10/newline
-      i:number <- add i:number, 1
+      done?:boolean <- greater-or-equal i, max
+      break-if done?
+      c:character <- index *line-contents, i
+      out <- write out, c
+      i <- add i, 1
       loop
     }
-#?     $dump-trace #? 1
-#?     $exit #? 1
     loop
   }
-  reply out:address:channel/same-as-ingredient:1
+  reply out/same-as-ingredient:1
 ]
 
 scenario buffer-lines-blocks-until-newline [
diff --git a/062array.mu b/062array.mu
index dff9d319..c54020c0 100644
--- a/062array.mu
+++ b/062array.mu
@@ -1,7 +1,7 @@
 scenario array-from-args [
   run [
     1:address:array:location <- new-array 0, 1, 2
-    2:array:location <- copy 1:address:array:location/lookup
+    2:array:location <- copy *1:address:array:location
   ]
   memory-should-contain [
     2 <- 3  # array length
@@ -18,23 +18,23 @@ recipe new-array [
   {
     # while read curr-value
     curr-value:location, exists?:boolean <- next-ingredient
-    break-unless exists?:boolean
-    capacity:number <- add capacity:number, 1
+    break-unless exists?
+    capacity <- add capacity, 1
     loop
   }
-  result:address:array:location <- new location:type, capacity:number
+  result:address:array:location <- new location:type, capacity
   rewind-ingredients
   i:number <- copy 0
   {
     # while read curr-value
-    done?:boolean <- greater-or-equal i:number, capacity:number
-    break-if done?:boolean
+    done?:boolean <- greater-or-equal i, capacity
+    break-if done?
     curr-value:location, exists?:boolean <- next-ingredient
-    assert exists?:boolean, [error in rewinding ingredients to new-array]
-    tmp:address:location <- index-address result:address:array:location/lookup, i:number
-    tmp:address:location/lookup <- copy curr-value:location
-    i:number <- add i:number, 1
+    assert exists?, [error in rewinding ingredients to new-array]
+    tmp:address:location <- index-address *result, i
+    *tmp <- copy curr-value
+    i <- add i, 1
     loop
   }
-  reply result:address:array:location
+  reply result
 ]
diff --git a/063list.mu b/063list.mu
index 51a33337..0ae881d4 100644
--- a/063list.mu
+++ b/063list.mu
@@ -14,27 +14,27 @@ recipe push [
   x:location <- next-ingredient
   in:address:list <- next-ingredient
   result:address:list <- new list:type
-  val:address:location <- get-address result:address:list/lookup, value:offset
-  val:address:location/lookup <- copy x:location
-  next:address:address:list <- get-address result:address:list/lookup, next:offset
-  next:address:address:list/lookup <- copy in:address:list
-  reply result:address:list
+  val:address:location <- get-address *result, value:offset
+  *val <- copy x
+  next:address:address:list <- get-address *result, next:offset
+  *next <- copy in
+  reply result
 ]
 
 # result:location <- first in:address:list
 recipe first [
   local-scope
   in:address:list <- next-ingredient
-  result:location <- get in:address:list/lookup, value:offset
-  reply result:location
+  result:location <- get *in, value:offset
+  reply result
 ]
 
 # result:address:list <- rest in:address:list
 recipe rest [
   local-scope
   in:address:list <- next-ingredient
-  result:address:list <- get in:address:list/lookup, next:offset
-  reply result:address:list
+  result:address:list <- get *in, next:offset
+  reply result
 ]
 
 scenario list-handling [
diff --git a/065duplex_list.mu b/065duplex_list.mu
index ba25e303..63ee9974 100644
--- a/065duplex_list.mu
+++ b/065duplex_list.mu
@@ -12,41 +12,41 @@ recipe push-duplex [
   x:location <- next-ingredient
   in:address:duplex-list <- next-ingredient
   result:address:duplex-list <- new duplex-list:type
-  val:address:location <- get-address result:address:duplex-list/lookup, value:offset
-  val:address:location/lookup <- copy x:location
-  next:address:address:duplex-list <- get-address result:address:duplex-list/lookup, next:offset
-  next:address:address:duplex-list/lookup <- copy in:address:duplex-list
-  reply-unless in:address:duplex-list, result:address:duplex-list
-  prev:address:address:duplex-list <- get-address in:address:duplex-list/lookup, prev:offset
-  prev:address:address:duplex-list/lookup <- copy result:address:duplex-list
-  reply result:address:duplex-list
+  val:address:location <- get-address *result, value:offset
+  *val <- copy x
+  next:address:address:duplex-list <- get-address *result, next:offset
+  *next <- copy in
+  reply-unless in, result
+  prev:address:address:duplex-list <- get-address *in, prev:offset
+  *prev <- copy result
+  reply result
 ]
 
 # result:location <- first-duplex in:address:duplex-list
 recipe first-duplex [
   local-scope
   in:address:duplex-list <- next-ingredient
-  reply-unless in:address:duplex-list, 0
-  result:location <- get in:address:duplex-list/lookup, value:offset
-  reply result:location
+  reply-unless in, 0
+  result:location <- get *in, value:offset
+  reply result
 ]
 
 # result:address:duplex-list <- next-duplex in:address:duplex-list
 recipe next-duplex [
   local-scope
   in:address:duplex-list <- next-ingredient
-  reply-unless in:address:duplex-list, 0
-  result:address:duplex-list <- get in:address:duplex-list/lookup, next:offset
-  reply result:address:duplex-list
+  reply-unless in, 0
+  result:address:duplex-list <- get *in, next:offset
+  reply result
 ]
 
 # result:address:duplex-list <- prev-duplex in:address:duplex-list
 recipe prev-duplex [
   local-scope
   in:address:duplex-list <- next-ingredient
-  reply-unless in:address:duplex-list, 0
-  result:address:duplex-list <- get in:address:duplex-list/lookup, prev:offset
-  reply result:address:duplex-list
+  reply-unless in, 0
+  result:address:duplex-list <- get *in, prev:offset
+  reply result
 ]
 
 scenario duplex-list-handling [
@@ -99,24 +99,24 @@ recipe insert-duplex [
   x:location <- next-ingredient
   in:address:duplex-list <- next-ingredient
   new-node:address:duplex-list <- new duplex-list:type
-  val:address:location <- get-address new-node:address:duplex-list/lookup, value:offset
-  val:address:location/lookup <- copy x:location
-  next-node:address:duplex-list <- get in:address:duplex-list/lookup, next:offset
+  val:address:location <- get-address *new-node, value:offset
+  *val <- copy x
+  next-node:address:duplex-list <- get *in, next:offset
   # in.next = new-node
-  y:address:address:duplex-list <- get-address in:address:duplex-list/lookup, next:offset
-  y:address:address:duplex-list/lookup <- copy new-node:address:duplex-list
+  y:address:address:duplex-list <- get-address *in, next:offset
+  *y <- copy new-node
   # new-node.prev = in
-  y:address:address:duplex-list <- get-address new-node:address:duplex-list/lookup, prev:offset
-  y:address:address:duplex-list/lookup <- copy in:address:duplex-list
+  y <- get-address *new-node, prev:offset
+  *y <- copy in
   # new-node.next = next-node
-  y:address:address:duplex-list <- get-address new-node:address:duplex-list/lookup, next:offset
-  y:address:address:duplex-list/lookup <- copy next-node:address:duplex-list
+  y <- get-address *new-node, next:offset
+  *y <- copy next-node
   # if next-node is not null
-  reply-unless next-node:address:duplex-list, new-node:address:duplex-list
+  reply-unless next-node, new-node
   # next-node.prev = new-node
-  y:address:address:duplex-list <- get-address next-node:address:duplex-list/lookup, prev:offset
-  y:address:address:duplex-list/lookup <- copy new-node:address:duplex-list
-  reply new-node:address:duplex-list  # just signalling something changed; don't rely on the result
+  y <- get-address *next-node, prev:offset
+  *y <- copy new-node
+  reply new-node  # just signalling something changed; don't rely on the result
 ]
 
 scenario inserting-into-duplex-list [
@@ -240,30 +240,30 @@ recipe remove-duplex [
   local-scope
   in:address:duplex-list <- next-ingredient
   # if 'in' is null, return
-  reply-unless in:address:duplex-list, in:address:duplex-list
-  next-node:address:duplex-list <- get in:address:duplex-list/lookup, next:offset
-  prev-node:address:duplex-list <- get in:address:duplex-list/lookup, prev:offset
+  reply-unless in, in
+  next-node:address:duplex-list <- get *in, next:offset
+  prev-node:address:duplex-list <- get *in, prev:offset
   # null in's pointers
-  x:address:address:duplex-list <- get-address in:address:duplex-list/lookup, next:offset
-  x:address:address:duplex-list/lookup <- copy 0
-  x:address:address:duplex-list <- get-address in:address:duplex-list/lookup, prev:offset
-  x:address:address:duplex-list/lookup <- copy 0
+  x:address:address:duplex-list <- get-address *in, next:offset
+  *x <- copy 0
+  x <- get-address *in, prev:offset
+  *x <- copy 0
   {
     # if next-node is not null
-    break-unless next-node:address:duplex-list
+    break-unless next-node
     # next-node.prev = prev-node
-    x:address:address:duplex-list <- get-address next-node:address:duplex-list/lookup, prev:offset
-    x:address:address:duplex-list/lookup <- copy prev-node:address:duplex-list
+    x <- get-address *next-node, prev:offset
+    *x <- copy prev-node
   }
   {
     # if prev-node is not null
-    break-unless prev-node:address:duplex-list
+    break-unless prev-node
     # prev-node.next = next-node
-    x:address:address:duplex-list <- get-address prev-node:address:duplex-list/lookup, next:offset
-    x:address:address:duplex-list/lookup <- copy next-node:address:duplex-list
-    reply prev-node:address:duplex-list
+    x <- get-address *prev-node, next:offset
+    *x <- copy next-node
+    reply prev-node
   }
-  reply next-node:address:duplex-list
+  reply next-node
 ]
 
 scenario removing-from-duplex-list [
@@ -358,8 +358,8 @@ scenario removing-from-singleton-list [
     1:address:duplex-list <- copy 0  # 1 points to singleton list
     1:address:duplex-list <- push-duplex 3, 1:address:duplex-list
     2:address:duplex-list <- remove-duplex 1:address:duplex-list
-    3:address:duplex-list <- get 1:address:duplex-list/lookup, next:offset
-    4:address:duplex-list <- get 1:address:duplex-list/lookup, prev:offset
+    3:address:duplex-list <- get *1:address:duplex-list, next:offset
+    4:address:duplex-list <- get *1:address:duplex-list, prev:offset
   ]
   memory-should-contain [
     2 <- 0  # remove returned null
diff --git a/066stream.mu b/066stream.mu
index 36c311c1..606d77e7 100644
--- a/066stream.mu
+++ b/066stream.mu
@@ -7,38 +7,38 @@ container stream [
 recipe new-stream [
   local-scope
   result:address:stream <- new stream:type
-  i:address:number <- get-address result:address:stream/lookup, index:offset
-  i:address:number/lookup <- copy 0
-  d:address:address:array:character <- get-address result:address:stream/lookup, data:offset
-  d:address:address:array:character/lookup <- next-ingredient
-  reply result:address:stream
+  i:address:number <- get-address *result, index:offset
+  *i <- copy 0
+  d:address:address:array:character <- get-address *result, data:offset
+  *d <- next-ingredient
+  reply result
 ]
 
 recipe rewind-stream [
   local-scope
   in:address:stream <- next-ingredient
-  x:address:number <- get-address in:address:stream/lookup, index:offset
-  x:address:number/lookup <- copy 0
-  reply in:address:stream/same-as-arg:0
+  x:address:number <- get-address *in, index:offset
+  *x <- copy 0
+  reply in/same-as-arg:0
 ]
 
 recipe read-line [
   local-scope
   in:address:stream <- next-ingredient
-  idx:address:number <- get-address in:address:stream/lookup, index:offset
-  s:address:array:character <- get in:address:stream/lookup, data:offset
-  next-idx:number <- find-next s:address:array:character, 10/newline, idx:address:number/lookup
-  result:address:array:character <- string-copy s:address:array:character, idx:address:number/lookup, next-idx:number
-  idx:address:number/lookup <- add next-idx:number, 1  # skip newline
-  reply result:address:array:character
+  idx:address:number <- get-address *in, index:offset
+  s:address:array:character <- get *in, data:offset
+  next-idx:number <- find-next s, 10/newline, *idx
+  result:address:array:character <- string-copy s, *idx, next-idx
+  *idx <- add next-idx, 1  # skip newline
+  reply result
 ]
 
 recipe end-of-stream? [
   local-scope
   in:address:stream <- next-ingredient
-  idx:number <- get in:address:stream/lookup, index:offset
-  s:address:array:character <- get in:address:stream/lookup, data:offset
-  len:number <- length s:address:array:character/lookup
-  result:boolean <- greater-or-equal idx:number, len:number
-  reply result:boolean
+  idx:address:number <- get *in, index:offset
+  s:address:array:character <- get *in, data:offset
+  len:number <- length *s
+  result:boolean <- greater-or-equal idx, len
+  reply result
 ]
diff --git a/071print.mu b/071print.mu
index 7b52b920..075318a9 100644
--- a/071print.mu
+++ b/071print.mu
@@ -17,71 +17,68 @@ container screen-cell [
 recipe new-fake-screen [
   local-scope
   result:address:screen <- new screen:type
-  width:address:number <- get-address result:address:screen/lookup, num-columns:offset
-  width:address:number/lookup <- next-ingredient
-  height:address:number <- get-address result:address:screen/lookup, num-rows:offset
-  height:address:number/lookup <- next-ingredient
-#?   $print height:address:number/lookup, 10/newline
-  row:address:number <- get-address result:address:screen/lookup, cursor-row:offset
-  row:address:number/lookup <- copy 0
-  column:address:number <- get-address result:address:screen/lookup, cursor-column:offset
-  column:address:number/lookup <- copy 0
-  bufsize:number <- multiply width:address:number/lookup, height:address:number/lookup
-  buf:address:address:array:screen-cell <- get-address result:address:screen/lookup, data:offset
-  buf:address:address:array:screen-cell/lookup <- new screen-cell:type, bufsize:number
-  clear-screen result:address:screen
-  reply result:address:screen
+  width:address:number <- get-address *result, num-columns:offset
+  *width <- next-ingredient
+  height:address:number <- get-address *result, num-rows:offset
+  *height <- next-ingredient
+  row:address:number <- get-address *result, cursor-row:offset
+  *row <- copy 0
+  column:address:number <- get-address *result, cursor-column:offset
+  *column <- copy 0
+  bufsize:number <- multiply *width, *height
+  buf:address:address:array:screen-cell <- get-address *result, data:offset
+  *buf <- new screen-cell:type, bufsize
+  clear-screen result
+  reply result
 ]
 
 recipe clear-screen [
   local-scope
   sc:address:screen <- next-ingredient
-#?   $print [clearing screen
-#? ] #? 1
   # if x exists
   {
-    break-unless sc:address:screen
+    break-unless sc
     # clear fake screen
-    buf:address:array:screen-cell <- get sc:address:screen/lookup, data:offset
-    max:number <- length buf:address:array:screen-cell/lookup
+    buf:address:array:screen-cell <- get *sc, data:offset
+    max:number <- length *buf
     i:number <- copy 0
     {
-      done?:boolean <- greater-or-equal i:number, max:number
-      break-if done?:boolean
-      curr:address:screen-cell <- index-address buf:address:array:screen-cell/lookup, i:number
-      curr-content:address:character <- get-address curr:address:screen-cell/lookup, contents:offset
-      curr-content:address:character/lookup <- copy [ ]
-      curr-color:address:character <- get-address curr:address:screen-cell/lookup, color:offset
-      curr-color:address:character/lookup <- copy 7/white
-      i:number <- add i:number, 1
+      done?:boolean <- greater-or-equal i, max
+      break-if done?
+      curr:address:screen-cell <- index-address *buf, i
+      curr-content:address:character <- get-address *curr, contents:offset
+      *curr-content <- copy [ ]
+      curr-color:address:character <- get-address *curr, color:offset
+      *curr-color <- copy 7/white
+      i <- add i, 1
       loop
     }
     # reset cursor
-    cur:address:number <- get-address sc:address:screen/lookup, cursor-row:offset
-    cur:address:number/lookup <- copy 0
-    cur:address:number <- get-address sc:address:screen/lookup, cursor-column:offset
-    cur:address:number/lookup <- copy 0
-    reply sc:address:screen/same-as-ingredient:0
+    x:address:number <- get-address *sc, cursor-row:offset
+    *x <- copy 0
+    x <- get-address *sc, cursor-column:offset
+    *x <- copy 0
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
   clear-display
-  reply sc:address:screen/same-as-ingredient:0
+  reply sc/same-as-ingredient:0
 ]
 
-recipe fake-screen-is-clear? [
+recipe fake-screen-is-empty? [
   local-scope
   sc:address:screen <- next-ingredient
-  reply-unless sc:address:screen, 1/true
-  buf:address:array:screen-cell <- get sc:address:screen/lookup, data:offset
+  reply-unless sc, 1/true
+  buf:address:array:screen-cell <- get *sc, data:offset
   i:number <- copy 0
-  len:number <- length buf:address:array:screen-cell/lookup
+  len:number <- length *buf
   {
-    done?:boolean <- greater-or-equal i:number, len:number
-    break-if done?:boolean
-    curr:screen-cell <- index buf:address:array:screen-cell/lookup, i:number
-    curr-contents:character <- get curr:screen-cell, contents:offset
-    i:number <- add i:number, 1
-    loop-unless curr-contents:character
+    done?:boolean <- greater-or-equal i, len
+    break-if done?
+    curr:screen-cell <- index *buf, i
+    curr-contents:character <- get curr, contents:offset
+    i <- add i, 1
+    loop-unless curr-contents
     # not 0
     reply 0/false
   }
@@ -95,91 +92,91 @@ recipe print-character [
   color:number, color-found?:boolean <- next-ingredient
   {
     # default color to white
-    break-if color-found?:boolean
-    color:number <- copy 7/white
+    break-if color-found?
+    color <- copy 7/white
   }
   bg-color:number, bg-color-found?:boolean <- next-ingredient
   {
     # default bg-color to black
-    break-if bg-color-found?:boolean
-    bg-color:number <- copy 0/black
+    break-if bg-color-found?
+    bg-color <- copy 0/black
   }
 #?   trace [app], [print character] #? 1
   {
     # if x exists
     # (handle special cases exactly like in the real screen)
-    break-unless sc:address:screen
-    width:number <- get sc:address:screen/lookup, num-columns:offset
-    height:number <- get sc:address:screen/lookup, num-rows:offset
+    break-unless sc
+    width:number <- get *sc, num-columns:offset
+    height:number <- get *sc, num-rows:offset
     # if cursor is out of bounds, silently exit
-    row:address:number <- get-address sc:address:screen/lookup, cursor-row:offset
-    legal?:boolean <- greater-or-equal row:address:number/lookup, 0
-    reply-unless legal?:boolean, sc:address:screen
-    legal?:boolean <- lesser-than row:address:number/lookup, height:number
-    reply-unless legal?:boolean, sc:address:screen
-    column:address:number <- get-address sc:address:screen/lookup, cursor-column:offset
-    legal?:boolean <- greater-or-equal column:address:number/lookup, 0
-    reply-unless legal?:boolean, sc:address:screen
-    legal?:boolean <- lesser-than column:address:number/lookup, width:number
-    reply-unless legal?:boolean, sc:address:screen
+    row:address:number <- get-address *sc, cursor-row:offset
+    legal?:boolean <- greater-or-equal *row, 0
+    reply-unless legal?, sc
+    legal? <- lesser-than *row, height
+    reply-unless legal?, sc
+    column:address:number <- get-address *sc, cursor-column:offset
+    legal? <- greater-or-equal *column, 0
+    reply-unless legal?, sc
+    legal? <- lesser-than *column, width
+    reply-unless legal?, sc
     # special-case: newline
     {
-      newline?:boolean <- equal c:character, 10/newline
-#?       $print c:character, [ ], newline?:boolean, 10/newline
-      break-unless newline?:boolean
+      newline?:boolean <- equal c, 10/newline
+#?       $print c, [ ], newline?, 10/newline
+      break-unless newline?
       {
         # unless cursor is already at bottom
-        bottom:number <- subtract height:number, 1
-        at-bottom?:boolean <- greater-or-equal row:address:number/lookup, bottom:number
-        break-if at-bottom?:boolean
+        bottom:number <- subtract height, 1
+        at-bottom?:boolean <- greater-or-equal *row, bottom
+        break-if at-bottom?
         # move it to the next row
-        column:address:number/lookup <- copy 0
-        row:address:number/lookup <- add row:address:number/lookup, 1
+        *column <- copy 0
+        *row <- add *row, 1
       }
-      reply sc:address:screen/same-as-ingredient:0
+      reply sc/same-as-ingredient:0
     }
     # save character in fake screen
-    index:number <- multiply row:address:number/lookup, width:number
-    index:number <- add index:number, column:address:number/lookup
-    buf:address:array:screen-cell <- get sc:address:screen/lookup, data:offset
-    len:number <- length buf:address:array:screen-cell/lookup
+    index:number <- multiply *row, width
+    index <- add index, *column
+    buf:address:array:screen-cell <- get *sc, data:offset
+    len:number <- length *buf
     # special-case: backspace
     {
-      backspace?:boolean <- equal c:character, 8
-      break-unless backspace?:boolean
+      backspace?:boolean <- equal c, 8
+      break-unless backspace?
       {
         # unless cursor is already at left margin
-        at-left?:boolean <- lesser-or-equal column:address:number/lookup, 0
-        break-if at-left?:boolean
+        at-left?:boolean <- lesser-or-equal *column, 0
+        break-if at-left?
         # clear previous location
-        column:address:number/lookup <- subtract column:address:number/lookup, 1
-        index:number <- subtract index:number, 1
-        cursor:address:screen-cell <- index-address buf:address:array:screen-cell/lookup, index:number
-        cursor-contents:address:character <- get-address cursor:address:screen-cell/lookup, contents:offset
-        cursor-color:address:number <- get-address cursor:address:screen-cell/lookup, color:offset
-        cursor-contents:address:character/lookup <- copy 32/space
-        cursor-color:address:number/lookup <- copy 7/white
+        *column <- subtract *column, 1
+        index <- subtract index, 1
+        cursor:address:screen-cell <- index-address *buf, index
+        cursor-contents:address:character <- get-address *cursor, contents:offset
+        *cursor-contents <- copy 32/space
+        cursor-color:address:number <- get-address *cursor, color:offset
+        *cursor-color <- copy 7/white
       }
-      reply sc:address:screen/same-as-ingredient:0
+      reply sc/same-as-ingredient:0
     }
-#?     $print [saving character ], c:character, [ to fake screen ], cursor:address/screen, 10/newline
-    cursor:address:screen-cell <- index-address buf:address:array:screen-cell/lookup, index:number
-    cursor-contents:address:character <- get-address cursor:address:screen-cell/lookup, contents:offset
-    cursor-color:address:number <- get-address cursor:address:screen-cell/lookup, color:offset
-    cursor-contents:address:character/lookup <- copy c:character
-    cursor-color:address:number/lookup <- copy color:number
+#?     $print [saving character ], c, [ to fake screen ], cursor, 10/newline
+    cursor:address:screen-cell <- index-address *buf, index
+    cursor-contents:address:character <- get-address *cursor, contents:offset
+    *cursor-contents <- copy c
+    cursor-color:address:number <- get-address *cursor, color:offset
+    *cursor-color <- copy color
     # increment column unless it's already all the way to the right
     {
-      right:number <- subtract width:number, 1
-      at-right?:boolean <- greater-or-equal column:address:number/lookup, right:number
-      break-if at-right?:boolean
-      column:address:number/lookup <- add column:address:number/lookup, 1
+      right:number <- subtract width, 1
+      at-right?:boolean <- greater-or-equal *column, right
+      break-if at-right?
+      *column <- add *column, 1
     }
-    reply sc:address:screen/same-as-ingredient:0
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
-  print-character-to-display c:character, color:number, bg-color:number
-  reply sc:address:screen/same-as-ingredient:0
+  print-character-to-display c, color, bg-color
+  reply sc/same-as-ingredient:0
 ]
 
 scenario print-character-at-top-left [
@@ -187,8 +184,8 @@ scenario print-character-at-top-left [
 #?     $start-tracing #? 3
     1:address:screen <- new-fake-screen 3/width, 2/height
     1:address:screen <- print-character 1:address:screen, 97  # 'a'
-    2:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    3:array:screen-cell <- copy 2:address:array:screen-cell/lookup
+    2:address:array:screen-cell <- get *1:address:screen, data:offset
+    3:array:screen-cell <- copy *2:address:array:screen-cell
   ]
   memory-should-contain [
     3 <- 6  # width*height
@@ -202,8 +199,8 @@ scenario print-character-color [
   run [
     1:address:screen <- new-fake-screen 3/width, 2/height
     1:address:screen <- print-character 1:address:screen, 97/a, 1/red
-    2:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    3:array:screen-cell <- copy 2:address:array:screen-cell/lookup
+    2:address:array:screen-cell <- get *1:address:screen, data:offset
+    3:array:screen-cell <- copy *2:address:array:screen-cell
   ]
   memory-should-contain [
     3 <- 6  # width*height
@@ -219,9 +216,9 @@ scenario print-backspace-character [
     1:address:screen <- new-fake-screen 3/width, 2/height
     1:address:screen <- print-character 1:address:screen, 97  # 'a'
     1:address:screen <- print-character 1:address:screen, 8  # backspace
-    2:number <- get 1:address:screen/lookup, cursor-column:offset
-    3:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    4:array:screen-cell <- copy 3:address:array:screen-cell/lookup
+    2:number <- get *1:address:screen, cursor-column:offset
+    3:address:array:screen-cell <- get *1:address:screen, data:offset
+    4:array:screen-cell <- copy *3:address:array:screen-cell
   ]
   memory-should-contain [
     2 <- 0  # cursor column
@@ -238,9 +235,9 @@ scenario print-extra-backspace-character [
     1:address:screen <- print-character 1:address:screen, 97  # 'a'
     1:address:screen <- print-character 1:address:screen, 8  # backspace
     1:address:screen <- print-character 1:address:screen, 8  # backspace
-    2:number <- get 1:address:screen/lookup, cursor-column:offset
-    3:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    4:array:screen-cell <- copy 3:address:array:screen-cell/lookup
+    2:number <- get *1:address:screen, cursor-column:offset
+    3:address:array:screen-cell <- get *1:address:screen, data:offset
+    4:array:screen-cell <- copy *3:address:array:screen-cell
   ]
   memory-should-contain [
     2 <- 0  # cursor column
@@ -257,9 +254,9 @@ scenario print-at-right-margin [
     1:address:screen <- print-character 1:address:screen, 97  # 'a'
     1:address:screen <- print-character 1:address:screen, 98  # 'b'
     1:address:screen <- print-character 1:address:screen, 99  # 'c'
-    2:number <- get 1:address:screen/lookup, cursor-column:offset
-    3:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    4:array:screen-cell <- copy 3:address:array:screen-cell/lookup
+    2:number <- get *1:address:screen, cursor-column:offset
+    3:address:array:screen-cell <- get *1:address:screen, data:offset
+    4:array:screen-cell <- copy *3:address:array:screen-cell
   ]
   memory-should-contain [
     2 <- 1  # cursor column
@@ -278,10 +275,10 @@ scenario print-newline-character [
     1:address:screen <- new-fake-screen 3/width, 2/height
     1:address:screen <- print-character 1:address:screen, 97  # 'a'
     1:address:screen <- print-character 1:address:screen, 10/newline
-    2:number <- get 1:address:screen/lookup, cursor-row:offset
-    3:number <- get 1:address:screen/lookup, cursor-column:offset
-    4:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    5:array:screen-cell <- copy 4:address:array:screen-cell/lookup
+    2:number <- get *1:address:screen, cursor-row:offset
+    3:number <- get *1:address:screen, cursor-column:offset
+    4:address:array:screen-cell <- get *1:address:screen, data:offset
+    5:array:screen-cell <- copy *4:address:array:screen-cell
   ]
   memory-should-contain [
     2 <- 1  # cursor row
@@ -299,8 +296,8 @@ scenario print-newline-at-bottom-line [
     1:address:screen <- print-character 1:address:screen, 10/newline
     1:address:screen <- print-character 1:address:screen, 10/newline
     1:address:screen <- print-character 1:address:screen, 10/newline
-    2:number <- get 1:address:screen/lookup, cursor-row:offset
-    3:number <- get 1:address:screen/lookup, cursor-column:offset
+    2:number <- get *1:address:screen, cursor-row:offset
+    3:number <- get *1:address:screen, cursor-column:offset
   ]
   memory-should-contain [
     2 <- 1  # cursor row
@@ -317,10 +314,10 @@ scenario print-at-bottom-right [
     1:address:screen <- print-character 1:address:screen, 99  # 'c'
     1:address:screen <- print-character 1:address:screen, 10/newline
     1:address:screen <- print-character 1:address:screen, 100  # 'd'
-    2:number <- get 1:address:screen/lookup, cursor-row:offset
-    3:number <- get 1:address:screen/lookup, cursor-column:offset
-    4:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    5:array:screen-cell <- copy 4:address:array:screen-cell/lookup
+    2:number <- get *1:address:screen, cursor-row:offset
+    3:number <- get *1:address:screen, cursor-column:offset
+    4:address:array:screen-cell <- get *1:address:screen, data:offset
+    5:array:screen-cell <- copy *4:address:array:screen-cell
   ]
   memory-should-contain [
     2 <- 1  # cursor row
@@ -343,27 +340,27 @@ recipe clear-line [
   sc:address:screen <- next-ingredient
   # if x exists, clear line in fake screen
   {
-    break-unless sc:address:screen
-    width:number <- get sc:address:screen/lookup, num-columns:offset
-    column:address:number <- get-address sc:address:screen/lookup, cursor-column:offset
-    original-column:number <- copy column:address:number/lookup
+    break-unless sc
+    width:number <- get *sc, num-columns:offset
+    column:address:number <- get-address *sc, cursor-column:offset
+    original-column:number <- copy *column
     # space over the entire line
 #?     $start-tracing #? 1
     {
-#?       $print column:address:number/lookup, 10/newline
-      right:number <- subtract width:number, 1
-      done?:boolean <- greater-or-equal column:address:number/lookup, right:number
-      break-if done?:boolean
-      print-character sc:address:screen, [ ]  # implicitly updates 'column'
+#?       $print *column, 10/newline
+      right:number <- subtract width, 1
+      done?:boolean <- greater-or-equal *column, right
+      break-if done?
+      print-character sc, [ ]  # implicitly updates 'column'
       loop
     }
     # now back to where the cursor was
-    column:address:number/lookup <- copy original-column:number
-    reply sc:address:screen/same-as-ingredient:0
+    *column <- copy original-column
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
   clear-line-on-display
-  reply sc:address:screen/same-as-ingredient:0
+  reply sc/same-as-ingredient:0
 ]
 
 recipe cursor-position [
@@ -371,13 +368,13 @@ recipe cursor-position [
   sc:address:screen <- next-ingredient
   # if x exists, lookup cursor in fake screen
   {
-    break-unless sc:address:screen
-    row:number <- get sc:address:screen/lookup, cursor-row:offset
-    column:number <- get sc:address:screen/lookup, cursor-column:offset
-    reply row:number, column:number, sc:address:screen/same-as-ingredient:0
+    break-unless sc
+    row:number <- get *sc, cursor-row:offset
+    column:number <- get *sc, cursor-column:offset
+    reply row, column, sc/same-as-ingredient:0
   }
-  row:number, column:number <- cursor-position-on-display
-  reply row:number, column:number, sc:address:screen/same-as-ingredient:0
+  row, column <- cursor-position-on-display
+  reply row, column, sc/same-as-ingredient:0
 ]
 
 recipe move-cursor [
@@ -387,16 +384,16 @@ recipe move-cursor [
   new-column:number <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
-    row:address:number <- get-address sc:address:screen/lookup, cursor-row:offset
-    row:address:number/lookup <- copy new-row:number
-    column:address:number <- get-address sc:address:screen/lookup, cursor-column:offset
-    column:address:number/lookup <- copy new-column:number
-    reply sc:address:screen/same-as-ingredient:0
+    break-unless sc
+    row:address:number <- get-address *sc, cursor-row:offset
+    *row <- copy new-row
+    column:address:number <- get-address *sc, cursor-column:offset
+    *column <- copy new-column
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
-  move-cursor-on-display new-row:number, new-column:number
-  reply sc:address:screen/same-as-ingredient:0
+  move-cursor-on-display new-row, new-column
+  reply sc/same-as-ingredient:0
 ]
 
 scenario clear-line-erases-printed-characters [
@@ -409,8 +406,8 @@ scenario clear-line-erases-printed-characters [
     1:address:screen <- move-cursor 1:address:screen, 0/row, 0/column
     # clear line
     1:address:screen <- clear-line 1:address:screen
-    2:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    3:array:screen-cell <- copy 2:address:array:screen-cell/lookup
+    2:address:array:screen-cell <- get *1:address:screen, data:offset
+    3:array:screen-cell <- copy *2:address:array:screen-cell
   ]
   # screen should be blank
   memory-should-contain [
@@ -435,25 +432,22 @@ recipe cursor-down [
   sc:address:screen <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
+    break-unless sc
     {
       # if row < height-1
-      height:number <- get sc:address:screen/lookup, num-rows:offset
-      row:address:number <- get-address sc:address:screen/lookup, cursor-row:offset
-      max:number <- subtract height:number, 1
-      at-bottom?:boolean <- greater-or-equal row:address:number/lookup, max:number
-      break-if at-bottom?:boolean
+      height:number <- get *sc, num-rows:offset
+      row:address:number <- get-address *sc, cursor-row:offset
+      max:number <- subtract height, 1
+      at-bottom?:boolean <- greater-or-equal *row, max
+      break-if at-bottom?
       # row = row+1
-#?       $print [AAA: ], row:address:number, [ -> ], row:address:number/lookup, 10/newline
-      row:address:number/lookup <- add row:address:number/lookup, 1
-#?       $print [BBB: ], row:address:number, [ -> ], row:address:number/lookup, 10/newline
-#?       $start-tracing #? 1
+      *row <- add *row, 1
     }
-    reply sc:address:screen/same-as-ingredient:0
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
   move-cursor-down-on-display
-  reply sc:address:screen/same-as-ingredient:0
+  reply sc/same-as-ingredient:0
 ]
 
 recipe cursor-up [
@@ -461,20 +455,20 @@ recipe cursor-up [
   sc:address:screen <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
+    break-unless sc
     {
       # if row > 0
-      row:address:number <- get-address sc:address:screen/lookup, cursor-row:offset
-      at-top?:boolean <- lesser-or-equal row:address:number/lookup, 0
-      break-if at-top?:boolean
+      row:address:number <- get-address *sc, cursor-row:offset
+      at-top?:boolean <- lesser-or-equal *row, 0
+      break-if at-top?
       # row = row-1
-      row:address:number/lookup <- subtract row:address:number/lookup, 1
+      *row <- subtract *row, 1
     }
-    reply sc:address:screen/same-as-ingredient:0
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
   move-cursor-up-on-display
-  reply sc:address:screen/same-as-ingredient:0
+  reply sc/same-as-ingredient:0
 ]
 
 recipe cursor-right [
@@ -482,22 +476,22 @@ recipe cursor-right [
   sc:address:screen <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
+    break-unless sc
     {
       # if column < width-1
-      width:number <- get sc:address:screen/lookup, num-columns:offset
-      column:address:number <- get-address sc:address:screen/lookup, cursor-column:offset
-      max:number <- subtract width:number, 1
-      at-bottom?:boolean <- greater-or-equal column:address:number/lookup, max:number
-      break-if at-bottom?:boolean
+      width:number <- get *sc, num-columns:offset
+      column:address:number <- get-address *sc, cursor-column:offset
+      max:number <- subtract width, 1
+      at-bottom?:boolean <- greater-or-equal *column, max
+      break-if at-bottom?
       # column = column+1
-      column:address:number/lookup <- add column:address:number/lookup, 1
+      *column <- add *column, 1
     }
-    reply sc:address:screen/same-as-ingredient:0
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
   move-cursor-right-on-display
-  reply sc:address:screen/same-as-ingredient:0
+  reply sc/same-as-ingredient:0
 ]
 
 recipe cursor-left [
@@ -505,37 +499,37 @@ recipe cursor-left [
   sc:address:screen <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
+    break-unless sc
     {
       # if column > 0
-      column:address:number <- get-address sc:address:screen/lookup, cursor-column:offset
-      at-top?:boolean <- lesser-or-equal column:address:number/lookup, 0
-      break-if at-top?:boolean
+      column:address:number <- get-address *sc, cursor-column:offset
+      at-top?:boolean <- lesser-or-equal *column, 0
+      break-if at-top?
       # column = column-1
-      column:address:number/lookup <- subtract column:address:number/lookup, 1
+      *column <- subtract *column, 1
     }
-    reply sc:address:screen/same-as-ingredient:0
+    reply sc/same-as-ingredient:0
   }
   # otherwise, real screen
   move-cursor-left-on-display
-  reply sc:address:screen/same-as-ingredient:0
+  reply sc/same-as-ingredient:0
 ]
 
 recipe cursor-to-start-of-line [
   local-scope
   sc:address:screen <- next-ingredient
-  row:number, _, sc:address:screen <- cursor-position sc:address:screen
+  row:number, _, sc <- cursor-position sc
   column:number <- copy 0
-  sc:address:screen <- move-cursor sc:address:screen, row:number, column:number
-  reply sc:address:screen/same-as-ingredient:0
+  sc <- move-cursor sc, row, column
+  reply sc/same-as-ingredient:0
 ]
 
 recipe cursor-to-next-line [
   local-scope
   screen:address <- next-ingredient
-  screen:address <- cursor-down screen:address
-  screen:address <- cursor-to-start-of-line screen:address
-  reply screen:address/same-as-ingredient:0
+  screen <- cursor-down screen
+  screen <- cursor-to-start-of-line screen
+  reply screen/same-as-ingredient:0
 ]
 
 recipe screen-width [
@@ -543,13 +537,13 @@ recipe screen-width [
   sc:address:screen <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
-    width:number <- get sc:address:screen/lookup, num-columns:offset
-    reply width:number
+    break-unless sc
+    width:number <- get *sc, num-columns:offset
+    reply width
   }
   # otherwise, real screen
   width:number <- display-width
-  reply width:number
+  reply width
 ]
 
 recipe screen-height [
@@ -557,13 +551,13 @@ recipe screen-height [
   sc:address:screen <- next-ingredient
   # if x exists, move cursor in fake screen
   {
-    break-unless sc:address:screen
-    height:number <- get sc:address:screen/lookup, num-rows:offset
-    reply height:number
+    break-unless sc
+    height:number <- get *sc, num-rows:offset
+    reply height
   }
   # otherwise, real screen
   height:number <- display-height
-  reply height:number
+  reply height
 ]
 
 recipe hide-cursor [
@@ -571,12 +565,12 @@ recipe hide-cursor [
   screen:address <- next-ingredient
   # if x exists (not real display), do nothing
   {
-    break-unless screen:address
-    reply screen:address
+    break-unless screen
+    reply screen
   }
   # otherwise, real screen
   hide-cursor-on-display
-  reply screen:address
+  reply screen
 ]
 
 recipe show-cursor [
@@ -584,12 +578,12 @@ recipe show-cursor [
   screen:address <- next-ingredient
   # if x exists (not real display), do nothing
   {
-    break-unless screen:address
-    reply screen:address
+    break-unless screen
+    reply screen
   }
   # otherwise, real screen
   show-cursor-on-display
-  reply screen:address
+  reply screen
 ]
 
 recipe hide-screen [
@@ -597,12 +591,12 @@ recipe hide-screen [
   screen:address <- next-ingredient
   # if x exists (not real display), do nothing
   {
-    break-unless screen:address
-    reply screen:address
+    break-unless screen
+    reply screen
   }
   # otherwise, real screen
   hide-display
-  reply screen:address
+  reply screen
 ]
 
 recipe show-screen [
@@ -610,12 +604,12 @@ recipe show-screen [
   screen:address <- next-ingredient
   # if x exists (not real display), do nothing
   {
-    break-unless screen:address
-    reply screen:address
+    break-unless screen
+    reply screen
   }
   # otherwise, real screen
   show-display
-  reply screen:address
+  reply screen
 ]
 
 recipe print-string [
@@ -625,26 +619,26 @@ recipe print-string [
   color:number, color-found?:boolean <- next-ingredient
   {
     # default color to white
-    break-if color-found?:boolean
-    color:number <- copy 7/white
+    break-if color-found?
+    color <- copy 7/white
   }
   bg-color:number, bg-color-found?:boolean <- next-ingredient
   {
     # default bg-color to black
-    break-if bg-color-found?:boolean
-    bg-color:number <- copy 0/black
+    break-if bg-color-found?
+    bg-color <- copy 0/black
   }
-  len:number <- length s:address:array:character/lookup
+  len:number <- length *s
   i:number <- copy 0
   {
-    done?:boolean <- greater-or-equal i:number, len:number
-    break-if done?:boolean
-    c:character <- index s:address:array:character/lookup, i:number
-    print-character screen:address, c:character, color:number, bg-color:number
-    i:number <- add i:number, 1
+    done?:boolean <- greater-or-equal i, len
+    break-if done?
+    c:character <- index *s, i
+    print-character screen, c, color, bg-color
+    i <- add i, 1
     loop
   }
-  reply screen:address/same-as-ingredient:0
+  reply screen/same-as-ingredient:0
 ]
 
 scenario print-string-stops-at-right-margin [
@@ -652,8 +646,8 @@ scenario print-string-stops-at-right-margin [
     1:address:screen <- new-fake-screen 3/width, 2/height
     2:address:array:character <- new [abcd]
     1:address:screen <- print-string 1:address:screen, 2:address:array:character
-    3:address:array:screen-cell <- get 1:address:screen/lookup, data:offset
-    4:array:screen-cell <- copy 3:address:array:screen-cell/lookup
+    3:address:array:screen-cell <- get *1:address:screen, data:offset
+    4:array:screen-cell <- copy *3:address:array:screen-cell
   ]
   memory-should-contain [
     4 <- 6  # width*height
@@ -674,17 +668,17 @@ recipe print-integer [
   color:number, color-found?:boolean <- next-ingredient
   {
     # default color to white
-    break-if color-found?:boolean
-    color:number <- copy 7/white
+    break-if color-found?
+    color <- copy 7/white
   }
   bg-color:number, bg-color-found?:boolean <- next-ingredient
   {
     # default bg-color to black
-    break-if bg-color-found?:boolean
-    bg-color:number <- copy 0/black
+    break-if bg-color-found?
+    bg-color <- copy 0/black
   }
   # todo: other bases besides decimal
-  s:address:array:character <- integer-to-decimal-string n:number
-  print-string screen:address, s:address:array:character, color:number, bg-color:number
-  reply screen:address/same-as-ingredient:0
+  s:address:array:character <- integer-to-decimal-string n
+  print-string screen, s, color, bg-color
+  reply screen/same-as-ingredient:0
 ]
diff --git a/074console.mu b/074console.mu
index 031f0781..b60e17cc 100644
--- a/074console.mu
+++ b/074console.mu
@@ -22,37 +22,35 @@ container console [
 recipe new-fake-console [
   local-scope
   result:address:console <- new console:type
-  buf:address:address:array:character <- get-address result:address:console/lookup, data:offset
-#?   $start-tracing #? 1
-  buf:address:address:array:character/lookup <- next-ingredient
-#?   $stop-tracing #? 1
-  idx:address:number <- get-address result:address:console/lookup, index:offset
-  idx:address:number/lookup <- copy 0
-  reply result:address:console
+  buf:address:address:array:character <- get-address *result, data:offset
+  *buf <- next-ingredient
+  idx:address:number <- get-address *result, index:offset
+  *idx <- copy 0
+  reply result
 ]
 
 recipe read-event [
   local-scope
   x:address:console <- next-ingredient
   {
-    break-unless x:address:console
-    idx:address:number <- get-address x:address:console/lookup, index:offset
-    buf:address:array:event <- get x:address:console/lookup, data:offset
+    break-unless x
+    idx:address:number <- get-address *x, index:offset
+    buf:address:array:event <- get *x, data:offset
     {
-      max:number <- length buf:address:array:event/lookup
-      done?:boolean <- greater-or-equal idx:address:number/lookup, max:number
-      break-unless done?:boolean
+      max:number <- length *buf
+      done?:boolean <- greater-or-equal *idx, max
+      break-unless done?
       dummy:address:event <- new event:type
-      reply dummy:address:event/lookup, x:address:console/same-as-ingredient:0, 1/found, 1/quit
+      reply *dummy, x/same-as-ingredient:0, 1/found, 1/quit
     }
-    result:event <- index buf:address:array:event/lookup, idx:address:number/lookup
-    idx:address:number/lookup <- add idx:address:number/lookup, 1
-    reply result:event, x:address:console/same-as-ingredient:0, 1/found, 0/quit
+    result:event <- index *buf, *idx
+    *idx <- add *idx, 1
+    reply result, x/same-as-ingredient:0, 1/found, 0/quit
   }
   # real event source is infrequent; avoid polling it too much
   switch
   result:event, found?:boolean <- check-for-interaction
-  reply result:event, x:address:console/same-as-ingredient:0, found?:boolean, 0/quit
+  reply result, x/same-as-ingredient:0, found?, 0/quit
 ]
 
 # variant of read-event for just keyboard events. Discards everything that
@@ -60,20 +58,13 @@ recipe read-event [
 # newlines, tabs, ctrl-d..
 recipe read-key [
   local-scope
-#?   $print default-space:address:array:location #? 1
-#?   $exit #? 1
-#?   $start-tracing #? 1
   console:address <- next-ingredient
-  x:event, console:address, found?:boolean, quit?:boolean <- read-event console:address
-#?   $print [aaa 1] #? 1
-  reply-if quit?:boolean, 0, console:address/same-as-ingredient:0, found?:boolean, quit?:boolean
-#?   $print [aaa 2] #? 1
-  reply-unless found?:boolean, 0, console:address/same-as-ingredient:0, found?:boolean, quit?:boolean
-#?   $print [aaa 3] #? 1
-  c:address:character <- maybe-convert x:event, text:variant
-  reply-unless c:address:character, 0, console:address/same-as-ingredient:0, 0/found, 0/quit
-#?   $print [aaa 4] #? 1
-  reply c:address:character/lookup, console:address/same-as-ingredient:0, 1/found, 0/quit
+  x:event, console, found?:boolean, quit?:boolean <- read-event console
+  reply-if quit?, 0, console/same-as-ingredient:0, found?, quit?
+  reply-unless found?, 0, console/same-as-ingredient:0, found?, quit?
+  c:address:character <- maybe-convert x, text:variant
+  reply-unless c, 0, console/same-as-ingredient:0, 0/found, 0/quit
+  reply *c, console/same-as-ingredient:0, 1/found, 0/quit
 ]
 
 recipe send-keys-to-channel [
@@ -82,23 +73,25 @@ recipe send-keys-to-channel [
   chan:address:channel <- next-ingredient
   screen:address <- next-ingredient
   {
-    c:character, console:address, found?:boolean, quit?:boolean <- read-key console:address
-    loop-unless found?:boolean
-    break-if quit?:boolean
-    assert c:character, [invalid event, expected text]
-    print-character screen:address, c:character
-    chan:address:channel <- write chan:address:channel, c:character
+    c:character, console, found?:boolean, quit?:boolean <- read-key console
+    loop-unless found?
+    break-if quit?
+    assert c, [invalid event, expected text]
+    screen <- print-character screen, c
+    chan <- write chan, c
     loop
   }
+  reply console/same-as-ingredient:0, chan/same-as-ingredient:1, screen/same-as-ingredient:2
 ]
 
 recipe wait-for-event [
   local-scope
   console:address <- next-ingredient
   {
-    _, console:address, found?:boolean <- read-event console:address
-    loop-unless found?:boolean
+    _, console, found?:boolean <- read-event console
+    loop-unless found?
   }
+  reply console/same-as-ingredient:0
 ]
 
 # use this helper to skip rendering if there's lots of other events queued up
@@ -106,10 +99,10 @@ recipe has-more-events? [
   local-scope
   console:address <- next-ingredient
   {
-    break-unless console:address
+    break-unless console
     # fake consoles should be plenty fast; never skip
     reply 0/false
   }
   result:boolean <- interactions-left?
-  reply result:boolean
+  reply result
 ]
diff --git a/edit.mu b/edit.mu
index d8df5822..e26872e8 100644
--- a/edit.mu
+++ b/edit.mu
@@ -2948,7 +2948,7 @@ recipe render-sandboxes [
   }
   {
     break-if sandbox-warnings
-    empty-screen?:boolean <- fake-screen-is-clear? sandbox-screen
+    empty-screen?:boolean <- fake-screen-is-empty? sandbox-screen
     break-if empty-screen?
     row, screen <- render-screen screen, sandbox-screen, left, right, row
   }