about summary refs log tree commit diff stats
path: root/archive/0.vm.arc
diff options
context:
space:
mode:
Diffstat (limited to 'archive/0.vm.arc')
-rw-r--r--archive/0.vm.arc/Readme.md21
-rw-r--r--archive/0.vm.arc/blocking.arc.t26
-rw-r--r--archive/0.vm.arc/buffered-stdin.mu28
-rw-r--r--archive/0.vm.arc/callcc.mu20
-rw-r--r--archive/0.vm.arc/channel.mu49
-rw-r--r--archive/0.vm.arc/charterm/charterm.rkt2798
-rw-r--r--archive/0.vm.arc/charterm/demo.rkt306
-rw-r--r--archive/0.vm.arc/charterm/doc.scrbl7
-rw-r--r--archive/0.vm.arc/charterm/info.rkt29
-rw-r--r--archive/0.vm.arc/charterm/main.rkt3
-rw-r--r--archive/0.vm.arc/charterm/planet-docs/doc/index.html117
-rw-r--r--archive/0.vm.arc/charterm/planet-docs/doc/racket.css234
-rw-r--r--archive/0.vm.arc/charterm/planet-docs/doc/scribble-common.js153
-rw-r--r--archive/0.vm.arc/charterm/planet-docs/doc/scribble-style.css0
-rw-r--r--archive/0.vm.arc/charterm/planet-docs/doc/scribble.css487
-rw-r--r--archive/0.vm.arc/charterm/test-charterm.rkt20
-rw-r--r--archive/0.vm.arc/chessboard.arc.t239
-rw-r--r--archive/0.vm.arc/chessboard.mu259
-rw-r--r--archive/0.vm.arc/color-repl.mu498
-rw-r--r--archive/0.vm.arc/counters.mu33
-rw-r--r--archive/0.vm.arc/edit.arc.t33
-rw-r--r--archive/0.vm.arc/edit.mu18
-rw-r--r--archive/0.vm.arc/exuberant-ctags-rc7
-rw-r--r--archive/0.vm.arc/factorial.mu22
-rw-r--r--archive/0.vm.arc/fork.mu18
-rw-r--r--archive/0.vm.arc/generic.mu30
-rw-r--r--archive/0.vm.arc/graphics.mu23
-rw-r--r--archive/0.vm.arc/highlights21
-rw-r--r--archive/0.vm.arc/load.arc28
-rwxr-xr-xarchive/0.vm.arc/mu27
-rw-r--r--archive/0.vm.arc/mu.arc3259
-rw-r--r--archive/0.vm.arc/mu.arc.t5208
-rw-r--r--archive/0.vm.arc/mu.arc.t.html4154
-rw-r--r--archive/0.vm.arc/render.vim93
-rw-r--r--archive/0.vm.arc/scratch.vim50
-rw-r--r--archive/0.vm.arc/stdin.mu27
-rw-r--r--archive/0.vm.arc/tangle.mu35
-rw-r--r--archive/0.vm.arc/trace.arc.t1659
-rw-r--r--archive/0.vm.arc/trace.mu1092
-rw-r--r--archive/0.vm.arc/vimrc.vim8
-rw-r--r--archive/0.vm.arc/x.mu6
41 files changed, 21145 insertions, 0 deletions
diff --git a/archive/0.vm.arc/Readme.md b/archive/0.vm.arc/Readme.md
new file mode 100644
index 00000000..b8292abb
--- /dev/null
+++ b/archive/0.vm.arc/Readme.md
@@ -0,0 +1,21 @@
+Original prototype, last modified 2015-03-14
+
+First install [Racket](http://racket-lang.org) (just for this prototype;
+last tested with v6.3). Then:
+
+  ```shell
+  $ cd mu/archives/1.vm
+  $ git clone http://github.com/arclanguage/anarki
+  $ cd anarki
+  $   git checkout d7290130a7  # last compatible snapshot
+  $ cd ..
+  $ ./mu test mu.arc.t  # run tests
+  ```
+
+Example programs:
+
+  ```shell
+  $ ./mu factorial.mu  # computes factorial of 5
+  $ ./mu fork.mu  # two threads print '33' and '34' forever
+  $ ./mu channel.mu  # two threads in a producer/consumer relationship
+  ```
diff --git a/archive/0.vm.arc/blocking.arc.t b/archive/0.vm.arc/blocking.arc.t
new file mode 100644
index 00000000..80f7f229
--- /dev/null
+++ b/archive/0.vm.arc/blocking.arc.t
@@ -0,0 +1,26 @@
+(selective-load "mu.arc" section-level)
+(set allow-raw-addresses*)
+
+(reset)
+(new-trace "blocking-example")
+(add-code
+  '((function reader [
+      (default-space:space-address <- new space:literal 30:literal/capacity)
+      (x:tagged-value 1:channel-address/space:global <- read 1:channel-address/space:global)
+     ])
+    (function main [
+      (default-space:space-address <- new space:literal 30:literal/capacity)
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer/routine <- fork-helper reader:fn default-space:space-address/globals 50:literal/limit)
+      ; write nothing to the channel
+;?       (sleep until-routine-done:literal 2:integer/routine)
+     ])))
+;? (= dump-trace* (obj whitelist '("schedule" "run")))
+(run 'main)
+;? (prn "completed:")
+;? (each r completed-routines*
+;?   (prn " " r))
+(when (ran-to-completion 'reader)
+  (prn "F - reader waits for input"))
+
+(reset)
diff --git a/archive/0.vm.arc/buffered-stdin.mu b/archive/0.vm.arc/buffered-stdin.mu
new file mode 100644
index 00000000..9a7bc7ae
--- /dev/null
+++ b/archive/0.vm.arc/buffered-stdin.mu
@@ -0,0 +1,28 @@
+; reads lines, prints them back when you hit 'enter'
+; dies if you wait a while, because so far we never free memory
+(function main [
+  (default-space:space-address <- new space:literal 30:literal)
+  (cursor-mode) ;? 1
+  ; hook up stdin
+  (stdin:channel-address <- init-channel 1:literal)
+  (fork-helper send-keys-to-stdin:fn nil:literal/globals nil:literal/limit nil:literal/keyboard stdin:channel-address)
+  ; buffer stdin
+  (buffered-stdin:channel-address <- init-channel 1:literal)
+  (fork-helper buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+  { begin
+    ; now read characters from the buffer until 'enter' is typed
+    (s:string-address <- new "? ")
+    (print-string nil:literal/terminal s:string-address)
+    { begin
+      (x:tagged-value buffered-stdin:channel-address/deref <- read buffered-stdin:channel-address)
+      (c:character <- maybe-coerce x:tagged-value character:literal)
+;?       ($print (("AAA " literal))) ;? 1
+;?       ($print c:character) ;? 1
+;?       ($print (("\n" literal))) ;? 1
+      (print-character nil:literal/terminal c:character)
+      (line-done?:boolean <- equal c:character ((#\newline literal)))
+      (loop-unless line-done?:boolean)
+    }
+    (loop)
+  }
+])
diff --git a/archive/0.vm.arc/callcc.mu b/archive/0.vm.arc/callcc.mu
new file mode 100644
index 00000000..20dffeff
--- /dev/null
+++ b/archive/0.vm.arc/callcc.mu
@@ -0,0 +1,20 @@
+; in mu, call-cc (http://en.wikipedia.org/wiki/Call-with-current-continuation)
+; is constructed out of a combination of two primitives:
+;   'current-continuation', which returns a continuation, and
+;   'continue-from', which takes a continuation to
+
+(function g [
+  (c:continuation <- current-continuation)  ; <-- loop back to here
+  (print-character nil:literal/terminal ((#\a literal)))
+  (reply c:continuation)
+])
+
+(function f [
+  (c:continuation <- g)
+  (reply c:continuation)
+])
+
+(function main [
+  (c:continuation <- f)
+  (continue-from c:continuation)            ; <-- ..when you hit this
+])
diff --git a/archive/0.vm.arc/channel.mu b/archive/0.vm.arc/channel.mu
new file mode 100644
index 00000000..61151833
--- /dev/null
+++ b/archive/0.vm.arc/channel.mu
@@ -0,0 +1,49 @@
+(function producer [
+  ; produce numbers 1 to 5 on a channel
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel-address <- next-input)
+  ; n = 0
+  (n:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- less-than n:integer 5:literal)
+    (break-unless done?:boolean)
+    ; other threads might get between these prints
+    ($print (("produce: " literal)))
+    (print-integer nil:literal/terminal n:integer)
+    ($print (("\n" literal)))
+    ; 'box' n into a dynamically typed 'tagged value' because that's what
+    ; channels take
+    (n2:integer <- copy n:integer)
+    (n3:tagged-value-address <- init-tagged-value integer:literal n2:integer)
+    (chan:channel-address/deref <- write chan:channel-address n3:tagged-value-address/deref)
+    (n:integer <- add n:integer 1:literal)
+    (loop)
+  }
+])
+
+(function consumer [
+  ; consume and print integers from a channel
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel-address <- next-input)
+  { begin
+    ; read a tagged value from the channel
+    (x:tagged-value chan:channel-address/deref <- read chan:channel-address)
+    ; unbox the tagged value into an integer
+    (n2:integer <- maybe-coerce x:tagged-value integer:literal)
+    ; other threads might get between these prints
+    ($print (("consume: " literal)))
+    (print-integer nil:literal/terminal n2:integer)
+    ($print (("\n" literal)))
+    (loop)
+  }
+])
+
+(function main [
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel-address <- init-channel 3:literal)
+  ; create two background 'routines' that communicate by a channel
+  (routine1:integer <- fork consumer:fn nil:literal/globals nil:literal/limit chan:channel-address)
+  (routine2:integer <- fork producer:fn nil:literal/globals nil:literal/limit chan:channel-address)
+  (sleep until-routine-done:literal routine1:integer)
+  (sleep until-routine-done:literal routine2:integer)
+])
diff --git a/archive/0.vm.arc/charterm/charterm.rkt b/archive/0.vm.arc/charterm/charterm.rkt
new file mode 100644
index 00000000..cae12098
--- /dev/null
+++ b/archive/0.vm.arc/charterm/charterm.rkt
@@ -0,0 +1,2798 @@
+#lang racket/base
+;; Copyright (c) Neil Van Dyke.  See file "info.rkt".
+
+(require (for-syntax racket/base
+                     racket/syntax)
+         racket/system
+         (planet neil/mcfly))
+
+(doc (section "Introduction")
+
+     (para "The "
+           "CharTerm"
+           " package provides a Racket interface for character-cell video
+display terminals on Unix-like systems -- such as for "
+           (as-index "GNU Screen")
+           " and "
+           (as-index (code "tmux"))
+           " sessions on "
+           (index '("cloud server" "server") "cloud servers")
+           ", "
+           (as-index "XTerm")
+           " windows on a workstation desktop, and some older hardware
+terminals (even the venerable "
+           (as-index "DEC VT100")
+           ").  Currently, it implements a subset of features available on most
+terminals.")
+
+     (para "This package could be used to implement a status/management console
+for a Racket-based server process (perhaps run in GNU Screen or "
+           (code "tmux")
+           " on a server machine, to be detached and reattached from SSH
+sessions), a lightweight user interface for a systems tool, a command-line
+REPL, a text editor, creative retro uses of old equipment, and, perhaps most
+importantly, a "
+           ;; (hyperlink "http://en.wikipedia.org/wiki/Rogue_%28computer_game%29"
+           "Rogue-like"
+           ;;)
+           " application.")
+
+     (para "The "
+           "CharTerm"
+           " package does not include any native code (such as from "
+           (as-index (code "terminfo"))
+           ", "
+           (as-index (code "termcap"))
+           ", "
+           (as-index (code "curses"))
+           ", or "
+           (as-index (code "ncurses"))
+           ") in the Racket process,
+such as through the Racket FFI or C extensions, so there is less potential for
+a problem involving native code to threaten the reliability or security of a
+program.  "
+           "CharTerm"
+           " is implemented in pure Racket code except for executing "
+           (code "/bin/stty")
+           " for some purposes.  Specifically, "
+           (code "/bin/stty")
+           " at startup time and shutdown time, to set modes, and (for terminal
+types that don't seem to support a screen size report control sequence) when
+getting screen size.  Besides security and stability, lower dependence on
+native code might also simplify porting to host platforms that don't have those
+native code facilities."))
+
+(doc (subsection "Demo")
+
+     (para "For a demonstration, the following command, run from a terminal, should install the "
+           "CharTerm"
+           " package (if not already installed), and run the demo:")
+
+     (commandline "racket -pm neil/charterm/demo")
+
+     (para "This demo reports what keys you pressed, while letting you edit a
+text field, and while displaying a clock.  The clock is updated roughly once
+per second, and is not updated during heavy keyboard input, such as when typing
+fast.  The demo responds to changing terminal sizes, such as when an XTerm is
+window is resized.  It also displays the determined terminal size, and some
+small tests of the "
+           (racket #:width)
+           " argument to "
+           (racket charterm-display)
+           ".  Exit the demo by pressing the "
+           (bold "Esc")
+           " key.")
+
+     (para "Note: Although this demo includes an editable text field, as proof
+of concept, the current version of "
+           "CharTerm"
+           " does not provide editable text fields as reusable functionality."))
+
+(doc (subsection "Simple Example")
+
+     (para "Here's your first "
+           "CharTerm"
+           " program:")
+
+     (RACKETBLOCK
+      (UNSYNTAX (code "#lang racket/base"))
+
+      (require (planet neil/charterm))
+
+      (with-charterm
+       (charterm-clear-screen)
+       (charterm-cursor 10 5)
+       (charterm-display "Hello, ")
+       (charterm-bold)
+       (charterm-display "you")
+       (charterm-normal)
+       (charterm-display ".")
+       (charterm-cursor 1 1)
+       (charterm-display "Press a key...")
+       (let ((key (charterm-read-key)))
+         (charterm-cursor 1 1)
+         (charterm-clear-line)
+         (printf "You pressed: ~S\r\n" key))))
+
+     (para "Now you're living the dream of the '70s."))
+
+(doc (section "Terminal Diversity")
+
+     (para "Like people, few terminals are exactly the same.")
+
+     (para "Some key (ha) terms (ha) used by "
+           "CharTerm"
+           " are:")
+
+     (itemlist (item (tech "termvar")
+                     " --- a string value like from the Unix-like "
+                     (code "TERM")
+                     " environment variable, used to determine a default "
+                     (tech "protocol")
+                     " and "
+                     (tech "keydec")
+                     ".")
+
+               (item (tech "protocol")
+                     " --- how to control the display, query for information, etc.")
+
+               (item (tech "keydec")
+                     " --- how to decode key encodings of a particular
+terminal.  A keydec is constructed from one or more keysets, can produce "
+                     (tech "keycode")
+                     "s or "
+                     (tech "keyinfo")
+                     "s.")
+
+               (item (tech "keyset")
+                     " --- a specification of encoding some of the keys in a
+particular terminal, including "
+                     (tech "keylabel")
+                     "s and "
+                     (tech "keycode")
+                     "s.")
+
+               (item (tech "keylabel")
+                     " --- a string for how a key is likely labeled on a
+keyboard, such as the DEC VT100 "
+                     (bold "PF1")
+                     " key would have a keylabel "
+                     (racket "PF1")
+                     " for a "
+                     (tech "keycode")
+                     " "
+                     (racket 'f1)
+                     ".")
+
+               (item (tech "keycode")
+                     " --- a value produced by a decoded key,
+such as a character for normal printable keys, like "
+                     (racket #\a)
+                     " and "
+                     (racket #\space)
+                     ", a symbol for some recognized unprintable keys, like "
+                     (racket 'escape)
+                     " and "
+                     (racket 'f1)
+                     ", or possibly a number for unrecognized keys.")
+
+               (item (tech "keyinfo")
+                     " --- an object that is used like a "
+                     (tech "keycode")
+                     ", except
+bundles together a keycode and a "
+                     (tech "keylabel")
+                     ", as well as alternatate keycodes and
+information about how the key was decoded (e.g., from which "
+                     (tech "keyset")
+                     ")."))
+
+     (para "These terms are discussed in the following subsections.")
+
+     (para "CharTerm"
+           " is developed with help of original documentation such as that
+curated by Paul Williams at "
+           (hyperlink "http://vt100.net/" "vt100.net")
+           ", various commentary found on the Web, observed behavior with
+modern software terminals like XTerm, various emulators for hardware terminals,
+and sometimes original hardware terminals.  Thanks to Mark Pearrow for
+contributing a TeleVideo 950, and Paul McCabe for a Wyse S50 WinTerm.")
+
+     (para "At time of this writing, the author is looking to acquire a DEC
+VT525, circa 1994, for ongoing testing.")
+
+     (para "The author welcomes feedback on useful improvements to "
+           "CharTerm"
+           "'s support for terminal diversity (no pun).  If you have a terminal
+that is sending an escape sequence not recognized by the demo, you can run the
+demo with the "
+           (Flag "n")
+           " (aka "
+           (DFlag "no-escape")
+           ") argument to see the exact byte sequence:")
+
+     (commandline "racket -pm- neil/charterm/demo -n")
+
+     (para "When "
+           (Flag "n")
+           " is used, this will be indicated by the bottom-most scrolling line,
+rather than saying ``"
+           (tt "To quit, press " (bold "Esc") ".")
+           "'' instead will say ``"
+           (tt "There is no escape from this demo.")
+           "'' You will have to kill the process through some other means."))
+
+(doc (subsection "Protocol")
+
+     (para "The first concept "
+           "CharTerm"
+           " has for distinguishing how to communicate with a terminal is what
+is what is called here "
+           (deftech "protocol")
+           ", which concerns everything except how keyboard keys are decoded.
+The following protocols are currently implemented:")
+
+     (itemlist
+
+      (item (deftech (code "ansi") " protocol")
+            " --- Terminals approximating ["
+            (tech "ANSI X3.64")
+            "], which is most terminals in use today, including software ones
+like XTerm.  This protocol is the emphasis of this package; the other protocols
+are for unusual situations.")
+
+      ;; (item (code "dec-vt100")
+      ;;       " --- The DEC VT100 and compatibles that could be considered "
+      ;;       (code "ansi")
+      ;;       " except don't have insert-line and delete-line.")
+
+      (item (deftech (code "wyse-wy50") " protocol")
+            " --- Terminals compatible with the Wyse WY-50.  This support is
+based on ["
+            (tech "WY-50-QRG")
+            "], ["
+            (tech "WY-60-UG")
+            "], ["
+            (tech "wy60")
+            "], and ["
+            (tech "PowerTerm")
+            "].  Note that video attributes are not supported, due to the WY-50's
+model of having video attribute changes occupy character cells; you may wish
+to run the Wyse terminal in an ANSI or VT100 mode.")
+
+      (item (deftech (code "televideo-925") " protocol")
+            " --- Terminals compatible with the TeleVideo 925.  This support is based on ["
+            (tech "TVI-925-IUG")
+            "] and behavior of ["
+            (tech "PowerTerm")
+            "].  Note that video attributes are not supported, due to the 925's
+model of having video attribute changes occupy character cells; you may wish to
+run your TeleVideo terminal in ANSI or VT100 mode, if it has one.")
+
+      (item (deftech (code "ascii") " protocol")
+            " --- Terminals that support ASCII but not much else that we know about.")))
+
+(define-syntax (%charterm:protocol-case stx)
+  (syntax-case stx (else)
+    ((_ ERROR-NAME ACTUAL-PROTO (PART0 PART1 PARTn ...) ...)
+     (let loop-clauses ((clause-stxes             (syntax->list #'((PART0 PART1 PARTn ...) ...)))
+                        (reverse-out-clause-stxes '())
+                        (else-stx                 #f)
+                        (need-protos-hash         (make-immutable-hasheq (map (lambda (proto)
+                                                                                (cons proto #t))
+                                                                              '(ansi
+                                                                                televideo-925
+                                                                                wyse-wy50)))))
+       (if (null? clause-stxes)
+           (let ((missing-protos (hash-keys need-protos-hash)))
+             (if (or else-stx (null? missing-protos))
+                 (quasisyntax/loc stx
+                   (let ((actual-proto ACTUAL-PROTO))
+                     (case actual-proto
+                       #,@(reverse reverse-out-clause-stxes)
+                       #,(or else-stx
+                             (syntax/loc stx
+                               (else (error ERROR-NAME
+                                            "unimplemented for protocol: ~S"
+                                            actual-proto)))))))
+                 (raise-syntax-error '%charterm:protocol-case
+                                     (format "missing protocols ~S" missing-protos)
+                                     stx)))
+           (let* ((clause-stx   (car clause-stxes))
+                  (clause-parts (syntax->list clause-stx))
+                  (part0-stx    (car clause-parts))
+                  (part0-e      (syntax-e part0-stx)))
+             (if (eq? 'else part0-e)
+                 (if else-stx
+                     (raise-syntax-error '%charterm:protocol-case
+                                         "else clause multiply defined"
+                                         clause-stx
+                                         #f
+                                         (list else-stx))
+                     (loop-clauses (cdr clause-stxes)
+                                   reverse-out-clause-stxes
+                                   clause-stx
+                                   need-protos-hash))
+                 (let loop-protos ((proto-stxes      (syntax->list (car (syntax->list clause-stx))))
+                                   (need-protos-hash need-protos-hash))
+                   (if (null? proto-stxes)
+                       (loop-clauses (cdr clause-stxes)
+                                     (cons clause-stx reverse-out-clause-stxes)
+                                     else-stx
+                                     need-protos-hash)
+                       (let* ((proto-stx (car proto-stxes))
+                              (proto-e   (syntax-e proto-stx)))
+                         (if (symbol? proto-e)
+                             (if (hash-has-key? need-protos-hash proto-e)
+                                 (loop-protos (cdr proto-stxes)
+                                              (hash-remove need-protos-hash proto-e))
+                                 (raise-syntax-error '%charterm:protocol-case
+                                                     "protocol unrecognized or multiply defined"
+                                                     proto-stx))
+                             (raise-syntax-error '%charterm:protocol-case
+                                                 "invalid protocol symbol"
+                                                 proto-stx))))))))))))
+
+(define-syntax (%charterm:unimplemented stx)
+  (syntax-case stx ()
+    ((_ CT ERROR-NAME)
+     (syntax/loc stx
+       (error ERROR-NAME
+              "unimplemented feature for protocol ~S"
+              (charterm-protocol CT))))))
+
+(doc (subsection "Key Encoding")
+
+     (para "While most video display control, they seem to vary more by key
+encoding.")
+
+     (para "The "
+           "CharTerm"
+           " author was motivated to increase the sophistication of its
+keyboard handling after a series of revelations on the Sunday of the long
+weekend in which "
+           "CharTerm"
+           " was initially written.  The first was discovering that four of the
+function keys that had been working fine in "
+           (code "rxvt")
+           " did not work in XTerm.  Dave Gilbert somewhat demystified this by
+pointing out that the original VT100 had only four function keys, which set
+into motion an unfortunate series of bad decisions by various developers of
+terminal software to be needlessly incompatible with each other.  After
+Googling, a horrifying 2005 Web post by Phil Gregory ["
+           (tech "Gregory")
+           "], which showed that key encoding among XTerm variants was even
+worse than one could ever fear.  Even if one already knew how much subtleties
+of old terminals varied (e.g., auto-newline behavior, whether an attribute
+change consumed a space, etc.), this incompatibility in newer software was
+surprising. Then, on a hunch, I tried the Linux Console on a Debian Squeeze
+machine, which surely is ANSI, and found, however, that it generated "
+           (italic "yet different")
+           " byte sequences, for the first "
+           (italic "five")
+           " (not four) function keys.  Then I compared all to the ["
+           (tech "ECMA-48")
+           "] standard, which turns out to be nigh-inscrutable, so which might
+help explain why everyone became so anti-social.")
+
+     (para "CharTerm"
+           " now provides the abstractions of "
+           (tech "keysets")
+           " and "
+           (tech "keydecs")
+           " to deal with this diversity in a maintainable way."))
+
+(doc (subsubsection "Keylabel")
+
+     (para "A "
+           (deftech "keylabel")
+           " is a Racket string for how a key is likely labeled on a particular terminal's keyboard.  Different keyboards may have different keylabels for the same "
+           (tech "keycode")
+           ".  For example, a VT100 has a "
+           (bold "PF1")
+           " key (keylabel "
+           (racket "PF1")
+           ", keycode "
+           (racket 'f1)
+           "), while many other keyboards would label the key "
+           (bold "F1")
+           " (keylabel "
+           (racket "F1")
+           ", keycode "
+           (racket 'f1)
+           ").  The keylabel currently is most useful for documenting and debugging, although it could later be used when giving instructions to the user, such as knowing whether to tell the user the "
+           (bold "Return")
+           " key or the "
+           (bold "Enter")
+           " key; the "
+           (bold "Backspace")
+           " or the "
+           (bold "Rubout")
+           " key; etc."))
+
+(doc (subsubsection "Keycode")
+
+     (para "A "
+           (deftech "keycode")
+           " is a value representing a key read from a terminal, which can be a Racket character, symbol, or number.  Keys corresponding to printable characters have keycodes as Racket characters.  Some keys corresponding to special non-printable characters can have keycodes of Racket symbols, such as "
+           (racket 'return)
+           ", "
+           (racket 'f1)
+           ", "
+           (racket 'up)
+           ", etc."))
+
+;; TODO: Document here all the symbol keycodes we define.
+
+(doc (defproc (charterm-keycode? (x any/c))
+         boolean?
+       "Predicate for whether or not "
+       (racket x)
+       " is a valid keycode."))
+(provide charterm-keycode?)
+(define (charterm-keycode? x)
+  (if (or (symbol? x)
+          (char? x)
+          (exact-nonnegative-integer? x))
+      #t
+      #f))
+
+(doc (subsubsection "Keyinfo")
+
+     (para "A "
+           (deftech "keyinfo")
+           " represents a "
+           (tech "keycode")
+           " for a key, a "
+           (tech "keylabel")
+           ", and how it is encoded as bytes.  It is represented in Racket as
+a "
+           (racket charterm-keyinfo)
+           " object."))
+
+(define-struct charterm-keyinfo
+  (keyset-id
+   bytelang
+   bytelist
+   keylabel
+   keycode
+   all-keycodes)
+  #:transparent)
+
+(doc (defproc (charterm-keyinfo? (x any/c))
+         boolean?)
+     "Predicate for whether or not "
+     (racket x)
+     " is a "
+     (racket charterm-keyinfo)
+     " object.")
+(provide charterm-keyinfo?)
+
+(doc (defproc*
+         (((charterm-keyinfo-keyset-id    (ki charterm-keyinfo?)) symbol?)
+          ((charterm-keyinfo-bytelang     (ki charterm-keyinfo?)) string?)
+          ((charterm-keyinfo-bytelist     (ki charterm-keyinfo?)) (listof byte?))
+          ((charterm-keyinfo-keylabel     (ki charterm-keyinfo?)) string?)
+          ((charterm-keyinfo-keycode      (ki charterm-keyinfo?)) charterm-keycode?)
+          ((charterm-keyinfo-all-keycodes (ki charterm-keyinfo?)) (listof charterm-keycode?)))
+       (para "Get information from a "
+             (racket charterm-keyinfo)
+             " object.")))
+(provide charterm-keyinfo-keyset-id
+         charterm-keyinfo-bytelang
+         charterm-keyinfo-bytelist
+         charterm-keyinfo-keylabel
+         charterm-keyinfo-keycode
+         charterm-keyinfo-all-keycodes)
+
+(define %charterm:bytestr-to-byte-hash
+  (make-hash
+   `(("nul"      . 0)
+     ("null"     . 0)
+     ("lf"       . 10)
+     ("linefeed" . 10)
+     ("cr"       . 13)
+     ("return"   . 13)
+     ("ret"      . 13)
+     ("esc"      . 27)
+     ("^["       . 27)
+     ("sp"       . 32)
+     ("space"    . 32)
+     ,@(for/list ((n (in-range 1 26)))
+         (cons (string #\^ (integer->char (+ 96 n)))
+               n))
+     ,@(for/list ((n (in-range 1 26)))
+         (cons (string-append "ctrl-"
+                              (string (integer->char (+ 96 n))))
+               n))
+     ,@(for/list ((n (in-range 32 127)))
+         (cons (string (integer->char n))
+               n))
+     ,@(for/list ((n (in-range 0 255)))
+         (cons (string-append "("
+                              (number->string n)
+                              ")")
+               n)))))
+
+(define (%charterm:bytestr->byte bytestr)
+  (hash-ref %charterm:bytestr-to-byte-hash bytestr))
+
+(define (%charterm:bytelang->bytelist bytelang secondary?)
+  (let ((bytelist (map %charterm:bytestr->byte
+                       (regexp-split #rx" +" bytelang))))
+    (if (and secondary? (not (= 1 (length bytelist))))
+        (error '%charterm:bytelang->bytelist
+               "bytelist for secondary keyset: ~S"
+               bytelist)
+        bytelist)))
+
+(define (%charterm:keycode->keylabel keycode)
+  (cond ((not keycode) #f)
+        ((symbol? keycode) (string-titlecase (symbol->string keycode)))
+        ((char?   keycode) (string keycode))
+        ((number? keycode) (number->string keycode))
+        (else (error '%charterm:keycode->keylabel
+                     "invalid keycode: ~S"
+                     keycode))))
+
+(define (%charterm:keylang->keyinfo keyset-id keylang secondary?)
+  (apply (lambda (bytelang . args)
+           (let-values (((bytelist)
+                         (%charterm:bytelang->bytelist bytelang secondary?))
+                        ((keylabel keycode all-keycodes)
+                         (let ((keylabel (car args)))
+                           (if (or (string? keylabel)
+                                   (not keylabel))
+                               (values keylabel
+                                       (cadr args)
+                                       (cdr args))
+                               (let ((keycode (car args)))
+                                 (values (%charterm:keycode->keylabel keycode)
+                                         keycode
+                                         args))))))
+             (make-charterm-keyinfo keyset-id
+                                    bytelang
+                                    bytelist
+                                    keylabel
+                                    keycode
+                                    all-keycodes)))
+         keylang))
+
+(doc (subsubsection "Keyset")
+
+     (para "A "
+           (deftech "keyset")
+           " is a specification of keys on a particular keyboard, including their "
+           (tech "keylabel")
+           ", encoding as bytes, and primary and alternate "
+           (tech #:key "keycode" "keycodes")
+           ".")
+
+     ;; TODO: Expose ability to construct keysets, once it's finalized.
+     (para "The means of constructing a keyset is currently internal to this package."))
+
+(define-struct charterm-keyset
+  (id primary-keyinfos secondary-keyinfos)
+  #:transparent)
+
+(doc (defproc (charterm-keyset? (x any/c))
+         boolean?
+       (para "Predicate for whether or not "
+             (racket x)
+             " is a keyset.")))
+(provide charterm-keyset?)
+
+(doc (defproc (charterm-keyset-id (ks charterm-keyset?))
+         symbol?)
+     (para "Get a symbol identifying the keyset."))
+(provide charterm-keyset-id)
+
+;; (define (%charterm:keyinfos? x)
+;;   (for/and ((x (in-list x)))
+;;     (charterm-keyinfo? x)))
+;;
+;; (define (%charterm:assert-keyinfos keyinfos)
+;;   (or (%charterm:keyinfos? keyinfos)
+;;       (error '%charterm:assert-keyinfos
+;;              "assertion failed: ~S"
+;;              keyinfos)))
+
+(define (make-charterm-keyset-from-keylangs keyset-id
+                                            keylangs
+                                            (secondary-keylangs '()))
+  (let ((primary-keyinfos   (map (lambda (keylang)
+                                   (%charterm:keylang->keyinfo keyset-id keylang #f))
+                                 keylangs))
+        (secondary-keyinfos (map (lambda (keylang)
+                                   (%charterm:keylang->keyinfo keyset-id keylang #t))
+                                 secondary-keylangs)))
+    ;; (%charterm:assert-keyinfos primary-keyinfos)
+    ;; (%charterm:assert-keyinfos secondary-keyinfos)
+    (charterm-keyset keyset-id
+                     primary-keyinfos
+                     secondary-keyinfos)))
+
+(doc (defthing charterm-ascii-keyset charterm-keyset?
+       (para "From the old ["
+             (tech "ASCII")
+             "] standard.  When defining a "
+             (tech "keydec")
+             ", this is good to have as a final keyset, after the others.")))
+(define charterm-ascii-keyset
+  (let ((keylangs
+         `(("(0)"   "NUL"       nul             null)
+           ("(1)"   "Ctrl-A"    ctrl-a          start-of-heading soh)
+           ("(2)"   "Ctrl-B"    ctrl-b          start-of-text stx)
+           ("(3)"   "Ctrl-C"    ctrl-c          end-of-text etx)
+           ("(4)"   "Ctrl-D"    ctrl-d          end-of-transmission eot)
+           ("(5)"   "Ctrl-E"    ctrl-e          enquiry enq)
+           ("(6)"   "Ctrl-F"    ctrl-f          acknowledge ack)
+           ("(7)"   "Ctrl-G"    ctrl-g          bell bel)
+           ("(8)"   "Backspace" backspace       ctrl-h bs)
+           ("(9)"   "Tab"       tab             ctrl-i horizontal-tab ht)
+           ("(10)"  "Linefeed"  linefeed        ctrl-j line-feed lf)
+           ("(11)"  "Ctrl-K"    ctrl-k          vertical-tab vt)
+           ("(12)"  "Ctrl-L"    ctrl-l          formfeed form-feed ff)
+           ("(13)"  "Return"    return          ctrl-m carriage-return cr)
+           ("(14)"  "Ctrl-N"    ctrl-n          shift-out so)
+           ("(15)"  "Ctrl-O"    ctrl-o          shift-in si)
+           ("(16)"  "Ctrl-P"    ctrl-p          data-link-escape dle)
+           ("(17)"  "Ctrl-Q"    ctrl-q          device-control-1 dc1)
+           ("(18)"  "Ctrl-R"    ctrl-r          device-control-2 dc2)
+           ("(19)"  "Ctrl-S"    ctrl-s          device-control-3 dc3)
+           ("(20)"  "Ctrl-T"    ctrl-t          device-control-4 dc4)
+           ("(21)"  "Ctrl-U"    ctrl-u          negative-acknowledgement nak)
+           ("(22)"  "Ctrl-V"    ctrl-v          synchronous-idle syn)
+           ("(23)"  "Ctrl-W"    ctrl-w          end-of-transmission-block etb)
+           ("(24)"  "Ctrl-X"    ctrl-x          cancel can)
+           ("(25)"  "Ctrl-Y"    ctrl-y          end-of-medium em)
+           ("(26)"  "Ctrl-Z"    ctrl-z          substitute sub)
+           ("(27)"  "Esc"       escape          esc)
+           ("(28)"  "FS"        file-separator  fs)
+           ("(29)"  "GS"        group-separator gs)
+           ("(30)"  "RS"        record-separtor rs)
+           ("(31)"  "US"        unit-separator  us)
+           ("(32)"  "Space"     #\space         space sp)
+           ("(127)" "Delete"    delete          del)
+           ,@(for/list ((n (in-range 32 127)))
+               (let ((c (integer->char n)))
+                 (list (string-append "(" (number->string n) ")")
+                       (string c)
+                       c))))))
+    (make-charterm-keyset-from-keylangs
+     'ascii
+     keylangs
+     keylangs)))
+
+(doc (defthing charterm-dec-vt100-keyset charterm-keyset?
+       (para "From the DEC VT100.  This currently defines the four function
+keys (labeled on the keyboard, "
+             (bold "PF1")
+             " through "
+             (bold "PF4")
+             ") as "
+             (racket 'f1)
+             " through "
+             (racket 'f4)
+             ", and the arrow keys.  ["
+             (tech "VT100-UG")
+             "] and ["
+             (tech "PowerTerm")
+             "] were used as references.")))
+(provide charterm-dec-vt100-keyset)
+(define  charterm-dec-vt100-keyset
+  (make-charterm-keyset-from-keylangs
+   'dec-vt100
+   '(("esc O P" "PF1" f1)
+     ("esc O Q" "PF2" f2)
+     ("esc O R" "PF3" f3)
+     ("esc O S" "PF4" f4)
+
+     ("esc [ A" up)
+     ("esc [ B" down)
+     ("esc [ C" right)
+     ("esc [ D" left)
+     
+     ;; Note: PowerTerm does not map PC key F1 like VT100, etc.  It maps all
+     ;; the PC F keys to other sequences that are like the VT220.
+     )))
+
+(doc (defthing charterm-dec-vt220-keyset charterm-keyset?
+       (para "From the DEC VT220.  This currently defines function keys "
+             (bold "F1")
+             " through "
+             (bold "F20")
+             ".")))
+(provide charterm-dec-vt220-keyset)
+(define  charterm-dec-vt220-keyset
+  (make-charterm-keyset-from-keylangs
+   'dec-vt220
+   '(
+     ("esc [ 1 1 ~" f1)
+     ("esc [ 1 2 ~" f2)
+     ("esc [ 1 3 ~" f3)
+     ("esc [ 1 4 ~" f4)
+     ("esc [ 1 5 ~" f5)
+     ("esc [ 1 7 ~" f6)
+     ("esc [ 1 8 ~" f7)
+     ("esc [ 1 9 ~" f8)
+     ("esc [ 2 0 ~" f9)
+     ("esc [ 2 1 ~" f10)
+     ("esc [ 2 3 ~" f11)
+     ("esc [ 2 4 ~" f12)
+     ("esc [ 2 5 ~" f13)
+     ("esc [ 2 6 ~" f14)
+     ("esc [ 2 8 ~" f15)
+     ("esc [ 2 9 ~" f16)
+     ("esc [ 3 1 ~" f17)
+     ("esc [ 3 2 ~" f18)
+     ("esc [ 3 3 ~" f19)
+     ("esc [ 3 4 ~" f20)
+
+     ;; TODO: Make the keylang expand to both "esc [" and "(155)" CSI or
+     ;; whatever.
+     
+     ("(155) 1 1 ~" f1)
+     ("(155) 1 2 ~" f2)
+     ("(155) 1 3 ~" f3)
+     ("(155) 1 4 ~" f4)
+     ("(155) 1 5 ~" f5)
+     ("(155) 1 7 ~" f6)
+     ("(155) 1 8 ~" f7)
+     ("(155) 1 9 ~" f8)
+     ("(155) 2 0 ~" f9)
+     ("(155) 2 1 ~" f10)
+     ("(155) 2 3 ~" f11)
+     ("(155) 2 4 ~" f12)
+     ("(155) 2 5 ~" f13)
+     ("(155) 2 6 ~" f14)
+     ("(155) 2 8 ~" f15)
+     ("(155) 2 9 ~" f16)
+     ("(155) 3 1 ~" f17)
+     ("(155) 3 2 ~" f18)
+     ("(155) 3 3 ~" f19)
+     ("(155) 3 4 ~" f20)
+
+     )))
+
+(doc (defthing charterm-screen-keyset charterm-keyset?
+       (para "From the "
+             (hyperlink "http://en.wikipedia.org/wiki/GNU_Screen"
+                        "GNU Screen")
+             " terminal multiplexer, according to ["
+             (tech "Gregory")
+             "].  Also used by "
+             (hyperlink "http://en.wikipedia.org/wiki/Tmux"
+                        (code "tmux"))
+             ".")))
+(provide charterm-screen-keyset)
+(define  charterm-screen-keyset
+  (make-charterm-keyset-from-keylangs
+   'screen
+   '(("esc O P"     f1)
+     ("esc O Q"     f2)
+     ("esc O R"     f3)
+     ("esc O S"     f4)
+     ("esc [ 1 5 ~" f5)
+     ("esc [ 1 7 ~" f6)
+     ("esc [ 1 8 ~" f7)
+     ("esc [ 1 9 ~" f8)
+     ("esc [ 2 0 ~" f9)
+     ("esc [ 2 1 ~" f10)
+     ("esc [ 2 3 ~" f11)
+     ("esc [ 2 4 ~" f12)
+
+     ("esc [ 3 ~" "Delete" delete del)
+     ("esc [ 7 ~" "Home" home)
+     ("esc [ 8 ~" "End"  end)
+     
+     ("(127)" "Backspace" backspace)
+     )))
+
+(doc (defthing charterm-linux-keyset charterm-keyset?
+       (para "From the Linux console.  Currently defines function keys "
+             (bold "F1")
+             " through "
+             (bold "F5")
+             " only, since the rest will be inherited from other keysets.")))
+(provide charterm-linux-keyset)
+(define charterm-linux-keyset
+  (make-charterm-keyset-from-keylangs
+   'linux
+   '(("esc [ [ A" f1)
+     ("esc [ [ B" f2)
+     ("esc [ [ C" f3)
+     ("esc [ [ D" f4)
+     ("esc [ [ E" f5))))
+
+(doc (defthing charterm-xterm-x11r6-keyset charterm-keyset?
+       (para "From the XTerm in X11R6, according to ["
+             (tech "Gregory")
+             "].")))
+(provide charterm-xterm-x11r6-keyset)
+(define  charterm-xterm-x11r6-keyset
+  (make-charterm-keyset-from-keylangs
+   'xterm-x11r6
+   '(("esc [ 1 1 ~"     f1)
+     ("esc [ 1 2 ~"     f2)
+     ("esc [ 1 3 ~"     f3)
+     ("esc [ 1 4 ~"     f4)
+     ("esc [ 1 5 ~"     f5)
+     ("esc [ 1 7 ~"     f6)
+     ("esc [ 1 8 ~"     f7)
+     ("esc [ 1 9 ~"     f8)
+     ("esc [ 2 0 ~"     f9)
+     ("esc [ 2 1 ~"     f10)
+     ("esc [ 2 3 ~"     f11)
+     ("esc [ 2 4 ~"     f12)
+     ("esc [ 1 1 ; 2 ~" f13)
+     ("esc [ 1 2 ; 2 ~" f14)
+     ("esc [ 1 3 ; 2 ~" f15)
+     ("esc [ 1 4 ; 2 ~" f16)
+     ("esc [ 1 5 ; 2 ~" f17)
+     ("esc [ 1 7 ; 2 ~" f18)
+     ("esc [ 1 8 ; 2 ~" f19)
+     ("esc [ 1 9 ; 2 ~" f20)
+     ("esc [ 2 0 ; 2 ~" f21)
+     ("esc [ 2 1 ; 2 ~" f22)
+     ("esc [ 2 3 ; 2 ~" f23)
+     ("esc [ 2 4 ; 2 ~" f24)
+     ("esc [ 1 1 ; 5 ~" f25)
+     ("esc [ 1 2 ; 5 ~" f26)
+     ("esc [ 1 3 ; 5 ~" f27)
+     ("esc [ 1 4 ; 5 ~" f28)
+     ("esc [ 1 5 ; 5 ~" f29)
+     ("esc [ 1 7 ; 5 ~" f30)
+     ("esc [ 1 8 ; 5 ~" f31)
+     ("esc [ 1 9 ; 5 ~" f32)
+     ("esc [ 2 0 ; 5 ~" f33)
+     ("esc [ 2 1 ; 5 ~" f34)
+     ("esc [ 2 3 ; 5 ~" f35)
+     ("esc [ 2 4 ; 5 ~" f36)
+     ("esc [ 1 1 ; 6 ~" f37)
+     ("esc [ 1 2 ; 6 ~" f38)
+     ("esc [ 1 3 ; 6 ~" f39)
+     ("esc [ 1 4 ; 6 ~" f40)
+     ("esc [ 1 5 ; 6 ~" f41)
+     ("esc [ 1 7 ; 6 ~" f42)
+     ("esc [ 1 8 ; 6 ~" f43)
+     ("esc [ 1 9 ; 6 ~" f44)
+     ("esc [ 2 0 ; 6 ~" f45)
+     ("esc [ 2 1 ; 6 ~" f46)
+     ("esc [ 2 3 ; 6 ~" f47)
+     ("esc [ 2 4 ; 6 ~" f48))))
+
+(doc (defthing charterm-xterm-xfree86-keyset charterm-keyset?
+       (para "From the XFree86 XTerm, according to ["
+             (tech "Gregory")
+             "].")))
+(provide charterm-xterm-xfree86-keyset)
+(define  charterm-xterm-xfree86-keyset
+  (make-charterm-keyset-from-keylangs
+   'xterm-xfree86
+   '(("esc O P"         f1)
+     ("esc O Q"         f2)
+     ("esc O R"         f3)
+     ("esc O S"         f4)
+     ("esc [ 1 5 ~"     f5)
+     ("esc [ 1 7 ~"     f6)
+     ("esc [ 1 8 ~"     f7)
+     ("esc [ 1 9 ~"     f8)
+     ("esc [ 2 0 ~"     f9)
+     ("esc [ 2 1 ~"     f10)
+     ("esc [ 2 3 ~"     f11)
+     ("esc [ 2 4 ~"     f12)
+     ("esc O 2 P"       f13)
+     ("esc O 2 Q"       f14)
+     ("esc O 2 R"       f15)
+     ("esc O 2 S"       f16)
+     ("esc [ 1 5 ; 2 ~" f17)
+     ("esc [ 1 7 ; 2 ~" f18)
+     ("esc [ 1 8 ; 2 ~" f19)
+     ("esc [ 1 9 ; 2 ~" f20)
+     ("esc [ 2 0 ; 2 ~" f21)
+     ("esc [ 2 1 ; 2 ~" f22)
+     ("esc [ 2 3 ; 2 ~" f23)
+     ("esc [ 2 4 ; 2 ~" f24)
+     ("esc O 5 P"       f25)
+     ("esc O 5 Q"       f26)
+     ("esc O 5 R"       f27)
+     ("esc O 5 S"       f28)
+     ("esc [ 1 5 ; 5 ~" f29)
+     ("esc [ 1 7 ; 5 ~" f30)
+     ("esc [ 1 8 ; 5 ~" f31)
+     ("esc [ 1 9 ; 5 ~" f32)
+     ("esc [ 2 0 ; 5 ~" f33)
+     ("esc [ 2 1 ; 5 ~" f34)
+     ("esc [ 2 3 ; 5 ~" f35)
+     ("esc [ 2 4 ; 5 ~" f36)
+     ("esc O 6 P"       f37)
+     ("esc O 6 Q"       f38)
+     ("esc O 6 R"       f39)
+     ("esc O 6 S"       f40)
+     ("esc [ 1 5 ; 6 ~" f41)
+     ("esc [ 1 7 ; 6 ~" f42)
+     ("esc [ 1 8 ; 6 ~" f43)
+     ("esc [ 1 9 ; 6 ~" f44)
+     ("esc [ 2 0 ; 6 ~" f45)
+     ("esc [ 2 1 ; 6 ~" f46)
+     ("esc [ 2 3 ; 6 ~" f47)
+     ("esc [ 2 4 ; 6 ~" f48))))
+
+(doc (defthing charterm-xterm-new-keyset charterm-keyset?
+       (para "From the current "
+             (code "xterm-new")
+             ", often called simply "
+             (code "xterm")
+             ", as developed by Thomas E. Dickey, and documented in ["
+             (tech "XTerm-ctlseqs")
+             "].  Several also came from decompiling a "
+             (code "terminfo")
+             " entry.  Thanks to Dickey for his emailed help.")))
+(provide charterm-xterm-new-keyset)
+(define  charterm-xterm-new-keyset
+  (make-charterm-keyset-from-keylangs
+   'xterm-new
+   '(
+
+     ;; CSI = "esc ["
+     ;; SS3 = "esc O"
+
+     ("esc [ A" up)
+     ("esc [ B" down)
+     ("esc [ C" right)
+     ("esc [ D" left)
+     ("esc [ H" home)
+     ("esc [ F" end)
+
+     ;; The following came from decompiling an xterm terminfo
+     ("esc O A" up)
+     ("esc O B" down)
+     ("esc O C" right)
+     ("esc O D" left)
+     ("esc O H" home)
+     ("esc O F" end)
+
+     ("esc O P" f1)
+     ("esc O Q" f2)
+     ("esc O R" f3)
+     ("esc O S" f4)
+     ("esc [ 1 5 ~" f5)
+     ("esc [ 1 7 ~" f6)
+     ("esc [ 1 8 ~" f7)
+     ("esc [ 1 9 ~" f8)
+     ("esc [ 2 0 ~" f9)
+     ("esc [ 2 1 ~" f10)
+     ("esc [ 2 3 ~" f11)
+     ("esc [ 2 4 ~" f12)
+
+     ("esc O I" tab kp-tab)
+     ("esc O M" "Enter" return enter kp-return kp-enter)
+     ("esc O P" "PF1" f1 kp-f1)
+     ("esc O Q" "PF2" f2 kp-f2)
+     ("esc O R" "PF3" f3 kp-f3)
+     ("esc O S" "PF4" f4 kp-f4)
+     ("esc [ 3 ~" "Delete" delete del kp-delete)
+     ("esc [ 2 ~" "Insert" insert ins kp-insert)
+     ("esc O F"   "End" end kp-end)
+     ("esc [ B" "Down" down kp-down)
+     ("esc [ 6 ~" "PgDn" pgdn kp-pgdn)
+     ("esc [ D" "Left" left kp-left)
+     ("esc [ E" "Begin" begin kp-begin)
+     ("esc [ C" "Right" right kp-right)
+     ("esc O H" "Home" home kp-home)
+     ("esc [ A" "Up" up kp-up)
+     ("esc [ 5 ~" "PgUp" pgup kp-pgup)
+
+     ("esc [ 1 1 ~" "F1" f1)
+     ("esc [ 1 2 ~" "F2" f2)
+     ("esc [ 1 3 ~" "F3" f3)
+     ("esc [ 1 4 ~" "F4" f4)
+
+     ;; TODO: continue working on this from dickey's xterm control sequences doc
+
+     )))
+
+(doc (defthing charterm-rxvt-keyset charterm-keyset?
+       (para "From the "
+             (hyperlink "http://en.wikipedia.org/wiki/Rxvt"
+                        (code "rxvt"))
+             " terminal emulator.  These come from ["
+             (tech "Gregory")
+             "], and
+currently define function keys "
+             (racket 'f1)
+             " through "
+             (racket 'f44)
+             ".")))
+(define charterm-rxvt-keyset
+  (make-charterm-keyset-from-keylangs
+   'rxvt
+   '(("esc [ 1 1 ~" f1)
+     ("esc [ 1 2 ~" f2)
+     ("esc [ 1 3 ~" f3)
+     ("esc [ 1 4 ~" f4)
+     ("esc [ 1 5 ~" f5)
+     ("esc [ 1 7 ~" f6)
+     ("esc [ 1 8 ~" f7)
+     ("esc [ 1 9 ~" f8)
+     ("esc [ 2 0 ~" f9)
+     ("esc [ 2 1 ~" f10)
+     ("esc [ 2 3 ~" shift-f1  f11) ;; TODO: These shift- and ctrl- are actually from termvar xterm in an rxvt
+     ("esc [ 2 4 ~" shift-f2  f12)
+     ("esc [ 2 5 ~" shift-f3  f13)
+     ("esc [ 2 6 ~" shift-f4  f14)
+     ("esc [ 2 8 ~" shift-f5  f15)
+     ("esc [ 2 9 ~" shift-f6  f16)
+     ("esc [ 3 1 ~" shift-f7  f17)
+     ("esc [ 3 2 ~" shift-f8  f18)
+     ("esc [ 3 3 ~" shift-f9  f19)
+     ("esc [ 3 4 ~" shift-f10 f20)
+     ("esc [ 2 3 $" shift-f11 f21)
+     ("esc [ 2 4 $" shift-f12 f22)
+     ("esc [ 1 1 ^" ctrl-f1   f23)
+     ("esc [ 1 2 ^" ctrl-f2   f24)
+     ("esc [ 1 3 ^" ctrl-f3   f25)
+     ("esc [ 1 4 ^" ctrl-f4   f26)
+     ("esc [ 1 5 ^" ctrl-f5   f27)
+     ("esc [ 1 7 ^" ctrl-f6   f28)
+     ("esc [ 1 8 ^" ctrl-f7   f29)
+     ("esc [ 1 9 ^" ctrl-f8   f30)
+     ("esc [ 2 0 ^" ctrl-f9   f31)
+     ("esc [ 2 1 ^" ctrl-f10  f32)
+     ("esc [ 2 3 ^" ctrl-f11  f33)
+     ("esc [ 2 4 ^" ctrl-f12  f34)
+     ("esc [ 2 5 ^" f35)
+     ("esc [ 2 6 ^" f36)
+     ("esc [ 2 8 ^" f37)
+     ("esc [ 2 9 ^" f38)
+     ("esc [ 3 1 ^" f39)
+     ("esc [ 3 2 ^" f40)
+     ("esc [ 3 3 ^" f41)
+     ("esc [ 3 4 ^" f42)
+     ("esc [ 2 3 @" f43)
+     ("esc [ 2 4 @" f44)
+     ("(127)" "Backspace" backspace) ; Override one from "ascii" keyset.
+     ;; TODO: actually, these arrow keys were observed in rxvt with termvar xterm.  which keyset should they be in?
+     ("esc [ A"     "Up" up)
+     ("esc [ B"     "Down" down)
+     ("esc [ C"     "Right" right)
+     ("esc [ D"     "Left" left)
+     ("esc [ 5 ~"   "PgUp" pgup page-up)
+     ("esc [ 6 ~"   "PgDn" pgdn page-down)
+     ("esc [ 7 ~"   "Home" home)
+     ("esc [ 8 ~"   "End"  end)
+     ("esc [ 3 ~"   "Delete" delete del)
+     ("esc [ 2 ~"   "Insert" insert ins)
+     )))
+
+(doc (defthing charterm-wyse-wy50-keyset charterm-keyset?
+       (para "From the Wyse WY-50, based on ["
+             (tech "WY-50-QRG")
+             "] and looking at photos of WY-50 keyboard, and tested in ["
+             (tech "wy60")
+             "] and ["
+             (tech "PowerTerm")
+             "].  The shifted function keys are provided as both "
+             (racket 'shift-f1)
+             " through "
+             (racket 'shift-16)
+             ", and "
+             (racket 'f17)
+             " through "
+             (racket 'f31)
+             ".")))
+(provide charterm-wyse-wy50-keyset)
+(define  charterm-wyse-wy50-keyset
+  (make-charterm-keyset-from-keylangs
+   'wyse-wy50
+   '(("^a @ cr"  f1)
+     ("^a A cr"  f2)
+     ("^a B cr"  f3)
+     ("^a C cr"  f4)
+     ("^a D cr"  f5)
+     ("^a E cr"  f6)
+     ("^a F cr"  f7)
+     ("^a G cr"  f8)
+     ("^a H cr"  f9)
+     ("^a I cr"  f10)
+     ("^a J cr"  f11)
+     ("^a K cr"  f12)
+     ("^a L cr"  f13)
+     ("^a M cr"  f14)
+     ("^a N cr"  f15)
+     ("^a O cr"  f16)
+     ("^a ` cr"  "Shift-F1" shift-f1 f17)
+     ("^a a cr"  "Shift-F2" shift-f2 f18)
+     ("^a b cr"  "Shift-F3" shift-f3 f19)
+     ("^a c cr"  "Shift-F4" shift-f4 f20)
+     ("^a d cr"  "Shift-F5" shift-f5 f21)
+     ("^a e cr"  "Shift-F6" shift-f6 f22)
+     ("^a f cr"  "Shift-F7" shift-f7 f23)
+     ("^a g cr"  "Shift-F8" shift-f8 f24)
+     ("^a h cr"  "Shift-F9" shift-f9 f25)
+     ("^a i cr"  "Shift-F10" shift-f10 f26)
+     ("^a j cr"  "Shift-F11" shift-f11 f27)
+     ("^a k cr"  "Shift-F12" shift-f12 f28)
+     ("^a l cr"  "Shift-F13" shift-f13 f29)
+     ("^a m cr"  "Shift-F14" shift-f14 f30)
+     ("^a n cr"  "Shift-F15" shift-f15 f31)
+     ("^a o cr"  "Shift-F16" shift-f16 f32)
+     ("ctrl-h"   "Left" left)
+     ("linefeed" "Down" down)
+     ("(11)"     "Up" up)
+     ("(12)"     "Right" right)
+     ("esc W"    "DEL Char" delete)
+     ("esc Q"    "INS Char" insert-char)
+     ("esc q"    "Ins" insert ins)
+     ("esc T"    "CLR Line" clear-line)
+     ("esc r"    "Repl" repl)
+     ("esc R"    "DEL Line" delete-line)
+     ("esc J"    "PAGE Prev" pgup page-up)
+     ("esc K"    "PAGE Next" pgdn page-down)
+     ("esc P"    "Print" print)
+     ("esc Y"    "CLR Screen" clear-screen)
+     ("(30)"     "Home" home record-separator rs)
+     ("(13)"     "Return" return)
+     ("(127)"    "Shift-Backspace" backspace shift-backspace)
+     )))
+
+(doc (defthing charterm-televideo-925-keyset charterm-keyset?
+       (para "From the TeleVideo 925, based on ["
+             (tech "TVI-925-IUG")
+             "], ["
+             (tech "PowerTerm")
+             "], and from looking at a TeleVideo 950 keyboard.")))
+(provide charterm-televideo-925-keyset charterm-keyset?)
+(define  charterm-televideo-925-keyset
+  (make-charterm-keyset-from-keylangs
+   'televideo-925
+   '(("ctrl-a @ cr" f1)
+     ("ctrl-a A cr" f2)
+     ("ctrl-a B cr" f3)
+     ("ctrl-a C cr" f4)
+     ("ctrl-a D cr" f5)
+     ("ctrl-a E cr" f6)
+     ("ctrl-a F cr" f7)
+     ("ctrl-a G cr" f8)
+     ("ctrl-a H cr" f9)
+     ("ctrl-a I cr" f10)
+     ("ctrl-a J cr" f11)
+
+     ("ctrl-a \\ cr" "SHIFT-F1" shift-f1)
+     ("ctrl-a a cr" "SHIFT-F2" shift-f2)
+     ("ctrl-a b cr" "SHIFT-F3" shift-f3)
+     ("ctrl-a c cr" "SHIFT-F4" shift-f4)
+     ("ctrl-a d cr" "SHIFT-F5" shift-f5)
+     ("ctrl-a e cr" "SHIFT-F6" shift-f6)
+     ("ctrl-a f cr" "SHIFT-F7" shift-f7)
+     ("ctrl-a g cr" "SHIFT-F8" shift-f8)
+     ("ctrl-a h cr" "SHIFT-F9" shift-f9)
+     ("ctrl-a i cr" "SHIFT-F10" shift-f10)
+     ("ctrl-a j cr" "SHIFT-F11" shift-f11)
+
+     ("ctrl-k" "Up" up ctrl-k)
+     ("ctrl-v" "Down" down ctrl-v)
+     ("ctrl-h" "Left" left ctrl-h)
+     ("ctrl-l" "Right" right ctrl-l)
+
+     ("esc W" "CHAR DELETE" delete del char-delete)
+
+     ("esc Q" "CHAR INSERT" insert ins char-insert)
+
+     ("esc j" "Reverse Linefeed" reverse-linefeed reverse-lf reverse-line-feed)
+
+     ("esc i" "BACK TAB" backtab back-tab)
+     ("ctrl-m" "RETURN" return ctrl-m)
+     ("ctrl-j" "LINEFEED" linefeed lf ctrl-j)
+     ("(127)" "DEL" delete del)
+     ;; ("esc Q" "CHAR INSERT" char-insert char-ins)
+
+     )))
+
+(doc (subsubsection "Keydec")
+
+     (para "A "
+           (deftech "keydec")
+           " object is a key decoder for a specific variety of terminal, such
+as for a specific "
+           (tech "termvar")
+           ".  A keydec is used to turn received key encodings from a terminal into "
+           (tech "keycode")
+           " or "
+           (tech "keyinfo")
+           " values.  A keydec is constructed from a prioritized list of "
+           (tech "keyset")
+           " objects, with earlier-listed keysets taking priority of
+later-listed keysets when there is conflict between them as to how to decode a
+particular byte sequence."))
+
+(define (%charterm:make-keytree (alist '()))
+  (make-immutable-hasheqv alist))
+
+(define (%charterm:keytree-add-keyinfo-if-can keytree keyinfo)
+  (let ((bytelist (charterm-keyinfo-bytelist keyinfo)))
+    (let loop-bytelist ((this-byte  (car bytelist))
+                        (rest-bytes (cdr bytelist))
+                        (node       keytree))
+      (cond ((hash? node)
+             (cond ((hash-ref node this-byte #f)
+                    => (lambda (existing-sub-node)
+                         ;; Node has a match for this byte, so do we have another
+                         ;; byte and can follow it?
+                         (if (null? rest-bytes)
+                             ;; Node has a match for this byte, but we have no
+                             ;; more bytes, so can't add.
+                             node
+                             ;; Node has a match for this byte, and we have more
+                             ;; bytes, so follow it.
+                             (hash-set node
+                                       this-byte
+                                       (loop-bytelist (car rest-bytes)
+                                                      (cdr rest-bytes)
+                                                      existing-sub-node)))))
+                   (else
+                    ;; Node has no match for this byte, so add new path.
+                    (hash-set node
+                              this-byte
+                              (let loop ((rest-bytes rest-bytes))
+                                (if (null? rest-bytes)
+                                    keyinfo
+                                    (%charterm:make-keytree
+                                     (cons (cons (car rest-bytes)
+                                                 (loop (cdr rest-bytes)))
+                                           '()))))))))
+
+            ((charterm-keyinfo? node)
+             ;; Node is already a keyinfo, so can't add.
+             node)
+            (else (error
+                   '%charterm:keytree-add-keyinfo-if-can
+                   "invalid node ~S with this-byte ~S, rest-bytes ~S, keyinfo ~S"
+                   node
+                   this-byte
+                   rest-bytes
+                   keyinfo))))))
+
+(define (%charterm:keytree-add-any-keyinfos-can keytree keyinfos)
+  (let loop ((keyinfos keyinfos)
+             (keytree  keytree))
+    (if (null? keyinfos)
+        keytree
+        (loop (cdr keyinfos)
+              (%charterm:keytree-add-keyinfo-if-can keytree
+                                                    (car keyinfos))))))
+
+(define (%charterm:make-keytree-from-keyinfoses keyinfoses)
+  (let loop ((keyinfoses keyinfoses)
+             (keytree (%charterm:make-keytree)))
+    (if (null? keyinfoses)
+        keytree
+        (let ((keyinfos (car keyinfoses)))
+          ;; (and (not (null? keyinfos))
+          ;;      (not (charterm-keyinfo? (car keyinfos)))
+          ;;      (error '%charterm:make-keytree-from-keyinfoses
+          ;;             "bad keyinfos: ~S"
+          ;;             keyinfos))
+          (loop (cdr keyinfoses)
+                (%charterm:keytree-add-any-keyinfos-can keytree
+                                                        keyinfos))))))
+
+(doc (defproc (charterm-keydec-id (kd charterm-keydec?))
+         symbol?
+       (para "Gets the ID symbol of the "
+             (tech "keydec")
+             " being used.")))
+(provide charterm-keydec-id)
+
+(struct charterm-keydec
+  (id
+   primary-keytree
+   secondary-keytree)
+  #:transparent)
+
+(define (charterm-make-keydec keydec-id . keysets)
+  (charterm-keydec keydec-id
+                   (%charterm:make-keytree-from-keyinfoses
+                    (map charterm-keyset-primary-keyinfos keysets))
+                   (%charterm:make-keytree-from-keyinfoses
+                    (map charterm-keyset-secondary-keyinfos keysets))))
+
+(doc (subsubsub*section "ANSI Keydecs"))
+
+(doc (defthing charterm-vt100-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "vt100")
+             ".")))
+(provide charterm-vt100-keydec)
+(define  charterm-vt100-keydec
+  (charterm-make-keydec 'vt100
+                        charterm-dec-vt100-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-xterm-new-keyset
+                        charterm-linux-keyset
+                        charterm-rxvt-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-vt220-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "vt220")
+             ".")))
+(provide charterm-vt220-keydec)
+(define  charterm-vt220-keydec
+  (charterm-make-keydec 'vt220
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-screen-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "screen")
+             ".")))
+(provide charterm-screen-keydec)
+(define  charterm-screen-keydec
+  (charterm-make-keydec 'screen
+                        charterm-screen-keyset
+                        charterm-linux-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-xterm-new-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-linux-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "linux")
+             ".")))
+(provide charterm-linux-keydec)
+(define  charterm-linux-keydec
+  (charterm-make-keydec 'linux
+                        charterm-linux-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-xterm-new-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-screen-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-xterm-new-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "xterm-new")
+             ".")))
+(provide charterm-xterm-new-keydec)
+(define  charterm-xterm-new-keydec
+  (charterm-make-keydec 'xterm-new
+                        charterm-xterm-new-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-rxvt-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-linux-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-xterm-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "xterm")
+             ".  Currently same as the keydec for "
+             (code "xterm")
+             ", except for a different ID.")))
+(provide charterm-xterm-keydec)
+(define  charterm-xterm-keydec
+  (charterm-make-keydec 'xterm
+                        charterm-xterm-new-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-rxvt-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-linux-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-rxvt-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "rxvt")
+             ".")))
+(provide charterm-rxvt-keydec)
+(define  charterm-rxvt-keydec
+  (charterm-make-keydec 'rxvt
+                        charterm-rxvt-keyset
+                        charterm-xterm-new-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-linux-keyset
+                        charterm-ascii-keyset))
+
+(doc (subsubsub*section "Wyse Keydecs"))
+
+(doc (defthing charterm-wy50-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "wy50")
+             ".")))
+(provide charterm-wy50-keydec)
+(define  charterm-wy50-keydec
+  (charterm-make-keydec 'wy50
+                        charterm-wyse-wy50-keyset
+                        charterm-ascii-keyset))
+
+(doc (subsubsub*section "TeleVideo Keydecs"))
+
+(doc (defthing charterm-tvi925-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "tvi925")
+             ".")))
+(provide charterm-tvi925-keydec)
+(define  charterm-tvi925-keydec
+  (charterm-make-keydec 'tvi925
+                        charterm-televideo-925-keyset
+                        charterm-ascii-keyset))
+
+(doc (subsubsub*section "ASCII Keydecs"))
+
+(doc (defthing charterm-ascii-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for "
+             (tech "termvar")
+             " "
+             (racket "ascii")
+             ".")))
+(provide charterm-ascii-keydec)
+(define  charterm-ascii-keydec
+  (charterm-make-keydec 'ascii
+                        charterm-ascii-keyset))
+
+(doc (subsubsub*section "Default Keydecs"))
+
+(doc (defthing charterm-ansi-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for any presumed ANSI-ish terminal, combining many ANSI-ish "
+             (tech "keysets")
+             ".")))
+(define charterm-ansi-keydec
+  (charterm-make-keydec 'ansi
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-xterm-new-keyset
+                        charterm-linux-keyset
+                        charterm-rxvt-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-ascii-keyset))
+
+(doc (defthing charterm-insane-keydec charterm-keydec?
+       (para (tech "Keydec")
+             " for the uniquely desperate situation of wanting to possibly have
+extensive key decoding for a terminal that might not even be ansi, but be
+Wyse, TeleVideo, or some other ASCII.")))
+(provide charterm-insane-keydec)
+(define  charterm-insane-keydec
+  (charterm-make-keydec 'insane
+                        charterm-xterm-new-keyset
+                        charterm-linux-keyset
+                        charterm-dec-vt220-keyset
+                        charterm-dec-vt100-keyset
+                        charterm-linux-keyset
+                        charterm-xterm-xfree86-keyset
+                        charterm-xterm-x11r6-keyset
+                        charterm-wyse-wy50-keyset
+                        charterm-televideo-925-keyset
+                        charterm-ascii-keyset))
+
+(doc (subsection "Termvar")
+
+     (para "A "
+           (deftech "termvar")
+           " is what the "
+           (code "charterm")
+           " package calls the value of the Unix-like "
+           (code "TERM")
+           " environment variable.  Each "
+           (tech "termvar")
+           " has a default "
+           (tech "protocol")
+           " and "
+           (tech "keydec")
+           ".  Note, however, that "
+           (code "TERM")
+           " is not always a precise indicator of the best protocol and keydec,
+but by default we work with what we have."))
+
+;; TODO: Document the termvars here?  Move this subsection?
+
+(doc (section (code "charterm") " Object")
+
+     (para "The "
+           (racket charterm)
+           " object captures the state of a session with a particular terminal.")
+
+     (para "A "
+           (racket charterm)
+           " object is also a synchronizable event, so it can be used with
+procedures such as "
+           (racket sync)
+           ".  As an event, it becomes ready when there is at least one byte
+available for reading from the terminal, and its synchronization result is
+itself."))
+
+(doc (defproc (charterm? (x any/c))
+         boolean?
+       (para "Predicate for whether or not "
+             (var x)
+             " is a "
+             (racket charterm)
+             ".")))
+(provide charterm?)
+
+(doc (defproc (charterm-termvar (ct charterm?))
+         (or/c #f string?))
+     (para "Gets the "
+           (tech "termvar")
+           "."))
+(provide charterm-termvar)
+
+(doc (defproc (charterm-protocol (ct charterm?))
+         symbol?)
+     (para "Gets the "
+           (tech "protocol")
+           "."))
+(provide charterm-protocol)
+
+(doc (defproc (charterm-keydec (ct charterm?))
+         symbol?)
+     (para "Gets the "
+           (tech "keydec")
+           "."))
+(provide (rename-out (charterm-keydec* charterm-keydec)))
+
+(define-struct charterm
+  (tty
+   in
+   out
+   evt
+   buf-size
+   buf
+   (buf-start #:mutable)
+   (buf-end #:mutable)
+   termvar
+   protocol
+   keydec*
+   (screensize #:mutable))
+  #:property prop:evt (struct-field-index evt))
+
+(define (%charterm:protocol-unimplemented error-name ct)
+  (error error-name
+         "protocol unimplemented: ~S"
+         (charterm-protocol ct)))
+
+(define (%charterm:protocol-unreachable error-name ct)
+  (error error-name
+         "internal error: protocol unreachable: ~S"
+         (charterm-protocol ct)))
+
+(define %charterm:stty-minus-f-arg-string
+  (case (system-type 'os)
+    ((macosx) "-f")
+    (else     "-F")))
+  
+(doc (defparam current-charterm ct (or/c #f charterm?)
+       (para "This parameter provides the default "
+             (racket charterm)
+             " for most of the other procedures.  It is usually set automatically by "
+             (racket call-with-charterm)
+             ", "
+             (racket with-charterm)
+             ", "
+             (racket open-charterm)
+             ", and "
+             (racket close-charterm)
+             ".")))
+(provide current-charterm)
+(define current-charterm (make-parameter #f))
+
+(doc (defproc (open-charterm
+               (#:tty      tty      (or/c #f path-string?) #f)
+               (#:current? current? boolean?               #t))
+         charterm?
+       (para "Returns an open "
+             (racket charterm)
+             " object, by opening I/O ports on the terminal device at "
+             (racket tty)
+             " (or, if "
+             (racket #f)
+             ", file "
+             (filepath "/dev/tty")
+             "), and setting raw mode and disabling echo (via "
+             (filepath "/bin/stty")
+             ").  If "
+             (racket current?)
+             " is true, the "
+             (racket current-charterm)
+             " parameter is also set to this object.")))
+(provide open-charterm)
+(define (open-charterm #:tty      (tty      #f)
+                       #:current? (current? #t))
+  (let* ((tty (cleanse-path (or tty "/dev/tty")))
+         (tty-str  (path->string tty)))
+    (or (system* "/bin/stty"
+                 %charterm:stty-minus-f-arg-string
+                 tty-str
+                 "raw"
+                 "-echo")
+        (error 'open-charterm
+               "stty ~S failed"
+               tty-str))
+    (with-handlers ((exn:fail? (lambda (e)
+                                 (with-handlers ((exn:fail? void))
+                                   (system* "/bin/stty"
+                                            %charterm:stty-minus-f-arg-string
+                                            tty-str
+                                            "sane"))
+                                 (raise e))))
+      (let*-values (((in out)   (open-input-output-file tty
+                                                        #:exists 'update))
+                    ((buf-size) 2048))
+        ;; TODO: Do we actually need to turn off buffering?
+        (file-stream-buffer-mode in  'none)
+        (file-stream-buffer-mode out 'none)
+        (let*-values
+            (((termvar) (getenv "TERM"))
+             ((termvar) (cond ((not termvar) #f)
+                              ((equal? "" termvar) #f)
+                              (else (string-downcase termvar))))
+             ((protocol keydec)
+              ;; TODO: Once the patterns have been fleshed out, make the exact
+              ;; matches a hash, and optimize the regexps.
+              (cond ((not termvar) (values #f #f))
+                    ;; Exact Matches:
+                    ((equal? "ascii"     termvar) (values 'ascii         charterm-ascii-keydec))
+                    ((equal? "dumb"      termvar) (values 'ascii         charterm-ascii-keydec))
+                    ((equal? "linux"     termvar) (values 'ansi      charterm-linux-keydec))
+                    ((equal? "rxvt"      termvar) (values 'ansi      charterm-rxvt-keydec))
+                    ((equal? "screen"    termvar) (values 'ansi      charterm-screen-keydec))
+                    ((equal? "tvi925"    termvar) (values 'televideo-925 charterm-tvi925-keydec))
+                    ((equal? "tvi950"    termvar) (values 'televideo-925 charterm-tvi925-keydec))
+                    ((equal? "vt100"     termvar) (values 'ansi      charterm-vt100-keydec))
+                    ((equal? "vt102"     termvar) (values 'ansi      charterm-vt100-keydec))
+                    ((equal? "vt220"     termvar) (values 'ansi      charterm-vt220-keydec))
+                    ((equal? "wy50"      termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((equal? "wy60"      termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((equal? "wy75"      termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((equal? "wyse50"    termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((equal? "wyse60"    termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((equal? "wyse75"    termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((equal? "xterm"     termvar) (values 'ansi      charterm-xterm-new-keydec))
+                    ((equal? "xterm-new" termvar) (values 'ansi      charterm-xterm-new-keydec))
+                    ;; ANSI-ish Guesses:
+                    ((regexp-match #rx"ansi$"  termvar) (values 'ansi charterm-ansi-keydec))
+                    ((regexp-match #rx"^ansi"  termvar) (values 'ansi charterm-ansi-keydec))
+                    ((regexp-match #rx"^xterm" termvar) (values 'ansi charterm-xterm-new-keydec))
+                    ((regexp-match #rx"^rxvt"  termvar) (values 'ansi charterm-rxvt-keydec))
+                    ((regexp-match #rx"^vt"    termvar) (values 'ansi charterm-rxvt-keydec))
+                    ;; Non-ANSI Guesses:
+                    ((regexp-match #rx"^wy"  termvar) (values 'wyse-wy50     charterm-wy50-keydec))
+                    ((regexp-match #rx"^tvi" termvar) (values 'televideo-925 charterm-tvi925-keydec))
+                    ;; Default:
+                    (else (values #f #f))))
+             ((protocol keydec)
+              (values (or protocol 'ansi)
+                      (or keydec charterm-ansi-keydec))))
+          (letrec ((wrapping-evt (wrap-evt in
+                                           (lambda (evt) ct)))
+                   (ct (make-charterm tty-str               ; tty
+                                      in                    ; in
+                                      out                   ; out
+                                      wrapping-evt          ; evt
+                                      buf-size              ; buf-size
+                                      (make-bytes buf-size) ; buf
+                                      0                     ; buf-start
+                                      0                     ; buf-end
+                                      termvar               ; termvar
+                                      protocol              ; protocol
+                                      keydec                ; keydec
+                                        ; screensize
+                                      (if (and (eq? protocol 'ansi)
+                                               (not (member termvar '("screen"))))
+                                          'control/stty/none
+                                          'stty/none))))
+            (and current?
+                 (current-charterm ct))
+            ct))))))
+
+(doc (defproc (close-charterm (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Closes "
+             (racket ct)
+             " by closing the I/O ports, and undoing "
+             (racket open-charterm)
+             "'s changes via "
+             (filepath "/bin/stty")
+             ".  If "
+             (racket current-charterm)
+             " is set to "
+             (racket ct)
+             ", then that parameter will be changed to "
+             (racket #f)
+             " for good measure.  You might wish to use "
+             (racket with-charterm)
+             " instead of worrying about calling "
+             (racket close-charterm)
+             " directly.")
+       (para "Note: If you exit your Racket process without properly closing the "
+             (racket charterm)
+             ", your terminal may be left in a crazy state.  You can fix it with
+the command:")
+       (commandline "stty sane")))
+(provide close-charterm)
+(define (close-charterm #:charterm (ct (current-charterm)))
+  (with-handlers ((exn:fail? void)) (close-input-port  (charterm-in ct)))
+  (with-handlers ((exn:fail? void)) (close-output-port (charterm-out ct)))
+  ;; TODO: Set the port fields of the struct to #f?
+  (if (with-handlers ((exn:fail? (lambda (e) #f)))
+        (system* "/bin/stty"
+                 %charterm:stty-minus-f-arg-string
+                 (charterm-tty ct)
+                 "cooked"
+                 "echo"))
+      (if (eq? ct (current-charterm))
+          (current-charterm #f)
+          (void))
+      (error 'close-charterm
+             "stty failed")))
+
+;; (define (call-with-charterm proc #:tty (tty #f))
+;;   (let* ((tty (cleanse-path tty))
+;;          (ct  (open-charterm #:tty tty #:current? #f)))
+;;     (dynamic-wind
+;;       void
+;;       (lambda ()
+;;         (proc ct))
+;;       (lambda ()
+;;         (close-charterm #:charterm ct)))))
+
+(doc (defform (with-charterm expr? ...))
+     (para "Opens a "
+           (racket charterm)
+           " and evaluates the body expressions in sequence with "
+           (racket current-charterm)
+           " set appropriately.  When control jumps out of the body, in a
+manner of speaking, the "
+           (racket charterm)
+           " is closed."))
+(provide with-charterm)
+(define-syntax (with-charterm stx)
+  (syntax-case stx ()
+    ((_ BODY0 BODYn ...)
+     #'(let ((ct #f))
+         (dynamic-wind
+           (lambda ()
+             (set! ct (open-charterm #:current? #t)))
+           (lambda ()
+             BODY0 BODYn ...)
+           (lambda ()
+             (close-charterm #:charterm ct)
+             (set! ct #f)))))))
+
+(doc (section "Terminal Information"))
+
+(doc (defproc (charterm-screen-size (#:charterm ct charterm? (current-charterm)))
+         (values (or/c #f exact-nonnegative-integer?)
+                 (or/c #f exact-nonnegative-integer?))
+       (para "Attempts to get the screen size, in character columns and rows.
+It may do this through a control sequence or through "
+             (code "/bin/stty")
+             ".  If unable to get a value, then default of (80,24) is used.")
+       (para "The current behavior in this version of "
+             (code "charterm")
+             " is to adaptively try different methods of getting screen size,
+and to remember what worked for the next time this procedure is called for "
+             (racket ct)
+             ".  For terminals that are identified as "
+             (code "screen")
+             " by the "
+             (code "TERM")
+             " environment variable (e.g., terminal emulators like GNU Screen
+and "
+             (code "tmux")
+             "), the current behavior is to not try the control sequence (which
+causes a 1-second delay waiting for a terminal response that never arrives),
+and to just use "
+             (code "stty")
+             ".  For all other terminals, the control sequence is tried first, before trying "
+             (code "stty")
+             ".  If neither the control sequence nor "
+             (code "stty")
+             " work, then neither method is tried again for "
+             (racket ct)
+             ", and instead the procedure always returns ("
+             (racket #f)
+             ", "
+             (racket #f)
+             ").  This behavior very well might change in future versions of "
+             (code "charterm")
+             ", and the author welcomes feedback on which methods work with
+which terminals.")))
+(provide charterm-screen-size)
+(define (charterm-screen-size #:charterm (ct (current-charterm)))
+  ;; TODO: Make it store screen side in slots of charterm object too.  Then
+  ;; create a "with-resizeable-charterm" form that has a resize handler (or
+  ;; maybe make the resize handler an argument to "with-charterm".
+  (let loop ()
+    (case (charterm-screensize ct)
+      ((control) (%charterm:screen-size-via-control ct))
+      ((stty)    (%charterm:screen-size-via-stty    ct))
+      ;; TODO: Instead of (80,24), maybe be sensitive to termvar.
+      ((none)    (values 80 24))
+      ((control/stty/none)
+       (let-values (((cols rows) (%charterm:screen-size-via-control ct)))
+         (if (and cols rows)
+             (values cols rows)
+             (begin (set-charterm-screensize! ct 'stty/none)
+                    (loop)))))
+      ((stty/none)
+       (let-values (((cols rows) (%charterm:screen-size-via-stty ct)))
+         (if (and cols rows)
+             (values cols rows)
+             (begin (set-charterm-screensize! ct 'none)
+                    (loop)))))
+      (else (error 'charterm-screen-size
+                   "invalid screensize ~S"
+                   (charterm-screensize ct))))))
+
+(define (%charterm:screen-size-via-control ct)
+  (%charterm:protocol-case
+   '%charterm:screen-size-via-control
+   (charterm-protocol ct)
+   ((ansi)
+    (%charterm:write-bytes ct #"\e[18t")
+    (cond ((%charterm:read-regexp-response ct #rx#"\e\\[8;([0-9]+);([0-9]+)t")
+           => (lambda (m)
+                (values (%charterm:bytes-ascii->nonnegative-integer (list-ref m 1))
+                        (%charterm:bytes-ascii->nonnegative-integer (list-ref m 0)))))
+          ;; TODO: We could do "ioctl" "TIOCGWINSZ", but that means FFI.
+          ;;
+          ;; TODO: We could execute "stty -a" (or perhaps "stty -g") to get
+          ;; around doing an FFI call.
+          (else (values #f #f))))
+   ((wyse-wy50 televideo-925)
+    (%charterm:protocol-unreachable '%charterm:screen-size-via-control ct))))
+
+(define (%charterm:screen-size-via-stty ct)
+  (let* ((stdout (open-output-bytes))
+         (stderr (open-output-bytes))
+         (proc   (list-ref (process*/ports stdout
+                                           (open-input-bytes #"")
+                                           stderr
+                                           "/bin/stty"
+                                           %charterm:stty-minus-f-arg-string
+                                           (charterm-tty ct)
+                                           "-a")
+                           4))
+         (bstr   (begin (proc 'wait)
+                        (get-output-bytes stdout))))
+    (if (eq? 'done-ok (proc 'status))
+        (let-values (((width height)
+                      (cond ((regexp-match-positions
+                              #rx#"rows +([0-9]+);.*columns +([0-9]+)"
+                              bstr)
+                             => (lambda (m)
+                                  (values (%charterm:bytes-ascii->nonnegative-integer
+                                           (subbytes bstr (caaddr m) (cdaddr m)))
+                                          (%charterm:bytes-ascii->nonnegative-integer
+                                           (subbytes bstr (caadr  m) (cdadr m))))))
+                            ((regexp-match-positions
+                              #rx#"columns +([0-9]+);.*rows +([0-9]+)"
+                              bstr)
+                             => (lambda (m)
+                                  (values (%charterm:bytes-ascii->nonnegative-integer
+                                           (subbytes bstr (caadr  m) (cdadr m)))
+                                          (%charterm:bytes-ascii->nonnegative-integer
+                                           (subbytes bstr (caaddr m) (cdaddr m))))))
+                            (else #f #f))))
+          ;; Note: These checks for 0 are for if "stty" returns 0, such as
+          ;; seems to happen in the emulator on the Wyse S50 when in SSH rather than Telnet.
+          (values (if (zero? width)  #f width)
+                  (if (zero? height) #f height)))
+        (values #f #f))))
+
+(doc (section "Display Control"))
+
+(define (%charterm:shift-buf ct)
+  (let ((buf-start (charterm-buf-start ct))
+        (buf-end   (charterm-buf-end   ct)))
+    (if (= buf-start buf-end)
+        ;; Buffer is empty, so are buf-start and buf-end at 0?
+        (if (zero? buf-end)
+            (void)
+            (begin (set-charterm-buf-start! ct 0)
+                   (set-charterm-buf-end!   ct 0)))
+        ;; Buffer is not empty, so is buf-start at 0?
+        ;;
+        ;; TODO: Maybe make this shift only if we need to to free N additional
+        ;; bytes at the end?
+        (if (zero? buf-start)
+            (void)
+            (let ((buf (charterm-buf ct)))
+              (bytes-copy! buf 0 buf buf-start buf-end)
+              (set-charterm-buf-start! ct 0)
+              (set-charterm-buf-end!   ct (- buf-end buf-start)))))))
+
+(define (%charterm:read-into-buf/timeout ct timeout)
+  (let ((in (charterm-in ct)))
+    (let loop ()
+      (let ((sync-result (sync/timeout/enable-break timeout in)))
+        (cond ((not sync-result) #f)
+              ((eq? sync-result in)
+               ;; TODO: if buf is empty, then read into start 0!
+               (let ((read-result (read-bytes-avail! (charterm-buf      ct)
+                                                     in
+                                                     (charterm-buf-end  ct)
+                                                     (charterm-buf-size ct))))
+                 (if (zero? read-result)
+                     ;; TODO: If there's a timeout, subtract from it?
+                     (loop)
+                     (begin (set-charterm-buf-end! ct (+ (charterm-buf-end ct) read-result))
+                            read-result))))
+              (else (error '%charterm:read-into-buf/timeout
+                           "*DEBUG* sync returned ~S"
+                           sync-result)))))))
+
+(define (%charterm:read-regexp-response ct rx #:timeout-seconds (timeout-seconds 1.0))
+  (let ((in (charterm-in ct)))
+    (%charterm:shift-buf ct)
+    ;; TODO: Implement timeout better, by checking clock and doing
+    ;; sync/timeout, or by setting timer.
+    (let loop ((timeout-seconds timeout-seconds))
+      (if (= (charterm-buf-end ct) (charterm-buf-size ct))
+          (begin
+            ;; TODO: Make this an exception instead of #f?
+            #f)
+          (begin (or (let ((buf       (charterm-buf       ct))
+                           (buf-start (charterm-buf-start ct))
+                           (buf-end   (charterm-buf-end   ct)))
+                       (cond ((regexp-match-positions rx
+                                                      buf
+                                                      buf-start
+                                                      buf-end)
+                              => (lambda (m)
+                                   ;; TODO: Audit and test some of this buffer
+                                   ;; code here and elsewhere.
+                                   (let ((match-start (caar m))
+                                         (match-end   (cdar m)))
+                                     (if (= match-start buf-start)
+                                         (set-charterm-buf-start! ct match-end)
+                                         (if (= match-end buf-end)
+                                             (set-charterm-buf-end! ct match-start)
+                                             (begin (bytes-copy! buf
+                                                                 match-start
+                                                                 buf
+                                                                 match-end
+                                                                 buf-end)
+                                                    (set-charterm-buf-end! ct
+                                                                           (+ match-start
+                                                                              (- buf-end
+                                                                                 match-end)))))))
+
+                                   (map (lambda (pos)
+                                          (subbytes buf (car pos) (cdr pos)))
+                                        (cdr m))))
+                             (else #f)))
+                     (if (%charterm:read-into-buf/timeout ct timeout-seconds)
+                         (loop timeout-seconds)
+                         #f
+                         )))))))
+
+(define (%charterm:bytes-ascii->nonnegative-integer bstr)
+  (let ((bstr-len (bytes-length bstr)))
+    (let loop ((i      0)
+               (result 0))
+      (if (= i bstr-len)
+          result
+          (let* ((b     (bytes-ref bstr i))
+                 (b-num (- b 48)))
+            (if (<= 0 b-num 9)
+                (loop (+ 1 i)
+                      (+ (* 10 result) b-num))
+                (error '%charterm:bytes-ascii->nonnegative-integer
+                       "invalid byte ~S"
+                       b)))))))
+
+(doc (subsection "Cursor"))
+
+(doc (defproc (charterm-cursor (x exact-positive-integer?)
+                               (y exact-positive-integer?)
+                               (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Positions the cursor at column "
+             (racket x)
+             ", row "
+             (racket y)
+             ", with the upper-left character cell being (1, 1).")))
+(provide charterm-cursor)
+(define (charterm-cursor x y #:charterm (ct (current-charterm)))
+  (%charterm:position ct x y))
+
+(doc (defproc (charterm-newline (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Sends a newline to the terminal.  This is typically a CR-LF
+sequence.")))
+(provide charterm-newline)
+(define (charterm-newline #:charterm (ct (current-charterm)))
+  (%charterm:write-bytes ct #"\r\n"))
+
+(doc (subsection "Displaying"))
+
+(define %charterm:err-byte 63)
+
+(doc (defproc (charterm-display
+               (#:charterm ct       charterm?                         (current-charterm))
+               (#:width    width    (or/c #f exact-positive-integer?) #f)
+               (#:pad      pad      (or/c 'width boolean?)            'width)
+               (#:truncate truncate (or/c 'width boolean?)            'width)
+               (           arg      any/c) ...)
+         void?
+       (para "Displays each "
+             (racket arg)
+             " on the terminal, as if formatted by "
+             (racket display)
+             ", with the exception that unprintable or non-ASCII characters
+might not be displayed.  (The exact behavior of what is permitted is expected
+to change in a later version of "
+             "CharTerm"
+             ", so avoid trying to send your own control sequences or using
+newlines, making assumptions about non-ASCII characters, etc.)")
+       (para "If "
+             (racket width)
+             " is a number, then "
+             (racket pad)
+             " and "
+             (racket truncate)
+             " specify whether or not to pad with spaces or truncate the output, respectively, to "
+             (racket width)
+             " characters.  When "
+             (racket pad)
+             " or "
+             (racket width)
+             " is "
+             (racket 'width)
+             ", that is a convenience meaning ``true if, and only if, "
+             (racket width)
+             " is not "
+             (racket #f)
+             ".''")))
+(provide charterm-display)
+(define (charterm-display #:charterm (ct       (current-charterm))
+                          #:width    (width    #f)
+                          #:pad      (pad      'width)
+                          #:truncate (truncate 'width)
+                          . args)
+  ;; TODO: make it replace unprintable and non-ascii characters with "?".  Even newlines, tabs, etc?
+  ;;
+  ;; TODO: Do we want buffering?
+  (let ((out      (charterm-out ct))
+        (pad      (if (eq? 'width pad)      (if width #t #f) pad))
+        (truncate (if (eq? 'width truncate) (if width #t #f) truncate)))
+    (and pad      (not width) (error 'charterm-display "#:pad cannot be true if #:width is not"))
+    (and truncate (not width) (error 'charterm-display "#:truncate cannot be true if #:width is not"))
+    (let loop ((args            args)
+               (remaining-width (or width 0)))
+      (if (null? args)
+          (if (and pad (> remaining-width 0))
+              ;; TODO: Get rid of this allocation.
+              (begin (%charterm:write-bytes ct (make-bytes remaining-width 32))
+                     (void))
+              (void))
+          (let* ((arg (car args))
+                 (bytes (cond ((bytes? arg)
+                               arg)
+                              ((string? arg)
+                               (string->bytes/latin-1 arg
+                                                      %charterm:err-byte
+                                                      0
+                                                      (if truncate
+                                                          (min (string-length arg)
+                                                               remaining-width)
+                                                          (string-length arg))))
+                              ((number? arg)
+                               (string->bytes/latin-1 (number->string arg)
+                                                      %charterm:err-byte))
+                              (else (let ((arg (format "~A" arg)))
+                                      (string->bytes/latin-1 arg
+                                                             %charterm:err-byte
+                                                             0
+                                                             (if truncate
+                                                                 (min (string-length arg)
+                                                                      remaining-width)
+                                                                 (string-length arg)))))))
+                 (remaining-width (- remaining-width (bytes-length bytes))))
+            (cond ((or (not truncate) (> remaining-width 0))
+                   (%charterm:write-bytes ct bytes)
+                   (loop (cdr args)
+                         remaining-width))
+                  ((zero? remaining-width)
+                   (%charterm:write-bytes ct bytes)
+                   (void))
+                  (else (%charterm:write-subbytes ct bytes 0 (+ (bytes-length bytes)
+                                                                remaining-width))
+                        (void))))))))
+
+(define (%charterm:send-code ct . args)
+  ;; TODO: Do we want buffering?
+  (let ((out (charterm-out ct)))
+    (let loop ((args args))
+      (if (null? args)
+          (void)
+          (let ((arg (car args)))
+            (cond ((bytes? arg)
+                   (write-bytes arg out))
+                  ((string? arg)
+                   (write-string arg out))
+                  ((integer? arg)
+                   (display (inexact->exact arg) out))
+                  ((pair? arg)
+                   (loop (car arg))
+                   (loop (cdr arg)))
+                  (else (error '%charterm:send-code
+                               "don't know how to send ~S"
+                               arg)))
+            (loop (cdr args)))))))
+
+;; (define %charterm:2-digit-bytes-vector
+;;   (vector #"00" #"01" #"02" #"03" #"04" #"05" #"06" #"07"
+;;           #"08" #"09" #"10" #"11" #"12" #"13" #"14" #"15"
+;;           #"16" #"17" #"18" #"19" #"20" #"21" #"22" #"23"
+;;           #"24" #"25" #"26" #"27" #"28" #"29" #"30" #"31"
+;;           #"32" #"33" #"34" #"35" #"36" #"37" #"38" #"39"
+;;           #"40" #"41" #"42" #"43" #"44" #"45" #"46" #"47"
+;;           #"48" #"49" #"50" #"51" #"52" #"53" #"54" #"55"
+;;           #"56" #"57" #"58" #"59" #"60" #"61" #"62" #"63"
+;;           #"64" #"65" #"66" #"67" #"68" #"68" #"69" #"70"
+;;           #"72" #"73" #"74" #"75" #"76" #"77" #"78" #"79"
+;;           #"80" #"81" #"82" #"83" #"84" #"85" #"86" #"87"))
+
+(define %charterm:televideo-925-cursor-position-to-byte-vector
+  (list->vector (cons #f
+                      (for/list ((n (in-range 1 96)))
+                        (+ 31 n)))))
+
+;; (provide/contract with error-checks on args
+(define (%charterm:position ct x y)
+  (%charterm:protocol-case
+   '%charterm:position
+   (charterm-protocol ct)
+   ((ansi)
+    (if (and (= 1 x) (= 1 y))
+        (%charterm:write-bytes ct #"\e[;H")
+        (%charterm:send-code ct #"\e[" y #";" x #"H")))
+   ((wyse-wy50)
+    ;; Note: We are using the WY-50 long codes because we don't know
+    ;; confidently that we are an 80-column screen.
+    (if (and (= 1 x) (= 1 y))
+        (%charterm:write-bytes ct #"\ea1R1C")
+        (%charterm:send-code ct #"\ea" y #"R" x #"C")))
+   ((televideo-925)
+    (if (and (= 1 x) (= 1 y))
+        (%charterm:write-bytes ct #"\e=  ")
+        (begin (%charterm:write-bytes ct #"\e=")
+               (%charterm:write-byte ct (vector-ref %charterm:televideo-925-cursor-position-to-byte-vector y))
+               (%charterm:write-byte ct (vector-ref %charterm:televideo-925-cursor-position-to-byte-vector x)))))))
+
+(doc (subsection "Video Attributes"))
+
+;; TODO: !!! document link to protocol section
+
+;; TODO: !!! define "charterm-has-video-attributes?"
+
+(doc (defproc*
+         (((charterm-normal    (#:charterm ct charterm? (current-charterm))) void?)
+          ((charterm-inverse   (#:charterm ct charterm? (current-charterm))) void?)
+          ((charterm-underline (#:charterm ct charterm? (current-charterm))) void?)
+          ((charterm-blink     (#:charterm ct charterm? (current-charterm))) void?)
+          ((charterm-bold      (#:charterm ct charterm? (current-charterm))) void?))
+       (para "Sets the "
+             (deftech "video attributes")
+             " for subsequent writes to the terminal.  In this version of "
+             (code "charterm")
+             ", each is mutually-exclusive, so, for example, setting "
+             (italic "bold")
+             " clears "
+             (italic "inverse")
+             ". Note that that video attributes are currently supported only for protocol "
+             (racket 'ansi)
+             ", due to limitations of the TeleVideo and Wyse models for
+video attributes.")))
+
+(provide charterm-normal)
+(define (charterm-normal #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-normal
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[m"))
+   ((wyse-wy50)     (void)) ; (%charterm:write-bytes ct #"\eA00"))
+   ((televideo-925) (void))))
+
+(provide charterm-inverse)
+(define (charterm-inverse #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-inverse
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[;7m"))
+   ((wyse-wy50)     (void)) ; (%charterm:write-bytes ct #"\eA04"))
+   ((televideo-925) (void))))
+
+(provide charterm-underline)
+(define (charterm-underline #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-underline
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[4m"))
+   ((wyse-wy50)     (void)) ; (%charterm:write-bytes ct #"\eA08"))
+   ((televideo-925) (void))))
+
+(provide charterm-blink)
+(define (charterm-blink #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-blink
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[5m"))
+   ((wyse-wy50)     (void)) ; (%charterm:write-bytes ct #"\eA02"))
+   ((televideo-925) (void))))
+
+(provide charterm-bold)
+(define (charterm-bold #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-bold
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[1m"))
+   ((wyse-wy50)     (void)) ; (%charterm:write-bytes ct #"\eA0<"))
+   ((televideo-925) (void))))
+
+(doc (subsection "Clearing"))
+
+(doc (defproc (charterm-clear-screen (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Clears the screen, including first setting the video attributes to
+normal, and positioning the cursor at (1, 1).")))
+(provide charterm-clear-screen)
+(define (charterm-clear-screen #:charterm (ct (current-charterm)))
+  ;; TODO: Have a #:style argument?  Or #:background argument?
+  (%charterm:protocol-case
+   'charterm-clear-screen
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[m\e[2J\e[;H"))
+   ((wyse-wy50)     (%charterm:write-bytes ct #"\e+\e*\ea1R1C"))
+   ((televideo-925) (%charterm:write-bytes ct #"\e+\e=  "))))
+
+(doc (defproc*
+         (((charterm-clear-line       (#:charterm ct charterm? (current-charterm))) void?)
+          ((charterm-clear-line-left  (#:charterm ct charterm? (current-charterm))) void?)
+          ((charterm-clear-line-right (#:charterm ct charterm? (current-charterm))) void?))
+       (para "Clears text from the line with the cursor, or part of the line with the cursor.")))
+
+(provide charterm-clear-line)
+(define (charterm-clear-line #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm:clear-line
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[2K"))
+   ((televideo-925) (%charterm:write-bytes ct #"\r\eT"))
+   ;; TODO: wyse-wy50 is clearing to nulls, not spaces.
+   ((wyse-wy50)     (%charterm:write-bytes ct #"\r\et"))))
+
+(provide charterm-clear-line-left)
+(define (charterm-clear-line-left #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-clear-line-left
+   (charterm-protocol ct)
+   ((ansi) (%charterm:write-bytes ct #"\e[1K"))
+   ((televideo-925 wyse-wy50)
+    ;; TODO: Do this by getting cursor position, then reposition and write spaces?
+    (%charterm:unimplemented ct 'clearterm-clear-line-left))))
+
+(provide charterm-clear-line-right)
+(define (charterm-clear-line-right #:charterm (ct (current-charterm)))
+  (%charterm:protocol-case
+   'charterm-clear-line-right
+   (charterm-protocol ct)
+   ((ansi)      (%charterm:write-bytes ct #"\e[K"))
+   ((televideo-925) (%charterm:write-bytes ct #"\eT"))
+   ;; TODO: wyse-wy50 is clearing to nulls, not spaces.
+   ((wyse-wy50)     (%charterm:write-bytes ct #"\et"))))
+
+(doc (subsection "Line Insert and Delete"))
+
+(doc (defproc (charterm-insert-line (count exact-positive-integer? 1)
+                                    (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Inserts "
+             (racket count)
+             " blank lines at cursor.  Note that not all terminals support
+this.")))
+(provide charterm-insert-line)
+(define (charterm-insert-line (count 1) #:charterm (ct (current-charterm)))
+  (if (integer? count)
+      (cond ((= count 0) (void))
+            ((> count 0)
+             (%charterm:protocol-case
+              'charterm-insert-line
+              (charterm-protocol ct)
+              ((ansi)                (%charterm:send-code ct #"\e[" count "L"))
+              ((wyse-wy50 televideo-925) (%charterm:write-bytes ct #"\eE"))))
+            (else (error 'charterm-insert-line
+                         "invalid count: ~S"
+                         count)))
+      (error 'charterm-insert-line
+             "invalid count: ~S"
+             count)))
+
+(doc (defproc (charterm-delete-line (count exact-positive-integer? 1)
+                                    (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Deletes "
+             (racket count)
+             " blank lines at cursor.  Note that not all terminals support
+this.")))
+(provide charterm-delete-line)
+(define (charterm-delete-line (count 1) #:charterm (ct (current-charterm)))
+  (if (integer? count)
+      (cond ((= count 0) (void))
+            ((> count 0)
+             (%charterm:protocol-case
+              'charterm-delete-line
+              (charterm-protocol ct)
+              ((ansi)
+               (%charterm:send-code ct #"\e[" count "M"))
+              ((wyse-wy50 televideo-925)
+               (if (= 1 count)
+                   (%charterm:write-bytes ct #"\eR")
+                   (let ((bstr (make-bytes (* 2 count) 82)))
+                     (let loop ((n (* 2 (- count 1))))
+                       (bytes-set! bstr n 27)
+                       (if (zero? n)
+                           (%charterm:write-bytes ct bstr)
+                           (loop (- n 2)))))))))
+            (else (error 'charterm-delete-line
+                         "invalid count: ~S"
+                         count)))
+      (error 'charterm-delete-line
+             "invalid count: ~S"
+             count)))
+
+(doc (subsubsection "Misc. Output"))
+
+(doc (defproc (charterm-bell (#:charterm ct charterm? (current-charterm)))
+         void?
+       (para "Rings the terminal bell.  This bell ringing might manifest as a
+beep, a flash of the screen, or nothing.")))
+(provide charterm-bell)
+(define (charterm-bell #:charterm (ct (current-charterm)))
+  (%charterm:write-bytes ct #"\007"))
+
+(doc (section "Keyboard Input")
+
+     ;; TODO: !!! document link to terminal diversity section
+
+     (para "Normally you will get keyboard input using the "
+           (racket charterm-read-key)
+           " procedure."))
+
+(doc (defproc (charterm-byte-ready? (#:charterm ct charterm? (current-charterm)))
+         boolean?
+       (para "Returns true/false for whether at least one byte is ready for
+reading (either in a buffer or on the port) from "
+             (racket ct)
+             ".  Note that, since some keys are encoded as multiple bytes, just
+because this procedure returns true doesn't mean that "
+             (racket charterm-read-key)
+             " won't block temporarily because it sees part of a potential
+multiple-byte key encoding.")))
+(provide charterm-byte-ready?)
+(define (charterm-byte-ready? #:charterm (ct (current-charterm)))
+  (or (> (charterm-buf-end ct) (charterm-buf-start ct))
+      (byte-ready? (charterm-in ct))))
+
+(doc (defproc (charterm-read-key
+               (#:charterm ct      charterm?           (current-charterm))
+               (#:timeout  timeout (or/c #f positive?) #f))
+         (or #f char? symbol?)
+       (para "Reads a key from "
+             (racket ct)
+             ", blocking indefinitely or until sometime after "
+             (racket timeout)
+             " seconds has been reached, if "
+             (racket timeout)
+             " is non-"
+             (racket #f)
+             ".  If timeout is reached, "
+             (racket #f)
+             " is returned.")
+       (para "Many keys are returned as characters, especially ones that
+correspond to printable characters.  For example, the unshifted "
+             (bold "Q")
+             " key is returned as character "
+             (racket #\q)
+             ".  Some other keys are returned as symbols, such as "
+             (racket 'return)
+             ", "
+             (racket 'escape)
+             ", "
+             (racket 'f1)
+             ", "
+             (racket 'shift-f12)
+             ", "
+             (racket 'right)
+             ", and many others.")
+       (para "Since some keys are sent as ambiguous sequences, "
+             (racket charterm-read-key)
+             " employs separate timeouts internally, such as to disambuate
+the "
+             (bold "Esc")
+             " key (byte sequence 27) from what on some terminals would be
+the "
+             (bold "F10")
+             " key (bytes sequence 27, 91, 50, 49, 126).")))
+(provide charterm-read-key)
+(define (charterm-read-key #:charterm (ct      (current-charterm))
+                           #:timeout  (timeout #f))
+  (%charterm:read-keyinfo-or-key 'charterm-read-key ct timeout #f))
+
+(doc (defproc (charterm-read-keyinfo
+               (#:charterm ct      charterm?           (current-charterm))
+               (#:timeout  timeout (or/c #f positive?) #f))
+         charterm-keyinfo?
+       (para "Like "
+             (racket charterm-read-keyinfo)
+             " except instead of returning a "
+             (tech "keycode")
+             ", it returns a "
+             (tech "keyinfo")
+             ".")))
+(provide charterm-read-keyinfo)
+(define (charterm-read-keyinfo #:charterm (ct      (current-charterm))
+                               #:timeout  (timeout #f))
+  (%charterm:read-keyinfo-or-key 'charterm-read-keyinfo ct timeout #t))
+
+(define (%charterm:read-keyinfo-or-key error-name ct timeout keyinfo?)
+  ;; TODO: Maybe make this shift decision smarter -- compile the key tree ahead
+  ;; of time so we know the max depth, and then we know exactly the max space
+  ;; we will need for this call.
+  (and (< (- (charterm-buf-size ct)
+             (charterm-buf-start ct))
+          10)
+       (%charterm:shift-buf ct))
+  (let ((buf       (charterm-buf        ct))
+        (buf-start (charterm-buf-start  ct))
+        (buf-end   (charterm-buf-end    ct))
+        (buf-size  (charterm-buf-size   ct))
+        (keydec    (charterm-keydec*    ct))
+        (b1        (%charterm:read-byte/timeout ct timeout)))
+    (if b1
+        (or (let loop ((tree        (charterm-keydec-primary-keytree keydec))
+                       (probe-start (+ 1 buf-start))
+                       (b           b1))
+              (cond ((hash-ref tree b #f)
+                     => (lambda (code-or-subtree)
+                          (cond ((hash? code-or-subtree)
+                                 ;; We have more subtree to search.
+                                 (if (or (< probe-start buf-end)
+                                         (and (< buf-end buf-size)
+                                              (%charterm:read-into-buf/timeout ct 0.5)))
+                                     ;; We have at least one more byte, so recurse.
+                                     (loop code-or-subtree
+                                           (+ 1 probe-start)
+                                           (bytes-ref buf probe-start))
+                                     ;; We have hit timeout or end of buffer, so
+                                     ;; just accept the original byte.
+                                     #f))
+                                ((charterm-keyinfo? code-or-subtree)
+                                 ;; We found our keyinfo, so consume the input and return the value.
+                                 (begin (set-charterm-buf-start! ct probe-start)
+                                        (if keyinfo?
+                                            code-or-subtree
+                                            (charterm-keyinfo-keycode code-or-subtree))
+                                        ))
+                                (else (error error-name
+                                             "invalid object in keytree keyinfo position: ~S"
+                                             code-or-subtree)))))
+                    (else #f)))
+            ;; We didn't find a key code, so try secondary keytree with initial byte.
+            (cond ((hash-ref (charterm-keydec-secondary-keytree keydec) b1 #f)
+                   => (lambda (keyinfo)
+                        (if keyinfo?
+                            keyinfo
+                            (charterm-keyinfo-keycode keyinfo))))
+                  (else (if keyinfo?
+                            ;; TODO: Cache these keyinfos for unrecognized keys
+                            ;; in the charterm object, or make a fallback
+                            ;; keyset for them (although the fallback keyset,
+                            ;; while it works for 8-bit characters, becomes
+                            ;; less practical if we implement multibyte).
+                            (make-charterm-keyinfo #f
+                                                   #f
+                                                   (list b1)
+                                                   "???"
+                                                   b1
+                                                   (list b1))
+                            (integer->char b1)))))
+        ;; Got a timeout, so return #f.
+        #f)))
+
+(define (%charterm:write-byte ct byt)
+  (write-byte byt (charterm-out ct)))
+
+(define (%charterm:write-bytes ct bstr . rest-bstrs)
+  (write-bytes bstr (charterm-out ct))
+  (or (null? rest-bstrs)
+      (for-each (lambda (bstr)
+                  (write-bytes bstr (charterm-out ct)))
+                rest-bstrs)))
+
+(define (%charterm:write-subbytes ct bstr start end)
+  (write-bytes bstr (charterm-out ct) start end))
+
+(define (%charterm:read-byte/timeout ct timeout)
+  (let ((buf-start (charterm-buf-start ct)))
+    (if (or (< buf-start (charterm-buf-end ct))
+            (%charterm:read-into-buf/timeout ct timeout))
+        (begin0 (bytes-ref (charterm-buf ct) buf-start)
+          (set-charterm-buf-start! ct (+ 1 buf-start)))
+        #f)))
+
+(define (%charterm:read-byte ct)
+  (%charterm:read-byte/timeout ct #f))
+
+(doc (section "References")
+
+     (para "[" (deftech "ANSI X3.64") "] "
+           (url "http://en.wikipedia.org/wiki/ANSI_escape_code"))
+
+     (para "[" (deftech "ASCII") "] "
+           (url "http://en.wikipedia.org/wiki/Ascii"))
+     
+     (para "[" (deftech "ECMA-43") "] "
+           (hyperlink "http://www.ecma-international.org/publications/standards/Ecma-043.htm"
+                      (italic "Standard ECMA-43: 8-bit Coded Character Set Structure and Rules"))
+           ", 3rd Ed., 1991-12")
+
+     (para "[" (deftech "ECMA-48") "] "
+           (hyperlink "http://www.ecma-international.org/publications/standards/Ecma-048.htm"
+                      (italic "Standard ECMA-48: Control Functions for Coded Character Sets"))
+           ", 5th Ed., 1991-06")
+
+     (para "[" (deftech "Gregory") "] "
+           "Phil Gregory, ``"
+           (hyperlink "http://aperiodic.net/phil/archives/Geekery/term-function-keys.html"
+                      "Terminal Function Key Escape Codes")
+           ",'' 2005-12-13 Web post, as viewed on 2012-06")
+
+     (para "[" (deftech "PowerTerm") "] "
+           "Ericom PowerTerm InterConnect 8.2.0.1000 terminal emulator, as run on Wyse S50 WinTerm")
+
+     (para "[" (deftech "TVI-925-IUG") "] "
+           (hyperlink "http://vt100.net/televideo/tvi925_ig.pdf"
+                      (italic "TeleVideo Model 925 CRT Terminal Installation and User's Guide")))
+
+     (para "[" (deftech "TVI-950-OM") "] "
+           (hyperlink "http://www.mirrorservice.org/sites/www.bitsavers.org/pdf/televideo/Operators_Manual_Model_950_1981.pdf"
+                      (italic "TeleVideo Operator's Manual Model 950"))
+           ", 1981")
+     
+     (para "[" (deftech "VT100-TM") "] "
+           "Digital Equipment Corp., "
+           (hyperlink "http://vt100.net/docs/vt100-tm/"
+                      (italic "VT100 Series Technical Manual"))
+           ", 2nd Ed., 1980-09")
+     
+     (para "[" (deftech "VT100-UG") "] "
+           "Digital Equipment Corp., "
+           (hyperlink "http://vt100.net/docs/vt100-ug/"
+                      (italic "VT100 User Guide"))
+           ", 3rd Ed., 1981-06")
+                      
+     (para "[" (deftech "VT100-WP") "] "
+           "Wikipedia, "
+           (hyperlink "http://en.wikipedia.org/wiki/VT100"
+                      "VT100"))
+
+     (para "[" (deftech "WY-50-QRG") "] "
+           (hyperlink "http://vt100.net/wyse/wy-50-qrg/wy-50-qrg.pdf"
+                      (italic "Wyse WY-50 Display Terminal Quick-Reference Guide")))
+
+     (para "[" (deftech "WY-60-UG") "] "
+           (hyperlink "http://vt100.net/wyse/wy-60-ug/wy-60-ug.pdf"
+                      (italic "Wyse WY-60 User's Guide")))
+
+     (para "[" (deftech "wy60") "] "
+           (hyperlink "http://code.google.com/p/wy60/"
+                      (code "wy60")
+                      " terminal emulator"))
+
+     (para "[" (deftech "XTerm-ctlseqs") "] "
+           "Edward Moy, Stephen Gildea, Thomas Dickey, ``"
+           (hyperlink "http://invisible-island.net/xterm/ctlseqs/ctlseqs.html"
+                      "Xterm Control Sequences")
+           ",'' 2012")
+
+     (para "[" (deftech "XTerm-Dickey") "] "
+           (url "http://invisible-island.net/xterm/"))
+
+     (para "[" (deftech "XTerm-FAQ") "] "
+           "Thomas E. Dickey, ``"
+           (hyperlink "http://invisible-island.net/xterm/xterm.faq.html"
+                      "XTerm FAQ")
+           ",'' dated 2012")
+
+     (para "[" (deftech "XTerm-WP") "] "
+           "Wikipedia, "
+           (hyperlink "http://en.wikipedia.org/wiki/Xterm"
+                      "xterm"))
+           
+     )
+
+(doc (section "Known Issues")
+
+     (itemlist
+
+      (item "Need to support ANSI alternate CSI for 8-bit terminals, even
+before supporting 8-bit characters and multibyte.")
+
+      (item "Only supports ASCII characters.  Adding UTF-8 support, for terminal emulators
+that support it, would be nice.")
+      
+      (item "Expose the character-decoding mini-language as a configurable
+option.  Perhaps wait until we implement timeout-based disambiguation at
+arbitrary points in the the DFA rather than just at the top.  Also, might be
+better to resolve multi-byte characters first, in case that affects the
+mini-language.")
+
+      (item "More controls for terminal features can be added.")
+      
+      (item "Currently only implemented to work on Unix-like systems like
+GNU/Linux.")
+
+      (item "Implement text input controls, either as part of this library or
+another, using "
+            (racket charterm-demo)
+            " as a starting point.")))
+
+;; Note: Different ways to test demo:
+;;
+;;           racket -t demo.rkt -m
+;; screen    racket -t demo.rkt -m
+;; tmux -c  "racket -t demo.rkt -m"
+;; xterm -e  racket -t demo.rkt -m
+;; rxvt -e   racket -t demo.rkt -m
+;; wy60 -c   racket -t demo.rkt -m
+;;
+;; racket -t demo.rkt -m- -n
+
+;; TODO: Source for TeleVideo manuals:
+;; http://www.mirrorservice.org/sites/www.bitsavers.org/pdf/televideo/
+
+;; TODO: Add shifted function keys from T60 keyboard (not USB one).
+
+(doc history
+
+     (#:planet 3:1 #:date "2013-05-13"
+               (itemlist
+                (item "Now uses lowercase "
+                      (code "-f")
+                      " argument on MacOS X.  (Thanks to Jens Axel S\u00F8gaard for reporting.)")
+                (item "Documentation tweaks.")))
+
+     (#:planet 3:0 #:date "2012-07-13"
+               (itemlist
+                (item "Changed ``"
+                      (code "ansi-ish")
+                      "'' in identifiers to ``"
+                      (code "ansi")
+                      "'', hence the PLaneT major version number change.")
+                (item "Documentation tweaks.")
+                (item "Renamed package from ``"
+                      (code "charterm")
+                      "'' to ``CharTerm''.")))
+
+     (#:planet 2:5 #:date "2012-06-28"
+               (itemlist
+                (item "A "
+                      (racket charterm)
+                      " object is now a synchronizable event.")
+                (item "Documentation tweaks.")))
+     
+     (#:planet 2:4 #:date "2012-06-25"
+               (itemlist
+                (item "Documentation fix for return type of "
+                      (racket charterm-read-keyinfo)
+                      ".")))
+     
+     (#:planet 2:3 #:date "2012-06-25"
+               (itemlist
+                (item "Fixed problem determining screen size on some
+XTerms.  (Thanks to Eli Barzilay for reporting.)")))
+
+     (#:planet 2:2 #:date "2012-06-25"
+               (itemlist
+                (item "Added another variation of encoding for XTerm arrow,
+Home, and End keys.  (Thanks to Eli Barzilay.)")))
+     
+     (#:planet 2:1 #:date "2012-06-24"
+               (itemlist
+                (item "Corrected PLaneT version number in "
+                      (racket require)
+                      " in an example.")))
+     
+     (#:planet 2:0 #:date "2012-06-24"
+               (itemlist
+                (item "Greatly increased the sophistication of handling of terminal diversity.")
+                (item "Added the "
+                      (code "wyse-wy50")
+                      " and "
+                      (code "televideo-950")
+                      " [Correction: "
+                      (code "televideo-925")
+                      "] protocols, for supporting the native modes of Wyse and
+TeleVideo terminals, respectively, and compatibles.")
+                (item "More support for different key encodings and termvars.")
+                (item "Demo is now in a separate file, mainly for convenience
+in giving command lines that run it.  This breaks a command line example
+previously documented, so changed PLaneT major version, although the
+previously-published example will need to have "
+                      (code ":1")
+                      " added to it anyway.")
+                (item (racket charterm-screen-size)
+                      " now defaults to (80,24) when all else fails.")
+                (item "Documentation changes.")))
+
+     (#:planet 1:1 #:date "2012-06-17"
+               (itemlist
+                (item "For "
+                      (code "screen")
+                      " and "
+                      (code "tmux")
+                      ", now gets screen size via "
+                      (code "stty")
+                      ".  This resolves the sluggishness reported with "
+                      (code "screen")
+                      ".  [Correction: In version 1:1, this behavior is
+adaptive for all terminals, with the shortcut for "
+                      (tech "termvar")
+                      " "
+                      (code "screen")
+                      " that it doesn't bother trying the control sequence.]")
+                (item "Documentation tweaks.")))
+
+     (#:planet 1:0 #:date "2012-06-16"
+               (itemlist
+                (item "Initial version."))))
diff --git a/archive/0.vm.arc/charterm/demo.rkt b/archive/0.vm.arc/charterm/demo.rkt
new file mode 100644
index 00000000..4cbff6e5
--- /dev/null
+++ b/archive/0.vm.arc/charterm/demo.rkt
@@ -0,0 +1,306 @@
+#lang racket/base
+;; For legal info, see file "info.rkt"
+
+(require racket/cmdline
+         racket/date
+         "charterm.rkt")
+
+(define (%charterm:string-pad-or-truncate str width)
+  (let ((len (string-length str)))
+    (cond ((= len width) str)
+          ((< len width) (string-append str (make-string (- width len) #\space)))
+          (else (substring str 0 width)))))
+
+(define (%charterm:bytes-pad-or-truncate bstr width)
+  (let ((len (bytes-length bstr)))
+    (cond ((= len width) bstr)
+          ((< len width)
+           (let ((new-bstr (make-bytes width 32)))
+             (bytes-copy! new-bstr 0 bstr)
+             new-bstr))
+          (else (subbytes bstr 0 width)))))
+
+(define-struct %charterm:demo-input
+  (x y width bytes used cursor)
+  #:mutable)
+
+(define (%charterm:make-demo-input x y width bstr)
+  (let ((new-bstr (%charterm:bytes-pad-or-truncate bstr width))
+        (used     (min (bytes-length bstr) width)))
+    (make-%charterm:demo-input x
+                               y
+                               width
+                               new-bstr
+                               used
+                               used)))
+
+(define (%charterm:demo-input-redraw di)
+  (charterm-cursor (%charterm:demo-input-x di)
+                   (%charterm:demo-input-y di))
+  (charterm-normal)
+  (charterm-underline)
+  (charterm-display (%charterm:demo-input-bytes di)
+                    #:width (%charterm:demo-input-width di))
+  (charterm-normal))
+
+(define (%charterm:demo-input-put-cursor di)
+  ;; Note: Commented-out debugging code:
+  ;;
+  ;; (and #t
+  ;;      (begin (charterm-normal)
+  ;;             (charterm-cursor (+ (%charterm:demo-input-x     di)
+  ;;                                   (%charterm:demo-input-width di)
+  ;;                                   1)
+  ;;                                (%charterm:demo-input-y di))
+  ;;             (charterm-display #" cursor: "
+  ;;                               (%charterm:demo-input-cursor di)
+  ;;                               #" used: "
+  ;;                               (%charterm:demo-input-used di))
+  ;;             (charterm-clear-line-right)))
+  (charterm-cursor (+ (%charterm:demo-input-x      di)
+                      (%charterm:demo-input-cursor di))
+                   (%charterm:demo-input-y di)))
+
+(define (%charterm:demo-input-cursor-left di)
+  (let ((cursor (%charterm:demo-input-cursor di)))
+    (if (zero? cursor)
+        (begin (charterm-bell)
+               (%charterm:demo-input-put-cursor di))
+        (begin (set-%charterm:demo-input-cursor! di (- cursor 1))
+               (%charterm:demo-input-put-cursor di)))))
+
+(define (%charterm:demo-input-cursor-right di)
+  (let ((cursor (%charterm:demo-input-cursor di)))
+    (if (= cursor (%charterm:demo-input-used di))
+        (begin (charterm-bell)
+               (%charterm:demo-input-put-cursor di))
+        (begin (set-%charterm:demo-input-cursor! di (+ cursor 1))
+               (%charterm:demo-input-put-cursor di)))))
+
+(define (%charterm:demo-input-backspace di)
+  (let ((cursor (%charterm:demo-input-cursor di)))
+    (if (zero? cursor)
+        (begin (charterm-bell)
+               (%charterm:demo-input-put-cursor di))
+        (let ((bstr (%charterm:demo-input-bytes di))
+              (used (%charterm:demo-input-used di)))
+          ;; TODO: test beginning/end of buffer, of used, of width
+          (bytes-copy! bstr (- cursor 1) bstr cursor used)
+          (bytes-set! bstr (- used 1) 32)
+          (set-%charterm:demo-input-used! di (- used 1))
+          (set-%charterm:demo-input-cursor! di (- cursor 1))
+          (%charterm:demo-input-redraw di)
+          (%charterm:demo-input-put-cursor di)))))
+
+(define (%charterm:demo-input-delete di)
+  (let ((cursor (%charterm:demo-input-cursor di))
+        (used   (%charterm:demo-input-used   di)))
+    (if (= cursor used)
+        (begin (charterm-bell)
+               (%charterm:demo-input-put-cursor di))
+        (let ((bstr (%charterm:demo-input-bytes di)))
+          (or (= cursor used)
+              (bytes-copy! bstr cursor bstr (+ 1 cursor) used))
+          (bytes-set! bstr (- used 1) 32)
+          (set-%charterm:demo-input-used! di (- used 1))
+          (%charterm:demo-input-redraw     di)
+          (%charterm:demo-input-put-cursor di)))))
+
+(define (%charterm:demo-input-insert-byte di new-byte)
+  (let ((used  (%charterm:demo-input-used  di))
+        (width (%charterm:demo-input-width di)))
+    (if (= used width)
+        (begin (charterm-bell)
+               (%charterm:demo-input-put-cursor di))
+        (let ((bstr   (%charterm:demo-input-bytes  di))
+              (cursor (%charterm:demo-input-cursor di)))
+          (or (= cursor used)
+              (bytes-copy! bstr (+ cursor 1) bstr cursor used))
+          (bytes-set! bstr cursor new-byte)
+          (set-%charterm:demo-input-used! di (+ 1 used))
+          (set-%charterm:demo-input-cursor! di (+ cursor 1))
+          (%charterm:demo-input-redraw di)
+          (%charterm:demo-input-put-cursor di)))))
+
+(provide charterm-demo)
+(define (charterm-demo #:tty     (tty     #f)
+                       #:escape? (escape? #t))
+  (let ((data-row 4)
+        (di       (%charterm:make-demo-input 10 2 18 #"Hello, world!")))
+    (with-charterm
+     (let ((ct (current-charterm)))
+       (let/ec done-ec
+         (let loop-remember-read-screen-size ((last-read-col-count 0)
+                                              (last-read-row-count 0))
+
+           (let loop-maybe-check-screen-size ()
+             (let*-values (((read-col-count read-row-count)
+                            (if (or (equal? 0 last-read-col-count)
+                                    (equal? 0 last-read-row-count)
+                                    (not (charterm-byte-ready?)))
+                                (charterm-screen-size)
+                                (values last-read-col-count
+                                        last-read-row-count)))
+                           ((read-screen-size? col-count row-count)
+                            (if (and read-col-count read-row-count)
+                                (values #t
+                                        read-col-count
+                                        read-row-count)
+                                (values #f
+                                        (or read-col-count 80)
+                                        (or read-row-count 24))))
+                           ((read-screen-size-changed?)
+                            (not (and (equal? read-col-count
+                                              last-read-col-count)
+                                      (equal? read-row-count
+                                              last-read-row-count))))
+                           ((clock-col)
+                            (let ((clock-col (- col-count 8)))
+                              (if (< clock-col 15)
+                                  #f
+                                  clock-col))))
+               ;; Did screen size change?
+               (if read-screen-size-changed?
+
+                   ;; Screen size changed.
+                   (begin (charterm-clear-screen)
+                          (charterm-cursor 1 1)
+                          (charterm-inverse)
+                          (charterm-display (%charterm:string-pad-or-truncate " charterm Demo"
+                                                                              col-count))
+                          (charterm-normal)
+
+                          (charterm-cursor 1 2)
+                          (charterm-inverse)
+                          (charterm-display #" Input: ")
+                          (charterm-normal)
+                          (%charterm:demo-input-redraw di)
+
+                          (charterm-cursor 1 data-row)
+                          (if escape?
+                               (begin
+                                 (charterm-display "To quit, press ")
+                                 (charterm-bold)
+                                 (charterm-display "Esc")
+                                 (charterm-normal)
+                                 (charterm-display "."))
+                               (charterm-display "There is no escape from this demo."))
+                               
+                          (charterm-cursor 1 data-row)
+                          (charterm-insert-line)
+                          (charterm-display "termvar ")
+                          (charterm-bold)
+                          (charterm-display (charterm-termvar ct))
+                          (charterm-normal)
+                          (charterm-display ", protocol ")
+                          (charterm-bold)
+                          (charterm-display (charterm-protocol ct))
+                          (charterm-normal)
+                          (charterm-display ", keydec ")
+                          (charterm-bold)
+                          (charterm-display (charterm-keydec-id (charterm-keydec ct)))
+                          (charterm-normal)
+
+                          (charterm-cursor 1 data-row)
+                          (charterm-insert-line)
+                          (charterm-display #"Screen size: ")
+                          (charterm-bold)
+                          (charterm-display col-count)
+                          (charterm-normal)
+                          (charterm-display #" x ")
+                          (charterm-bold)
+                          (charterm-display row-count)
+                          (charterm-normal)
+                          (or read-screen-size?
+                              (charterm-display #" (guessing; terminal would not tell us)"))
+
+                          (charterm-cursor 1 data-row)
+                          (charterm-insert-line)
+                          (charterm-display #"Widths:")
+                          (for-each (lambda (bytes)
+                                      (charterm-display #" [")
+                                      (charterm-underline)
+                                      (charterm-display bytes #:width 3)
+                                      (charterm-normal)
+                                      (charterm-display #"]"))
+                                    '(#"" #"a" #"ab" #"abc" #"abcd"))
+
+                          ;; (and (eq? 'wy50 (charterm-protocol ct))
+                          ;;      (begin
+                          ;;        (charterm-cursor 1 data-row)
+                          ;;        (charterm-insert-line)
+                          ;;        (charterm-display #"Wyse WY-50 delete character: ab*c\010\010\eW")))
+
+                          (loop-remember-read-screen-size read-col-count
+                                                          read-row-count))
+                   ;; Screen size didn't change (or we didn't check).
+                   (begin
+                     (and clock-col
+                          (begin (charterm-inverse)
+                                 (charterm-cursor clock-col 1)
+                                 (charterm-display (parameterize ((date-display-format 'iso-8601))
+                                                     (substring (date->string (current-date) #t)
+                                                                11)))
+                                 (charterm-normal)))
+
+                     (let loop-fast-next-key ()
+                       (%charterm:demo-input-put-cursor di)
+                       (let ((keyinfo (charterm-read-keyinfo #:timeout 1)))
+                         (if keyinfo
+                             (let ((keycode (charterm-keyinfo-keycode keyinfo)))
+                               (charterm-cursor 1 data-row)
+                               (charterm-insert-line)
+                               (charterm-display "Read key: ")
+                               (charterm-bold)
+                               (charterm-display (or (charterm-keyinfo-keylabel keyinfo) "???"))
+                               (charterm-normal)
+                               (charterm-display (format " ~S"
+                                                         `(,(charterm-keyinfo-keyset-id    keyinfo)
+                                                           ,(charterm-keyinfo-bytelang     keyinfo)
+                                                           ,(charterm-keyinfo-bytelist     keyinfo)
+                                                           ,@(charterm-keyinfo-all-keycodes keyinfo))))
+                               (if (char? keycode)
+                                   (let ((key-num (char->integer keycode)))
+                                     (if (<= 32 key-num 126)
+                                         (begin (%charterm:demo-input-insert-byte di key-num)
+                                                (loop-fast-next-key))
+                                         (loop-fast-next-key)))
+                                   (case keycode
+                                     ((left)
+                                      (%charterm:demo-input-cursor-left di)
+                                      (loop-fast-next-key))
+                                     ((right)
+                                      (%charterm:demo-input-cursor-right di)
+                                      (loop-fast-next-key))
+                                     ((backspace)
+                                      (%charterm:demo-input-backspace di)
+                                      (loop-fast-next-key))
+                                     ((delete)
+                                      (%charterm:demo-input-delete di)
+                                      (loop-fast-next-key))
+                                     ((escape)
+                                      (if escape?
+                                          (begin
+                                            (charterm-clear-screen)
+                                            (charterm-display "You have escaped the charterm demo!")
+                                            (charterm-newline)
+                                            (done-ec))
+                                          (loop-fast-next-key)))
+                                     (else (loop-fast-next-key)))))
+                             (begin
+                               ;; (charterm-display "Timeout.")
+                               (loop-maybe-check-screen-size)))))))))))))))
+
+(provide main)
+(define (main . args)
+  ;; TODO: Accept TTY as an argument.
+  (let ((tty     #f)
+        (escape? #t))
+    (command-line #:program "(charterm Demo)"
+                  #:once-each
+                  (("--tty" "-t") arg "The TTY to use (default: /dev/tty)." (set! tty arg))
+                  #:once-any
+                  (("--escape"    "-e") "Esc key quits program (default)." (set! escape? #t))
+                  (("--no-escape" "-n") "Esc key does not quit program."   (set! escape? #f)))
+    (charterm-demo #:tty     tty
+                   #:escape? escape?)))
diff --git a/archive/0.vm.arc/charterm/doc.scrbl b/archive/0.vm.arc/charterm/doc.scrbl
new file mode 100644
index 00000000..67040691
--- /dev/null
+++ b/archive/0.vm.arc/charterm/doc.scrbl
@@ -0,0 +1,7 @@
+#lang scribble/manual
+@; THIS-FILE-WAS-GENERATED-BY-MCFLY-TOOLS (planet neil/mcfly-tools:1:=12)
+@(require (for-syntax   racket/base)
+          (for-template racket/base)
+          (planet neil/mcfly:1:3/mcfly-scribble)
+          (planet neil/mcfly:1:3/mcfly-expand))
+@(mcfly-expand "charterm.rkt")
diff --git a/archive/0.vm.arc/charterm/info.rkt b/archive/0.vm.arc/charterm/info.rkt
new file mode 100644
index 00000000..64eeaefe
--- /dev/null
+++ b/archive/0.vm.arc/charterm/info.rkt
@@ -0,0 +1,29 @@
+#lang setup/infotab
+
+(define mcfly-planet       'neil/charterm:3:1)
+(define name               "CharTerm")
+(define mcfly-subtitle     "Character-cell Terminal Interface in Racket")
+(define blurb              (list name ": Character-cell Terminal Interface"))
+(define homepage           "http://www.neilvandyke.org/racket-charterm/")
+(define mcfly-author       "Neil Van Dyke")
+(define repositories       '("4.x"))
+(define categories         '(misc))
+(define can-be-loaded-with 'all)
+(define scribblings        '(("doc.scrbl" () (library))))
+(define primary-file       "main.rkt")
+(define mcfly-start        "charterm.rkt")
+(define mcfly-files        '(defaults
+                              "charterm.rkt"
+                              "demo.rkt"
+                              "test-charterm.rkt"))
+(define mcfly-license      "LGPLv3")
+
+(define mcfly-legal
+    "Copyright 2012 -- 2013 Neil Van Dyke.  This program is Free Software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser General
+Public License as published by the Free Software Foundation; either version 3
+of the License, or (at your option) any later version.  This program is
+distributed in the hope that it will be useful, but without any warranty;
+without even the implied warranty of merchantability or fitness for a
+particular purpose.  See http://www.gnu.org/licenses/ for details.  For other
+licenses and consulting, please contact the author.")
diff --git a/archive/0.vm.arc/charterm/main.rkt b/archive/0.vm.arc/charterm/main.rkt
new file mode 100644
index 00000000..5566a73f
--- /dev/null
+++ b/archive/0.vm.arc/charterm/main.rkt
@@ -0,0 +1,3 @@
+#lang racket/base
+(require "charterm.rkt")
+(provide (all-from-out "charterm.rkt"))
diff --git a/archive/0.vm.arc/charterm/planet-docs/doc/index.html b/archive/0.vm.arc/charterm/planet-docs/doc/index.html
new file mode 100644
index 00000000..79d311c9
--- /dev/null
+++ b/archive/0.vm.arc/charterm/planet-docs/doc/index.html
@@ -0,0 +1,117 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><title>CharTerm: Character-cell Terminal Interface in Racket</title><link rel="stylesheet" type="text/css" href="scribble.css" title="default" /><link rel="stylesheet" type="text/css" href="racket.css" title="default" /><link rel="stylesheet" type="text/css" href="scribble-style.css" title="default" /><script type="text/javascript" src="scribble-common.js"></script><!--[if IE 6]><style type="text/css">.SIEHidden { overflow: hidden; }</style><![endif]--></head><body id="scribble-racket-lang-org"><div class="tocset"><div class="tocview"><div class="tocviewlist" style="margin-bottom: 1em;"><div class="tocviewtitle"><table cellspacing="0" cellpadding="0"><tr><td style="width: 1em;"><a href="javascript:void(0);" title="Expand/Collapse" class="tocviewtoggle" onclick="TocviewToggle(this,&quot;tocview_0&quot;);">&#9658;</a></td><td></td><td><a href="/" class="tocviewselflink" data-pltdoc="x">Char<span class="mywbr"> &nbsp;</span>Term:<span class="mywbr"> &nbsp;</span> Character-<wbr></wbr>cell Terminal Interface in Racket</a></td></tr></table></div><div class="tocviewsublistonly" style="display: none;" id="tocview_0"><table cellspacing="0" cellpadding="0"><tr><td align="right">1&nbsp;</td><td><a href="/#%28part._.Introduction%29" class="tocviewlink" data-pltdoc="x">Introduction</a></td></tr><tr><td align="right">2&nbsp;</td><td><a href="/#%28part._.Terminal_.Diversity%29" class="tocviewlink" data-pltdoc="x">Terminal Diversity</a></td></tr><tr><td align="right">3&nbsp;</td><td><a href="/#%28part._charterm_.Object%29" class="tocviewlink" data-pltdoc="x"><span class="RktSym">charterm</span><span class="RktMeta"></span> Object</a></td></tr><tr><td align="right">4&nbsp;</td><td><a href="/#%28part._.Terminal_.Information%29" class="tocviewlink" data-pltdoc="x">Terminal Information</a></td></tr><tr><td align="right">5&nbsp;</td><td><a href="/#%28part._.Display_.Control%29" class="tocviewlink" data-pltdoc="x">Display Control</a></td></tr><tr><td align="right">6&nbsp;</td><td><a href="/#%28part._.Keyboard_.Input%29" class="tocviewlink" data-pltdoc="x">Keyboard Input</a></td></tr><tr><td align="right">7&nbsp;</td><td><a href="/#%28part._.References%29" class="tocviewlink" data-pltdoc="x">References</a></td></tr><tr><td align="right">8&nbsp;</td><td><a href="/#%28part._.Known_.Issues%29" class="tocviewlink" data-pltdoc="x">Known Issues</a></td></tr><tr><td align="right">9&nbsp;</td><td><a href="/#%28part._.History%29" class="tocviewlink" data-pltdoc="x">History</a></td></tr><tr><td align="right">10&nbsp;</td><td><a href="/#%28part._.Legal%29" class="tocviewlink" data-pltdoc="x">Legal</a></td></tr></table></div></div></div><div class="tocsub"><table class="tocsublist" cellspacing="0"><tr><td><span class="tocsublinknumber">1<tt>&nbsp;</tt></span><a href="#(part._.Introduction)" class="tocsubseclink" data-pltdoc="x">Introduction</a></td></tr><tr><td><span class="tocsublinknumber">1.1<tt>&nbsp;</tt></span><a href="#(part._.Demo)" class="tocsubseclink" data-pltdoc="x">Demo</a></td></tr><tr><td><span class="tocsublinknumber">1.2<tt>&nbsp;</tt></span><a href="#(part._.Simple_.Example)" class="tocsubseclink" data-pltdoc="x">Simple Example</a></td></tr><tr><td><span class="tocsublinknumber">2<tt>&nbsp;</tt></span><a href="#(part._.Terminal_.Diversity)" class="tocsubseclink" data-pltdoc="x">Terminal Diversity</a></td></tr><tr><td><span class="tocsublinknumber">2.1<tt>&nbsp;</tt></span><a href="#(part._.Protocol)" class="tocsubseclink" data-pltdoc="x">Protocol</a></td></tr><tr><td><span class="tocsublinknumber">2.2<tt>&nbsp;</tt></span><a href="#(part._.Key_.Encoding)" class="tocsubseclink" data-pltdoc="x">Key Encoding</a></td></tr><tr><td><span class="tocsublinknumber">2.2.1<tt>&nbsp;</tt></span><a href="#(part._.Keylabel)" class="tocsubseclink" data-pltdoc="x">Keylabel</a></td></tr><tr><td><span class="tocsublinknumber">2.2.2<tt>&nbsp;</tt></span><a href="#(part._.Keycode)" class="tocsubseclink" data-pltdoc="x">Keycode</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keycode~3f))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keycode?</span></span></a></td></tr><tr><td><span class="tocsublinknumber">2.2.3<tt>&nbsp;</tt></span><a href="#(part._.Keyinfo)" class="tocsubseclink" data-pltdoc="x">Keyinfo</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo~3f))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo?</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-keyset-id))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo-<wbr></wbr>keyset-<wbr></wbr>id</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-bytelang))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo-<wbr></wbr>bytelang</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-bytelist))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo-<wbr></wbr>bytelist</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-keylabel))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo-<wbr></wbr>keylabel</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-keycode))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo-<wbr></wbr>keycode</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-all-keycodes))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyinfo-<wbr></wbr>all-<wbr></wbr>keycodes</span></span></a></td></tr><tr><td><span class="tocsublinknumber">2.2.4<tt>&nbsp;</tt></span><a href="#(part._.Keyset)" class="tocsubseclink" data-pltdoc="x">Keyset</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyset~3f))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyset?</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyset-id))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keyset-<wbr></wbr>id</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-ascii-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>ascii-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-dec-vt100-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>dec-<wbr></wbr>vt100-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-dec-vt220-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>dec-<wbr></wbr>vt220-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-screen-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>screen-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-linux-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>linux-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-x11r6-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>xterm-<wbr></wbr>x11r6-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-xfree86-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>xterm-<wbr></wbr>xfree86-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-new-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>xterm-<wbr></wbr>new-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-rxvt-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>rxvt-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-wyse-wy50-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>wyse-<wbr></wbr>wy50-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-televideo-925-keyset))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>televideo-<wbr></wbr>925-<wbr></wbr>keyset</span></span></a></td></tr><tr><td><span class="tocsublinknumber">2.2.5<tt>&nbsp;</tt></span><a href="#(part._.Keydec)" class="tocsubseclink" data-pltdoc="x">Keydec</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keydec-id))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keydec-<wbr></wbr>id</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-vt100-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>vt100-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-vt220-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>vt220-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-screen-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>screen-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-linux-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>linux-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-new-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>xterm-<wbr></wbr>new-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>xterm-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-rxvt-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>rxvt-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-wy50-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>wy50-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-tvi925-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>tvi925-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-ascii-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>ascii-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-ansi-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>ansi-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-insane-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>insane-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><span class="tocsublinknumber">2.3<tt>&nbsp;</tt></span><a href="#(part._.Termvar)" class="tocsubseclink" data-pltdoc="x">Termvar</a></td></tr><tr><td><span class="tocsublinknumber">3<tt>&nbsp;</tt></span><a href="#(part._charterm_.Object)" class="tocsubseclink" data-pltdoc="x"><span class="RktSym">charterm</span><span class="RktMeta"></span> Object</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm~3f))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm?</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-termvar))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>termvar</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-protocol))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>protocol</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keydec))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>keydec</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._current-charterm))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">current-<wbr></wbr>charterm</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._open-charterm))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">open-<wbr></wbr>charterm</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._close-charterm))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">close-<wbr></wbr>charterm</span></span></a></td></tr><tr><td><a href="#(form._((planet._main..rkt._(neil._charterm..plt._3._1))._with-charterm))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">with-<wbr></wbr>charterm</span></span></a></td></tr><tr><td><span class="tocsublinknumber">4<tt>&nbsp;</tt></span><a href="#(part._.Terminal_.Information)" class="tocsubseclink" data-pltdoc="x">Terminal Information</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-screen-size))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>screen-<wbr></wbr>size</span></span></a></td></tr><tr><td><span class="tocsublinknumber">5<tt>&nbsp;</tt></span><a href="#(part._.Display_.Control)" class="tocsubseclink" data-pltdoc="x">Display Control</a></td></tr><tr><td><span class="tocsublinknumber">5.1<tt>&nbsp;</tt></span><a href="#(part._.Cursor)" class="tocsubseclink" data-pltdoc="x">Cursor</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-cursor))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>cursor</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-newline))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>newline</span></span></a></td></tr><tr><td><span class="tocsublinknumber">5.2<tt>&nbsp;</tt></span><a href="#(part._.Displaying)" class="tocsubseclink" data-pltdoc="x">Displaying</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-display))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>display</span></span></a></td></tr><tr><td><span class="tocsublinknumber">5.3<tt>&nbsp;</tt></span><a href="#(part._.Video_.Attributes)" class="tocsubseclink" data-pltdoc="x">Video Attributes</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-normal))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>normal</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-inverse))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>inverse</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-underline))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>underline</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-blink))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>blink</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-bold))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>bold</span></span></a></td></tr><tr><td><span class="tocsublinknumber">5.4<tt>&nbsp;</tt></span><a href="#(part._.Clearing)" class="tocsubseclink" data-pltdoc="x">Clearing</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-screen))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>clear-<wbr></wbr>screen</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-line))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>clear-<wbr></wbr>line</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-line-left))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>clear-<wbr></wbr>line-<wbr></wbr>left</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-line-right))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>clear-<wbr></wbr>line-<wbr></wbr>right</span></span></a></td></tr><tr><td><span class="tocsublinknumber">5.5<tt>&nbsp;</tt></span><a href="#(part._.Line_.Insert_and_.Delete)" class="tocsubseclink" data-pltdoc="x">Line Insert and Delete</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-insert-line))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>insert-<wbr></wbr>line</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-delete-line))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>delete-<wbr></wbr>line</span></span></a></td></tr><tr><td><span class="tocsublinknumber">5.5.1<tt>&nbsp;</tt></span><a href="#(part._.Misc__.Output)" class="tocsubseclink" data-pltdoc="x">Misc. Output</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-bell))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>bell</span></span></a></td></tr><tr><td><span class="tocsublinknumber">6<tt>&nbsp;</tt></span><a href="#(part._.Keyboard_.Input)" class="tocsubseclink" data-pltdoc="x">Keyboard Input</a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-byte-ready~3f))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>byte-<wbr></wbr>ready?</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-read-key))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>read-<wbr></wbr>key</span></span></a></td></tr><tr><td><a href="#(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-read-keyinfo))" class="tocsubnonseclink" data-pltdoc="x"><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-<wbr></wbr>read-<wbr></wbr>keyinfo</span></span></a></td></tr><tr><td><span class="tocsublinknumber">7<tt>&nbsp;</tt></span><a href="#(part._.References)" class="tocsubseclink" data-pltdoc="x">References</a></td></tr><tr><td><span class="tocsublinknumber">8<tt>&nbsp;</tt></span><a href="#(part._.Known_.Issues)" class="tocsubseclink" data-pltdoc="x">Known Issues</a></td></tr><tr><td><span class="tocsublinknumber">9<tt>&nbsp;</tt></span><a href="#(part._.History)" class="tocsubseclink" data-pltdoc="x">History</a></td></tr><tr><td><span class="tocsublinknumber">10<tt>&nbsp;</tt></span><a href="#(part._.Legal)" class="tocsubseclink" data-pltdoc="x">Legal</a></td></tr></table></div></div><div class="maincolumn"><div class="main"><div class="versionbox"><span class="versionNoNav">3:1</span></div><h2><a name="(part._.Char.Term__.Character-cell_.Terminal_.Interface_in_.Racket)"></a><a name="(mod-path._(planet._neil/charterm~3a3~3a1))"></a>CharTerm: Character-cell Terminal Interface in Racket</h2><div class="SAuthorListBox"><span class="SAuthorList"><p class="author">Neil Van Dyke</p></span></div><p><div class="SIntrapara"></div><div class="SIntrapara">License: <a href="/#%28part._.Legal%29" class="plainlink" data-pltdoc="x">LGPLv3</a> <span class="hspace">&nbsp;</span> Web: <a href="http://www.neilvandyke.org/racket-charterm/" class="plainlink">http://www.neilvandyke.org/racket-charterm/</a>
+</div><div class="SIntrapara"><table cellspacing="0" class="defmodule"><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym"><a href="/servlets/doc-search.rkt?tag=KCgzKSAwICgpIDAgKCkgKCkgKHEgZm9ybSAoKGxpYiAicmFja2V0L3ByaXZhdGUvYmFzZS5y%0D%0Aa3QiKSByZXF1aXJlKSkp%0D%0A" class="RktStxLink" data-pltdoc="x">require</a></span><span class="stt"> </span><span class="RktPn">(</span><span class="RktSym">planet</span><span class="stt"> </span><span class="RktSym">neil/charterm:3:1</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></div></p><h3>1<tt>&nbsp;</tt><a name="(part._.Introduction)"></a>Introduction</h3><p><div class="SIntrapara">The CharTerm package provides a Racket interface for character-cell video
+display terminals on Unix-like systems &ndash; such as for <a name="(idx._(gentag._0))"></a>GNU Screen and <a name="(idx._(gentag._1))"></a><span class="RktSym">tmux</span><span class="RktMeta"></span> sessions on <a name="(idx._(gentag._2))"></a>cloud servers, <a name="(idx._(gentag._3))"></a>XTerm windows on a workstation desktop, and some older hardware
+terminals (even the venerable <a name="(idx._(gentag._4))"></a>DEC VT100).  Currently, it implements a subset of features available on most
+terminals.</div><div class="SIntrapara">This package could be used to implement a status/management console
+for a Racket-based server process (perhaps run in GNU Screen or <span class="RktSym">tmux</span><span class="RktMeta"></span> on a server machine, to be detached and reattached from SSH
+sessions), a lightweight user interface for a systems tool, a command-line
+REPL, a text editor, creative retro uses of old equipment, and, perhaps most
+importantly, a Rogue-like application.</div><div class="SIntrapara">The CharTerm package does not include any native code (such as from <a name="(idx._(gentag._5))"></a><span class="RktSym">terminfo</span><span class="RktMeta"></span>, <a name="(idx._(gentag._6))"></a><span class="RktSym">termcap</span><span class="RktMeta"></span>, <a name="(idx._(gentag._7))"></a><span class="RktSym">curses</span><span class="RktMeta"></span>, or <a name="(idx._(gentag._8))"></a><span class="RktSym">ncurses</span><span class="RktMeta"></span>) in the Racket process,
+such as through the Racket FFI or C extensions, so there is less potential for
+a problem involving native code to threaten the reliability or security of a
+program.  CharTerm is implemented in pure Racket code except for executing <span class="RktSym">/bin/stty</span><span class="RktMeta"></span> for some purposes.  Specifically, <span class="RktSym">/bin/stty</span><span class="RktMeta"></span> at startup time and shutdown time, to set modes, and (for terminal
+types that don&rsquo;t seem to support a screen size report control sequence) when
+getting screen size.  Besides security and stability, lower dependence on
+native code might also simplify porting to host platforms that don&rsquo;t have those
+native code facilities.</div></p><h4>1.1<tt>&nbsp;</tt><a name="(part._.Demo)"></a>Demo</h4><p><div class="SIntrapara">For a demonstration, the following command, run from a terminal, should install the CharTerm package (if not already installed), and run the demo:</div><div class="SIntrapara"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">racket -pm neil/charterm/demo</span></div><div class="SIntrapara">This demo reports what keys you pressed, while letting you edit a
+text field, and while displaying a clock.  The clock is updated roughly once
+per second, and is not updated during heavy keyboard input, such as when typing
+fast.  The demo responds to changing terminal sizes, such as when an XTerm is
+window is resized.  It also displays the determined terminal size, and some
+small tests of the <span class="RktPn">#:width</span> argument to <span class="RktSym">charterm-display</span>.  Exit the demo by pressing the <span style="font-weight: bold">Esc</span> key.</div><div class="SIntrapara">Note: Although this demo includes an editable text field, as proof
+of concept, the current version of CharTerm does not provide editable text fields as reusable functionality.</div></p><h4>1.2<tt>&nbsp;</tt><a name="(part._.Simple_.Example)"></a>Simple Example</h4><p><div class="SIntrapara">Here&rsquo;s your first CharTerm program:</div><div class="SIntrapara"><blockquote class="SCodeFlow"><table cellspacing="0" class="RktBlk"><tr><td><span class="RktMeta">#lang</span><span class="hspace">&nbsp;</span><span class="RktMeta"></span><a href="/servlets/doc-search.rkt?tag=KCgzKSAwICgpIDAgKCkgKCkgKHEgbW9kLXBhdGggInJhY2tldC9iYXNlIikp%0D%0A" class="RktModLink" data-pltdoc="x"><span class="RktSym">racket/base</span></a><span class="RktMeta"></span></td></tr><tr><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym">require</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">planet</span><span class="hspace">&nbsp;</span><span class="RktSym">neil/charterm</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym">with-charterm</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-clear-screen</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-cursor</span><span class="hspace">&nbsp;</span><span class="RktVal">10</span><span class="hspace">&nbsp;</span><span class="RktVal">5</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-display</span><span class="hspace">&nbsp;</span><span class="RktVal">"Hello, "</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-bold</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-display</span><span class="hspace">&nbsp;</span><span class="RktVal">"you"</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-normal</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-display</span><span class="hspace">&nbsp;</span><span class="RktVal">"."</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-cursor</span><span class="hspace">&nbsp;</span><span class="RktVal">1</span><span class="hspace">&nbsp;</span><span class="RktVal">1</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-display</span><span class="hspace">&nbsp;</span><span class="RktVal">"Press a key..."</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">let</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktPn">(</span><span class="RktSym">key</span><span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-read-key</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-cursor</span><span class="hspace">&nbsp;</span><span class="RktVal">1</span><span class="hspace">&nbsp;</span><span class="RktVal">1</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">charterm-clear-line</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;&nbsp;</span><span class="RktPn">(</span><span class="RktSym">printf</span><span class="hspace">&nbsp;</span><span class="RktVal">"You pressed: ~S\r\n"</span><span class="hspace">&nbsp;</span><span class="RktSym">key</span><span class="RktPn">)</span><span class="RktPn">)</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Now you&rsquo;re living the dream of the &rsquo;70s.</div></p><h3>2<tt>&nbsp;</tt><a name="(part._.Terminal_.Diversity)"></a>Terminal Diversity</h3><p><div class="SIntrapara">Like people, few terminals are exactly the same.</div><div class="SIntrapara">Some key (ha) terms (ha) used by CharTerm are:</div><div class="SIntrapara"><ul><li><p><a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> &#8212;<wbr></wbr> a string value like from the Unix-like <span class="RktSym">TERM</span><span class="RktMeta"></span> environment variable, used to determine a default <a href="/#%28tech._protocol%29" class="techoutside" data-pltdoc="x"><span class="techinside">protocol</span></a> and <a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydec</span></a>.</p></li><li><p><a href="/#%28tech._protocol%29" class="techoutside" data-pltdoc="x"><span class="techinside">protocol</span></a> &#8212;<wbr></wbr> how to control the display, query for information, etc.</p></li><li><p><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydec</span></a> &#8212;<wbr></wbr> how to decode key encodings of a particular
+terminal.  A keydec is constructed from one or more keysets, can produce <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a>s or <a href="/#%28tech._keyinfo%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyinfo</span></a>s.</p></li><li><p><a href="/#%28tech._keyset%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyset</span></a> &#8212;<wbr></wbr> a specification of encoding some of the keys in a
+particular terminal, including <a href="/#%28tech._keylabel%29" class="techoutside" data-pltdoc="x"><span class="techinside">keylabel</span></a>s and <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a>s.</p></li><li><p><a href="/#%28tech._keylabel%29" class="techoutside" data-pltdoc="x"><span class="techinside">keylabel</span></a> &#8212;<wbr></wbr> a string for how a key is likely labeled on a
+keyboard, such as the DEC VT100 <span style="font-weight: bold">PF1</span> key would have a keylabel <span class="RktVal">"PF1"</span> for a <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a> <span class="RktVal">'</span><span class="RktVal">f1</span>.</p></li><li><p><a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a> &#8212;<wbr></wbr> a value produced by a decoded key,
+such as a character for normal printable keys, like <span class="RktVal">#\a</span> and <span class="RktVal">#\space</span>, a symbol for some recognized unprintable keys, like <span class="RktVal">'</span><span class="RktVal">escape</span> and <span class="RktVal">'</span><span class="RktVal">f1</span>, or possibly a number for unrecognized keys.</p></li><li><p><a href="/#%28tech._keyinfo%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyinfo</span></a> &#8212;<wbr></wbr> an object that is used like a <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a>, except
+bundles together a keycode and a <a href="/#%28tech._keylabel%29" class="techoutside" data-pltdoc="x"><span class="techinside">keylabel</span></a>, as well as alternatate keycodes and
+information about how the key was decoded (e.g., from which <a href="/#%28tech._keyset%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyset</span></a>).</p></li></ul></div><div class="SIntrapara">These terms are discussed in the following subsections.</div><div class="SIntrapara">CharTerm is developed with help of original documentation such as that
+curated by Paul Williams at <a href="http://vt100.net/">vt100.net</a>, various commentary found on the Web, observed behavior with
+modern software terminals like XTerm, various emulators for hardware terminals,
+and sometimes original hardware terminals.  Thanks to Mark Pearrow for
+contributing a TeleVideo 950, and Paul McCabe for a Wyse S50 WinTerm.</div><div class="SIntrapara">At time of this writing, the author is looking to acquire a DEC
+VT525, circa 1994, for ongoing testing.</div><div class="SIntrapara">The author welcomes feedback on useful improvements to CharTerm&rsquo;s support for terminal diversity (no pun).  If you have a terminal
+that is sending an escape sequence not recognized by the demo, you can run the
+demo with the <span class="nobreak"><span class="stt">-n</span></span> (aka <span class="nobreak"><span class="stt">--no-escape</span></span>) argument to see the exact byte sequence:</div><div class="SIntrapara"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">racket -pm- neil/charterm/demo -n</span></div><div class="SIntrapara">When <span class="nobreak"><span class="stt">-n</span></span> is used, this will be indicated by the bottom-most scrolling line,
+rather than saying &ldquo;<span class="stt">To quit, press </span><span style="font-weight: bold">Esc</span><span class="stt">.</span>&rdquo; instead will say &ldquo;<span class="stt">There is no escape from this demo.</span>&rdquo; You will have to kill the process through some other means.</div></p><h4>2.1<tt>&nbsp;</tt><a name="(part._.Protocol)"></a>Protocol</h4><p><div class="SIntrapara">The first concept CharTerm has for distinguishing how to communicate with a terminal is what
+is what is called here <a name="(tech._protocol)"></a><span style="font-style: italic">protocol</span>, which concerns everything except how keyboard keys are decoded.
+The following protocols are currently implemented:</div><div class="SIntrapara"><ul><li><p><a name="(tech._ansi._protocol)"></a><span style="font-style: italic"><span class="RktSym">ansi</span><span class="RktMeta"></span> protocol</span> &#8212;<wbr></wbr> Terminals approximating [<a href="/#%28tech._ansi._x3..64%29" class="techoutside" data-pltdoc="x"><span class="techinside">ANSI X3.64</span></a>], which is most terminals in use today, including software ones
+like XTerm.  This protocol is the emphasis of this package; the other protocols
+are for unusual situations.</p></li><li><p><a name="(tech._wyse._wy50._protocol)"></a><span style="font-style: italic"><span class="RktSym">wyse-wy50</span><span class="RktMeta"></span> protocol</span> &#8212;<wbr></wbr> Terminals compatible with the Wyse WY-50.  This support is
+based on [<a href="/#%28tech._wy._50._qrg%29" class="techoutside" data-pltdoc="x"><span class="techinside">WY-50-QRG</span></a>], [<a href="/#%28tech._wy._60._ug%29" class="techoutside" data-pltdoc="x"><span class="techinside">WY-60-UG</span></a>], [<a href="/#%28tech._wy60%29" class="techoutside" data-pltdoc="x"><span class="techinside">wy60</span></a>], and [<a href="/#%28tech._powerterm%29" class="techoutside" data-pltdoc="x"><span class="techinside">PowerTerm</span></a>].  Note that video attributes are not supported, due to the WY-50&rsquo;s
+model of having video attribute changes occupy character cells; you may wish
+to run the Wyse terminal in an ANSI or VT100 mode.</p></li><li><p><a name="(tech._televideo._925._protocol)"></a><span style="font-style: italic"><span class="RktSym">televideo-925</span><span class="RktMeta"></span> protocol</span> &#8212;<wbr></wbr> Terminals compatible with the TeleVideo 925.  This support is based on [<a href="/#%28tech._tvi._925._iug%29" class="techoutside" data-pltdoc="x"><span class="techinside">TVI-925-IUG</span></a>] and behavior of [<a href="/#%28tech._powerterm%29" class="techoutside" data-pltdoc="x"><span class="techinside">PowerTerm</span></a>].  Note that video attributes are not supported, due to the 925&rsquo;s
+model of having video attribute changes occupy character cells; you may wish to
+run your TeleVideo terminal in ANSI or VT100 mode, if it has one.</p></li><li><p><a name="(tech._ascii._protocol)"></a><span style="font-style: italic"><span class="RktSym">ascii</span><span class="RktMeta"></span> protocol</span> &#8212;<wbr></wbr> Terminals that support ASCII but not much else that we know about.</p></li></ul></div></p><h4>2.2<tt>&nbsp;</tt><a name="(part._.Key_.Encoding)"></a>Key Encoding</h4><p><div class="SIntrapara">While most video display control, they seem to vary more by key
+encoding.</div><div class="SIntrapara">The CharTerm author was motivated to increase the sophistication of its
+keyboard handling after a series of revelations on the Sunday of the long
+weekend in which CharTerm was initially written.  The first was discovering that four of the
+function keys that had been working fine in <span class="RktSym">rxvt</span><span class="RktMeta"></span> did not work in XTerm.  Dave Gilbert somewhat demystified this by
+pointing out that the original VT100 had only four function keys, which set
+into motion an unfortunate series of bad decisions by various developers of
+terminal software to be needlessly incompatible with each other.  After
+Googling, a horrifying 2005 Web post by Phil Gregory [<a href="/#%28tech._gregory%29" class="techoutside" data-pltdoc="x"><span class="techinside">Gregory</span></a>], which showed that key encoding among XTerm variants was even
+worse than one could ever fear.  Even if one already knew how much subtleties
+of old terminals varied (e.g., auto-newline behavior, whether an attribute
+change consumed a space, etc.), this incompatibility in newer software was
+surprising. Then, on a hunch, I tried the Linux Console on a Debian Squeeze
+machine, which surely is ANSI, and found, however, that it generated <span style="font-style: italic">yet different</span> byte sequences, for the first <span style="font-style: italic">five</span> (not four) function keys.  Then I compared all to the [<a href="/#%28tech._ecma._48%29" class="techoutside" data-pltdoc="x"><span class="techinside">ECMA-48</span></a>] standard, which turns out to be nigh-inscrutable, so which might
+help explain why everyone became so anti-social.</div><div class="SIntrapara">CharTerm now provides the abstractions of <a href="/#%28tech._keyset%29" class="techoutside" data-pltdoc="x"><span class="techinside">keysets</span></a> and <a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydecs</span></a> to deal with this diversity in a maintainable way.</div></p><h5>2.2.1<tt>&nbsp;</tt><a name="(part._.Keylabel)"></a>Keylabel</h5><p>A <a name="(tech._keylabel)"></a><span style="font-style: italic">keylabel</span> is a Racket string for how a key is likely labeled on a particular terminal&rsquo;s keyboard.  Different keyboards may have different keylabels for the same <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a>.  For example, a VT100 has a <span style="font-weight: bold">PF1</span> key (keylabel <span class="RktVal">"PF1"</span>, keycode <span class="RktVal">'</span><span class="RktVal">f1</span>), while many other keyboards would label the key <span style="font-weight: bold">F1</span> (keylabel <span class="RktVal">"F1"</span>, keycode <span class="RktVal">'</span><span class="RktVal">f1</span>).  The keylabel currently is most useful for documenting and debugging, although it could later be used when giving instructions to the user, such as knowing whether to tell the user the <span style="font-weight: bold">Return</span> key or the <span style="font-weight: bold">Enter</span> key; the <span style="font-weight: bold">Backspace</span> or the <span style="font-weight: bold">Rubout</span> key; etc.</p><h5>2.2.2<tt>&nbsp;</tt><a name="(part._.Keycode)"></a>Keycode</h5><p><div class="SIntrapara">A <a name="(tech._keycode)"></a><span style="font-style: italic">keycode</span> is a value representing a key read from a terminal, which can be a Racket character, symbol, or number.  Keys corresponding to printable characters have keycodes as Racket characters.  Some keys corresponding to special non-printable characters can have keycodes of Racket symbols, such as <span class="RktVal">'</span><span class="RktVal">return</span>, <span class="RktVal">'</span><span class="RktVal">f1</span>, <span class="RktVal">'</span><span class="RktVal">up</span>, etc.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keycode~3f))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keycode?</span></span><span class="hspace">&nbsp;</span><span class="RktVar">x</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">x</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">any/c</span></td></tr></table></blockquote></div><div class="SIntrapara">Predicate for whether or not <span class="RktVar">x</span> is a valid keycode.</div></p><h5>2.2.3<tt>&nbsp;</tt><a name="(part._.Keyinfo)"></a>Keyinfo</h5><p><div class="SIntrapara">A <a name="(tech._keyinfo)"></a><span style="font-style: italic">keyinfo</span> represents a <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a> for a key, a <a href="/#%28tech._keylabel%29" class="techoutside" data-pltdoc="x"><span class="techinside">keylabel</span></a>, and how it is encoded as bytes.  It is represented in Racket as
+a <span class="RktSym">charterm-keyinfo</span> object.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo~3f))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo?</span></span><span class="hspace">&nbsp;</span><span class="RktVar">x</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">x</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">any/c</span></td></tr></table></blockquote></div><div class="SIntrapara">Predicate for whether or not <span class="RktSym">x</span> is a <span class="RktSym">charterm-keyinfo</span> object.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-keyset-id))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo-keyset-id</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ki</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">symbol?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ki</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyinfo?</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-bytelang))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo-bytelang</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ki</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">string?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ki</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyinfo?</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-bytelist))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo-bytelist</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ki</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">listof</span><span class="hspace">&nbsp;</span><span class="RktSym">byte?</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ki</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyinfo?</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-keylabel))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo-keylabel</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ki</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">string?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ki</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyinfo?</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-keycode))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo-keycode</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ki</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keycode?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ki</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyinfo?</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyinfo-all-keycodes))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyinfo-all-keycodes</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ki</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">listof</span><span class="hspace">&nbsp;</span><span class="RktSym">charterm-keycode?</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ki</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyinfo?</span></td></tr></table></blockquote></div><div class="SIntrapara">Get information from a <span class="RktSym">charterm-keyinfo</span> object.</div></p><h5>2.2.4<tt>&nbsp;</tt><a name="(part._.Keyset)"></a>Keyset</h5><p><div class="SIntrapara">A <a name="(tech._keyset)"></a><span style="font-style: italic">keyset</span> is a specification of keys on a particular keyboard, including their <a href="/#%28tech._keylabel%29" class="techoutside" data-pltdoc="x"><span class="techinside">keylabel</span></a>, encoding as bytes, and primary and alternate <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycodes</span></a>.</div><div class="SIntrapara">The means of constructing a keyset is currently internal to this package.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyset~3f))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyset?</span></span><span class="hspace">&nbsp;</span><span class="RktVar">x</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">x</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">any/c</span></td></tr></table></blockquote></div><div class="SIntrapara">Predicate for whether or not <span class="RktVar">x</span> is a keyset.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keyset-id))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keyset-id</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ks</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">symbol?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ks</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></td></tr></table></blockquote></div><div class="SIntrapara">Get a symbol identifying the keyset.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-ascii-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-ascii-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the old [<a href="/#%28tech._ascii%29" class="techoutside" data-pltdoc="x"><span class="techinside">ASCII</span></a>] standard.  When defining a <a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydec</span></a>, this is good to have as a final keyset, after the others.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-dec-vt100-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-dec-vt100-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the DEC VT100.  This currently defines the four function
+keys (labeled on the keyboard, <span style="font-weight: bold">PF1</span> through <span style="font-weight: bold">PF4</span>) as <span class="RktVal">'</span><span class="RktVal">f1</span> through <span class="RktVal">'</span><span class="RktVal">f4</span>, and the arrow keys.  [<a href="/#%28tech._vt100._ug%29" class="techoutside" data-pltdoc="x"><span class="techinside">VT100-UG</span></a>] and [<a href="/#%28tech._powerterm%29" class="techoutside" data-pltdoc="x"><span class="techinside">PowerTerm</span></a>] were used as references.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-dec-vt220-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-dec-vt220-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the DEC VT220.  This currently defines function keys <span style="font-weight: bold">F1</span> through <span style="font-weight: bold">F20</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-screen-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-screen-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the <a href="http://en.wikipedia.org/wiki/GNU_Screen">GNU Screen</a> terminal multiplexer, according to [<a href="/#%28tech._gregory%29" class="techoutside" data-pltdoc="x"><span class="techinside">Gregory</span></a>].  Also used by <a href="http://en.wikipedia.org/wiki/Tmux"><span class="RktSym">tmux</span><span class="RktMeta"></span></a>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-linux-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-linux-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the Linux console.  Currently defines function keys <span style="font-weight: bold">F1</span> through <span style="font-weight: bold">F5</span> only, since the rest will be inherited from other keysets.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-x11r6-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-xterm-x11r6-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the XTerm in X11R6, according to [<a href="/#%28tech._gregory%29" class="techoutside" data-pltdoc="x"><span class="techinside">Gregory</span></a>].</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-xfree86-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-xterm-xfree86-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the XFree86 XTerm, according to [<a href="/#%28tech._gregory%29" class="techoutside" data-pltdoc="x"><span class="techinside">Gregory</span></a>].</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-new-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-xterm-new-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the current <span class="RktSym">xterm-new</span><span class="RktMeta"></span>, often called simply <span class="RktSym">xterm</span><span class="RktMeta"></span>, as developed by Thomas E. Dickey, and documented in [<a href="/#%28tech._xterm._ctlseq%29" class="techoutside" data-pltdoc="x"><span class="techinside">XTerm-ctlseqs</span></a>].  Several also came from decompiling a <span class="RktSym">terminfo</span><span class="RktMeta"></span> entry.  Thanks to Dickey for his emailed help.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-rxvt-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-rxvt-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the <a href="http://en.wikipedia.org/wiki/Rxvt"><span class="RktSym">rxvt</span><span class="RktMeta"></span></a> terminal emulator.  These come from [<a href="/#%28tech._gregory%29" class="techoutside" data-pltdoc="x"><span class="techinside">Gregory</span></a>], and
+currently define function keys <span class="RktVal">'</span><span class="RktVal">f1</span> through <span class="RktVal">'</span><span class="RktVal">f44</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-wyse-wy50-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-wyse-wy50-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the Wyse WY-50, based on [<a href="/#%28tech._wy._50._qrg%29" class="techoutside" data-pltdoc="x"><span class="techinside">WY-50-QRG</span></a>] and looking at photos of WY-50 keyboard, and tested in [<a href="/#%28tech._wy60%29" class="techoutside" data-pltdoc="x"><span class="techinside">wy60</span></a>] and [<a href="/#%28tech._powerterm%29" class="techoutside" data-pltdoc="x"><span class="techinside">PowerTerm</span></a>].  The shifted function keys are provided as both <span class="RktVal">'</span><span class="RktVal">shift-f1</span> through <span class="RktVal">'</span><span class="RktVal">shift-16</span>, and <span class="RktVal">'</span><span class="RktVal">f17</span> through <span class="RktVal">'</span><span class="RktVal">f31</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-televideo-925-keyset))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-televideo-925-keyset</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keyset?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">From the TeleVideo 925, based on [<a href="/#%28tech._tvi._925._iug%29" class="techoutside" data-pltdoc="x"><span class="techinside">TVI-925-IUG</span></a>], [<a href="/#%28tech._powerterm%29" class="techoutside" data-pltdoc="x"><span class="techinside">PowerTerm</span></a>], and from looking at a TeleVideo 950 keyboard.</div></p><h5>2.2.5<tt>&nbsp;</tt><a name="(part._.Keydec)"></a>Keydec</h5><p><div class="SIntrapara">A <a name="(tech._keydec)"></a><span style="font-style: italic">keydec</span> object is a key decoder for a specific variety of terminal, such
+as for a specific <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a>.  A keydec is used to turn received key encodings from a terminal into <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a> or <a href="/#%28tech._keyinfo%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyinfo</span></a> values.  A keydec is constructed from a prioritized list of <a href="/#%28tech._keyset%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyset</span></a> objects, with earlier-listed keysets taking priority of
+later-listed keysets when there is conflict between them as to how to decode a
+particular byte sequence.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keydec-id))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keydec-id</span></span><span class="hspace">&nbsp;</span><span class="RktVar">kd</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">symbol?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">kd</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></td></tr></table></blockquote></div><div class="SIntrapara">Gets the ID symbol of the <a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydec</span></a> being used.</div><div class="SIntrapara"><span class="SSubSubSubSection">ANSI Keydecs</span></div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-vt100-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-vt100-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"vt100"</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-vt220-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-vt220-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"vt220"</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-screen-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-screen-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"screen"</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-linux-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-linux-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"linux"</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-new-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-xterm-new-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"xterm-new"</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-xterm-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-xterm-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"xterm"</span>.  Currently same as the keydec for <span class="RktSym">xterm</span><span class="RktMeta"></span>, except for a different ID.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-rxvt-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-rxvt-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"rxvt"</span>.</div><div class="SIntrapara"><span class="SSubSubSubSection">Wyse Keydecs</span></div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-wy50-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-wy50-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"wy50"</span>.</div><div class="SIntrapara"><span class="SSubSubSubSection">TeleVideo Keydecs</span></div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-tvi925-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-tvi925-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"tvi925"</span>.</div><div class="SIntrapara"><span class="SSubSubSubSection">ASCII Keydecs</span></div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-ascii-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-ascii-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktVal">"ascii"</span>.</div><div class="SIntrapara"><span class="SSubSubSubSection">Default Keydecs</span></div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-ansi-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-ansi-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for any presumed ANSI-ish terminal, combining many ANSI-ish <a href="/#%28tech._keyset%29" class="techoutside" data-pltdoc="x"><span class="techinside">keysets</span></a>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>value</p></div></div><p class="RForeground"><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-insane-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-insane-keydec</span></span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm-keydec?</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara"><a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">Keydec</span></a> for the uniquely desperate situation of wanting to possibly have
+extensive key decoding for a terminal that might not even be ansi, but be
+Wyse, TeleVideo, or some other ASCII.</div></p><h4>2.3<tt>&nbsp;</tt><a name="(part._.Termvar)"></a>Termvar</h4><p>A <a name="(tech._termvar)"></a><span style="font-style: italic">termvar</span> is what the <span class="RktSym">charterm</span><span class="RktMeta"></span> package calls the value of the Unix-like <span class="RktSym">TERM</span><span class="RktMeta"></span> environment variable.  Each <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> has a default <a href="/#%28tech._protocol%29" class="techoutside" data-pltdoc="x"><span class="techinside">protocol</span></a> and <a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydec</span></a>.  Note, however, that <span class="RktSym">TERM</span><span class="RktMeta"></span> is not always a precise indicator of the best protocol and keydec,
+but by default we work with what we have.</p><h3>3<tt>&nbsp;</tt><a name="(part._charterm_.Object)"></a><span class="RktSym">charterm</span><span class="RktMeta"></span> Object</h3><p><div class="SIntrapara">The <span class="RktSym">charterm</span> object captures the state of a session with a particular terminal.</div><div class="SIntrapara">A <span class="RktSym">charterm</span> object is also a synchronizable event, so it can be used with
+procedures such as <span class="RktSym">sync</span>.  As an event, it becomes ready when there is at least one byte
+available for reading from the terminal, and its synchronization result is
+itself.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm~3f))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm?</span></span><span class="hspace">&nbsp;</span><span class="RktVar">x</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">x</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">any/c</span></td></tr></table></blockquote></div><div class="SIntrapara">Predicate for whether or not <span class="RktVar">x</span> is a <span class="RktSym">charterm</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-termvar))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-termvar</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">string?</span><span class="RktPn">)</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span></td></tr></table></blockquote></div><div class="SIntrapara">Gets the <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-protocol))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-protocol</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">symbol?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span></td></tr></table></blockquote></div><div class="SIntrapara">Gets the <a href="/#%28tech._protocol%29" class="techoutside" data-pltdoc="x"><span class="techinside">protocol</span></a>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-keydec))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-keydec</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">symbol?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span></td></tr></table></blockquote></div><div class="SIntrapara">Gets the <a href="/#%28tech._keydec%29" class="techoutside" data-pltdoc="x"><span class="techinside">keydec</span></a>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>parameter</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._current-charterm))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">current-charterm</span></span><span class="RktPn"></span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="RktPn">)</span></p></blockquote></td></tr><tr><td><span class="RktPn">(</span><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">current-charterm</span></span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym"><a href="/servlets/doc-search.rkt?tag=KCgzKSAwICgpIDAgKCkgKCkgKHEgZGVmICgocXVvdGUgIyVrZXJuZWwpIHZvaWQ%2FKSkp%0D%0A" class="RktValLink" data-pltdoc="x">void?</a></span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">This parameter provides the default <span class="RktSym">charterm</span> for most of the other procedures.  It is usually set automatically by <span class="RktSym">call-with-charterm</span>, <span class="RktSym">with-charterm</span>, <span class="RktSym">open-charterm</span>, and <span class="RktSym">close-charterm</span>.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><table cellspacing="0" class="prototype RForeground"><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._open-charterm))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">open-charterm</span></span></td><td><span class="hspace">&nbsp;</span>[</td><td><span class="RktPn">#:tty</span><span class="hspace">&nbsp;</span><span class="RktVar">tty</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">#:current?</span><span class="hspace">&nbsp;</span><span class="RktVar">current?</span>]<span class="RktPn">)</span></td><td><span class="hspace">&nbsp;</span></td><td>&rarr;</td><td><span class="hspace">&nbsp;</span></td><td><span class="RktSym">charterm?</span></td></tr></table></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">tty</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">path-string?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">#f</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">current?</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">#t</span></td></tr></table></blockquote></div><div class="SIntrapara">Returns an open <span class="RktSym">charterm</span> object, by opening I/O ports on the terminal device at <span class="RktVar">tty</span> (or, if <span class="RktVal">#f</span>, file <span class="stt">"/dev/tty"</span>), and setting raw mode and disabling echo (via <span class="stt">"/bin/stty"</span>).  If <span class="RktVar">current?</span> is true, the <span class="RktSym">current-charterm</span> parameter is also set to this object.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._close-charterm))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">close-charterm</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Closes <span class="RktVar">ct</span> by closing the I/O ports, and undoing <span class="RktSym">open-charterm</span>&rsquo;s changes via <span class="stt">"/bin/stty"</span>.  If <span class="RktSym">current-charterm</span> is set to <span class="RktVar">ct</span>, then that parameter will be changed to <span class="RktVal">#f</span> for good measure.  You might wish to use <span class="RktSym">with-charterm</span> instead of worrying about calling <span class="RktSym">close-charterm</span> directly.</div><div class="SIntrapara">Note: If you exit your Racket process without properly closing the <span class="RktSym">charterm</span>, your terminal may be left in a crazy state.  You can fix it with
+the command:</div><div class="SIntrapara"><span class="hspace">&nbsp;&nbsp;</span><span class="stt">stty sane</span></div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>syntax</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(form._((planet._main..rkt._(neil._charterm..plt._3._1))._with-charterm))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">with-charterm</span></span><span class="hspace">&nbsp;</span><span class="RktVar">expr?</span><span class="hspace">&nbsp;</span><span class="RktMeta">...</span><span class="RktPn">)</span></p></blockquote></td></tr></table></blockquote></div><div class="SIntrapara">Opens a <span class="RktSym">charterm</span> and evaluates the body expressions in sequence with <span class="RktSym">current-charterm</span> set appropriately.  When control jumps out of the body, in a
+manner of speaking, the <span class="RktSym">charterm</span> is closed.</div></p><h3>4<tt>&nbsp;</tt><a name="(part._.Terminal_.Information)"></a>Terminal Information</h3><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-screen-size))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-screen-size</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span></p></blockquote></td></tr><tr><td><table cellspacing="0" class="prototype"><tr><td><span class="hspace">&nbsp;</span></td><td>&rarr;</td><td><span class="hspace">&nbsp;</span></td><td><table cellspacing="0"><tr><td><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">exact-nonnegative-integer?</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">exact-nonnegative-integer?</span><span class="RktPn">)</span></td></tr></table></td></tr></table></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Attempts to get the screen size, in character columns and rows.
+It may do this through a control sequence or through <span class="RktSym">/bin/stty</span><span class="RktMeta"></span>.  If unable to get a value, then default of (80,24) is used.</div><div class="SIntrapara">The current behavior in this version of <span class="RktSym">charterm</span><span class="RktMeta"></span> is to adaptively try different methods of getting screen size,
+and to remember what worked for the next time this procedure is called for <span class="RktVar">ct</span>.  For terminals that are identified as <span class="RktSym">screen</span><span class="RktMeta"></span> by the <span class="RktSym">TERM</span><span class="RktMeta"></span> environment variable (e.g., terminal emulators like GNU Screen
+and <span class="RktSym">tmux</span><span class="RktMeta"></span>), the current behavior is to not try the control sequence (which
+causes a 1-second delay waiting for a terminal response that never arrives),
+and to just use <span class="RktSym">stty</span><span class="RktMeta"></span>.  For all other terminals, the control sequence is tried first, before trying <span class="RktSym">stty</span><span class="RktMeta"></span>.  If neither the control sequence nor <span class="RktSym">stty</span><span class="RktMeta"></span> work, then neither method is tried again for <span class="RktVar">ct</span>, and instead the procedure always returns (<span class="RktVal">#f</span>, <span class="RktVal">#f</span>).  This behavior very well might change in future versions of <span class="RktSym">charterm</span><span class="RktMeta"></span>, and the author welcomes feedback on which methods work with
+which terminals.</div></p><h3>5<tt>&nbsp;</tt><a name="(part._.Display_.Control)"></a>Display Control</h3><h4>5.1<tt>&nbsp;</tt><a name="(part._.Cursor)"></a>Cursor</h4><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-cursor))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-cursor</span></span><span class="hspace">&nbsp;</span><span class="RktVar">x</span><span class="hspace">&nbsp;</span><span class="RktVar">y</span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">x</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">exact-positive-integer?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">y</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">exact-positive-integer?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Positions the cursor at column <span class="RktVar">x</span>, row <span class="RktVar">y</span>, with the upper-left character cell being (1, 1).</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-newline))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-newline</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Sends a newline to the terminal.  This is typically a CR-LF
+sequence.</div></p><h4>5.2<tt>&nbsp;</tt><a name="(part._.Displaying)"></a>Displaying</h4><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><table cellspacing="0" class="prototype RForeground"><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-display))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-display</span></span></td><td><span class="hspace">&nbsp;</span>[</td><td><span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">#:width</span><span class="hspace">&nbsp;</span><span class="RktVar">width</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">#:pad</span><span class="hspace">&nbsp;</span><span class="RktVar">pad</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">#:truncate</span><span class="hspace">&nbsp;</span><span class="RktVar">truncate</span>]</td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktVar">arg</span><span class="hspace">&nbsp;</span><span class="RktMeta">...</span><span class="RktPn">)</span></td><td><span class="hspace">&nbsp;</span></td><td>&rarr;</td><td><span class="hspace">&nbsp;</span></td><td><span class="RktSym">void?</span></td></tr></table></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">width</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">exact-positive-integer?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">#f</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">pad</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">width</span><span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">width</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">truncate</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">width</span><span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">'</span><span class="RktVal">width</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">arg</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">any/c</span></td></tr></table></blockquote></div><div class="SIntrapara">Displays each <span class="RktVar">arg</span> on the terminal, as if formatted by <span class="RktSym">display</span>, with the exception that unprintable or non-ASCII characters
+might not be displayed.  (The exact behavior of what is permitted is expected
+to change in a later version of CharTerm, so avoid trying to send your own control sequences or using
+newlines, making assumptions about non-ASCII characters, etc.)</div><div class="SIntrapara">If <span class="RktVar">width</span> is a number, then <span class="RktVar">pad</span> and <span class="RktVar">truncate</span> specify whether or not to pad with spaces or truncate the output, respectively, to <span class="RktVar">width</span> characters.  When <span class="RktVar">pad</span> or <span class="RktVar">width</span> is <span class="RktVal">'</span><span class="RktVal">width</span>, that is a convenience meaning &ldquo;true if, and only if, <span class="RktVar">width</span> is not <span class="RktVal">#f</span>.&rdquo;</div></p><h4>5.3<tt>&nbsp;</tt><a name="(part._.Video_.Attributes)"></a>Video Attributes</h4><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-normal))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-normal</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-inverse))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-inverse</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-underline))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-underline</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-blink))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-blink</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-bold))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-bold</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Sets the <a name="(tech._video._attribute)"></a><span style="font-style: italic">video attributes</span> for subsequent writes to the terminal.  In this version of <span class="RktSym">charterm</span><span class="RktMeta"></span>, each is mutually-exclusive, so, for example, setting <span style="font-style: italic">bold</span> clears <span style="font-style: italic">inverse</span>. Note that that video attributes are currently supported only for protocol <span class="RktVal">'</span><span class="RktVal">ansi</span>, due to limitations of the TeleVideo and Wyse models for
+video attributes.</div></p><h4>5.4<tt>&nbsp;</tt><a name="(part._.Clearing)"></a>Clearing</h4><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-screen))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-clear-screen</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Clears the screen, including first setting the video attributes to
+normal, and positioning the cursor at (1, 1).</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-line))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-clear-line</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-line-left))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-clear-line-left</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-clear-line-right))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-clear-line-right</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Clears text from the line with the cursor, or part of the line with the cursor.</div></p><h4>5.5<tt>&nbsp;</tt><a name="(part._.Line_.Insert_and_.Delete)"></a>Line Insert and Delete</h4><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-insert-line))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-insert-line</span></span><span class="hspace">&nbsp;</span>[<span class="RktVar">count</span><span class="hspace">&nbsp;</span><span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">count</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">exact-positive-integer?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">1</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Inserts <span class="RktVar">count</span> blank lines at cursor.  Note that not all terminals support
+this.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-delete-line))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-delete-line</span></span><span class="hspace">&nbsp;</span>[<span class="RktVar">count</span><span class="hspace">&nbsp;</span><span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">count</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">exact-positive-integer?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">1</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Deletes <span class="RktVar">count</span> blank lines at cursor.  Note that not all terminals support
+this.</div></p><h5>5.5.1<tt>&nbsp;</tt><a name="(part._.Misc__.Output)"></a>Misc. Output</h5><p><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-bell))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-bell</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">void?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Rings the terminal bell.  This bell ringing might manifest as a
+beep, a flash of the screen, or nothing.</div></p><h3>6<tt>&nbsp;</tt><a name="(part._.Keyboard_.Input)"></a>Keyboard Input</h3><p><div class="SIntrapara">Normally you will get keyboard input using the <span class="RktSym">charterm-read-key</span> procedure.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><p class="RForeground"><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-byte-ready~3f))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-byte-ready?</span></span><span class="hspace">&nbsp;</span>[<span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span>]<span class="RktPn">)</span><span class="hspace">&nbsp;</span>&rarr;<span class="hspace">&nbsp;</span><span class="RktSym">boolean?</span></p></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr></table></blockquote></div><div class="SIntrapara">Returns true/false for whether at least one byte is ready for
+reading (either in a buffer or on the port) from <span class="RktVar">ct</span>.  Note that, since some keys are encoded as multiple bytes, just
+because this procedure returns true doesn&rsquo;t mean that <span class="RktSym">charterm-read-key</span> won&rsquo;t block temporarily because it sees part of a potential
+multiple-byte key encoding.</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><table cellspacing="0" class="prototype RForeground"><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-read-key))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-read-key</span></span></td><td><span class="hspace">&nbsp;</span>[</td><td><span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">#:timeout</span><span class="hspace">&nbsp;</span><span class="RktVar">timeout</span>]<span class="RktPn">)</span></td><td><span class="hspace">&nbsp;</span></td><td>&rarr;</td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">(</span><span class="RktSym">or</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">char?</span><span class="hspace">&nbsp;</span><span class="RktSym">symbol?</span><span class="RktPn">)</span></td></tr></table></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">timeout</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">positive?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">#f</span></td></tr></table></blockquote></div><div class="SIntrapara">Reads a key from <span class="RktVar">ct</span>, blocking indefinitely or until sometime after <span class="RktVar">timeout</span> seconds has been reached, if <span class="RktVar">timeout</span> is non-<span class="RktVal">#f</span>.  If timeout is reached, <span class="RktVal">#f</span> is returned.</div><div class="SIntrapara">Many keys are returned as characters, especially ones that
+correspond to printable characters.  For example, the unshifted <span style="font-weight: bold">Q</span> key is returned as character <span class="RktVal">#\q</span>.  Some other keys are returned as symbols, such as <span class="RktVal">'</span><span class="RktVal">return</span>, <span class="RktVal">'</span><span class="RktVal">escape</span>, <span class="RktVal">'</span><span class="RktVal">f1</span>, <span class="RktVal">'</span><span class="RktVal">shift-f12</span>, <span class="RktVal">'</span><span class="RktVal">right</span>, and many others.</div><div class="SIntrapara">Since some keys are sent as ambiguous sequences, <span class="RktSym">charterm-read-key</span> employs separate timeouts internally, such as to disambuate
+the <span style="font-weight: bold">Esc</span> key (byte sequence 27) from what on some terminals would be
+the <span style="font-weight: bold">F10</span> key (bytes sequence 27, 91, 50, 49, 126).</div><div class="SIntrapara"><blockquote class="SVInsetFlow"><table cellspacing="0" class="boxed RBoxed"><tr><td><blockquote class="SubFlow"><div class="RBackgroundLabel SIEHidden"><div class="RBackgroundLabelInner"><p>procedure</p></div></div><table cellspacing="0" class="prototype RForeground"><tr><td><span class="RktPn">(</span><a name="(def._((planet._main..rkt._(neil._charterm..plt._3._1))._charterm-read-keyinfo))"></a><span title="Provided from: (planet neil/charterm:3:1)"><span class="RktSym">charterm-read-keyinfo</span></span></td><td><span class="hspace">&nbsp;</span>[</td><td><span class="RktPn">#:charterm</span><span class="hspace">&nbsp;</span><span class="RktVar">ct</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td></tr><tr><td><span class="hspace">&nbsp;</span></td><td><span class="hspace">&nbsp;</span></td><td><span class="RktPn">#:timeout</span><span class="hspace">&nbsp;</span><span class="RktVar">timeout</span>]<span class="RktPn">)</span></td><td><span class="hspace">&nbsp;</span></td><td>&rarr;</td><td><span class="hspace">&nbsp;</span></td><td><span class="RktSym">charterm-keyinfo?</span></td></tr></table></blockquote></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">ct</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktSym">charterm?</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">current-charterm</span><span class="RktPn">)</span></td></tr><tr><td><span class="hspace">&nbsp;&nbsp;</span><span class="RktVar">timeout</span><span class="hspace">&nbsp;</span>:<span class="hspace">&nbsp;</span><span class="RktPn">(</span><span class="RktSym">or/c</span><span class="hspace">&nbsp;</span><span class="RktVal">#f</span><span class="hspace">&nbsp;</span><span class="RktSym">positive?</span><span class="RktPn">)</span><span class="hspace">&nbsp;</span>=<span class="hspace">&nbsp;</span><span class="RktVal">#f</span></td></tr></table></blockquote></div><div class="SIntrapara">Like <span class="RktSym">charterm-read-keyinfo</span> except instead of returning a <a href="/#%28tech._keycode%29" class="techoutside" data-pltdoc="x"><span class="techinside">keycode</span></a>, it returns a <a href="/#%28tech._keyinfo%29" class="techoutside" data-pltdoc="x"><span class="techinside">keyinfo</span></a>.</div></p><h3>7<tt>&nbsp;</tt><a name="(part._.References)"></a>References</h3><p><div class="SIntrapara">[<a name="(tech._ansi._x3..64)"></a><span style="font-style: italic">ANSI X3.64</span>] <a href="http://en.wikipedia.org/wiki/ANSI_escape_code"><span class="url">http://en.wikipedia.org/wiki/ANSI_escape_code</span></a></div><div class="SIntrapara">[<a name="(tech._ascii)"></a><span style="font-style: italic">ASCII</span>] <a href="http://en.wikipedia.org/wiki/Ascii"><span class="url">http://en.wikipedia.org/wiki/Ascii</span></a></div><div class="SIntrapara">[<a name="(tech._ecma._43)"></a><span style="font-style: italic">ECMA-43</span>] <a href="http://www.ecma-international.org/publications/standards/Ecma-043.htm"><span style="font-style: italic">Standard ECMA-43: 8-bit Coded Character Set Structure and Rules</span></a>, 3rd Ed., 1991-12</div><div class="SIntrapara">[<a name="(tech._ecma._48)"></a><span style="font-style: italic">ECMA-48</span>] <a href="http://www.ecma-international.org/publications/standards/Ecma-048.htm"><span style="font-style: italic">Standard ECMA-48: Control Functions for Coded Character Sets</span></a>, 5th Ed., 1991-06</div><div class="SIntrapara">[<a name="(tech._gregory)"></a><span style="font-style: italic">Gregory</span>] Phil Gregory, &ldquo;<a href="http://aperiodic.net/phil/archives/Geekery/term-function-keys.html">Terminal Function Key Escape Codes</a>,&rdquo; 2005-12-13 Web post, as viewed on 2012-06</div><div class="SIntrapara">[<a name="(tech._powerterm)"></a><span style="font-style: italic">PowerTerm</span>] Ericom PowerTerm InterConnect 8.2.0.1000 terminal emulator, as run on Wyse S50 WinTerm</div><div class="SIntrapara">[<a name="(tech._tvi._925._iug)"></a><span style="font-style: italic">TVI-925-IUG</span>] <a href="http://vt100.net/televideo/tvi925_ig.pdf"><span style="font-style: italic">TeleVideo Model 925 CRT Terminal Installation and User&rsquo;s Guide</span></a></div><div class="SIntrapara">[<a name="(tech._tvi._950._om)"></a><span style="font-style: italic">TVI-950-OM</span>] <a href="http://www.mirrorservice.org/sites/www.bitsavers.org/pdf/televideo/Operators_Manual_Model_950_1981.pdf"><span style="font-style: italic">TeleVideo Operator&rsquo;s Manual Model 950</span></a>, 1981</div><div class="SIntrapara">[<a name="(tech._vt100._tm)"></a><span style="font-style: italic">VT100-TM</span>] Digital Equipment Corp., <a href="http://vt100.net/docs/vt100-tm/"><span style="font-style: italic">VT100 Series Technical Manual</span></a>, 2nd Ed., 1980-09</div><div class="SIntrapara">[<a name="(tech._vt100._ug)"></a><span style="font-style: italic">VT100-UG</span>] Digital Equipment Corp., <a href="http://vt100.net/docs/vt100-ug/"><span style="font-style: italic">VT100 User Guide</span></a>, 3rd Ed., 1981-06</div><div class="SIntrapara">[<a name="(tech._vt100._wp)"></a><span style="font-style: italic">VT100-WP</span>] Wikipedia, <a href="http://en.wikipedia.org/wiki/VT100">VT100</a></div><div class="SIntrapara">[<a name="(tech._wy._50._qrg)"></a><span style="font-style: italic">WY-50-QRG</span>] <a href="http://vt100.net/wyse/wy-50-qrg/wy-50-qrg.pdf"><span style="font-style: italic">Wyse WY-50 Display Terminal Quick-Reference Guide</span></a></div><div class="SIntrapara">[<a name="(tech._wy._60._ug)"></a><span style="font-style: italic">WY-60-UG</span>] <a href="http://vt100.net/wyse/wy-60-ug/wy-60-ug.pdf"><span style="font-style: italic">Wyse WY-60 User&rsquo;s Guide</span></a></div><div class="SIntrapara">[<a name="(tech._wy60)"></a><span style="font-style: italic">wy60</span>] <a href="http://code.google.com/p/wy60/"><span class="RktSym">wy60</span><span class="RktMeta"></span> terminal emulator</a></div><div class="SIntrapara">[<a name="(tech._xterm._ctlseq)"></a><span style="font-style: italic">XTerm-ctlseqs</span>] Edward Moy, Stephen Gildea, Thomas Dickey, &ldquo;<a href="http://invisible-island.net/xterm/ctlseqs/ctlseqs.html">Xterm Control Sequences</a>,&rdquo; 2012</div><div class="SIntrapara">[<a name="(tech._xterm._dickey)"></a><span style="font-style: italic">XTerm-Dickey</span>] <a href="http://invisible-island.net/xterm/"><span class="url">http://invisible-island.net/xterm/</span></a></div><div class="SIntrapara">[<a name="(tech._xterm._faq)"></a><span style="font-style: italic">XTerm-FAQ</span>] Thomas E. Dickey, &ldquo;<a href="http://invisible-island.net/xterm/xterm.faq.html">XTerm FAQ</a>,&rdquo; dated 2012</div><div class="SIntrapara">[<a name="(tech._xterm._wp)"></a><span style="font-style: italic">XTerm-WP</span>] Wikipedia, <a href="http://en.wikipedia.org/wiki/Xterm">xterm</a></div></p><h3>8<tt>&nbsp;</tt><a name="(part._.Known_.Issues)"></a>Known Issues</h3><ul><li><p>Need to support ANSI alternate CSI for 8-bit terminals, even
+before supporting 8-bit characters and multibyte.</p></li><li><p>Only supports ASCII characters.  Adding UTF-8 support, for terminal emulators
+that support it, would be nice.</p></li><li><p>Expose the character-decoding mini-language as a configurable
+option.  Perhaps wait until we implement timeout-based disambiguation at
+arbitrary points in the the DFA rather than just at the top.  Also, might be
+better to resolve multi-byte characters first, in case that affects the
+mini-language.</p></li><li><p>More controls for terminal features can be added.</p></li><li><p>Currently only implemented to work on Unix-like systems like
+GNU/Linux.</p></li><li><p>Implement text input controls, either as part of this library or
+another, using <span class="RktSym">charterm-demo</span> as a starting point.</p></li></ul><h3>9<tt>&nbsp;</tt><a name="(part._.History)"></a>History</h3><ul><li><p><div class="SIntrapara">PLaneT 3:1 &#8212;<wbr></wbr> 2013-05-13</div><div class="SIntrapara"><ul><li><p>Now uses lowercase <span class="RktSym"><span class="nobreak">-f</span></span><span class="RktMeta"></span> argument on MacOS X.  (Thanks to Jens Axel S&#248;gaard for reporting.)</p></li><li><p>Documentation tweaks.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 3:0 &#8212;<wbr></wbr> 2012-07-13</div><div class="SIntrapara"><ul><li><p>Changed &ldquo;<span class="RktSym">ansi-ish</span><span class="RktMeta"></span>&rdquo; in identifiers to &ldquo;<span class="RktSym">ansi</span><span class="RktMeta"></span>&rdquo;, hence the PLaneT major version number change.</p></li><li><p>Documentation tweaks.</p></li><li><p>Renamed package from &ldquo;<span class="RktSym">charterm</span><span class="RktMeta"></span>&rdquo; to &ldquo;CharTerm&rdquo;.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 2:5 &#8212;<wbr></wbr> 2012-06-28</div><div class="SIntrapara"><ul><li><p>A <span class="RktSym">charterm</span> object is now a synchronizable event.</p></li><li><p>Documentation tweaks.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 2:4 &#8212;<wbr></wbr> 2012-06-25</div><div class="SIntrapara"><ul><li><p>Documentation fix for return type of <span class="RktSym">charterm-read-keyinfo</span>.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 2:3 &#8212;<wbr></wbr> 2012-06-25</div><div class="SIntrapara"><ul><li><p>Fixed problem determining screen size on some
+XTerms.  (Thanks to Eli Barzilay for reporting.)</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 2:2 &#8212;<wbr></wbr> 2012-06-25</div><div class="SIntrapara"><ul><li><p>Added another variation of encoding for XTerm arrow,
+Home, and End keys.  (Thanks to Eli Barzilay.)</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 2:1 &#8212;<wbr></wbr> 2012-06-24</div><div class="SIntrapara"><ul><li><p>Corrected PLaneT version number in <span class="RktSym">require</span> in an example.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 2:0 &#8212;<wbr></wbr> 2012-06-24</div><div class="SIntrapara"><ul><li><p>Greatly increased the sophistication of handling of terminal diversity.</p></li><li><p>Added the <span class="RktSym">wyse-wy50</span><span class="RktMeta"></span> and <span class="RktSym">televideo-950</span><span class="RktMeta"></span> [Correction: <span class="RktSym">televideo-925</span><span class="RktMeta"></span>] protocols, for supporting the native modes of Wyse and
+TeleVideo terminals, respectively, and compatibles.</p></li><li><p>More support for different key encodings and termvars.</p></li><li><p>Demo is now in a separate file, mainly for convenience
+in giving command lines that run it.  This breaks a command line example
+previously documented, so changed PLaneT major version, although the
+previously-published example will need to have <span class="RktSym">:1</span><span class="RktMeta"></span> added to it anyway.</p></li><li><p><span class="RktSym">charterm-screen-size</span> now defaults to (80,24) when all else fails.</p></li><li><p>Documentation changes.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 1:1 &#8212;<wbr></wbr> 2012-06-17</div><div class="SIntrapara"><ul><li><p>For <span class="RktSym">screen</span><span class="RktMeta"></span> and <span class="RktSym">tmux</span><span class="RktMeta"></span>, now gets screen size via <span class="RktSym">stty</span><span class="RktMeta"></span>.  This resolves the sluggishness reported with <span class="RktSym">screen</span><span class="RktMeta"></span>.  [Correction: In version 1:1, this behavior is
+adaptive for all terminals, with the shortcut for <a href="/#%28tech._termvar%29" class="techoutside" data-pltdoc="x"><span class="techinside">termvar</span></a> <span class="RktSym">screen</span><span class="RktMeta"></span> that it doesn&rsquo;t bother trying the control sequence.]</p></li><li><p>Documentation tweaks.</p></li></ul></div></p></li><li><p><div class="SIntrapara">PLaneT 1:0 &#8212;<wbr></wbr> 2012-06-16</div><div class="SIntrapara"><ul><li><p>Initial version.</p></li></ul></div></p></li></ul><h3>10<tt>&nbsp;</tt><a name="(part._.Legal)"></a>Legal</h3><p>Copyright 2012 &ndash; 2013 Neil Van Dyke.  This program is Free Software; you
+can redistribute it and/or modify it under the terms of the GNU Lesser General
+Public License as published by the Free Software Foundation; either version 3
+of the License, or (at your option) any later version.  This program is
+distributed in the hope that it will be useful, but without any warranty;
+without even the implied warranty of merchantability or fitness for a
+particular purpose.  See http://www.gnu.org/licenses/ for details.  For other
+licenses and consulting, please contact the author.</p></div></div><div id="contextindicator">&nbsp;</div></body></html>
\ No newline at end of file
diff --git a/archive/0.vm.arc/charterm/planet-docs/doc/racket.css b/archive/0.vm.arc/charterm/planet-docs/doc/racket.css
new file mode 100644
index 00000000..021e4da5
--- /dev/null
+++ b/archive/0.vm.arc/charterm/planet-docs/doc/racket.css
@@ -0,0 +1,234 @@
+
+/* See the beginning of "scribble.css". */
+
+/* Monospace: */
+.RktIn, .RktRdr, .RktPn, .RktMeta,
+.RktMod, .RktKw, .RktVar, .RktSym,
+.RktRes, .RktOut, .RktCmt, .RktVal,
+.RktBlk {
+  font-family: monospace;
+  white-space: inherit;
+}
+
+/* Serif: */
+.inheritedlbl {
+  font-family: serif;
+}
+
+/* Sans-serif: */
+.RBackgroundLabelInner {
+  font-family: sans-serif;
+}
+
+/* ---------------------------------------- */
+/* Inherited methods, left margin */
+
+.inherited {
+  width: 100%;
+  margin-top: 0.5em;
+  text-align: left;
+  background-color: #ECF5F5;
+}
+
+.inherited td {
+  font-size: 82%;
+  padding-left: 1em;
+  text-indent: -0.8em;
+  padding-right: 0.2em;
+}
+
+.inheritedlbl {
+  font-style: italic;
+}
+
+/* ---------------------------------------- */
+/* Racket text styles */
+
+.RktIn {
+  color: #cc6633;
+  background-color: #eeeeee;
+}
+
+.RktInBG {
+  background-color: #eeeeee;
+}
+
+.RktRdr {
+}
+
+.RktPn {
+  color: #843c24;
+}
+
+.RktMeta {
+  color: black;
+}
+
+.RktMod {
+  color: black;
+}
+
+.RktOpt {
+  color: black;
+}
+
+.RktKw {
+  color: black;
+  /* font-weight: bold; */
+}
+
+.RktErr {
+  color: red;
+  font-style: italic;
+}
+
+.RktVar {
+  color: #262680;
+  font-style: italic;
+}
+
+.RktSym {
+  color: #262680;
+}
+
+.RktValLink {
+  text-decoration: none;
+  color: blue;
+}
+
+.RktModLink {
+  text-decoration: none;
+  color: blue;
+}
+
+.RktStxLink {
+  text-decoration: none;
+  color: black;
+  /* font-weight: bold; */
+}
+
+.RktRes {
+  color: #0000af;
+}
+
+.RktOut {
+  color: #960096;
+}
+
+.RktCmt {
+  color: #c2741f;
+}
+
+.RktVal {
+  color: #228b22;
+}
+
+/* ---------------------------------------- */
+/* Some inline styles */
+
+.together {
+  width: 100%;
+}
+
+.prototype, .argcontract, .RBoxed {
+  white-space: nowrap;
+}
+
+.prototype td {
+  vertical-align: text-top;
+}
+.longprototype td {
+  vertical-align: bottom;
+}
+
+.RktBlk {
+  white-space: inherit;
+  text-align: left;
+}
+
+.RktBlk tr {
+  white-space: inherit;
+}
+
+.RktBlk td {
+  vertical-align: baseline;
+  white-space: inherit;
+}
+
+.argcontract td {
+  vertical-align: text-top;
+}
+
+.highlighted {
+  background-color: #ddddff;
+}
+
+.defmodule {
+  width: 100%;
+  background-color: #F5F5DC;
+}
+
+.specgrammar {
+  float: right;
+}
+
+.RBibliography td {
+  vertical-align: text-top;
+}
+
+.leftindent {
+ margin-left: 1em;
+ margin-right: 0em;
+}
+
+.insetpara {
+ margin-left: 1em;
+ margin-right: 1em;
+}
+
+.Rfilebox {
+}
+
+.Rfiletitle {
+  text-align: right;
+  margin: 0em 0em 0em 0em;
+}
+
+.Rfilename {
+  border-top: 1px solid #6C8585;
+  border-right: 1px solid #6C8585;
+  padding-left: 0.5em;
+  padding-right: 0.5em;
+  background-color: #ECF5F5;
+}
+
+.Rfilecontent {
+  margin: 0em 0em 0em 0em;
+}
+
+/* ---------------------------------------- */
+/* For background labels */
+
+.RBackgroundLabel {
+   float: right;
+   width: 0px;
+   height: 0px;
+}
+
+.RBackgroundLabelInner {
+   position: relative;
+   width: 25em;
+   left: -25.5em;
+   top: 0px;
+   text-align: right;
+   color: white;
+   z-index: 0;
+   font-weight: bold;
+}
+
+.RForeground {
+   position: relative;
+   left: 0px;
+   top: 0px;
+   z-index: 1;
+}
diff --git a/archive/0.vm.arc/charterm/planet-docs/doc/scribble-common.js b/archive/0.vm.arc/charterm/planet-docs/doc/scribble-common.js
new file mode 100644
index 00000000..00eec767
--- /dev/null
+++ b/archive/0.vm.arc/charterm/planet-docs/doc/scribble-common.js
@@ -0,0 +1,153 @@
+// Common functionality for PLT documentation pages
+
+// Page Parameters ------------------------------------------------------------
+
+var page_query_string =
+  (location.href.search(/\?([^#]+)(?:#|$)/) >= 0) && RegExp.$1;
+
+var page_args =
+  ((function(){
+      if (!page_query_string) return [];
+      var args = page_query_string.split(/[&;]/);
+      for (var i=0; i<args.length; i++) {
+        var a = args[i];
+        var p = a.indexOf('=');
+        if (p >= 0) args[i] = [a.substring(0,p), a.substring(p+1)];
+        else args[i] = [a, false];
+      }
+      return args;
+    })());
+
+function GetPageArg(key, def) {
+  for (var i=0; i<page_args.length; i++)
+    if (page_args[i][0] == key) return unescape(page_args[i][1]);
+  return def;
+}
+
+function MergePageArgsIntoLink(a) {
+  if (page_args.length == 0 ||
+      (!a.attributes["data-pltdoc"]) || (a.attributes["data-pltdoc"].value == ""))
+    return;
+  a.href.search(/^([^?#]*)(?:\?([^#]*))?(#.*)?$/);
+  if (RegExp.$2.length == 0) {
+    a.href = RegExp.$1 + "?" + page_query_string + RegExp.$3;
+  } else {
+    // need to merge here, precedence to arguments that exist in `a'
+    var i, j;
+    var prefix = RegExp.$1, str = RegExp.$2, suffix = RegExp.$3;
+    var args = str.split(/[&;]/);
+    for (i=0; i<args.length; i++) {
+      j = args[i].indexOf('=');
+      if (j) args[i] = args[i].substring(0,j);
+    }
+    var additions = "";
+    for (i=0; i<page_args.length; i++) {
+      var exists = false;
+      for (j=0; j<args.length; j++)
+        if (args[j] == page_args[i][0]) { exists = true; break; }
+      if (!exists) str += "&" + page_args[i][0] + "=" + page_args[i][1];
+    }
+    a.href = prefix + "?" + str + suffix;
+  }
+}
+
+// Cookies --------------------------------------------------------------------
+
+function GetCookie(key, def) {
+  var i, cookiestrs;
+  try {
+    if (document.cookie.length <= 0) return def;
+    cookiestrs = document.cookie.split(/; */);
+  } catch (e) { return def; }
+  for (i = 0; i < cookiestrs.length; i++) {
+    var cur = cookiestrs[i];
+    var eql = cur.indexOf('=');
+    if (eql >= 0 && cur.substring(0,eql) == key)
+      return unescape(cur.substring(eql+1));
+  }
+  return def;
+}
+
+function SetCookie(key, val) {
+  var d = new Date();
+  d.setTime(d.getTime()+(365*24*60*60*1000));
+  try {
+    document.cookie =
+      key + "=" + escape(val) + "; expires="+ d.toGMTString() + "; path=/";
+  } catch (e) {}
+}
+
+// note that this always stores a directory name, ending with a "/"
+function SetPLTRoot(ver, relative) {
+  var root = location.protocol + "//" + location.host
+           + NormalizePath(location.pathname.replace(/[^\/]*$/, relative));
+  SetCookie("PLT_Root."+ver, root);
+}
+
+// adding index.html works because of the above
+function GotoPLTRoot(ver, relative) {
+  var u = GetCookie("PLT_Root."+ver, null);
+  if (u == null) return true; // no cookie: use plain up link
+  // the relative path is optional, default goes to the toplevel start page
+  if (!relative) relative = "index.html";
+  location = u + relative;
+  return false;
+}
+
+// Utilities ------------------------------------------------------------------
+
+var normalize_rxs = [/\/\/+/g, /\/\.(\/|$)/, /\/[^\/]*\/\.\.(\/|$)/];
+function NormalizePath(path) {
+  var tmp, i;
+  for (i = 0; i < normalize_rxs.length; i++)
+    while ((tmp = path.replace(normalize_rxs[i], "/")) != path) path = tmp;
+  return path;
+}
+
+// `noscript' is problematic in some browsers (always renders as a
+// block), use this hack instead (does not always work!)
+// document.write("<style>mynoscript { display:none; }</style>");
+
+// Interactions ---------------------------------------------------------------
+
+function DoSearchKey(event, field, ver, top_path) {
+  var val = field.value;
+  if (event && event.keyCode == 13) {
+    var u = GetCookie("PLT_Root."+ver, null);
+    if (u == null) u = top_path; // default: go to the top path
+    u += "search/index.html?q=" + escape(val);
+    if (page_query_string) u += "&" + page_query_string;
+    location = u;
+    return false;
+  }
+  return true;
+}
+
+function TocviewToggle(glyph, id) {
+  var s = document.getElementById(id).style;
+  var expand = s.display == "none";
+  s.display = expand ? "block" : "none";
+  glyph.innerHTML = expand ? "&#9660;" : "&#9658;";
+}
+
+// Page Init ------------------------------------------------------------------
+
+// Note: could make a function that inspects and uses window.onload to chain to
+// a previous one, but this file needs to be required first anyway, since it
+// contains utilities for all other files.
+var on_load_funcs = [];
+function AddOnLoad(fun) { on_load_funcs.push(fun); }
+window.onload = function() {
+  for (var i=0; i<on_load_funcs.length; i++) on_load_funcs[i]();
+};
+
+AddOnLoad(function(){
+    var links = document.getElementsByTagName("a");
+    for (var i=0; i<links.length; i++) MergePageArgsIntoLink(links[i]);
+    var label = GetPageArg("ctxtname",false);
+    if (!label) return;
+    var indicator = document.getElementById("contextindicator");
+    if (!indicator) return;
+    indicator.innerHTML = label;
+    indicator.style.display = "block";
+  });
diff --git a/archive/0.vm.arc/charterm/planet-docs/doc/scribble-style.css b/archive/0.vm.arc/charterm/planet-docs/doc/scribble-style.css
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/archive/0.vm.arc/charterm/planet-docs/doc/scribble-style.css
diff --git a/archive/0.vm.arc/charterm/planet-docs/doc/scribble.css b/archive/0.vm.arc/charterm/planet-docs/doc/scribble.css
new file mode 100644
index 00000000..d521d28f
--- /dev/null
+++ b/archive/0.vm.arc/charterm/planet-docs/doc/scribble.css
@@ -0,0 +1,487 @@
+
+/* CSS seems backward: List all the classes for which we want a
+   particular font, so that the font can be changed in one place.  (It
+   would be nicer to reference a font definition from all the places
+   that we want it.)
+
+   As you read the rest of the file, remember to double-check here to
+   see if any font is set. */
+
+/* Monospace: */
+.maincolumn, .refpara, .refelem, .tocset, .stt, .hspace, .refparaleft, .refelemleft {
+  font-family: monospace;
+}
+
+/* Serif: */
+.main, .refcontent, .tocview, .tocsub, i {
+  font-family: serif;
+}
+
+/* Sans-serif: */
+.version, .versionNoNav {
+  font-family: sans-serif;
+}
+
+/* ---------------------------------------- */
+
+p, .SIntrapara {
+  display: block;
+  margin: 1em 0;
+}
+
+h2 { /* per-page main title */
+  margin-top: 0;
+}
+
+h3, h4, h5, h6, h7, h8 {
+  margin-top: 1.75em;
+  margin-bottom: 0.5em;
+}
+
+.SSubSubSubSection {
+  font-weight: bold;
+  font-size: 0.83em; /* should match h5; from HTML 4 reference */
+}
+
+/* Needed for browsers like Opera, and eventually for HTML 4 conformance.
+   This means that multiple paragraphs in a table element do not have a space
+   between them. */
+table p {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+/* ---------------------------------------- */
+/* Main */
+
+body {
+  color: black;
+  background-color: #ffffff;
+}
+
+table td {
+  padding-left: 0;
+  padding-right: 0;
+}
+
+.maincolumn {
+  width: 43em;
+  margin-right: -40em;
+  margin-left: 15em;
+}
+
+.main {
+  text-align: left;
+}
+
+/* ---------------------------------------- */
+/* Navigation */
+
+.navsettop, .navsetbottom {
+  background-color: #f0f0e0;
+  padding: 0.25em 0 0.25em 0;
+}
+
+.navsettop {
+  margin-bottom: 1.5em;
+  border-bottom: 2px solid #e0e0c0;
+}
+
+.navsetbottom {
+  margin-top: 2em;
+  border-top: 2px solid #e0e0c0;
+}
+
+.navleft {
+  margin-left: 1ex;
+  position: relative;
+  float: left;
+  white-space: nowrap;
+}
+.navright {
+  margin-right: 1ex;
+  position: relative;
+  float: right;
+  white-space: nowrap;
+}
+.nonavigation {
+  color: #e0e0e0;
+}
+
+.searchform {
+  display: inline;
+  margin: 0;
+  padding: 0;
+}
+
+.searchbox {
+  width: 16em;
+  margin: 0px;
+  padding: 0px;
+  background-color: #eee;
+  border: 1px solid #ddd;
+  text-align: center;
+  vertical-align: middle;
+}
+
+#contextindicator {
+  position: fixed;
+  background-color: #c6f;
+  color: #000;
+  font-family: monospace;
+  font-weight: bold;
+  padding: 2px 10px;
+  display: none;
+  right: 0;
+  bottom: 0;
+}
+
+/* ---------------------------------------- */
+/* Version */
+
+.versionbox {
+  position: relative;
+  float: right;
+  left: 2em;
+  height: 0em;
+  width: 13em;
+  margin: 0em -13em 0em 0em;
+}
+.version {
+  font-size: small;
+}
+.versionNoNav {
+  font-size: xx-small; /* avoid overlap with author */
+}
+
+.version:before, .versionNoNav:before {
+  content: "Version ";
+}
+
+/* ---------------------------------------- */
+/* Margin notes */
+
+.refpara, .refelem {
+  position: relative;
+  float: right;
+  left: 2em;
+  height: 0em;
+  width: 13em;
+  margin: 0em -13em 0em 0em;
+}
+
+.refpara, .refparaleft {
+  top: -1em;
+}
+
+.refcolumn {
+  background-color: #F5F5DC;
+  display: block;
+  position: relative;
+  width: 13em;
+  font-size: 85%;
+  border: 0.5em solid #F5F5DC;
+  margin: 0 0 0 0;
+}
+
+.refcontent {
+  margin: 0 0 0 0;
+}
+
+.refcontent p {
+  margin-top: 0;
+  margin-bottom: 0;
+}
+
+.refparaleft {
+  position: relative;
+  float: left;
+  right: 2em;
+  height: 0em;
+  width: 13em;
+  margin: 0em 0em 0em -13em;
+}
+
+.refcolumnleft, .refelemleft {
+  background-color: #F5F5DC;
+  display: block;
+  position: relative;
+  width: 13em;
+  font-size: 85%;
+  border: 0.5em solid #F5F5DC;
+  margin: 0 0 0 0;
+}
+
+
+/* ---------------------------------------- */
+/* Table of contents, inline */
+
+.toclink {
+  text-decoration: none;
+  color: blue;
+  font-size: 85%;
+}
+
+.toptoclink {
+  text-decoration: none;
+  color: blue;
+  font-weight: bold;
+}
+
+/* ---------------------------------------- */
+/* Table of contents, left margin */
+
+.tocset {
+  position: relative;
+  float: left;
+  width: 12.5em;
+  margin-right: 2em;
+}
+.tocset td {
+  vertical-align: text-top;
+}
+
+.tocview {
+  text-align: left;
+  background-color: #f0f0e0;
+}
+
+.tocsub {
+  text-align: left;
+  margin-top: 0.5em;
+  background-color: #f0f0e0;
+}
+
+.tocviewlist, .tocsublist {
+  margin-left: 0.2em;
+  margin-right: 0.2em;
+  padding-top: 0.2em;
+  padding-bottom: 0.2em;
+}
+.tocviewlist table {
+  font-size: 82%;
+}
+
+.tocviewsublist, .tocviewsublistonly, .tocviewsublisttop, .tocviewsublistbottom {
+  margin-left: 0.4em;
+  border-left: 1px solid #bbf;
+  padding-left: 0.8em;
+}
+.tocviewsublist {
+  margin-bottom: 1em;
+}
+.tocviewsublist table,
+.tocviewsublistonly table,
+.tocviewsublisttop table,
+.tocviewsublistbottom table {
+  font-size: 75%;
+}
+
+.tocviewtitle * {
+  font-weight: bold;
+}
+
+.tocviewlink {
+  text-decoration: none;
+  color: blue;
+}
+
+.tocviewselflink {
+  text-decoration: underline;
+  color: blue;
+}
+
+.tocviewtoggle {
+  text-decoration: none;
+  color: blue;
+  font-size: 75%; /* looks better, and avoids bounce when toggling sub-sections due to font alignments */
+}
+
+.tocsublist td {
+  padding-left: 1em;
+  text-indent: -1em;
+}
+
+.tocsublinknumber {
+  font-size: 82%;
+}
+
+.tocsublink {
+  font-size: 82%;
+  text-decoration: none;
+}
+
+.tocsubseclink {
+  font-size: 82%;
+  text-decoration: none;
+}
+
+.tocsubnonseclink {
+  font-size: 82%;
+  text-decoration: none;
+  padding-left: 0.5em;
+}
+
+.tocsubtitle {
+  font-size: 82%;
+  font-style: italic;
+  margin: 0.2em;
+}
+
+.sepspace {
+  font-size: 40%;
+}
+
+.septitle {
+  font-size: 70%;
+}
+
+/* ---------------------------------------- */
+/* Some inline styles */
+
+.indexlink {
+  text-decoration: none;
+}
+
+.nobreak {
+  white-space: nowrap;
+}
+
+.stt {
+}
+
+.title {
+  font-size: 200%;
+  font-weight: normal;
+  margin-top: 2.8em;
+  text-align: center;
+}
+
+pre { margin-left: 2em; }
+blockquote { margin-left: 2em; }
+
+ol          { list-style-type: decimal; }
+ol ol       { list-style-type: lower-alpha; }
+ol ol ol    { list-style-type: lower-roman; }
+ol ol ol ol { list-style-type: upper-alpha; }
+
+i {
+}
+
+.SCodeFlow {
+  display: block;
+  margin-left: 1em;
+  margin-bottom: 0em;
+  margin-right: 1em;
+  margin-top: 0em;
+  white-space: nowrap;  
+}
+
+.SVInsetFlow {
+  display: block;
+  margin-left: 0em;
+  margin-bottom: 0em;
+  margin-right: 0em;
+  margin-top: 0em;
+}
+
+.SubFlow {
+  display: block;
+  margin: 0em;
+}
+
+.boxed {
+  width: 100%;
+  background-color: #E8E8FF;
+}
+
+.hspace {
+}
+
+.slant {
+  font-style: oblique;
+}
+
+.badlink {
+  text-decoration: underline;
+  color: red;
+}
+
+.plainlink {
+  text-decoration: none;
+  color: blue;
+}
+
+.techoutside       { text-decoration: underline; color: #b0b0b0; }
+.techoutside:hover { text-decoration: underline; color: blue; }
+
+/* .techinside:hover doesn't work with FF, .techinside:hover>
+   .techinside doesn't work with IE, so use both (and IE doesn't
+   work with inherit in the second one, so use blue directly) */
+.techinside                    { color: black; }
+.techinside:hover              { color: blue; }
+.techoutside:hover>.techinside { color: inherit; }
+
+.SCentered {
+  text-align: center;
+}
+
+.imageleft {
+  float: left;
+  margin-right: 0.3em;
+}
+
+.Smaller{
+  font-size: 82%;
+}
+
+.Larger{
+  font-size: 122%;
+}
+
+/* A hack, inserted to break some Scheme ids: */
+.mywbr {
+  width: 0;
+  font-size: 1px;
+}
+
+.compact li p {
+  margin: 0em;
+  padding: 0em;
+}
+
+.noborder img {
+  border: 0;
+}
+
+.SAuthorListBox {
+  position: relative;
+  float: right;
+  left: 2em;
+  top: -2.5em;
+  height: 0em;
+  width: 13em;
+  margin: 0em -13em 0em 0em;
+}
+.SAuthorList {
+  font-size: 82%;
+}
+.SAuthorList:before {
+  content: "by ";
+}
+.author {
+  display: inline;
+  white-space: nowrap;
+}
+
+/* print styles : hide the navigation elements */
+@media print {
+  .tocset,
+  .navsettop,
+  .navsetbottom { display: none; }
+  .maincolumn {
+    width: auto;
+    margin-right: 13em;
+    margin-left: 0;
+  }
+}
diff --git a/archive/0.vm.arc/charterm/test-charterm.rkt b/archive/0.vm.arc/charterm/test-charterm.rkt
new file mode 100644
index 00000000..04eb376f
--- /dev/null
+++ b/archive/0.vm.arc/charterm/test-charterm.rkt
@@ -0,0 +1,20 @@
+#lang racket/base
+;; For legal info, see file "charterm.rkt".
+
+;; (require (planet neil/charterm:1))
+(require "charterm.rkt")
+
+(with-charterm
+ (charterm-clear-screen)
+ (charterm-cursor 10 5)
+ (charterm-display "Hello, ")
+ (charterm-bold)
+ (charterm-display "you")
+ (charterm-normal)
+ (charterm-display ".")
+ (charterm-cursor 1 1)
+ (charterm-display "Press a key...")
+ (let ((key (charterm-read-key)))
+   (charterm-cursor 1 1)
+   (charterm-clear-line)
+   (printf "You pressed: ~S\r\n" key)))
diff --git a/archive/0.vm.arc/chessboard.arc.t b/archive/0.vm.arc/chessboard.arc.t
new file mode 100644
index 00000000..eb365b69
--- /dev/null
+++ b/archive/0.vm.arc/chessboard.arc.t
@@ -0,0 +1,239 @@
+(selective-load "mu.arc" section-level)
+(set allow-raw-addresses*)
+(add-code:readfile "chessboard.mu")
+(freeze function*)
+(load-system-functions)
+
+(reset2)
+(new-trace "read-move-legal")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (stdin:channel-address <- init-channel 1:literal)
+  (r:integer/routine <- fork read-move:fn nil:literal/globals 2000:literal/limit stdin:channel-address)
+  (c:character <- copy ((#\a literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (c:character <- copy ((#\2 literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (c:character <- copy ((#\- literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (c:character <- copy ((#\a literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (c:character <- copy ((#\4 literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (c:character <- copy ((#\newline literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (sleep until-routine-done:literal r:integer/routine)
+)
+(each routine completed-routines*
+;?   (prn "  " routine)
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~ran-to-completion 'read-move)
+  (prn "F - chessboard accepts legal moves (<rank><file>-<rank><file>)"))
+; todo: we can't test that keys pressed are printed to screen
+; but that's at a lower level
+;? (quit)
+
+(reset2)
+(new-trace "read-move-incomplete")
+; initialize some variables at specific raw locations
+;? (prn "== init")
+(run-code test-init
+  (1:channel-address/raw <- init-channel 1:literal)
+  (2:terminal-address/raw <- init-fake-terminal 20:literal 10:literal)
+  (3:string-address/raw <- get 2:terminal-address/raw/deref data:offset))
+(wipe completed-routines*)
+; the component under test; we'll be running this repeatedly
+(let read-move-routine (make-routine 'read-move memory*.1 memory*.2)
+;?   (prn "== first key")
+  (run-code send-first-key
+    (default-space:space-address <- new space:literal 30:literal/capacity)
+    (c:character <- copy ((#\a literal)))
+    (x:tagged-value <- save-type c:character)
+    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value))
+  (wipe completed-routines*)
+  ; check that read-move consumes it and then goes to sleep
+  (enq read-move-routine running-routines*)
+  (run-more)
+  (when (ran-to-completion 'read-move)
+    (prn "F - chessboard waits after first letter of move"))
+  (wipe completed-routines*)
+  ; send in a few more letters
+;?   (prn "== more keys")
+  (restart read-move-routine)
+  (run-code send-more-keys
+    (default-space:space-address <- new space:literal 30:literal/capacity)
+    (c:character <- copy ((#\2 literal)))
+    (x:tagged-value <- save-type c:character)
+    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value)
+    (c:character <- copy ((#\- literal)))
+    (x:tagged-value <- save-type c:character)
+    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value)
+    (c:character <- copy ((#\a literal)))
+    (x:tagged-value <- save-type c:character)
+    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value)
+    (c:character <- copy ((#\4 literal)))
+    (x:tagged-value <- save-type c:character)
+    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value))
+  ; check that read-move consumes them and then goes to sleep
+  (when (ran-to-completion 'read-move)
+    (prn "F - chessboard waits after each subsequent letter of move until the last"))
+  (wipe completed-routines*)
+  ; send final key
+;?   (prn "== final key")
+  (restart read-move-routine)
+;?   (set dump-trace*)
+  (run-code send-final-key
+    (default-space:space-address <- new space:literal 30:literal/capacity)
+    (c:character <- copy ((#\newline literal)))
+    (x:tagged-value <- save-type c:character)
+    (1:channel-address/raw/deref <- write 1:channel-address/raw x:tagged-value))
+  ; check that read-move consumes it and -- this time -- returns
+  (when (~ran-to-completion 'read-move)
+    (prn "F - 'read-move' completes after final letter of move"))
+)
+
+(reset2)
+(new-trace "read-move-quit")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (stdin:channel-address <- init-channel 1:literal)
+  (dummy:terminal-address <- init-fake-terminal 20:literal 10:literal)
+  (r:integer/routine <- fork-helper read-move:fn nil:literal/globals 2000:literal/limit stdin:channel-address dummy:terminal-address)
+  (c:character <- copy ((#\q literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (sleep until-routine-done:literal r:integer/routine)
+)
+(when (~ran-to-completion 'read-move)
+  (prn "F - chessboard quits on move starting with 'q'"))
+
+(reset2)
+(new-trace "read-illegal-file")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (stdin:channel-address <- init-channel 1:literal)
+  (dummy:terminal-address <- init-fake-terminal 20:literal 10:literal)
+  (r:integer/routine <- fork-helper read-file:fn nil:literal/globals 2000:literal/limit stdin:channel-address dummy:terminal-address)
+  (c:character <- copy ((#\i literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (sleep until-routine-done:literal r:integer/routine)
+)
+;? (each routine completed-routines*
+;?   (prn "  " routine))
+(when (or (ran-to-completion 'read-file)
+          (let routine routine-running!read-file
+            (~posmatch "file too high" rep.routine!error)))
+  (prn "F - 'read-file' checks that file lies between 'a' and 'h'"))
+
+(reset2)
+(new-trace "read-illegal-rank")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (stdin:channel-address <- init-channel 1:literal)
+  (dummy:terminal-address <- init-fake-terminal 20:literal 10:literal)
+  (r:integer/routine <- fork-helper read-rank:fn nil:literal/globals 2000:literal/limit stdin:channel-address dummy:terminal-address)
+  (c:character <- copy ((#\9 literal)))
+  (x:tagged-value <- save-type c:character)
+  (stdin:channel-address/deref <- write stdin:channel-address x:tagged-value)
+  (sleep until-routine-done:literal r:integer/routine)
+)
+(when (or (ran-to-completion 'read-rank)
+          (let routine routine-running!read-rank
+            (~posmatch "rank too high" rep.routine!error)))
+  (prn "F - 'read-rank' checks that rank lies between '1' and '8'"))
+
+(reset2)
+(new-trace "print-board")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+;?   ($print (("init-array\n" literal))) ;? 1
+  (initial-position:integer-array-address <- init-array ((#\R literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\r literal))
+                                              ((#\N literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\n literal))
+                                              ((#\B literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\b literal))
+                                              ((#\Q literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\q literal))
+                                              ((#\K literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\k literal))
+                                              ((#\B literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\b literal))
+                                              ((#\N literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\n literal))
+                                              ((#\R literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\r literal)))
+;?   ($print (("init-board\n" literal))) ;? 1
+  (b:board-address <- init-board initial-position:integer-array-address)
+  (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+  (print-board screen:terminal-address b:board-address)
+  (1:string-address/raw <- get screen:terminal-address/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+;? (prn memory*.1)
+(when (~screen-contains memory*.1 20
+          (+ "8 | r n b q k b n r "
+             "7 | p p p p p p p p "
+             "6 | _ _ _ _ _ _ _ _ "
+             "5 | _ _ _ _ _ _ _ _ "
+             "4 | _ _ _ _ _ _ _ _ "
+             "3 | _ _ _ _ _ _ _ _ "
+             "2 | P P P P P P P P "
+             "1 | R N B Q K B N R "
+             "  +---------------- "
+             "    a b c d e f g h "))
+  (prn "F - print-board works; chessboard begins at @memory*.1"))
+
+; todo: how to fold this more elegantly with the previous test?
+(reset2)
+(new-trace "make-move")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; fake screen
+  (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+  ; initial position
+  (initial-position:integer-array-address <- init-array ((#\R literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\r literal))
+                                              ((#\N literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\n literal))
+                                              ((#\B literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\b literal))
+                                              ((#\Q literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\q literal))
+                                              ((#\K literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\k literal))
+                                              ((#\B literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\b literal))
+                                              ((#\N literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\n literal))
+                                              ((#\R literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\r literal)))
+  (b:board-address <- init-board initial-position:integer-array-address)
+  ; move: a2-a4
+  (m:move-address <- new move:literal)
+  (f:integer-integer-pair-address <- get-address m:move-address/deref from:offset)
+  (dest:integer-address <- get-address f:integer-integer-pair-address/deref 0:offset)
+  (dest:integer-address/deref <- copy 0:literal)  ; from-file: a
+  (dest:integer-address <- get-address f:integer-integer-pair-address/deref 1:offset)
+  (dest:integer-address/deref <- copy 1:literal)  ; from-rank: 2
+  (t0:integer-integer-pair-address <- get-address m:move-address/deref to:offset)
+  (dest:integer-address <- get-address t0:integer-integer-pair-address/deref 0:offset)
+  (dest:integer-address/deref <- copy 0:literal)  ; to-file: a
+  (dest:integer-address <- get-address t0:integer-integer-pair-address/deref 1:offset)
+  (dest:integer-address/deref <- copy 3:literal)  ; to-rank: 4
+  (b:board-address <- make-move b:board-address m:move-address)
+  (print-board screen:terminal-address b:board-address)
+  (1:string-address/raw <- get screen:terminal-address/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+;? (prn memory*.1)
+(when (~screen-contains memory*.1 20
+          (+ "8 | r n b q k b n r "
+             "7 | p p p p p p p p "
+             "6 | _ _ _ _ _ _ _ _ "
+             "5 | _ _ _ _ _ _ _ _ "
+             "4 | P _ _ _ _ _ _ _ "
+             "3 | _ _ _ _ _ _ _ _ "
+             "2 | _ P P P P P P P "
+             "1 | R N B Q K B N R "
+             "  +---------------- "
+             "    a b c d e f g h "))
+  (prn "F - make-move works; chessboard begins at @memory*.1"))
+
+(reset2)
diff --git a/archive/0.vm.arc/chessboard.mu b/archive/0.vm.arc/chessboard.mu
new file mode 100644
index 00000000..45fc12da
--- /dev/null
+++ b/archive/0.vm.arc/chessboard.mu
@@ -0,0 +1,259 @@
+;; data structure: board
+(primitive square)
+(address square-address (square))  ; pointer. verbose but sadly necessary for now
+(array file (square))  ; ranks and files are arrays of squares
+(address file-address (file))
+(address file-address-address (file-address))  ; pointer to a pointer
+(array board (file-address))
+(address board-address (board))
+
+(function init-board [
+  (default-space:space-address <- new space:literal 30:literal)
+  (initial-position:integer-array-address <- next-input)
+  ; assert(length(initial-position) == 64)
+;?   ($print initial-position:integer-array-address/deref) ;? 1
+  (len:integer <- length initial-position:integer-array-address/deref)
+;?   ($print len:integer) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (correct-length?:boolean <- equal len:integer 64:literal)
+  (assert correct-length?:boolean (("chessboard had incorrect size" literal)))
+  (b:board-address <- new board:literal 8:literal)
+  (col:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- equal col:integer 8:literal)
+    (break-if done?:boolean)
+    (file:file-address-address <- index-address b:board-address/deref col:integer)
+    (file:file-address-address/deref <- init-file initial-position:integer-array-address col:integer)
+    (col:integer <- add col:integer 1:literal)
+    (loop)
+  }
+  (reply b:board-address)
+])
+
+(function init-file [
+  (default-space:space-address <- new space:literal 30:literal)
+  (position:integer-array-address <- next-input)
+  (index:integer <- next-input)
+  (index:integer <- multiply index:integer 8:literal)
+  (result:file-address <- new file:literal 8:literal)
+  (row:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- equal row:integer 8:literal)
+    (break-if done?:boolean)
+    (dest:square-address <- index-address result:file-address/deref row:integer)
+    (dest:square-address/deref <- index position:integer-array-address/deref index:integer)
+    (row:integer <- add row:integer 1:literal)
+    (index:integer <- add index:integer 1:literal)
+    (loop)
+  }
+  (reply result:file-address)
+])
+
+(function print-board [
+  (default-space:space-address <- new space:literal 30:literal)
+  (screen:terminal-address <- next-input)
+  (b:board-address <- next-input)
+  (row:integer <- copy 7:literal)
+  ; print each row
+  { begin
+    (done?:boolean <- less-than row:integer 0:literal)
+    (break-if done?:boolean)
+    ; print rank number as a legend
+    (rank:integer <- add row:integer 1:literal)
+    (print-integer screen:terminal-address rank:integer)
+    (s:string-address <- new " | ")
+    (print-string screen:terminal-address s:string-address)
+    ; print each square in the row
+    (col:integer <- copy 0:literal)
+    { begin
+      (done?:boolean <- equal col:integer 8:literal)
+      (break-if done?:boolean)
+      (f:file-address <- index b:board-address/deref col:integer)
+      (s:square <- index f:file-address/deref row:integer)
+      (print-character screen:terminal-address s:square)
+      (print-character screen:terminal-address ((#\space literal)))
+      (col:integer <- add col:integer 1:literal)
+      (loop)
+    }
+    (row:integer <- subtract row:integer 1:literal)
+    (cursor-to-next-line screen:terminal-address)
+    (loop)
+  }
+  ; print file letters as legend
+  (s:string-address <- new "  +----------------")
+  (print-string screen:terminal-address s:string-address)
+  (cursor-to-next-line screen:terminal-address)
+  (s:string-address <- new "    a b c d e f g h")
+  (print-string screen:terminal-address s:string-address)
+  (cursor-to-next-line screen:terminal-address)
+])
+
+;; data structure: move
+(and-record move [
+  from:integer-integer-pair
+  to:integer-integer-pair
+])
+
+(address move-address (move))
+
+(function read-move [
+  (default-space:space-address <- new space:literal 30:literal)
+  (stdin:channel-address <- next-input)
+  (from-file:integer <- read-file stdin:channel-address)
+  { begin
+    (break-if from-file:integer)
+    (reply nil:literal)
+  }
+  (from-rank:integer <- read-rank stdin:channel-address)
+  (expect-stdin stdin:channel-address ((#\- literal)))
+  (to-file:integer <- read-file stdin:channel-address)
+  (to-rank:integer <- read-rank stdin:channel-address)
+  (expect-stdin stdin:channel-address ((#\newline literal)))
+  ; construct the move object
+  (result:move-address <- new move:literal)
+  (f:integer-integer-pair-address <- get-address result:move-address/deref from:offset)
+  (dest:integer-address <- get-address f:integer-integer-pair-address/deref 0:offset)
+  (dest:integer-address/deref <- copy from-file:integer)
+  (dest:integer-address <- get-address f:integer-integer-pair-address/deref 1:offset)
+  (dest:integer-address/deref <- copy from-rank:integer)
+  (t0:integer-integer-pair-address <- get-address result:move-address/deref to:offset)
+  (dest:integer-address <- get-address t0:integer-integer-pair-address/deref 0:offset)
+  (dest:integer-address/deref <- copy to-file:integer)
+  (dest:integer-address <- get-address t0:integer-integer-pair-address/deref 1:offset)
+  (dest:integer-address/deref <- copy to-rank:integer)
+  (reply result:move-address)
+])
+
+; todo: assumes stdin is always at raw address 1
+(function read-file [
+  (default-space:space-address <- new space:literal 30:literal)
+  (stdin:channel-address <- next-input)
+  (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+;?   ($print x:tagged-value) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (a:character <- copy ((#\a literal)))
+  (file-base:integer <- character-to-integer a:character)
+  (c:character <- maybe-coerce x:tagged-value character:literal)
+;?   ($print (("AAA " literal))) ;? 1
+;?   ($print c:character) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  { begin
+    (quit:boolean <- equal c:character ((#\q literal)))
+    (break-unless quit:boolean)
+    (reply nil:literal)
+  }
+  (file:integer <- character-to-integer c:character)
+  (file:integer <- subtract file:integer file-base:integer)
+  ; assert('a' <= from-file <= 'h')
+  (above-min:boolean <- greater-or-equal file:integer 0:literal)
+  (assert above-min:boolean (("file too low" literal)))
+  (below-max:boolean <- lesser-or-equal file:integer 7:literal)
+  (assert below-max:boolean (("file too high" literal)))
+  (reply file:integer)
+])
+
+(function read-rank [
+  (default-space:space-address <- new space:literal 30:literal)
+  (stdin:channel-address <- next-input)
+  (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+  (c:character <- maybe-coerce x:tagged-value character:literal)
+;?   ($print (("BBB " literal))) ;? 1
+;?   ($print c:character) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  { begin
+    (quit:boolean <- equal c:character ((#\q literal)))
+    (break-unless quit:boolean)
+    (reply nil:literal)
+  }
+  (rank:integer <- character-to-integer c:character)
+  (one:character <- copy ((#\1 literal)))
+  (rank-base:integer <- character-to-integer one:character)
+  (rank:integer <- subtract rank:integer rank-base:integer)
+  ; assert('1' <= rank <= '8')
+  (above-min:boolean <- greater-or-equal rank:integer 0:literal)
+  (assert above-min:boolean (("rank too low" literal)))
+  (below-max:boolean <- lesser-or-equal rank:integer 7:literal)
+  (assert below-max:boolean (("rank too high" literal)))
+  (reply rank:integer)
+])
+
+; slurp a character and check that it matches
+(function expect-stdin [
+  (default-space:space-address <- new space:literal 30:literal)
+  (stdin:channel-address <- next-input)
+  (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+  (c:character <- maybe-coerce x:tagged-value character:literal)
+  (expected:character <- next-input)
+  (match?:boolean <- equal c:character expected:character)
+  (assert match?:boolean (("expected character not found" literal)))
+])
+
+(function make-move [
+  (default-space:space-address <- new space:literal 30:literal)
+  (b:board-address <- next-input)
+  (m:move-address <- next-input)
+  (x:integer-integer-pair <- get m:move-address/deref from:offset)
+  (from-file:integer <- get x:integer-integer-pair 0:offset)
+  (from-rank:integer <- get x:integer-integer-pair 1:offset)
+  (f:file-address <- index b:board-address/deref from-file:integer)
+  (src:square-address <- index-address f:file-address/deref from-rank:integer)
+  (x:integer-integer-pair <- get m:move-address/deref to:offset)
+  (to-file:integer <- get x:integer-integer-pair 0:offset)
+  (to-rank:integer <- get x:integer-integer-pair 1:offset)
+  (f:file-address <- index b:board-address/deref to-file:integer)
+  (dest:square-address <- index-address f:file-address/deref to-rank:integer)
+  (dest:square-address/deref <- copy src:square-address/deref)
+  (src:square-address/deref <- copy ((#\_ literal)))
+  (reply b:board-address)
+])
+
+(function chessboard [
+  (default-space:space-address <- new space:literal 30:literal)
+  (initial-position:integer-array-address <- init-array ((#\R literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\r literal))
+                                                        ((#\N literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\n literal))
+                                                        ((#\B literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\b literal))
+                                                        ((#\Q literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\q literal))
+                                                        ((#\K literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\k literal))
+                                                        ((#\B literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\b literal))
+                                                        ((#\N literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\n literal))
+                                                        ((#\R literal)) ((#\P literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\_ literal)) ((#\p literal)) ((#\r literal)))
+  (b:board-address <- init-board initial-position:integer-array-address)
+  (cursor-mode)
+  ; hook up stdin
+  (stdin:channel-address <- init-channel 1:literal)
+  (fork-helper send-keys-to-stdin:fn nil:literal/globals nil:literal/limit nil:literal/keyboard stdin:channel-address)
+  ; buffer stdin
+  (buffered-stdin:channel-address <- init-channel 1:literal)
+  (fork-helper buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+  ($print (("Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves." literal)))
+  (cursor-to-next-line nil:literal/terminal)
+  { begin
+    (cursor-to-next-line nil:literal/terminal)
+    (print-board nil:literal/terminal b:board-address)
+    (cursor-to-next-line nil:literal/terminal)
+    ($print (("Type in your move as <from square>-<to square>. For example: 'a2-a4'. Then press <enter>." literal)))
+    (cursor-to-next-line nil:literal/terminal)
+    ($print (("Hit 'q' to exit." literal)))
+    (cursor-to-next-line nil:literal/terminal)
+    ($print (("move: " literal)))
+    (m:move-address <- read-move buffered-stdin:channel-address)
+;?     (retro-mode) ;? 1
+;?     ($print stdin:channel-address) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+;?     ($print buffered-stdin:channel-address) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+;?     ($dump-memory) ;? 1
+;?     (cursor-mode) ;? 1
+    (break-unless m:move-address)
+    (b:board-address <- make-move b:board-address m:move-address)
+    (loop)
+  }
+  (retro-mode)
+])
+
+(function main [
+  (chessboard)
+])
+
+; todo:
+;   backspace, ctrl-u
diff --git a/archive/0.vm.arc/color-repl.mu b/archive/0.vm.arc/color-repl.mu
new file mode 100644
index 00000000..ced6a89f
--- /dev/null
+++ b/archive/0.vm.arc/color-repl.mu
@@ -0,0 +1,498 @@
+; a simple line editor for reading lisp expressions.
+; colors strings and comments. nested parens get different colors.
+;
+; needs to do its own raw keyboard/screen management since we need to decide
+; how to color each key right as it is printed.
+; lots of logic devoted to handling backspace correctly.
+
+; keyboard screen abort continuation -> string
+(function read-expression [
+  (default-space:space-address <- new space:literal 60:literal)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  (abort:continuation <- next-input)
+  (history:buffer-address <- next-input)  ; buffer of strings
+  (history-length:integer <- get history:buffer-address/deref length:offset)
+  (current-history-index:integer <- copy history-length:integer)
+  (result:buffer-address <- init-buffer 10:literal)  ; string to maybe add to
+  (open-parens:integer <- copy 0:literal)  ; for balancing parens and tracking nesting depth
+  ; we can change color when backspacing over parens or comments or strings,
+  ; but we need to know that they aren't escaped
+  (escapes:buffer-address <- init-buffer 5:literal)
+  ; to not return after just a comment
+  (not-empty?:boolean <- copy nil:literal)
+  { begin
+    ; repeatedly read keys from the keyboard
+    ;   test: 34<enter>
+    (done?:boolean <- process-key default-space:space-address k:keyboard-address screen:terminal-address)
+    (loop-unless done?:boolean)
+  }
+  ; trim trailing newline in result (easier history management below)
+  { begin
+    (l:character <- last result:buffer-address)
+    (trailing-newline?:boolean <- equal l:character ((#\newline literal)))
+    (break-unless trailing-newline?:boolean)
+    (len:integer-address <- get-address result:buffer-address/deref length:offset)
+    (len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
+  }
+  ; test: 3<enter> => size of s is 2
+  (s:string-address <- to-array result:buffer-address)
+  (reply s:string-address)
+])
+
+(function process-key [  ; return t to signal end of expression
+  (default-space:space-address <- new space:literal 60:literal)
+  (0:space-address/names:read-expression <- next-input)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  (c:character <- wait-for-key k:keyboard-address silent:literal/terminal)
+  (len:integer-address <- get-address result:buffer-address/space:1/deref length:offset)
+  (maybe-cancel-this-expression c:character abort:continuation/space:1)
+  ; check for ctrl-d and exit
+  { begin
+    (eof?:boolean <- equal c:character ((ctrl-d literal)))
+    (break-unless eof?:boolean)
+    ; return empty expression
+    (s:string-address-address <- get-address result:buffer-address/space:1/deref data:offset)
+    (s:string-address-address/deref <- copy nil:literal)
+    (reply t:literal)
+  }
+  ; check for backspace
+  ;   test: 3<backspace>4<enter>
+  ;   todo: backspace past newline
+  { begin
+    (backspace?:boolean <- equal c:character ((#\backspace literal)))
+    (break-unless backspace?:boolean)
+    (print-character screen:terminal-address c:character/backspace)
+    { begin
+      ; delete last character if any
+      (zero?:boolean <- lesser-or-equal len:integer-address/deref 0:literal)
+      (break-if zero?:boolean)
+      (len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
+      ; switch colors
+      ;   test: "a"<backspace>bc"
+      ;   test: "a\"<backspace>bc"
+      { begin
+        (backspaced-over-close-quote?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\" literal)) escapes:buffer-address/space:1)  ; "
+        (break-unless backspaced-over-close-quote?:boolean)
+        (slurp-string result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address)
+        (reply nil:literal)
+      }
+      ;   test: (+ 1 (<backspace>2)
+      ;   test: (+ 1 #\(<backspace><backspace><backspace>2)
+      { begin
+        (backspaced-over-open-paren?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\( literal)) escapes:buffer-address/space:1)
+        (break-unless backspaced-over-open-paren?:boolean)
+        (open-parens:integer/space:1 <- subtract open-parens:integer/space:1 1:literal)
+        (reply nil:literal)
+      }
+      ;   test: (+ 1 2)<backspace> 3)
+      ;   test: (+ 1 2#\)<backspace><backspace><backspace> 3)
+      { begin
+        (backspaced-over-close-paren?:boolean <- backspaced-over-unescaped? result:buffer-address/space:1 ((#\) literal)) escapes:buffer-address/space:1)
+        (break-unless backspaced-over-close-paren?:boolean)
+        (open-parens:integer/space:1 <- add open-parens:integer/space:1 1:literal)
+        (reply nil:literal)
+      }
+    }
+    (reply nil:literal)
+  }
+  ; up arrow; switch to previous item in history
+  { begin
+    (up-arrow?:boolean <- equal c:character ((up literal)))
+    (break-unless up-arrow?:boolean)
+    ; if history exists
+    ;   test: <up><enter>  up without history has no effect
+    { begin
+      (empty-history?:boolean <- lesser-or-equal history-length:integer/space:1 0:literal)
+      (break-unless empty-history?:boolean)
+      (reply nil:literal)
+    }
+    ; if pointer not already at start of history
+    ;   test: 34<enter><up><up><enter>  up past history has no effect
+    { begin
+      (at-history-start?:boolean <- lesser-or-equal current-history-index:integer/space:1 0:literal)
+      (break-unless at-history-start?:boolean)
+      (reply nil:literal)
+    }
+    ; then update history index, copy into current buffer
+    ;   test: 34<enter><up><enter>  up restores previous command
+    ;   test todo: 34<enter>23<up>34<down><enter>  up doesn't mess up typing on current line
+    ;   test todo: 34<enter><up>5<enter><up><up>  commands don't modify history
+    ;   test todo: multi-line expressions
+    ; identify the history item
+    (current-history-index:integer/space:1 <- subtract current-history-index:integer/space:1 1:literal)
+    (switch-to-history 0:space-address screen:terminal-address)
+    ; <enter> is trimmed in the history expression, so wait for the human to
+    ; hit <enter> again or backspace to make edits
+    (reply nil:literal)
+  }
+  ; down arrow; switch to next item in history
+  { begin
+    (down-arrow?:boolean <- equal c:character ((down literal)))
+    (break-unless down-arrow?:boolean)
+    ; if history exists
+    ;   test: <down><enter>  down without history has no effect
+    { begin
+      (empty-history?:boolean <- lesser-or-equal history-length:integer/space:1 0:literal)
+      (break-unless empty-history?:boolean)
+      (reply nil:literal)
+    }
+    ; if pointer not already at end of history
+    ;   test: 34<enter><down><down><enter>  up past history has no effect
+    { begin
+      (x:integer <- subtract history-length:integer/space:1 1:literal)
+      (before-history-end?:boolean <- greater-or-equal current-history-index:integer/space:1 x:integer)
+      (break-unless before-history-end?:boolean)
+      (reply nil:literal)
+    }
+    ; then update history index, copy into current buffer
+    ;   test: 34<enter><up><enter>  up restores previous command
+    ;   test todo: 34<enter>23<up>34<down><enter>  up doesn't mess up typing on current line
+    ;   test todo: 34<enter><up>5<enter><up><up>  commands don't modify history
+    ;   test todo: multi-line expressions
+    ; identify the history item
+    (current-history-index:integer/space:1 <- add current-history-index:integer/space:1 1:literal)
+    (switch-to-history 0:space-address screen:terminal-address)
+    ; <enter> is trimmed in the history expression, so wait for the human to
+    ; hit <enter> again or backspace to make edits
+    (reply nil:literal)
+  }
+  ; if it's a newline, decide whether to return
+  ;   test: <enter>34<enter>
+  { begin
+    (newline?:boolean <- equal c:character ((#\newline literal)))
+    (break-unless newline?:boolean)
+    (print-character screen:terminal-address c:character/newline)
+    (at-top-level?:boolean <- lesser-or-equal open-parens:integer/space:1 0:literal)
+    (end-expression?:boolean <- and at-top-level?:boolean not-empty?:boolean/space:1)
+    (reply end-expression?:boolean)
+  }
+  ; printable character; save
+;?   ($print (("append\n" literal))) ;? 2
+  (result:buffer-address/space:1 <- append result:buffer-address/space:1 c:character)
+;?   ($print (("done\n" literal))) ;? 2
+  ; if it's backslash, read, save and print one additional character
+  ;   test: (prn #\()
+  { begin
+    (backslash?:boolean <- equal c:character ((#\\ literal)))
+    (break-unless backslash?:boolean)
+    (print-character screen:terminal-address c:character/backslash 7:literal/white)
+    (result:buffer-address/space:1 escapes:buffer-address/space:1 <- slurp-escaped-character result:buffer-address/space:1 7:literal/white escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address)
+    (reply nil:literal)
+  }
+  ; if it's a semi-colon, parse a comment
+  { begin
+    (comment?:boolean <- equal c:character ((#\; literal)))
+    (break-unless comment?:boolean)
+    (print-character screen:terminal-address c:character/semi-colon 4:literal/fg/blue)
+    (comment-read?:boolean <- slurp-comment result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address)
+    ; return if comment was read (i.e. consumed a newline)
+    ; test: ;a<backspace><backspace> (shouldn't end command until <enter>)
+    { begin
+      (break-if comment-read?:boolean)
+      (reply nil:literal)
+    }
+    ; and we're not within parens
+    ;   test: (+ 1 2)  ; comment<enter>
+    ;   test: (+ 1<enter>; abc<enter>2)<enter>
+    ;   test: ; comment<enter>(+ 1 2)<enter>
+    ;   too expensive to build: 3<backspace>; comment<enter>(+ 1 2)<enter>
+    (at-top-level?:boolean <- lesser-or-equal open-parens:integer/space:1 0:literal)
+    (end-expression?:boolean <- and at-top-level?:boolean not-empty?:boolean/space:1)
+    (reply end-expression?:boolean)
+  }
+  ; if it's not whitespace, set not-empty? and continue
+  { begin
+    (space?:boolean <- equal c:character ((#\space literal)))
+    (break-if space?:boolean)
+    (newline?:boolean <- equal c:character ((#\newline literal)))
+    (break-if newline?:boolean)
+    (tab?:boolean <- equal c:character ((tab literal)))
+    (break-if tab?:boolean)
+    (not-empty?:boolean/space:1 <- copy t:literal)
+    ; fall through
+  }
+  ; if it's a quote, parse a string
+  { begin
+    (string-started?:boolean <- equal c:character ((#\" literal)))  ; for vim: "
+    (break-unless string-started?:boolean)
+    (print-character screen:terminal-address c:character/open-quote 6:literal/fg/cyan)
+    (slurp-string result:buffer-address/space:1 escapes:buffer-address/space:1 abort:continuation/space:1 k:keyboard-address screen:terminal-address)
+    (reply nil:literal)
+  }
+  ; color parens by depth, so they're easy to balance
+  ;   test: (+ 1 1)<enter>
+  ;   test: (def foo () (+ 1 (* 2 3)))<enter>
+  { begin
+    (open-paren?:boolean <- equal c:character ((#\( literal)))
+    (break-unless open-paren?:boolean)
+    (_ color-code:integer <- divide-with-remainder open-parens:integer/space:1 3:literal)  ; 3 distinct colors for parens
+    (color-code:integer <- add color-code:integer 1:literal)
+    (print-character screen:terminal-address c:character/open-paren color-code:integer)
+    (open-parens:integer/space:1 <- add open-parens:integer/space:1 1:literal)
+;?     ($print open-parens:integer/space:1) ;? 2
+    (reply nil:literal)
+  }
+  { begin
+    (close-paren?:boolean <- equal c:character ((#\) literal)))
+    (break-unless close-paren?:boolean)
+    (open-parens:integer/space:1 <- subtract open-parens:integer/space:1 1:literal)
+    (_ color-code:integer <- divide-with-remainder open-parens:integer/space:1 3:literal)  ; 3 distinct colors for parens
+    (color-code:integer <- add color-code:integer 1:literal)
+    (print-character screen:terminal-address c:character/close-paren color-code:integer)
+;?     ($print open-parens:integer/space:1) ;? 2
+    (reply nil:literal)
+  }
+  ; if all else fails, print the character without color
+  (print-character screen:terminal-address c:character/regular)
+  ;   todo: error on space outside parens, like python
+  ;   todo: []
+  ;   todo: history on up/down
+  (reply nil:literal)
+])
+
+(function switch-to-history [
+  (default-space:space-address <- new space:literal 30:literal)
+  (0:space-address/names:read-expression <- next-input)
+  (screen:terminal-address <- next-input)
+  (clear-repl-state 0:space-address)
+  (curr-history:string-address <- buffer-index history:buffer-address/space:1 current-history-index:integer/space:1)
+  (curr-history-len:integer <- length curr-history:string-address/deref)
+  ; and retype it into the current expression
+  (hist:keyboard-address <- init-keyboard curr-history:string-address)
+  (hist-index:integer-address <- get-address hist:keyboard-address/deref index:offset)
+  { begin
+    (done?:boolean <- greater-or-equal hist-index:integer-address/deref curr-history-len:integer)
+    (break-if done?:boolean)
+    (sub-return:boolean <- process-key 0:space-address hist:keyboard-address screen:terminal-address)
+    (assert-false sub-return:boolean (("recursive call to process keys thought it was done" literal)))
+    (loop)
+  }
+])
+
+(function clear-repl-state [
+  (default-space:space-address/names:read-expression <- next-input)
+  ; clear result
+  (len:integer-address <- get-address result:buffer-address/deref length:offset)
+  (backspace-over len:integer-address/deref screen:terminal-address)
+  (len:integer-address/deref <- copy 0:literal)
+  ; clear other state accumulated for the existing expression
+  (open-parens:integer <- copy 0:literal)
+  (escapes:buffer-address <- init-buffer 5:literal)
+  (not-empty?:boolean <- copy nil:literal)
+])
+
+(function backspace-over [
+  (default-space:space-address <- new space:literal 30:literal)
+  (len:integer <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (done?:boolean <- lesser-or-equal len:integer 0:literal)
+    (break-if done?:boolean)
+    (print-character screen:terminal-address ((#\backspace literal)))
+    (len:integer <- subtract len:integer 1:literal)
+    (loop)
+  }
+])
+
+; list of characters, list of indices of escaped characters, abort continuation
+; -> whether a comment was consumed (can also return by backspacing past comment leader ';')
+(function slurp-comment [
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (escapes:buffer-address <- next-input)
+  (abort:continuation <- next-input)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  ; test: ; abc<enter>
+  { begin
+    next-key-in-comment
+    (c:character <- wait-for-key k:keyboard-address silent:literal/terminal)
+    (maybe-cancel-this-expression c:character abort:continuation screen:terminal-address)  ; test: check needs to come before print
+    (print-character screen:terminal-address c:character 4:literal/fg/blue)
+    ; handle backspace
+    ;   test: ; abc<backspace><backspace>def<enter>
+    ;   todo: how to exit comment?
+    { begin
+      (backspace?:boolean <- equal c:character ((#\backspace literal)))
+      (break-unless backspace?:boolean)
+      (len:integer-address <- get-address in:buffer-address/deref length:offset)
+      ; buffer has to have at least the semi-colon so can't be empty
+      (len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
+      ; if we erase start of comment, return
+      (comment-deleted?:boolean <- backspaced-over-unescaped? in:buffer-address ((#\; literal)) escapes:buffer-address)  ; "
+      (jump-unless comment-deleted?:boolean next-key-in-comment:offset)  ; loop
+      (reply nil:literal/read-comment?)
+    }
+    (in:buffer-address <- append in:buffer-address c:character)
+    (newline?:boolean <- equal c:character ((#\newline literal)))
+    (loop-unless newline?:boolean)
+  }
+  (reply t:literal/read-comment?)
+])
+
+(function slurp-string [
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (escapes:buffer-address <- next-input)
+  (abort:continuation <- next-input)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  ; test: "abc"
+  { begin
+    next-key-in-string
+    (c:character <- wait-for-key k:keyboard-address silent:literal/terminal)
+    (maybe-cancel-this-expression c:character abort:continuation screen:terminal-address)  ; test: check needs to come before print
+    (print-character screen:terminal-address c:character 6:literal/fg/cyan)
+    ; handle backspace
+    ;   test: "abc<backspace>d"
+    ;   todo: how to exit string?
+    { begin
+      (backspace?:boolean <- equal c:character ((#\backspace literal)))
+      (break-unless backspace?:boolean)
+      (len:integer-address <- get-address in:buffer-address/deref length:offset)
+      ; typed a quote before calling slurp-string, so can't be empty
+      (len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
+      ; if we erase start of string, return
+      ;   test: "<backspace>34
+      (string-deleted?:boolean <- backspaced-over-unescaped? in:buffer-address ((#\" literal)) escapes:buffer-address)  ; "
+;?       ($print string-deleted?:boolean) ;? 1
+      (jump-if string-deleted?:boolean end:offset)  ; break
+      (jump next-key-in-string:offset)  ; loop
+    }
+    (in:buffer-address <- append in:buffer-address c:character)
+    ; break on quote -- unless escaped by backslash
+    ;   test: "abc\"ef"
+    { begin
+      (backslash?:boolean <- equal c:character ((#\\ literal)))
+      (break-unless backslash?:boolean)
+      (in:buffer-address escapes:buffer-address <- slurp-escaped-character in:buffer-address 6:literal/cyan escapes:buffer-address abort:continuation k:keyboard-address screen:terminal-address)
+      (jump next-key-in-string:offset)  ; loop
+    }
+    ; if not backslash
+    (end-quote?:boolean <- equal c:character ((#\" literal)))  ; for vim: "
+    (loop-unless end-quote?:boolean)
+  }
+  end
+])
+
+; buffer to add character to, color to print it in to the screen, abort continuation
+(function slurp-escaped-character [
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (color-code:integer <- next-input)
+  (escapes:buffer-address <- next-input)
+  (abort:continuation <- next-input)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  (c:character <- wait-for-key k:keyboard-address silent:literal/terminal)
+  (maybe-cancel-this-expression c:character abort:continuation screen:terminal-address)  ; test: check needs to come before print
+  (print-character screen:terminal-address c:character color-code:integer)
+  (len:integer-address <- get-address in:buffer-address/deref length:offset)
+  (escapes:buffer-address <- append escapes:buffer-address len:integer-address/deref)
+;?   ($print (("+" literal))) ;? 1
+  ; handle backspace
+  ;   test: "abc\<backspace>def"
+  ;   test: #\<backspace>
+  { begin
+    (backspace?:boolean <- equal c:character ((#\backspace literal)))
+    (break-unless backspace?:boolean)
+    ; just typed a backslash, so buffer can't be empty
+    (len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
+    (elen:integer-address <- get-address escapes:buffer-address/deref length:offset)
+    (elen:integer-address/deref <- subtract elen:integer-address/deref 1:literal)
+;?     ($print (("-" literal))) ;? 1
+    (reply in:buffer-address/same-as-arg:0 escapes:buffer-address/same-as-arg:2)
+  }
+  ; if not backspace, save and return
+  (in:buffer-address <- append in:buffer-address c:character)
+  (reply in:buffer-address/same-as-arg:0 escapes:buffer-address/same-as-arg:2)
+])
+
+(function backspaced-over-unescaped? [
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (expected:character <- next-input)
+  (escapes:buffer-address <- next-input)
+  ; char just backspaced over matches
+  { begin
+    (c:character <- past-last in:buffer-address)
+    (char-match?:boolean <- equal c:character expected:character)
+    (break-if char-match?:boolean)
+    (reply nil:literal)
+  }
+  ; and char before cursor is not an escape
+  { begin
+    (most-recent-escape:integer <- last escapes:buffer-address)
+    (last-idx:integer <- get in:buffer-address/deref length:offset)
+;?     ($print most-recent-escape:integer) ;? 1
+;?     ($print last-idx:integer) ;? 1
+    (was-unescaped?:boolean <- not-equal last-idx:integer most-recent-escape:integer)
+    (break-if was-unescaped?:boolean)
+    (reply nil:literal)
+  }
+  (reply t:literal)
+])
+
+; return the character past the end of the buffer, if there's room
+(function past-last [
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (n:integer <- get in:buffer-address/deref length:offset)
+  (s:string-address <- get in:buffer-address/deref data:offset)
+  (capacity:integer <- length s:string-address/deref)
+  { begin
+    (no-space?:boolean <- greater-or-equal n:integer capacity:integer)
+    (break-unless no-space?:boolean)
+    (reply ((#\null literal)))
+  }
+  (result:character <- index s:string-address/deref n:integer)
+  (reply result:character)
+])
+
+(function maybe-cancel-this-expression [
+  ; check for ctrl-g and abort
+  (default-space:space-address <- new space:literal 30:literal)
+  (c:character <- next-input)
+  (abort:continuation <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (interrupt?:boolean <- equal c:character ((ctrl-g literal)))
+    (break-unless interrupt?:boolean)
+    (print-character screen:terminal-address ((#\^ literal)))
+    (print-character screen:terminal-address ((#\G literal)))
+    (print-character screen:terminal-address ((#\newline literal)))
+    (continue-from abort:continuation)
+  }
+])
+
+(function main [
+  (default-space:space-address <- new space:literal 30:literal)
+  (cursor-mode)
+  ($print (("connected to anarki! type in an expression, then hit enter. ctrl-d exits. ctrl-g clears the current expression." literal)))
+  (print-character nil:literal/terminal ((#\newline literal)))
+  ; todo: ctrl-g shouldn't clear history
+  (abort:continuation <- current-continuation)
+  (history:buffer-address <- init-buffer 5:literal)  ; buffer of buffers of strings, one per expression typed in
+  { begin
+    (s:string-address <- read-expression nil:literal/keyboard nil:literal/terminal abort:continuation history:buffer-address)
+    (break-unless s:string-address)
+;?     (x:integer <- length s:string-address/deref) ;? 1
+;?     ($print x:integer) ;? 1
+;?     ($print ((#\newline literal))) ;? 1
+    (history:buffer-address <- append history:buffer-address s:string-address)
+;?     (len:integer <- get history:buffer-address/deref length:offset) ;? 1
+;?     ($print len:integer) ;? 1
+;?     ($print ((#\newline literal))) ;? 1
+    (retro-mode)  ; print errors cleanly
+;?       (print-string nil:literal/terminal s:string-address) ;? 1
+      (t:string-address <- $eval s:string-address)
+    (cursor-mode)
+    ($print (("=> " literal)))
+    (print-string nil:literal/terminal t:string-address)
+    (print-character nil:literal/terminal ((#\newline literal)))
+    (print-character nil:literal/terminal ((#\newline literal)))  ; empty line separates each expression and result
+    (loop)
+  }
+])
diff --git a/archive/0.vm.arc/counters.mu b/archive/0.vm.arc/counters.mu
new file mode 100644
index 00000000..0e414513
--- /dev/null
+++ b/archive/0.vm.arc/counters.mu
@@ -0,0 +1,33 @@
+(function init-counter [
+  (default-space:space-address <- new space:literal 30:literal)
+  (n:integer <- next-input)
+  (reply default-space:space-address)
+ ])
+
+(function increment-counter [
+  (default-space:space-address <- new space:literal 30:literal)
+  (0:space-address/names:init-counter <- next-input)  ; setup outer space; it *must* come from 'init-counter'
+  (x:integer <- next-input)
+  (n:integer/space:1 <- add n:integer/space:1 x:integer)
+  (reply n:integer/space:1)
+ ])
+
+(function main [
+  (default-space:space-address <- new space:literal 30:literal)
+  ; counter A
+  (a:space-address <- init-counter 34:literal)
+  ; counter B
+  (b:space-address <- init-counter 23:literal)
+  ; increment both by 2 but in different ways
+  (increment-counter a:space-address 1:literal)
+  (bres:integer <- increment-counter b:space-address 2:literal)
+  (ares:integer <- increment-counter a:space-address 1:literal)
+  ; check results
+  ($print (("Contents of counters a: " literal)))
+  (print-integer nil:literal/terminal ares:integer)
+  ($print ((" b: " literal)))
+  (print-integer nil:literal/terminal bres:integer)
+  ($print (("\n" literal)))
+ ])
+
+; compare http://www.paulgraham.com/accgen.html
diff --git a/archive/0.vm.arc/edit.arc.t b/archive/0.vm.arc/edit.arc.t
new file mode 100644
index 00000000..ff039602
--- /dev/null
+++ b/archive/0.vm.arc/edit.arc.t
@@ -0,0 +1,33 @@
+(selective-load "mu.arc" section-level)
+(set allow-raw-addresses*)
+
+(section 100
+
+(reset)
+(new-trace "new-screen")
+(add-code:readfile "edit.mu")
+(add-code
+  '((function test-new-screen [
+      (1:screen-address/global <- new-screen 5:literal 5:literal)
+     ])))
+;? (each stmt function*!new-screen
+;?   (prn stmt))
+(let routine make-routine!test-new-screen
+  (let before rep.routine!alloc
+;?     (= dump-trace* (obj blacklist '("sz" "m" "setm" "addr" "cvt0" "cvt1")))
+    (run 'test-new-screen)
+;?     (prn memory*)
+;?     (prn memory*.2001)
+    (when (~is (memory* memory*.1) 5)  ; number of rows
+      (prn "F - newly-allocated screen doesn't have the right number of rows: @(memory* memory*!2001)"))
+    (let row-pointers (let base (+ 1 memory*.1)
+                        (range base (+ base 4)))
+  ;?     (prn row-pointers)
+      (when (some nil (map memory* row-pointers))
+        (prn "F - newly-allocated screen didn't initialize all of its row pointers"))
+      (when (~all 5 (map memory* (map memory* row-pointers)))
+        (prn "F - newly-allocated screen didn't initialize all of its row lengths")))))
+
+(reset)
+
+)  ; section 100 for all editor code
diff --git a/archive/0.vm.arc/edit.mu b/archive/0.vm.arc/edit.mu
new file mode 100644
index 00000000..ebf43161
--- /dev/null
+++ b/archive/0.vm.arc/edit.mu
@@ -0,0 +1,18 @@
+; a screen is an array of pointers to lines, in turn arrays of characters
+
+(function new-screen [
+  (default-space:space-address <- new space:literal 30:literal)
+  (nrows:integer <- next-input)
+  (ncols:integer <- next-input)
+  (result:screen-address <- new screen:literal nrows:integer)
+  (rowidx:integer <- copy 0:literal)
+  { begin
+    (curr-line-address-address:line-address-address <- index-address result:screen-address/deref rowidx:integer)
+    (curr-line-address-address:line-address-address/deref <- new line:literal ncols:integer)
+    (curr-line-address:line-address <- copy curr-line-address-address:line-address-address/deref)
+    (rowidx:integer <- add rowidx:integer 1:literal)
+    (x:boolean <- not-equal rowidx:integer nrows:integer)
+    (loop-if x:boolean)
+  }
+  (reply result:screen-address)
+])
diff --git a/archive/0.vm.arc/exuberant-ctags-rc b/archive/0.vm.arc/exuberant-ctags-rc
new file mode 100644
index 00000000..7d99b0b8
--- /dev/null
+++ b/archive/0.vm.arc/exuberant-ctags-rc
@@ -0,0 +1,7 @@
+--langdef=mu
+--langmap=mu:.mu
+--regex-mu=/^\(function[ \t]+([^ \t\[]+)/\1/d,definition/
+--regex-mu=/^\(recipe[ \t]+([^ \t\[]+)/\1/d,definition/
+--regex-mu=/^\(and-record[ \t]+([^ \t\[]+)/\1/t,type/
+--regex-mu=/^\(address[ \t]+([^ \t\[]+)/\1/t,type/
+--regex-mu=/^\(array[ \t]+([^ \t\[]+)/\1/t,type/
diff --git a/archive/0.vm.arc/factorial.mu b/archive/0.vm.arc/factorial.mu
new file mode 100644
index 00000000..96a28fd3
--- /dev/null
+++ b/archive/0.vm.arc/factorial.mu
@@ -0,0 +1,22 @@
+(function factorial [
+  (default-space:space-address <- new space:literal 30:literal)
+  (n:integer <- next-input)
+  { begin
+    ; if n=0 return 1
+    (zero?:boolean <- equal n:integer 0:literal)
+    (break-unless zero?:boolean)
+    (reply 1:literal)
+  }
+  ; return n*factorial(n-1)
+  (x:integer <- subtract n:integer 1:literal)
+  (subresult:integer <- factorial x:integer)
+  (result:integer <- multiply subresult:integer n:integer)
+  (reply result:integer)
+])
+
+(function main [
+  (1:integer <- factorial 5:literal)
+  ($print (("result: " literal)))
+  (print-integer nil:literal/terminal 1:integer)
+  ($print (("\n" literal)))
+])
diff --git a/archive/0.vm.arc/fork.mu b/archive/0.vm.arc/fork.mu
new file mode 100644
index 00000000..8d6463a8
--- /dev/null
+++ b/archive/0.vm.arc/fork.mu
@@ -0,0 +1,18 @@
+(function main [
+  (fork thread2:fn)
+  (default-space:space-address <- new space:literal 2:literal)
+  (x:integer <- copy 34:literal)
+  { begin
+    (print-integer nil:literal/terminal x:integer)
+    (loop)
+  }
+])
+
+(function thread2 [
+  (default-space:space-address <- new space:literal 2:literal)
+  (y:integer <- copy 35:literal)
+  { begin
+    (print-integer nil:literal/terminal y:integer)
+    (loop)
+  }
+])
diff --git a/archive/0.vm.arc/generic.mu b/archive/0.vm.arc/generic.mu
new file mode 100644
index 00000000..1c4b9bb0
--- /dev/null
+++ b/archive/0.vm.arc/generic.mu
@@ -0,0 +1,30 @@
+; To demonstrate generic functions, we'll construct a factorial function with
+; separate base and recursive clauses. Compare factorial.mu.
+
+; factorial n = n*factorial(n-1)
+(function factorial [
+  (default-space:space-address <- new space:literal 30:literal)
+  (n:integer <- input 0:literal)
+  (x:integer <- subtract n:integer 1:literal)
+  (subresult:integer <- factorial x:integer)
+  (result:integer <- multiply subresult:integer n:integer)
+  (reply result:integer)
+])
+
+; factorial 0 = 1
+(function factorial [
+  (default-space:space-address <- new space:literal 30:literal)
+  (n:integer <- input 0:literal)
+  { begin
+    (zero?:boolean <- equal n:integer 0:literal)
+    (break-unless zero?:boolean)
+    (reply 1:literal)
+  }
+])
+
+(function main [
+  (1:integer <- factorial 5:literal)
+  ($print (("result: " literal)))
+  (print-integer nil:literal/terminal 1:integer)
+  ($print (("\n" literal)))
+])
diff --git a/archive/0.vm.arc/graphics.mu b/archive/0.vm.arc/graphics.mu
new file mode 100644
index 00000000..f25395ef
--- /dev/null
+++ b/archive/0.vm.arc/graphics.mu
@@ -0,0 +1,23 @@
+; open a viewport, print coordinates of mouse clicks
+; currently need to ctrl-c to exit after closing the viewport
+(function main [
+  (window-on (("practice" literal)) 300:literal 300:literal)
+  { begin
+    (pos:integer-integer-pair click?:boolean <- mouse-position)
+    (loop-unless click?:boolean)
+    (x:integer <- get pos:integer-integer-pair 0:offset)
+    (y:integer <- get pos:integer-integer-pair 1:offset)
+;?     ($print (("AAA " literal)))
+;?     ($print x:integer)
+;?     ($print ((", " literal)))
+;?     ($print y:integer)
+;?     ($print (("\n" literal)))
+    (print-integer nil:literal/terminal x:integer)
+    (print-character nil:literal/terminal ((#\, literal)))
+    (print-character nil:literal/terminal ((#\space literal)))
+    (print-integer nil:literal/terminal y:integer)
+    (print-character nil:literal/terminal ((#\newline literal)))
+    (loop)
+  }
+  (window-off)
+])
diff --git a/archive/0.vm.arc/highlights b/archive/0.vm.arc/highlights
new file mode 100644
index 00000000..bb81fb56
--- /dev/null
+++ b/archive/0.vm.arc/highlights
@@ -0,0 +1,21 @@
+" vim: ft=vim
+" Data-flow highlighting: http://www.reddit.com/r/programming/comments/1w76um/coding_in_color/cezpios
+
+highlight highlight_97a5a5e3 ctermfg=205
+call matchadd('highlight_97a5a5e3', '\<ncols\>')
+highlight highlight_1f88e41c ctermfg=139
+call matchadd('highlight_1f88e41c', '\<nrows\>')
+highlight highlight_6da20a96 ctermfg=141
+call matchadd('highlight_6da20a96', '\<rowidx\>')
+highlight highlight_ae83eebb ctermfg=149
+call matchadd('highlight_ae83eebb', 'curr-line-address-address')
+highlight highlight_bb695e14 ctermfg=36
+call matchadd('highlight_bb695e14', '\<default-scope\>')
+highlight highlight_1e44ab4f ctermfg=208
+call matchadd('highlight_1e44ab4f', '\<first-arg\>')
+highlight highlight_3323f077 ctermfg=208
+call matchadd('highlight_3323f077', '\<first-arg-box\>')
+highlight highlight_74fc42b2 ctermfg=220
+call matchadd('highlight_74fc42b2', 'second-arg')
+highlight highlight_ff6f0571 ctermfg=220
+call matchadd('highlight_ff6f0571', 'second-arg-box')
diff --git a/archive/0.vm.arc/load.arc b/archive/0.vm.arc/load.arc
new file mode 100644
index 00000000..b9037aa4
--- /dev/null
+++ b/archive/0.vm.arc/load.arc
@@ -0,0 +1,28 @@
+; support for dividing arc files into sections of different level, and
+; selectively loading just sections at or less than a given level
+
+; usage:
+;   load.arc [level] [arc files] -- [mu files]
+
+(def selective-load (file (o level 999))
+;?   (prn "loading @file at level @level")
+  (fromfile file
+    (whilet expr (read)
+;?       (prn car.expr)
+      (if (is 'section expr.0)
+        (when (<= expr.1 level)
+          (each x (cut expr 2)
+            (eval x)))
+        (eval expr))
+;?       (prn car.expr " done")
+      )))
+
+(= section-level 999)
+(point break
+(each x (map [fromstring _ (read)] cdr.argv)
+  (if (isa x 'int)
+        (= section-level x)
+      (is '-- x)
+        (break)  ; later args are mu files
+      :else
+        (selective-load string.x section-level))))
diff --git a/archive/0.vm.arc/mu b/archive/0.vm.arc/mu
new file mode 100755
index 00000000..858438b8
--- /dev/null
+++ b/archive/0.vm.arc/mu
@@ -0,0 +1,27 @@
+#!/bin/bash
+#
+# To run a program:
+#   $ mu [mu files]
+# To run a file of tests (in arc):
+#   $ mu test [arc files]
+# To start an interactive session:
+#   $ mu repl
+#
+# To mess with load levels and selectively run parts of the codebase, skip
+# this script and call load.arc directly.
+
+if [[ $1 == "test" ]]
+then
+  shift
+  ./anarki/arc load.arc "$@"  # test currently assumed to be arc files rather than mu files
+elif [[ $1 == "repl" ]]
+then
+  if [ "$(type rlwrap)" ]
+  then
+    rlwrap -C mu ./anarki/arc mu.arc
+  else
+    ./anarki/arc mu.arc
+  fi
+else
+  ./anarki/arc load.arc mu.arc -- "$@"  # mu files from args
+fi
diff --git a/archive/0.vm.arc/mu.arc b/archive/0.vm.arc/mu.arc
new file mode 100644
index 00000000..2aebd3d5
--- /dev/null
+++ b/archive/0.vm.arc/mu.arc
@@ -0,0 +1,3259 @@
+(ero "initializing mu.. (takes ~5s)")
+;; profiler (http://arclanguage.org/item?id=11556)
+; Keeping this right on top as a reminder to profile before guessing at why my
+; program is slow.
+(mac proc (name params . body)
+  `(def ,name ,params ,@body nil))
+
+(mac filter-log (msg f x)
+  `(ret x@ ,x
+     (prn ,msg (,f x@))))
+
+(= times* (table))
+
+(mac deftimed (name args . body)
+  `(do
+     (def ,(sym (string name "_core")) ,args
+        ,@body)
+     (def ,name ,args
+      (let t0 (msec)
+        (ret ans ,(cons (sym (string name "_core")) args)
+          (update-time ,(string name) t0))))))
+
+(proc update-time(name t0) ; call directly in recursive functions
+  (or= times*.name (list 0 0))
+  (with ((a b)  times*.name
+         timing (- (msec) t0))
+    (= times*.name
+       (list
+         (+ a timing)
+         (+ b 1)))))
+
+(def print-times()
+  (prn (current-process-milliseconds))
+  (prn "gc " (current-gc-milliseconds))
+  (each (name time) (tablist times*)
+    (prn name " " time)))
+
+;; what happens when our virtual machine starts up
+(= initialization-fns* (queue))
+(def reset ()
+  (each f (as cons initialization-fns*)
+    (f)))
+
+(mac on-init body
+  `(enq (fn () ,@body)
+        initialization-fns*))
+
+;; persisting and checking traces for each test
+(= traces* (queue))
+(= trace-dir* ".traces/")
+(ensure-dir trace-dir*)
+(= curr-trace-file* nil)
+(on-init
+  (awhen curr-trace-file*
+    (tofile (+ trace-dir* it)
+      (each (label trace) (as cons traces*)
+        (pr label ": " trace))))
+  (= curr-trace-file* nil)
+  (= traces* (queue)))
+
+(def new-trace (filename)
+  (prn "== @filename")
+;?   )
+  (= curr-trace-file* filename))
+
+(= dump-trace* nil)
+(def trace (label . args)
+  (when (or (is dump-trace* t)
+            (and dump-trace* (is label "-"))
+            (and dump-trace* (pos label dump-trace*!whitelist))
+            (and dump-trace* (no dump-trace*!whitelist) (~pos label dump-trace*!blacklist)))
+    (apply prn label ": " args))
+  (enq (list label (apply tostring:prn args))
+       traces*)
+  (car args))
+
+(on-init
+  (wipe dump-trace*))
+
+(redef tr args  ; why am I still returning to prn when debugging? Will this help?
+  (do1 nil
+       (apply trace "-" args)))
+
+(def tr2 (msg arg)
+  (tr msg arg)
+  arg)
+
+(def check-trace-contents (msg expected-contents)
+  (unless (trace-contents-match expected-contents)
+    (prn "F - " msg)
+    (prn "  trace contents")
+    (print-trace-contents-mismatch expected-contents)))
+
+(def trace-contents-match (expected-contents)
+  (each (label msg) (as cons traces*)
+    (when (and expected-contents
+               (is label expected-contents.0.0)
+               (posmatch expected-contents.0.1 msg))
+      (pop expected-contents)))
+  (no expected-contents))
+
+(def print-trace-contents-mismatch (expected-contents)
+  (each (label msg) (as cons traces*)
+    (whenlet (expected-label expected-msg)  expected-contents.0
+      (if (and (is label expected-label)
+               (posmatch expected-msg msg))
+        (do (pr "  * ")
+            (pop expected-contents))
+        (pr "    "))
+      (pr label ": " msg)))
+  (prn "  couldn't find")
+  (each (expected-label expected-msg)  expected-contents
+    (prn "  ! " expected-label ": " expected-msg)))
+
+(def check-trace-doesnt-contain (msg (label unexpected-contents))
+  (when (some (fn ((l s))
+                (and (is l label)  (posmatch unexpected-contents msg)))
+              (as cons traces*))
+    (prn "F - " msg)
+    (prn "  trace contents")
+    (each (l msg) (as cons traces*)
+      (if (and (is l label)
+               (posmatch unexpected-contents msg))
+        (pr "  X ")
+        (pr "    "))
+      (pr label ": " msg))))
+
+;; virtual machine state
+
+; things that a future assembler will need separate memory for:
+;   code; types; args channel
+;   at compile time: mapping names to locations
+(on-init
+  (= type* (table))  ; name -> type info
+  (= memory* (table))  ; address -> value  (make this a vector?)
+  (= function* (table))  ; name -> [instructions]
+  ; transforming mu programs
+  (= location* (table))  ; function -> {name -> index into default-space}
+  (= next-space-generator* (table))  ; function -> name of function generating next space
+  ; each function's next space will usually always come from a single function
+  (= next-routine-id* 0)
+  (= continuation* (table))
+  )
+
+(on-init
+  (= type* (obj
+              ; Each type must be scalar or array, sum or product or primitive
+              type (obj size 1)  ; implicitly scalar and primitive
+              type-address (obj size 1  address t  elem '(type))
+              type-array (obj array t  elem '(type))
+              type-array-address (obj size 1  address t  elem '(type-array))
+              location (obj size 1  address t  elem '(location))  ; assume it points to an atom
+              integer (obj size 1)
+              boolean (obj size 1)
+              boolean-address (obj size 1  address t  elem '(boolean))
+              byte (obj size 1)
+              byte-address (obj  size 1  address t  elem '(byte))
+              string (obj array t  elem '(byte))  ; inspired by Go
+              ; an address contains the location of a specific type
+              string-address (obj size 1  address t  elem '(string))
+              string-address-address (obj size 1  address t  elem '(string-address))
+              string-address-array (obj array t  elem '(string-address))
+              string-address-array-address (obj size 1  address t  elem '(string-address-array))
+              string-address-array-address-address (obj size 1  address t  elem '(string-address-array-address))
+              ; 'character' will be of larger size when mu supports unicode
+              ; we're currently undisciplined about mixing 'byte' and 'character'
+              ; realistic test of indiscipline in general
+              character (obj size 1)  ; int32 like a Go rune
+              character-address (obj size 1  address t  elem '(character))
+              ; a buffer makes it easy to append to a string/array
+              ; todo: make this generic
+              ; data isn't a 'real' array: its length is stored outside it,
+              ; so for example, 'print-string' won't work on it.
+              buffer (obj size 2  and-record t  elems '((integer) (string-address))  fields '(length data))
+              buffer-address (obj size 1  address t  elem '(buffer))
+              ; a stream makes it easy to read from a string/array
+              stream (obj size 2  and-record t  elems '((integer) (string-address))  fields '(pointer data))
+              stream-address (obj size 1  address t  elem '(stream))
+              ; isolating function calls
+              space (obj array t  elem '(location))  ; by convention index 0 points to outer space
+              space-address (obj size 1  address t  elem '(space))
+              ; arrays consist of an integer length followed by that many
+              ; elements, all of the same type
+              integer-array (obj array t  elem '(integer))
+              integer-array-address (obj size 1  address t  elem '(integer-array))
+              integer-array-address-address (obj size 1  address t  elem '(integer-array-address))
+              integer-address (obj size 1  address t  elem '(integer))  ; pointer to int
+              integer-address-address (obj size 1  address t  elem '(integer-address))
+              ; and-records consist of a multiple fields of different types
+              integer-boolean-pair (obj size 2  and-record t  elems '((integer) (boolean))  fields '(int bool))
+              integer-boolean-pair-address (obj size 1  address t  elem '(integer-boolean-pair))
+              integer-boolean-pair-array (obj array t  elem '(integer-boolean-pair))
+              integer-boolean-pair-array-address (obj size 1  address t  elem '(integer-boolean-pair-array))
+              integer-integer-pair (obj size 2  and-record t  elems '((integer) (integer)))
+              integer-integer-pair-address (obj size 1  address t  elem '(integer-integer-pair))
+              integer-point-pair (obj size 2  and-record t  elems '((integer) (integer-integer-pair)))
+              integer-point-pair-address (obj size 1  address t  elem '(integer-point-pair))
+              integer-point-pair-address-address (obj size 1  address t  elem '(integer-point-pair-address))
+              ; tagged-values are the foundation of dynamic types
+              tagged-value (obj size 2  and-record t  elems '((type) (location))  fields '(type payload))
+              tagged-value-address (obj size 1  address t  elem '(tagged-value))
+              tagged-value-array (obj array t  elem '(tagged-value))
+              tagged-value-array-address (obj size 1  address t  elem '(tagged-value-array))
+              tagged-value-array-address-address (obj size 1  address t  elem '(tagged-value-array-address))
+              ; heterogeneous lists
+              list (obj size 2  and-record t  elems '((tagged-value) (list-address))  fields '(car cdr))
+              list-address (obj size 1  address t  elem '(list))
+              list-address-address (obj size 1  address t  elem '(list-address))
+              ; parallel routines use channels to synchronize
+              channel (obj size 3  and-record t  elems '((integer) (integer) (tagged-value-array-address))  fields '(first-full first-free circular-buffer))
+              ; be careful of accidental copies to channels
+              channel-address (obj size 1  address t  elem '(channel))
+              ; opaque pointer to a call stack
+              ; todo: save properly in allocated memory
+              continuation (obj size 1)
+              ; editor
+              line (obj array t  elem '(character))
+              line-address (obj size 1  address t  elem '(line))
+              line-address-address (obj size 1  address t  elem '(line-address))
+              screen (obj array t  elem '(line-address))
+              screen-address (obj size 1  address t  elem '(screen))
+              ; fake screen
+              terminal (obj size 5  and-record t  elems '((integer) (integer) (integer) (integer) (string-address))  fields '(num-rows num-cols cursor-row cursor-col data))
+              terminal-address (obj size 1  address t  elem '(terminal))
+              ; fake keyboard
+              keyboard (obj size 2  and-record t  elems '((integer) (string-address))  fields '(index data))
+              keyboard-address (obj size 1  address t  elem '(keyboard))
+              )))
+
+;; managing concurrent routines
+
+(on-init
+;?   (prn "-- resetting memory allocation")
+  (= Memory-allocated-until 1000)
+  (= Allocation-chunk 100000))
+
+; routine = runtime state for a serial thread of execution
+(def make-routine (fn-name . args)
+  (let curr-alloc Memory-allocated-until
+;?     (prn "-- allocating routine: @curr-alloc")
+    (++ Memory-allocated-until Allocation-chunk)
+    (annotate 'routine (obj alloc curr-alloc  alloc-max Memory-allocated-until
+        call-stack
+          (list (obj fn-name fn-name  pc 0  args args  caller-arg-idx 0))))
+        ; other fields we use in routine:
+        ;   sleep: conditions
+        ;   limit: number of cycles this routine can use
+        ;   running-since: start of the clock for counting cycles this routine has used
+
+    ; todo: do memory management in mu
+    ))
+
+(defextend empty (x)  (isa x 'routine)
+  (no rep.x!call-stack))
+
+(def stack (routine)
+  ((rep routine) 'call-stack))
+
+(def push-stack (routine op)
+  (push (obj fn-name op  pc 0  caller-arg-idx 0  t0 (msec))
+        rep.routine!call-stack))
+
+(def pop-stack (routine)
+;?   (update-time label.routine (msec)) ;? 1
+  (pop rep.routine!call-stack))
+
+(def top (routine)
+  stack.routine.0)
+
+(def label (routine)
+  (whenlet stack stack.routine
+    (or= stack.0!label
+         (label2 stack))))
+(def label2 (stack)
+         (string:intersperse "/" (map [_ 'fn-name] stack)));))
+
+(def body (routine)
+  (function* stack.routine.0!fn-name))
+
+(mac pc (routine (o idx 0))  ; assignable
+  `((((rep ,routine) 'call-stack) ,idx) 'pc))
+
+(mac caller-arg-idx (routine (o idx 0))  ; assignable
+  `((((rep ,routine) 'call-stack) ,idx) 'caller-arg-idx))
+
+(mac caller-args (routine)  ; assignable
+  `((((rep ,routine) 'call-stack) 0) 'args))
+(mac caller-operands (routine)  ; assignable
+  `((((rep ,routine) 'call-stack) 0) 'caller-operands))
+(mac caller-results (routine)  ; assignable
+  `((((rep ,routine) 'call-stack) 0) 'caller-results))
+
+(mac results (routine)  ; assignable
+  `((((rep ,routine) 'call-stack) 0) 'results))
+(mac reply-args (routine)  ; assignable
+  `((((rep ,routine) 'call-stack) 0) 'reply-args))
+
+(def waiting-for-exact-cycle? (routine)
+  (is 'until rep.routine!sleep.0))
+
+(def ready-to-wake-up (routine)
+  (assert no.routine*)
+  (case rep.routine!sleep.0
+    until
+      (> curr-cycle* rep.routine!sleep.1)
+    until-location-changes
+      (~is rep.routine!sleep.2 (memory* rep.routine!sleep.1))
+    until-routine-done
+      (find [and _ (is rep._!id rep.routine!sleep.1)]
+            completed-routines*)
+    ))
+
+(on-init
+  (= running-routines* (queue))  ; simple round-robin scheduler
+  ; set of sleeping routines; don't modify routines while they're in this table
+  (= sleeping-routines* (table))
+  (= completed-routines* nil)  ; audit trail
+  (= routine* nil)
+  (= abort-routine* (parameter nil))
+  (= curr-cycle* 0)
+  (= scheduling-interval* 500)
+  (= scheduler-switch-table* nil)  ; hook into scheduler for debugging
+  )
+
+; like arc's 'point' but you can also call ((abort-routine*)) in nested calls
+(mac routine-mark body
+  (w/uniq (g p)
+    `(ccc (fn (,g)
+            (parameterize abort-routine* (fn ((o ,p)) (,g ,p))
+              ,@body)))))
+
+(def run fn-names
+  (freeze function*)
+;?   (prn function*!main) ;? 1
+  (load-system-functions)
+  (apply run-more fn-names))
+
+; assume we've already frozen; throw on a few more routines and continue scheduling
+(def run-more fn-names
+  (each it fn-names
+    (enq make-routine.it running-routines*))
+  (while (~empty running-routines*)
+    (= routine* deq.running-routines*)
+    (when rep.routine*!limit
+      ; start the clock if it wasn't already running
+      (or= rep.routine*!running-since curr-cycle*))
+    (trace "schedule" label.routine*)
+    (routine-mark
+      (run-for-time-slice scheduling-interval*))
+    (update-scheduler-state)))
+
+; prepare next iteration of round-robin scheduler
+;
+; state before: routine* running-routines* sleeping-routines*
+; state after: running-routines* (with next routine to run at head) sleeping-routines*
+;
+; responsibilities:
+;   add routine* to either running-routines* or sleeping-routines* or completed-routines*
+;   wake up any necessary sleeping routines (which might be waiting for a
+;     particular time or for a particular memory location to change)
+;   detect termination: all non-helper routines completed
+;   detect deadlock: kill all sleeping routines when none can be woken
+(def update-scheduler-state ()
+  (when routine*
+;?     (prn "update scheduler state: " routine*)
+    (if
+        rep.routine*!sleep
+          (do (trace "schedule" "pushing " label.routine* " to sleep queue")
+              ; keep the clock ticking at rep.routine*!running-since
+              (set sleeping-routines*.routine*))
+        rep.routine*!error
+          (do (trace "schedule" "done with dead routine " label.routine*)
+;?               (tr rep.routine*)
+              (push routine* completed-routines*))
+        empty.routine*
+          (do (trace "schedule" "done with routine " label.routine*)
+              (push routine* completed-routines*))
+        (no rep.routine*!limit)
+          (do (trace "schedule" "scheduling " label.routine* " for further processing")
+              (enq routine* running-routines*))
+        (> rep.routine*!limit 0)
+          (do (trace "schedule" "scheduling " label.routine* " for further processing (limit)")
+              ; stop the clock and debit the time on it from the routine
+              (-- rep.routine*!limit (- curr-cycle* rep.routine*!running-since))
+              (wipe rep.routine*!running-since)
+              (if (<= rep.routine*!limit 0)
+                (do (trace "schedule" "routine ran out of time")
+                    (push routine* completed-routines*))
+                (enq routine* running-routines*)))
+        :else
+          (err "illegal scheduler state"))
+    (= routine* nil))
+  (each (routine _) routine-canon.sleeping-routines*
+    (when (aand rep.routine!limit (<= it (- curr-cycle* rep.routine!running-since)))
+      (trace "schedule" "routine timed out")
+      (wipe sleeping-routines*.routine)
+      (push routine completed-routines*)
+;?       (tr completed-routines*)
+      ))
+  (each (routine _) routine-canon.sleeping-routines*
+    (when (ready-to-wake-up routine)
+      (trace "schedule" "waking up " label.routine)
+      (wipe sleeping-routines*.routine)  ; do this before modifying routine
+      (wipe rep.routine!sleep)
+      (++ pc.routine)
+      (enq routine running-routines*)))
+  ; optimization for simulated time
+  (when (empty running-routines*)
+    (whenlet exact-sleeping-routines (keep waiting-for-exact-cycle? keys.sleeping-routines*)
+      (let next-wakeup-cycle (apply min (map [rep._!sleep 1] exact-sleeping-routines))
+        (= curr-cycle* (+ 1 next-wakeup-cycle)))
+      (trace "schedule" "skipping to cycle " curr-cycle*)
+      (update-scheduler-state)))
+  (when (and (or (~empty running-routines*)
+                 (~empty sleeping-routines*))
+             (all [rep._ 'helper] (as cons running-routines*))
+             (all [rep._ 'helper] keys.sleeping-routines*))
+    (trace "schedule" "just helpers left; stopping everything")
+    (until (empty running-routines*)
+      (push (deq running-routines*) completed-routines*))
+    (each (routine _) sleeping-routines*
+;?       (prn " " label.routine) ;? 0
+      (wipe sleeping-routines*.routine)
+      (push routine completed-routines*)))
+  (detect-deadlock)
+  )
+
+(def detect-deadlock ()
+  (when (and (empty running-routines*)
+             (~empty sleeping-routines*)
+             (~some 'literal (map (fn(_) rep._!sleep.1)
+                                  keys.sleeping-routines*)))
+    (each (routine _) sleeping-routines*
+      (wipe sleeping-routines*.routine)
+      (= rep.routine!error "deadlock detected")
+      (push routine completed-routines*))))
+
+(def die (msg)
+  (tr "die: " msg)
+  (= rep.routine*!error msg)
+  (iflet abort-continuation (abort-routine*)
+    (abort-continuation)))
+
+;; running a single routine
+
+; value of an arg or oarg, stripping away all metadata
+; wish I could have this flag an error when arg is incorrectly formed
+(mac v (operand)  ; for value
+  `((,operand 0) 0))
+
+; routines consist of instrs
+; instrs consist of oargs, op and args
+(def parse-instr (instr)
+  (iflet delim (pos '<- instr)
+    (do (when (atom (instr (+ delim 1)))
+          (err "operator not tokenized in @instr; maybe you need to freeze functions*?"))
+        (list (cut instr 0 delim)  ; oargs
+              (v (instr (+ delim 1)))  ; op
+              (cut instr (+ delim 2))))  ; args
+    (list nil (v car.instr) cdr.instr)))
+
+(def metadata (operand)
+  cdr.operand)
+
+(def ty (operand)
+  (cdr operand.0))
+
+(def literal? (operand)
+  (unless (acons ty.operand)
+    (err "no type in operand @operand"))
+  (in ty.operand.0 'literal 'offset 'fn))
+
+(def typeinfo (operand)
+  (or (type* ty.operand.0)
+      (err "unknown type @(tostring prn.operand)")))
+
+; operand accessors
+(def nondummy (operand)  ; precondition for helpers below
+  (~is '_ operand))
+
+; just for convenience, 'new' instruction sometimes takes a raw string and
+; allocates just enough space to store it
+(def not-raw-string (operand)
+  (~isa operand 'string))
+
+(def address? (operand)
+  (or (is ty.operand.0 'location)
+      typeinfo.operand!address))
+
+($:require "charterm/main.rkt")
+($:require graphics/graphics)
+;? ($:require "terminal-color/terminal-color/main.rkt") ;? 1
+(= Viewport nil)
+; http://rosettacode.org/wiki/Terminal_control/Coloured_text#Racket
+($:define (tput . xs) (system (apply ~a 'tput " " (add-between xs " "))) (void))
+($:define (foreground color) (tput 'setaf color))
+($:define (background color) (tput 'setab color))
+($:define (reset) (tput 'sgr0))
+
+(= new-string-foo* nil)
+(= last-print* 0)
+
+; run instructions from 'routine*' for 'time-slice'
+(def run-for-time-slice (time-slice)
+  (point return
+    (for ninstrs 0 (< ninstrs time-slice) (++ ninstrs)
+      (if (empty body.routine*) (err "@stack.routine*.0!fn-name not defined"))
+      ; falling out of end of function = implicit reply
+      (while (>= pc.routine* (len body.routine*))
+        (pop-stack routine*)
+        (if empty.routine* (return ninstrs))
+        (when (pos '<- (body.routine* pc.routine*))
+          (die "No results returned: @(tostring:pr (body.routine* pc.routine*))"))
+        (++ pc.routine*))
+      (++ curr-cycle*)
+      (when (no ($.current-charterm))
+        (let curr (seconds)
+          (when (~is curr last-print*)
+            (prn curr " " curr-cycle* " " len.running-routines*)
+            (= last-print* curr))))
+;?       (trace "run" "-- " int-canon.memory*) ;? 1
+;?       (trace "run" curr-cycle*)
+      (trace "run" label.routine* " " pc.routine* ": " (body.routine* pc.routine*))
+;?       (trace "run" routine*)
+      (when (atom (body.routine* pc.routine*))  ; label
+;?         (tr "label") ;? 1
+        (when (aand scheduler-switch-table*
+                    (alref it (body.routine* pc.routine*)))
+          (++ pc.routine*)
+          (trace "run" label.routine* " " pc.routine* ": " "context-switch forced " abort-routine*)
+          ((abort-routine*)))
+        (++ pc.routine*)
+        (continue))
+      (let (oarg op arg)  (parse-instr (body.routine* pc.routine*))
+;?         (tr op) ;? 1
+        (let results
+              (case op
+                ; arithmetic
+                add
+                  (+ (m arg.0) (m arg.1))
+                subtract
+                  (- (m arg.0) (m arg.1))
+                multiply
+                  (* (m arg.0) (m arg.1))
+                divide
+                  (/ (real (m arg.0)) (m arg.1))
+                divide-with-remainder
+                  (list (trunc:/ (m arg.0) (m arg.1))
+                        (mod (m arg.0) (m arg.1)))
+
+                ; boolean
+                and
+                  (and (m arg.0) (m arg.1))
+                or
+                  (or (m arg.0) (m arg.1))
+                not
+                  (not (m arg.0))
+
+                ; comparison
+                equal
+;?                   (do (prn (m arg.0) " vs " (m arg.1))
+                  (is (m arg.0) (m arg.1))
+;?                   )
+                not-equal
+                  (~is (m arg.0) (m arg.1))
+                less-than
+                  (< (m arg.0) (m arg.1))
+                greater-than
+                  (> (m arg.0) (m arg.1))
+                lesser-or-equal
+                  (<= (m arg.0) (m arg.1))
+                greater-or-equal
+                  (>= (m arg.0) (m arg.1))
+
+                ; control flow
+                jump
+                  (do (= pc.routine* (+ 1 pc.routine* (v arg.0)))
+                      (continue))
+                jump-if
+                  (when (m arg.0)
+                    (= pc.routine* (+ 1 pc.routine* (v arg.1)))
+                    (continue))
+                jump-unless  ; convenient helper
+                  (unless (m arg.0)
+                    (= pc.routine* (+ 1 pc.routine* (v arg.1)))
+                    (continue))
+
+                ; data management: scalars, arrays, and-records (structs)
+                copy
+                  (m arg.0)
+                get
+                  (with (operand  (canonize arg.0)
+                         idx  (v arg.1))
+                    (assert (iso '(offset) (ty arg.1)) "record index @arg.1 must have type 'offset'")
+                    (assert (< -1 idx (len typeinfo.operand!elems)) "@idx is out of bounds of record @operand")
+                    (m `((,(apply + v.operand
+                                    (map (fn(x) (sizeof `((_ ,@x))))
+                                         (firstn idx typeinfo.operand!elems)))
+                          ,@typeinfo.operand!elems.idx)
+                         (raw))))
+                get-address
+                  (with (operand  (canonize arg.0)
+                         idx  (v arg.1))
+                    (assert (iso '(offset) (ty arg.1)) "record index @arg.1 must have type 'offset'")
+                    (assert (< -1 idx (len typeinfo.operand!elems)) "@idx is out of bounds of record @operand")
+                    (apply + v.operand
+                             (map (fn(x) (sizeof `((_ ,@x))))
+                                  (firstn idx typeinfo.operand!elems))))
+                index
+                  (withs (operand  (canonize arg.0)
+                          elemtype  typeinfo.operand!elem
+                          idx  (m arg.1))
+;?                     (write arg.0)
+;?                     (pr " => ")
+;?                     (write operand)
+;?                     (prn)
+                    (unless (< -1 idx array-len.operand)
+                      (die "@idx is out of bounds of array @operand"))
+                    (m `((,(+ v.operand
+                              1  ; for array size
+                              (* idx (sizeof `((_ ,@elemtype)))))
+                           ,@elemtype)
+                         (raw))))
+                index-address
+                  (withs (operand  (canonize arg.0)
+                          elemtype  typeinfo.operand!elem
+                          idx  (m arg.1))
+                    (unless (< -1 idx array-len.operand)
+                      (die "@idx is out of bounds of array @operand"))
+                    (+ v.operand
+                       1  ; for array size
+                       (* idx (sizeof `((_ ,@elemtype))))))
+                new
+                  (if (isa arg.0 'string)
+                    ; special-case: allocate space for a literal string
+                    (new-string arg.0)
+                    (let type (v arg.0)
+                      (assert (iso '(literal) (ty arg.0)) "new: second arg @arg.0 must be literal")
+                      (if (no type*.type)  (err "no such type @type"))
+                      ; todo: initialize memory. currently racket does it for us
+                      (if type*.type!array
+                        (new-array type (m arg.1))
+                        (new-scalar type))))
+                sizeof
+                  (sizeof `((_ ,(m arg.0))))
+                length
+                  (let base arg.0
+                    (if (or typeinfo.base!array address?.base)
+                      array-len.base
+                      -1))
+
+                ; tagged-values require one primitive
+                save-type
+                  (annotate 'record `(,((ty arg.0) 0) ,(m arg.0)))
+
+                ; code points for characters
+                character-to-integer
+                  ($.char->integer (m arg.0))
+                integer-to-character
+                  ($.integer->char (m arg.0))
+
+                ; multiprocessing
+                fork
+                  ; args: fn globals-table args ...
+                  (let routine  (apply make-routine (m arg.0) (map m (nthcdr 3 arg)))
+                    (= rep.routine!id ++.next-routine-id*)
+                    (= rep.routine!globals (when (len> arg 1) (m arg.1)))
+                    (= rep.routine!limit (when (len> arg 2) (m arg.2)))
+                    (enq routine running-routines*)
+                    rep.routine!id)
+                fork-helper
+                  ; args: fn globals-table args ...
+                  (let routine  (apply make-routine (m arg.0) (map m (nthcdr 3 arg)))
+                    (= rep.routine!id ++.next-routine-id*)
+                    (set rep.routine!helper)
+                    (= rep.routine!globals (when (len> arg 1) (m arg.1)))
+                    (= rep.routine!limit (when (len> arg 2) (m arg.2)))
+                    (enq routine running-routines*)
+                    rep.routine!id)
+                sleep
+                  (do
+                    (case (v arg.0)
+                      for-some-cycles
+                        (let wakeup-time (+ curr-cycle* (v arg.1))
+                          (trace "run" label.routine* " " pc.routine* ": " "sleeping until " wakeup-time)
+                          (= rep.routine*!sleep `(until ,wakeup-time)))
+                      until-location-changes
+                        (= rep.routine*!sleep `(until-location-changes ,(addr arg.1) ,(m arg.1)))
+                      until-routine-done
+                        (= rep.routine*!sleep `(until-routine-done ,(m arg.1)))
+                      ; else
+                        (die "badly formed 'sleep' call @(tostring:prn (body.routine* pc.routine*))")
+                      )
+                    ((abort-routine*)))
+                assert
+                  (unless (m arg.0)
+                    (die (v arg.1)))  ; other routines will be able to look at the error status
+                assert-false
+                  (when (m arg.0)
+                    (die (v arg.1)))
+
+                ; cursor-based (text mode) interaction
+                cursor-mode
+                  ;(do1 nil (system "/bin/stty -F /dev/tty raw"))
+                  (do1 nil (if (no ($.current-charterm)) ($.open-charterm)))
+                retro-mode
+                  ;(do1 nil (system "/bin/stty -F /dev/tty sane"))
+                  (do1 nil (if ($.current-charterm) ($.close-charterm)))
+                clear-host-screen
+                  (do1 nil (pr "\e[m\e[2J\e[;H"))
+                clear-line-on-host
+                  (do1 nil (pr "\e[2K"))
+                cursor-on-host
+                  (do1 nil (pr (+ "\e[" (m arg.0) ";" (m arg.1) "H")))
+                cursor-on-host-to-next-line
+                  (do1 nil (pr "\r\n"))
+                cursor-up-on-host
+                  (do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "A")))
+                cursor-down-on-host
+                  (do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "B")))
+                cursor-right-on-host
+                  (do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "C")))
+                cursor-left-on-host
+                  (do1 nil (pr (+ "\e[" (aif (len> arg 0) (or m arg.0) 1) "D")))
+                print-character-to-host
+                  (do1 nil
+                       (assert (in (type:m arg.0) 'char 'sym) (rep (m arg.0)))
+;?                        (write (m arg.0))  (pr " => ")  (prn (type (m arg.0)))
+                       (if (no ($.current-charterm))
+                         (pr (m arg.0))
+                         (caselet x (m arg.0)
+                           ; todo: test these exceptions
+                           #\newline
+                             (pr "\r\n")
+                           #\backspace
+                             ; backspace doesn't clear after moving the cursor
+                             (pr "\b \b")
+                           ctrl-c
+                             (do ($.close-charterm)
+                                 (die "interrupted"))
+                           ;else
+                             (if (and (len> arg 2)
+                                      (m arg.2))
+                                   (do
+                                     ($.foreground (m arg.1))
+                                     ($.background (m arg.2))
+                                     (pr x)
+                                     ($.reset))
+                                 (and (len> arg 1)
+                                      (m arg.1))
+                                   (do
+                                     ($.foreground (m arg.1))
+                                     (pr x)
+                                     ($.reset))
+                                 :else
+                                   (pr x))))
+                       )
+                read-key-from-host
+                  (if ($.current-charterm)
+                        (and ($.charterm-byte-ready?)
+                             (ret result ($.charterm-read-key)
+                               (case result
+                                 ; charterm exceptions
+                                 return
+                                   (= result #\newline)
+                                 backspace
+                                   (= result #\backspace)
+                                 )))
+                      ($.graphics-open?)
+                        ($.ready-key-press Viewport))
+
+                ; graphics
+                window-on
+                  (do1 nil
+                    ($.open-graphics)
+                    (= Viewport ($.open-viewport (m arg.0)  ; name
+                                                 (m arg.1) (m arg.2))))  ; width height
+                window-off
+                  (do1 nil
+                    ($.close-viewport Viewport)  ; why doesn't this close the window? works in naked racket. not racket vs arc.
+                    ($.close-graphics)
+                    (= Viewport nil))
+                mouse-position
+                  (aif ($.ready-mouse-click Viewport)
+                    (let posn ($.mouse-click-posn it)
+                      (list (annotate 'record (list ($.posn-x posn) ($.posn-y posn))) t))
+                    (list nil nil))
+                wait-for-mouse
+                  (let posn ($.mouse-click-posn ($.get-mouse-click Viewport))
+                    (list (annotate 'record (list ($.posn-x posn) ($.posn-y posn))) t))
+                ; clear-screen in cursor mode above
+                rectangle
+                  (do1 nil
+                    (($.draw-solid-rectangle Viewport)
+                        ($.make-posn (m arg.0) (m arg.1))  ; origin
+                        (m arg.2)  (m arg.3)  ; width height
+                        (m arg.4)))  ; color
+                point
+                  (do1 nil
+                    (($.draw-pixel Viewport) ($.make-posn (m arg.0) (m arg.1))
+                                             (m arg.2)))  ; color
+
+                image
+                  (do1 nil
+                    (($.draw-pixmap Viewport) (m arg.0)  ; filename
+                                              ($.make-posn (m arg.1) (m arg.2))))
+                color-at
+                  (let pixel (($.get-color-pixel Viewport) ($.make-posn (m arg.0) (m arg.1)))
+                    (prn ($.rgb-red pixel) " " ($.rgb-blue pixel) " " ($.rgb-green pixel))
+                    ($:rgb-red pixel))
+
+                ; debugging aides
+                $dump-memory
+                  (do1 nil
+                    (prn:repr int-canon.memory*))
+                $dump-trace
+                  (tofile arg.0
+                    (each (label trace) (as cons traces*)
+                      (pr label ": " trace)))
+                $start-tracing
+                  (do1 nil
+                    (set dump-trace*))
+                $stop-tracing
+                  (do1 nil
+                    (wipe dump-trace*))
+                $dump-routine
+                  (do1 nil
+                    ($.close-charterm)
+                    (prn routine*)
+                    ($.open-charterm)
+                    )
+                $dump-channel
+                  (do1 nil
+                    ($.close-charterm)
+                    (withs (x (m arg.0)
+                            y (memory* (+ x 2)))
+                      (prn label.routine* " -- " x " -- " (list (memory* x)
+                                                                (memory* (+ x 1))
+                                                                (memory* (+ x 2)))
+                                                   " -- " (list (memory* y)
+                                                                (memory* (+ y 1))
+                                                                (repr:memory* (+ y 2))
+                                                                (memory* (+ y 3))
+                                                                (repr:memory* (+ y 4)))))
+                    ($.open-charterm)
+                    )
+                $quit
+                  (quit)
+                $wait-for-key-from-host
+                  (when ($.current-charterm)
+                    (ret result ($.charterm-read-key)
+                      (case result
+                        ; charterm exceptions
+                        return
+                          (= result #\newline)
+                        backspace
+                          (= result #\backspace)
+                        )))
+                $print
+                  (do1 nil
+;?                        (write (m arg.0))  (pr " => ")  (prn (type (m arg.0)))
+                       (if (no ($.current-charterm))
+                         (pr (m arg.0))
+                         (unless disable-debug-prints-in-console-mode*
+                           (caselet x (m arg.0)
+                             #\newline
+                               (pr "\r\n")
+                             #\backspace
+                               ; backspace doesn't clear after moving the cursor
+                               (pr "\b \b")
+                             ctrl-c
+                               (do ($.close-charterm)
+                                   (die "interrupted"))
+                             ;else
+                               (pr x)))
+                          ))
+                $write
+                  (do1 nil
+                    (write (m arg.0)))
+                $eval
+                  (new-string:repr:eval:read:to-arc-string (m arg.0))
+;?                   (let x (to-arc-string (m arg.0)) ;? 1
+;?                     (prn x) ;? 1
+;?                     (new-string:repr:eval x)) ;? 1
+
+                $clear-trace
+                  (do1 nil (wipe interactive-traces*))
+                $save-trace
+                  (let x (filter-log "CCC: " len
+                         (string
+                           (filter-log "BBB: " len
+                           (map [string:intersperse ": " _]
+                                (filter-log "AAA: " len
+                                (as cons (interactive-traces* (m arg.0)))))
+                                )))
+;?                   (let x (string:map [string:intersperse ": " _]
+;?                                      (apply join
+;?                                             (map [as cons _] rev.interactive-traces*)))
+                    (prn "computed trace; now saving to memory\n")
+;?                     (write x)(write #\newline) ;? 1
+;?                     (prn x) ;? 1
+                    (set new-string-foo*)
+                    (do1 (new-string x)
+                      (wipe new-string-foo*)))
+
+                ; first-class continuations
+                current-continuation
+                  (w/uniq continuation-name
+                    (trace "continuation" "saving @(repr rep.routine*!call-stack) to @continuation-name")
+                    (= continuation*.continuation-name (copy rep.routine*!call-stack))
+                    continuation-name)
+                continue-from
+                  (let continuation-name (m arg.0)
+                    (trace "continuation" "restoring @continuation-name")
+                    (trace "continuation" continuation*.continuation-name)
+                    (= rep.routine*!call-stack continuation*.continuation-name)
+                    (trace "continuation" "call stack is now @(repr rep.routine*!call-stack)")
+;?                     (++ pc.routine*) ;? 1
+                    (continue))
+;?                     ((abort-routine*))) ;? 1
+
+                ; user-defined functions
+                next-input
+                  (let idx caller-arg-idx.routine*
+                    (++ caller-arg-idx.routine*)
+                    (trace "arg" repr.arg " " idx " " (repr caller-args.routine*))
+                    (if (len> caller-args.routine* idx)
+                      (list caller-args.routine*.idx t)
+                      (list nil nil)))
+                input
+                  (do (assert (iso '(literal) (ty arg.0)))
+                      (= caller-arg-idx.routine* (v arg.0))
+                      (let idx caller-arg-idx.routine*
+                        (++ caller-arg-idx.routine*)
+                        (trace "arg" repr.arg " " idx " " (repr caller-args.routine*))
+                        (if (len> caller-args.routine* idx)
+                          (list caller-args.routine*.idx t)
+                          (list nil nil))))
+                rewind-inputs
+                  (do1 nil
+                       (= caller-arg-idx.routine* 0))
+                ; type and otype won't always easily compile. be careful.
+                type
+                  (ty (caller-operands.routine* (v arg.0)))
+                otype
+                  (ty (caller-results.routine* (v arg.0)))
+                prepare-reply
+                  (prepare-reply arg)
+                reply
+                  (do (when arg
+                        (prepare-reply arg))
+                      (with (results results.routine*
+                             reply-args reply-args.routine*)
+                        (pop-stack routine*)
+                        (if empty.routine* (return ninstrs))
+                        (let (call-oargs _ call-args)  (parse-instr (body.routine* pc.routine*))
+;?                           (trace "reply" repr.arg " " repr.call-oargs) ;? 1
+                          (each (dest reply-arg val)  (zip call-oargs reply-args results)
+                            (trace "run" label.routine* " " pc.routine* ": " repr.val " => " dest)
+                            (when nondummy.dest
+                              (whenlet argidx (alref metadata.reply-arg 'same-as-arg)
+                                (unless (is v.dest (v call-args.argidx))
+                                  (die "'same-as-arg' output arg in @repr.reply-args can't bind to @repr.call-oargs")))
+                              (setm dest val))))
+                        (++ pc.routine*)
+                        (while (>= pc.routine* (len body.routine*))
+                          (pop-stack routine*)
+                          (when empty.routine* (return ninstrs))
+                          (++ pc.routine*))
+                        (continue)))
+                ; else try to call as a user-defined function
+                  (do (if function*.op
+                        (with (callee-args (accum yield
+                                             (each a arg
+                                               (yield (m a))))
+                               callee-operands (accum yield
+                                                 (each a arg
+                                                   (yield a)))
+                               callee-results (accum yield
+                                                (each a oarg
+                                                  (yield a))))
+                          (push-stack routine* op)
+                          (= caller-args.routine* callee-args)
+                          (= caller-operands.routine* callee-operands)
+                          (= caller-results.routine* callee-results))
+                        (err "no such op @op"))
+                      (continue))
+                )
+              ; opcode generated some 'results'
+              ; copy to output args
+              (if (acons results)
+                (each (dest val) (zip oarg results)
+                  (unless (is dest '_)
+                    (trace "run" label.routine* " " pc.routine* ": " repr.val " => " dest)
+                    (setm dest val)))
+                (when oarg  ; must be a list
+                  (trace "run" label.routine* " " pc.routine* ": " repr.results " => " oarg.0)
+                  (setm oarg.0 results)))
+              )
+        (++ pc.routine*)))
+    (return time-slice)))
+
+(def prepare-reply (args)
+  (= results.routine*
+     (accum yield
+       (each a args
+         (yield (m a)))))
+  (= reply-args.routine* args))
+
+; helpers for memory access respecting
+;   immediate addressing - 'literal' and 'offset'
+;   direct addressing - default
+;   indirect addressing - 'deref'
+;   relative addressing - if routine* has 'default-space'
+
+(def m (loc)  ; read memory, respecting metadata
+  (point return
+    (when (literal? loc)
+      (return v.loc))
+    (when (is v.loc 'default-space)
+      (return rep.routine*!call-stack.0!default-space))
+;?     (trace "mem" loc) ;? 1
+    (assert (isa v.loc 'int) "addresses must be numeric (problem in convert-names?): @repr.loc")
+    (ret result
+      (with (n  sizeof.loc
+             addr  addr.loc)
+;?         (trace "mem" "reading " n " locations starting at " addr) ;? 1
+        (if (is 1 n)
+              memory*.addr
+            :else
+              (annotate 'record
+                        (map memory* (addrs addr n)))))
+      (trace "mem" loc " => " result))))
+
+(def setm (loc val)  ; set memory, respecting metadata
+;?   (tr 111)
+  (point return
+;?   (tr 112)
+    (when (is v.loc 'default-space)
+      (assert (is 1 sizeof.loc) "can't store compounds in default-space @loc")
+      (= rep.routine*!call-stack.0!default-space val)
+      (return))
+;?   (tr 120)
+    (assert (isa v.loc 'int) "can't store to non-numeric address (problem in convert-names?)")
+;?     (trace "mem" loc " <= " repr.val) ;? 1
+    (with (n  (if (isa val 'record) (len rep.val) 1)
+           addr  addr.loc
+           typ  typeof.loc)
+;?       (trace "mem" "size of " loc " is " n) ;? 1
+      (assert n "setm: can't compute type of @loc")
+      (assert addr "setm: null pointer @loc")
+      (if (is 1 n)
+        (do (assert (~isa val 'record) "setm: record of size 1 @(tostring prn.val)")
+            (trace "mem" loc ": " addr " <= " repr.val)
+            (= memory*.addr val))
+        (do (if type*.typ!array
+              ; size check for arrays
+              (when (~is n
+                         (+ 1  ; array length
+                            (* rep.val.0 (sizeof `((_ ,@type*.typ!elem))))))
+                (die "writing invalid array @(tostring prn.val)"))
+              ; size check for non-arrays
+              (when (~is sizeof.loc n)
+                (die "writing to incorrect size @(tostring pr.val) => @loc")))
+            (let addrs (addrs addr n)
+              (each (dest src) (zip addrs rep.val)
+                (trace "mem" loc ": " dest " <= " repr.src)
+                (= memory*.dest src))))))))
+
+(def typeof (operand)
+  (let loc absolutize.operand
+    (while (pos '(deref) metadata.loc)
+      (zap deref loc))
+    ty.loc.0))
+
+(def addr (operand)
+  (v canonize.operand))
+
+(def addrs (n sz)
+  (accum yield
+    (repeat sz
+      (yield n)
+      (++ n))))
+
+(def canonize (operand)
+;?   (tr "0: @operand")
+  (ret operand
+;?     (prn "1: " operand)
+;?     (tr "1: " operand)  ; todo: why does this die?
+    (zap absolutize operand)
+;?     (tr "2: @repr.operand")
+    (while (pos '(deref) metadata.operand)
+      (zap deref operand)
+;?       (tr "3: @repr.operand")
+      )))
+
+(def array-len (operand)
+  (trace "array-len" operand)
+  (zap canonize operand)
+  (if typeinfo.operand!array
+        (m `((,v.operand integer) ,@metadata.operand))
+      :else
+        (err "can't take len of non-array @operand")))
+
+(def sizeof (x)
+;?   (trace "sizeof" x) ;? 1
+  (assert acons.x)
+  (zap canonize x)
+  (point return
+;?   (tr "sizeof: checking @x for array")
+  (when typeinfo.x!array
+;?     (tr "sizeof: @x is an array")
+    (assert (~is '_ v.x) "sizeof: arrays require a specific variable")
+    (return (+ 1 (* array-len.x (sizeof `((_ ,@typeinfo.x!elem)))))))
+;?   (tr "sizeof: not an array")
+  (when typeinfo.x!and-record
+;?     (tr "sizeof: @x is an and-record")
+    (return (sum idfn
+                 (accum yield
+                   (each elem typeinfo.x!elems
+                     (yield (sizeof `((_ ,@elem)))))))))
+;?   (tr "sizeof: @x is a primitive")
+  (return typeinfo.x!size)))
+
+(def absolutize (operand)
+  (if (no routine*)
+        operand
+      (in v.operand '_ 'default-space)
+        operand
+      (pos '(raw) metadata.operand)
+        operand
+      (is 'global space.operand)
+        (aif rep.routine*!globals
+          `((,(+ it 1 v.operand) ,@(cdr operand.0))
+            ,@(rem [caris _ 'space] metadata.operand)
+            (raw))
+          (die "routine has no globals: @operand"))
+      :else
+        (iflet base rep.routine*!call-stack.0!default-space
+          (space-base (rem [caris _ 'space] operand)
+                      base
+                      space.operand)
+          operand)))
+
+(def space-base (operand base space)
+;?   (prn operand " " base) ;? 1
+  (if (is 0 space)
+    ; base case
+    (if (< v.operand memory*.base)
+      `((,(+ base 1 v.operand) ,@(cdr operand.0))
+        ,@metadata.operand
+        (raw))
+      (die "no room for var @operand in routine of size @memory*.base"))
+    ; recursive case
+    (space-base operand (memory* (+ base 1))  ; location 0 points to next space
+                (- space 1))))
+
+(def space (operand)
+  (or (alref metadata.operand 'space)
+      0))
+
+(def deref (operand)
+  (assert (pos '(deref) metadata.operand))
+  (assert address?.operand)
+  (cons `(,(memory* v.operand) ,@typeinfo.operand!elem)
+        (drop-one '(deref) metadata.operand)))
+
+(def drop-one (f x)
+  (when acons.x  ; proper lists only
+    (if (testify.f car.x)
+      cdr.x
+      (cons car.x (drop-one f cdr.x)))))
+
+; memory allocation
+
+(def alloc (sz)
+  (when (> sz (- rep.routine*!alloc-max rep.routine*!alloc))
+    (let curr-alloc Memory-allocated-until
+      (= rep.routine*!alloc curr-alloc)
+      (++ Memory-allocated-until Allocation-chunk)
+      (= rep.routine*!alloc-max Memory-allocated-until)))
+  (ret result rep.routine*!alloc
+    (++ rep.routine*!alloc sz)))
+
+(def new-scalar (type)
+;?   (tr "new scalar: @type")
+  (alloc (sizeof `((_ ,type)))))
+
+(def new-array (type size)
+;?   (tr "new array: @type @size")
+  (ret result (alloc (+ 1 (* (sizeof `((_ ,@type*.type!elem))) size)))
+    (= memory*.result size)))
+
+(def new-string (literal-string)
+;?   (tr "new string: @literal-string")
+  (ret result (alloc (+ 1 len.literal-string))
+    (= memory*.result len.literal-string)
+    (on c literal-string
+      (when (and new-string-foo* (is 0 (mod index 100)))
+        (prn index " " repr.c))
+      (= (memory* (+ result 1 index)) c))))
+
+(def to-arc-string (string-address)
+  (let len (memory* string-address)
+    (string:map memory* (range (+ string-address 1)
+                               (+ string-address len)))))
+
+;; desugar structured assembly based on blocks
+
+(def convert-braces (instrs)
+;?   (prn "convert-braces " instrs)
+  (let locs ()  ; list of information on each brace: (open/close pc)
+    (let pc 0
+      (loop (instrs instrs)
+        (each instr instrs
+;?           (tr instr)
+          (if (or atom.instr (~is 'begin instr.0))  ; label or regular instruction
+                (do
+                  (trace "c{0" pc " " instr " -- " locs)
+                  (++ pc))
+                ; hack: racket replaces braces with parens, so we need the
+                ; keyword 'begin' to delimit blocks.
+                ; ultimately there'll be no nesting and braces will just be
+                ; in an instr by themselves.
+              :else  ; brace
+                (do
+                  (push `(open ,pc) locs)
+                  (recur cdr.instr)
+                  (push `(close ,pc) locs))))))
+    (zap rev locs)
+;?     (tr "-")
+    (with (pc  0
+           stack  ())  ; elems are pcs
+      (accum yield
+        (loop (instrs instrs)
+          (each instr instrs
+;?             (tr "- " instr)
+            (point continue
+            (when (atom instr)  ; label
+              (yield instr)
+              (++ pc)
+              (continue))
+            (when (is car.instr 'begin)
+              (push pc stack)
+              (recur cdr.instr)
+              (pop stack)
+              (continue))
+            (with ((oarg op arg)  (parse-instr instr)
+                   yield-new-instr  (fn (new-instr)
+                                      (trace "c{1" "@pc X " instr " => " new-instr)
+                                      (yield new-instr))
+                   yield-unchanged  (fn ()
+                                      (trace "c{1" "@pc ✓ " instr)
+                                      (yield instr)))
+              (when (in op 'break 'break-if 'break-unless 'loop 'loop-if 'loop-unless)
+                (assert (is oarg nil) "@op: can't take oarg in @instr"))
+              (case op
+                break
+                  (yield-new-instr `(((jump)) ((,(close-offset pc locs (and arg (v arg.0))) offset))))
+                break-if
+                  (yield-new-instr `(((jump-if)) ,arg.0 ((,(close-offset pc locs (and cdr.arg (v arg.1))) offset))))
+                break-unless
+                  (yield-new-instr `(((jump-unless)) ,arg.0 ((,(close-offset pc locs (and cdr.arg (v arg.1))) offset))))
+                loop
+                  (yield-new-instr `(((jump)) ((,(open-offset pc stack (and arg (v arg.0))) offset))))
+                loop-if
+                  (yield-new-instr `(((jump-if)) ,arg.0 ((,(open-offset pc stack (and cdr.arg (v arg.1))) offset))))
+                loop-unless
+                  (yield-new-instr `(((jump-unless)) ,arg.0 ((,(open-offset pc stack (and cdr.arg (v arg.1))) offset))))
+                ;else
+                  (yield-unchanged)))
+            (++ pc))))))))
+
+(def close-offset (pc locs nblocks)
+  (or= nblocks 1)
+;?   (tr nblocks)
+  (point return
+;?   (tr "close " pc " " locs)
+  (let stacksize 0
+    (each (state loc) locs
+      (point continue
+;?       (tr stacksize "/" done " " state " " loc)
+      (when (<= loc pc)
+        (continue))
+;?       (tr "process " stacksize loc)
+      (if (is 'open state) (++ stacksize) (-- stacksize))
+      ; last time
+;?       (tr "process2 " stacksize loc)
+      (when (is stacksize (* -1 nblocks))
+;?         (tr "close now " loc)
+        (return (- loc pc 1))))))))
+
+(def open-offset (pc stack nblocks)
+  (or= nblocks 1)
+  (- (stack (- nblocks 1)) 1 pc))
+
+;; convert jump targets to offsets
+
+(def convert-labels (instrs)
+;?   (tr "convert-labels " instrs)
+  (let labels (table)
+    (let pc 0
+      (each instr instrs
+        (when (~acons instr)
+;?           (tr "label " pc)
+          (= labels.instr pc))
+        (++ pc)))
+    (let pc 0
+      (each instr instrs
+        (when (and acons.instr
+                   (acons car.instr)
+                   (in (v car.instr) 'jump 'jump-if 'jump-unless))
+          (each arg cdr.instr
+;?             (tr "trying " arg " " ty.arg ": " v.arg " => " (labels v.arg))
+            (when (and (is ty.arg.0 'offset)
+                       (isa v.arg 'sym)
+                       (labels v.arg))
+              (= v.arg (- (labels v.arg) pc 1)))))
+        (++ pc))))
+  instrs)
+
+;; convert symbolic names to raw memory locations
+
+(def add-next-space-generator (instrs name)
+;?   (prn "== @name")
+  (each instr instrs
+    (when acons.instr
+      (let (oargs op args)  (parse-instr instr)
+        (each oarg oargs
+          (when (and (nondummy oarg)
+                     (is v.oarg 0)
+                     (iso ty.oarg '(space-address)))
+            (assert (or (no next-space-generator*.name)
+                        (is next-space-generator*.name (alref oarg 'names)))
+                    "function can have only one next-space-generator environment")
+            (tr "next-space-generator of @name is @(alref oarg 'names)")
+            (= next-space-generator*.name (alref oarg 'names))))))))
+
+; just a helper for testing; in practice we unbundle assign-names-to-location
+; and replace-names-with-location.
+(def convert-names (instrs (o name))
+;?   (tr "convert-names " instrs)
+  (= location*.name (assign-names-to-location instrs name))
+;?   (tr "save names for function @name: @(tostring:pr location*.name)") ;? 1
+  (replace-names-with-location instrs name))
+
+(def assign-names-to-location (instrs name (o init-locations))
+  (trace "cn0" "convert-names in @name")
+;?   (prn name ": " location*) ;? 1
+  (point return
+  (ret location (or init-locations (table))
+    ; if default-space in first instruction has a name, begin with its bindings
+    (when (acons instrs.0)  ; not a label
+      (let first-oarg-of-first-instr instrs.0.0  ; hack: assumes the standard default-space boilerplate
+        (when (and (nondummy first-oarg-of-first-instr)
+                   (is 'default-space (v first-oarg-of-first-instr))
+                   (assoc 'names metadata.first-oarg-of-first-instr))
+          (let old-names (location*:alref metadata.first-oarg-of-first-instr 'names)
+            (unless old-names
+;?               (prn "@name requires bindings for @(alref metadata.first-oarg-of-first-instr 'names) which aren't computed yet. Waiting.") ;? 1
+              (return nil))
+            (= location copy.old-names))))) ; assumption: we've already converted names for 'it'
+;?     (unless empty.location (prn location)) ;? 2
+    (with (isa-field  (table)
+           idx  (+ 1  ; 0 always reserved for next space
+                   (or (apply max vals.location)  ; skip past bindings already shared from elsewhere
+                       0))
+           already-location (copy location)
+           )
+      (each instr instrs
+        (point continue
+        (when atom.instr
+          (continue))
+        (trace "cn0" instr " " canon.location " " canon.isa-field)
+        (let (oargs op args)  (parse-instr instr)
+;?           (tr "about to rename args: @op")
+          (when (in op 'get 'get-address)
+            ; special case: map field offset by looking up type table
+            (with (basetype  (typeof args.0)
+                   field  (v args.1))
+;?               (tr 111 " " args.0 " " basetype)
+              (assert type*.basetype!and-record "get on non-record @args.0")
+;?               (tr 112)
+              (trace "cn0" "field-access @field in @args.0 of type @basetype")
+              (when (isa field 'sym)
+                (unless (already-location field)
+                  (assert (or (~location field) isa-field.field) "field @args.1 is also a variable"))
+                (when (~location field)
+                  (trace "cn0" "new field; computing location")
+;?                   (tr "aa " type*.basetype)
+                  (assert type*.basetype!fields "no field names available for @instr")
+;?                   (tr "bb")
+                  (iflet idx (pos field type*.basetype!fields)
+                    (do (set isa-field.field)
+                        (trace "cn0" "field location @idx")
+                        (= location.field idx))
+                    (assert nil "couldn't find field in @instr"))))))
+          ; map args to location indices
+          (each arg args
+            (trace "cn0" "checking arg " arg)
+            (when (and nondummy.arg not-raw-string.arg (~literal? arg))
+              (assert (~isa-field v.arg) "arg @arg is also a field name")
+              (when (maybe-add arg location idx)
+                ; todo: test this
+                (err "use before set: @arg"))))
+;?           (tr "about to rename oargs")
+          ; map oargs to location indices
+          (each arg oargs
+            (trace "cn0" "checking oarg " arg)
+            (when (and nondummy.arg not-raw-string.arg)
+              (assert (~isa-field v.arg) "oarg @arg is also a field name")
+              (when (maybe-add arg location idx)
+                (trace "cn0" "location for oarg " arg ": " idx)
+                ; todo: can't allocate arrays on the stack
+                (++ idx (sizeof `((_ ,@ty.arg))))))))))))))
+
+(def replace-names-with-location (instrs name)
+  (each instr instrs
+    (when (acons instr)
+      (let (oargs op args)  (parse-instr instr)
+        (each arg args
+          (convert-name arg name))
+        (each arg oargs
+          (convert-name arg name)))))
+  (each instr instrs
+    (trace "cn1" instr))
+  instrs)
+
+(= allow-raw-addresses* nil)
+(def check-default-space (instrs name)
+  (unless allow-raw-addresses*
+    (let oarg-names (accum yield
+                      (each (oargs _ _) (map parse-instr (keep acons  ; non-label
+                                                               instrs))
+                        (each oarg oargs
+                          (when nondummy.oarg
+                            (yield v.oarg)))))
+      (when (~pos 'default-space oarg-names)
+        (prn "function @name has no default-space")))))
+
+; assign an index to an arg
+(def maybe-add (arg location idx)
+  (trace "maybe-add" arg)
+  (when (and nondummy.arg
+;?              (prn arg " " (assoc 'space arg))
+             (~assoc 'space arg)
+             (~literal? arg)
+             (~location v.arg)
+             (isa v.arg 'sym)
+             (~in v.arg 'nil 'default-space)
+             (~pos '(raw) metadata.arg))
+    (= (location v.arg) idx)))
+
+; convert the arg to corresponding index
+(def convert-name (arg default-name)
+;?   (prn "111 @arg @default-name")
+  (when (and nondummy.arg not-raw-string.arg
+             (~is ty.arg.0 'literal))  ; can't use 'literal?' because we want to rename offsets
+;?     (prn "112 @arg")
+    (let name (space-to-name arg default-name)
+;?       (prn "113 @arg @name @keys.location* @(tostring:pr location*.name)")
+;?       (when (is arg '((y integer) (space 1)))
+;?         (prn "@arg => @name"))
+      (when (aand location*.name (it v.arg))
+;?         (prn 114)
+        (zap location*.name v.arg))
+;?       (prn 115)
+      )))
+
+(def space-to-name (arg default-name)
+  (ret name default-name
+    (when (~is space.arg 'global)
+      (repeat space.arg
+        (zap next-space-generator* name)))))
+
+(proc check-numeric-address (instrs name)
+  (unless allow-raw-addresses*
+    (on instr instrs
+      (when acons.instr  ; not a label
+        (let (oargs op args)  (parse-instr instr)
+          (each arg oargs
+            (when (and acons.arg  ; not dummy _ or raw string
+                       (isa v.arg 'int)
+                       (~is v.arg 0)
+                       (~pos '(raw) metadata.arg)
+                       (~literal? arg))
+              (prn "using a raw integer address @repr.arg in @name (instruction #@index)")))
+          (each arg args
+            (when (and acons.arg  ; not dummy _ or raw string
+                       (isa v.arg 'int)
+                       (~is v.arg 0)
+                       (~pos '(raw) metadata.arg)
+                       (~literal? arg))
+              (prn "using a raw integer address @repr.arg in @name (instruction #@index)"))))))))
+
+;; literate tangling system for reordering code
+
+(def convert-quotes (instrs)
+  (let deferred (queue)
+    (each instr instrs
+      (when (acons instr)
+        (case instr.0
+          defer
+            (let (q qinstrs)  instr.1
+              (assert (is 'make-br-fn q) "defer: first arg must be [quoted]")
+              (each qinstr qinstrs
+                (enq qinstr deferred))))))
+    (accum yield
+      (each instr instrs
+        (if atom.instr  ; label
+              (yield instr)
+            (is instr.0 'defer)
+              nil  ; skip
+            (is instr.0 'reply)
+              (do
+                (when cdr.instr  ; return values
+                  (= instr.0 'prepare-reply)
+                  (yield instr))
+                (each instr (as cons deferred)
+                  (yield instr))
+                (yield '(reply)))
+            :else
+              (yield instr)))
+      (each instr (as cons deferred)
+        (yield instr)))))
+
+(on-init
+  (= before* (table))  ; label -> queue of fragments
+  (= after* (table)))  ; label -> list of fragments
+
+; see add-code below for adding to before* and after*
+
+(def insert-code (instrs (o name))
+;?   (tr "insert-code " instrs)
+  (loop (instrs instrs)
+    (accum yield
+      (each instr instrs
+        (if (and (acons instr) (~is 'begin car.instr))
+              ; simple instruction
+              (yield instr)
+            (and (acons instr) (is 'begin car.instr))
+              ; block
+              (yield `{begin ,@(recur cdr.instr)})
+            (atom instr)
+              ; label
+              (do
+;?                 (prn "tangling " instr)
+                (each fragment (as cons (or (and name (before* (sym:string name '/ instr)))
+                                            before*.instr))
+                  (each instr fragment
+                    (yield instr)))
+                (yield instr)
+                (each fragment (or (and name (after* (sym:string name '/ instr)))
+                                   after*.instr)
+                  (each instr fragment
+                    (yield instr)))))))))
+
+;; loading code into the virtual machine
+
+(def add-code (forms)
+  (each (op . rest)  forms
+    (case op
+      ; function <name> [ <instructions> ]
+      ; don't apply our lightweight tools just yet
+      function!
+        (let (name (_make-br-fn body))  rest
+          (assert (is 'make-br-fn _make-br-fn))
+          (= name (v tokenize-arg.name))
+          (= function*.name body))
+      function
+        (let (name (_make-br-fn body))  rest
+          (assert (is 'make-br-fn _make-br-fn))
+          (= name (v tokenize-arg.name))
+          (when function*.name
+            (prn "adding new clause to @name"))
+          (= function*.name (join body function*.name)))
+
+      ; and-record <type> [ <name:types> ]
+      and-record
+        (let (name (_make-br-fn fields))  rest
+          (assert (is 'make-br-fn _make-br-fn))
+          (= name (v tokenize-arg.name))
+          (let fields (map tokenize-arg fields)
+            (= type*.name (obj size len.fields
+                               and-record t
+                               ; dump all metadata for now except field name and type
+                               elems (map cdar fields)
+                               fields (map caar fields)))))
+
+      ; primitive <type>
+      primitive
+        (let (name) rest
+          (= name (v tokenize-arg.name))
+          (= type*.name (obj size 1)))
+
+      ; address <type> <elem-type>
+      address
+        (let (name types)  rest
+          (= name (v tokenize-arg.name))
+          (= type*.name (obj size 1
+                             address t
+                             elem types)))
+
+      ; array <type> <elem-type>
+      array
+        (let (name types)  rest
+          (= name (v tokenize-arg.name))
+          (= type*.name (obj array t
+                             elem types)))
+
+      ; before <label> [ <instructions> ]
+      ;
+      ; multiple before directives => code in order
+      before
+        (let (label (_make-br-fn fragment))  rest
+          (assert (is 'make-br-fn _make-br-fn))
+          ; todo: stop using '/' in non-standard manner
+          ;(= label (v tokenize-arg.label))
+          (or= before*.label (queue))
+          (enq fragment before*.label))
+
+      ; after <label> [ <instructions> ]
+      ;
+      ; multiple after directives => code in *reverse* order
+      ; (if initialization order in a function is A B, corresponding
+      ; finalization order should be B A)
+      after
+        (let (label (_make-br-fn fragment))  rest
+          (assert (is 'make-br-fn _make-br-fn))
+          ; todo: stop using '/' in non-standard manner
+          ;(= label (v tokenize-arg.label))
+          (push fragment after*.label))
+
+      ;else
+        (prn "unrecognized top-level " (cons op rest))
+      )))
+
+(def freeze (function-table)
+  (each (name body)  canon.function-table
+;?     (prn "freeze " name)
+    (= function-table.name (convert-labels:convert-braces:tokenize-args:insert-code body name)))
+  (each (name body)  canon.function-table
+    (check-default-space body name))
+  (each (name body)  canon.function-table
+    (check-numeric-address body name))
+  (each (name body)  canon.function-table
+    (add-next-space-generator body name))
+  ; keep converting names until none remain
+  ; (we need to skip unrecognized spaces)
+  (let change t
+    (while change
+      (= change nil)
+      (each (name body)  canon.function-table
+;?         (prn name) ;? 1
+        (when (no location*.name)
+          (= change t))
+        (or= location*.name (assign-names-to-location body name)))))
+;?   (each (name body)  canon.function-table ;? 1
+;?     (or= location*.name (assign-names-to-location body name))) ;? 1
+  (each (name body)  canon.function-table
+    (= function-table.name (replace-names-with-location body name)))
+  ; we could clear location* at this point, but maybe we'll find a use for it
+  )
+
+(def freeze-another (fn-name)
+  (= function*.fn-name (convert-labels:convert-braces:tokenize-args:insert-code function*.fn-name fn-name))
+  (check-default-space function*.fn-name fn-name)
+  (add-next-space-generator function*.fn-name fn-name)
+  (= location*.fn-name (assign-names-to-location function*.fn-name fn-name location*.fn-name))
+  (replace-names-with-location function*.fn-name fn-name))
+
+(def tokenize-arg (arg)
+;?   (tr "tokenize-arg " arg)
+  (if (in arg '<- '_)
+        arg
+      (isa arg 'sym)
+        (map [map [fromstring _ (read)] _]
+             (map [tokens _ #\:]
+                  (tokens string.arg #\/)))
+      :else
+        arg))
+
+(def tokenize-args (instrs)
+;?   (tr "tokenize-args " instrs)
+;?   (prn2 "@(tostring prn.instrs) => "
+  (accum yield
+    (each instr instrs
+      (if atom.instr
+            (yield instr)
+          (is 'begin instr.0)
+            (yield `{begin ,@(tokenize-args cdr.instr)})
+          :else
+            (yield (map tokenize-arg instr))))))
+;?   )
+
+(def prn2 (msg . args)
+  (pr msg)
+  (apply prn args))
+
+(def canon (table)
+  (sort (compare < [tostring (prn:car _)]) (as cons table)))
+
+(def int-canon (table)
+  (sort (compare < car) (as cons table)))
+
+(def routine-canon (routine-table)
+  (sort (compare < label:car) (as cons routine-table)))
+
+(def repr (val)
+  (tostring write.val))
+
+;; test helpers
+
+(def memory-contains (addr value)
+;?   (prn "Looking for @value starting at @addr")
+  (loop (addr addr
+         idx  0)
+;?     (prn "@idx vs @addr")
+    (if (>= idx len.value)
+          t
+        (~is memory*.addr value.idx)
+          (do1 nil
+               (prn "@addr should contain @value.idx but contains @memory*.addr"))
+        :else
+          (recur (+ addr 1) (+ idx 1)))))
+
+(def memory-contains-array (addr value)
+  (and (>= memory*.addr len.value)
+       (loop (addr (+ addr 1)  ; skip count
+              idx  0)
+         (if (>= idx len.value)
+               t
+             (~is memory*.addr value.idx)
+               nil
+             :else
+               (recur (+ addr 1) (+ idx 1))))))
+
+; like memory-contains-array but shows diffs
+(def memory-contains-array-verbose (addr value)
+  (prn "Mismatch when looking at @addr, size @memory*.addr vs @len.value")
+  (and (>= memory*.addr len.value)
+       (loop (addr (+ addr 1)  ; skip count
+              idx  0)
+         (and (< idx len.value) (prn "comparing @idx: @memory*.addr and @value.idx"))
+         (if (>= idx len.value)
+               t
+             (~is memory*.addr value.idx)
+               (do1 nil
+                    (prn "@addr should contain @(repr value.idx) but contains @(repr memory*.addr)")
+                    (recur (+ addr 1) (+ idx 1)))
+             :else
+               (recur (+ addr 1) (+ idx 1))))))
+
+; like memory-contains-array but shows diffs in 2D
+(def screen-contains (addr width value)
+  (or (memory-contains-array addr value)
+      (do1 nil
+          (prn "Mismatch detected. Screen contents:")
+          (with (row-start-addr  (+ addr 1)  ; skip count
+                 idx  0)
+            (for row 0  (< row (/ len.value width))  (do ++.row  (++ row-start-addr width))
+              (pr ". ")
+              (for col 0  (< col width)  ++.col
+                (with (expected  value.idx
+                       got  (memory* (+ col row-start-addr)))
+                  (pr got)
+                  (pr (if (is expected got) " " "X")))
+                ++.idx)
+              (prn " .")
+              )))))
+
+; run code in tests
+(mac run-code (name . body)
+  ; careful to avoid re-processing functions and adding noise to traces
+  `(do
+     (prn "-- " ',name)
+     (trace "===" ',name)
+     (wipe (function* ',name))
+     (add-code '((function ,name [ ,@body ])))
+     (freeze-another ',name)
+;?      (set dump-trace*) ;? 1
+     (run-more ',name)))
+
+; kludge to prevent reloading functions in .mu files for every test
+(def reset2 ()
+  (= memory* (table))
+  (= Memory-allocated-until 1000)
+  (awhen curr-trace-file*
+    (tofile (+ trace-dir* it)
+      (each (label trace) (as cons traces*)
+        (pr label ": " trace))))
+  (= curr-trace-file* nil)
+  (= traces* (queue))
+  (wipe dump-trace*)
+  (wipe function*!main)
+  (wipe location*!main)
+  (= running-routines* (queue))
+  (= sleeping-routines* (table))
+  (wipe completed-routines*)
+  (wipe routine*)
+  (= abort-routine* (parameter nil))
+  (= curr-cycle* 0)
+  (= scheduling-interval* 500)
+  (= scheduler-switch-table* nil)
+  )
+
+(= disable-debug-prints-in-console-mode* nil)
+(def test-only-settings ()
+  (set allow-raw-addresses*)
+  (set disable-debug-prints-in-console-mode*))
+
+(def routine-that-ran (f)
+  (find [some [is f _!fn-name] stack._]
+        completed-routines*))
+
+(def routine-running (f)
+  (or
+    (find [some [is f _!fn-name] stack._]
+          completed-routines*)
+    (find [some [is f _!fn-name] stack._]
+          (as cons running-routines*))
+    (find [some [is f _!fn-name] stack._]
+          (keys sleeping-routines*))
+    (and routine*
+         (some [is f _!fn-name] stack.routine*)
+         routine*)))
+
+(def ran-to-completion (f)
+  ; if a routine calling f ran to completion there'll be no sign of it in any
+  ; completed call-stacks.
+  (~routine-that-ran f))
+
+(def restart (routine)
+  (while (in top.routine!fn-name 'read 'write)
+    (pop-stack routine))
+  (wipe rep.routine!sleep)
+  (wipe rep.routine!error)
+  (enq routine running-routines*))
+
+(def dump (msg routine)
+  (prn "= @msg " rep.routine!sleep)
+  (prn:rem [in car._ 'sleep 'call-stack] (as cons rep.routine))
+  (each frame rep.routine!call-stack
+    (prn " @frame!fn-name")
+    (each (key val) frame
+      (unless (is key 'fn-name)
+        (prn "  " key " " val)))))
+
+;; system software
+; create once, load before every test
+
+(reset)
+(= system-function* (table))
+
+(mac init-fn (name . body)
+  (let real-name (v tokenize-arg.name)
+    `(= (system-function* ',real-name) ',body)))
+
+(def load-system-functions ()
+  (each (name f) system-function*
+    (= (function* name)
+       (system-function* name))))
+
+; allow running mu.arc without load.arc
+(unless bound!section (= section do))
+
+(section 100
+
+(init-fn maybe-coerce
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:tagged-value-address <- new tagged-value:literal)
+  (x:tagged-value-address/deref <- next-input)
+  (p:type <- next-input)
+  (xtype:type <- get x:tagged-value-address/deref type:offset)
+  (match?:boolean <- equal xtype:type p:type)
+  { begin
+    (break-if match?:boolean)
+    (reply 0:literal nil:literal)
+  }
+  (xvalue:location <- get x:tagged-value-address/deref payload:offset)
+  (reply xvalue:location match?:boolean))
+
+(init-fn init-tagged-value
+  (default-space:space-address <- new space:literal 30:literal)
+  ; assert sizeof:arg.0 == 1
+  (xtype:type <- next-input)
+  (xtypesize:integer <- sizeof xtype:type)
+  (xcheck:boolean <- equal xtypesize:integer 1:literal)
+  (assert xcheck:boolean)
+  ; todo: check that arg 0 matches the type? or is that for the future typechecker?
+  (result:tagged-value-address <- new tagged-value:literal)
+  ; result->type = arg 0
+  (resulttype:location <- get-address result:tagged-value-address/deref type:offset)
+  (resulttype:location/deref <- copy xtype:type)
+  ; result->payload = arg 1
+  (locaddr:location <- get-address result:tagged-value-address/deref payload:offset)
+  (locaddr:location/deref <- next-input)
+  (reply result:tagged-value-address))
+
+(init-fn list-next  ; list-address -> list-address
+  (default-space:space-address <- new space:literal 30:literal)
+  (base:list-address <- next-input)
+  (result:list-address <- get base:list-address/deref cdr:offset)
+  (reply result:list-address))
+
+(init-fn list-value-address  ; list-address -> tagged-value-address
+  (default-space:space-address <- new space:literal 30:literal)
+  (base:list-address <- next-input)
+  (result:tagged-value-address <- get-address base:list-address/deref car:offset)
+  (reply result:tagged-value-address))
+
+; create a list out of a list of args
+; only integers for now
+(init-fn init-list
+  (default-space:space-address <- new space:literal 30:literal)
+  ; new-list = curr = new list
+  (result:list-address <- new list:literal)
+  (curr:list-address <- copy result:list-address)
+  { begin
+    ; while read curr-value
+    (curr-value:integer exists?:boolean <- next-input)
+    (break-unless exists?:boolean)
+    ; curr.cdr = new list
+    (next:list-address-address <- get-address curr:list-address/deref cdr:offset)
+    (next:list-address-address/deref <- new list:literal)
+    ; curr = curr.cdr
+    (curr:list-address <- list-next curr:list-address)
+    ; curr.car = type:curr-value
+    (dest:tagged-value-address <- list-value-address curr:list-address)
+    (dest:tagged-value-address/deref <- save-type curr-value:integer)
+    (loop)
+  }
+  ; return new-list.cdr
+  (result:list-address <- list-next result:list-address)  ; memory leak
+  (reply result:list-address))
+
+; create an array out of a list of scalar args
+; only integers for now
+(init-fn init-array
+  (default-space:space-address <- new space:literal 30:literal)
+  (capacity:integer <- copy 0:literal)
+  { begin
+    ; while read curr-value
+    (curr-value:integer exists?:boolean <- next-input)
+    (break-unless exists?:boolean)
+    (capacity:integer <- add capacity:integer 1:literal)
+    (loop)
+  }
+  (result:integer-array-address <- new integer-array:literal capacity:integer)
+  (rewind-inputs)
+;?   (xxx:integer <- next-input) ;? 1
+;?   ($print xxx:integer) ;? 1
+;?   (rewind-inputs) ;? 1
+  (i:integer <- copy 0:literal)
+  { begin
+    ; while read curr-value
+    (done?:boolean <- greater-or-equal i:integer capacity:integer)
+    (break-if done?:boolean)
+    (curr-value:integer exists?:boolean <- next-input)
+    (assert exists?:boolean)
+    (tmp:integer-address <- index-address result:integer-array-address/deref i:integer)
+    (tmp:integer-address/deref <- copy curr-value:integer)
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+  (reply result:integer-array-address))
+
+(init-fn list-length
+  (default-space:space-address <- new space:literal 30:literal)
+  (curr:list-address <- next-input)
+;?   ; recursive
+;?   { begin
+;?     ; if empty list return 0
+;?     (t1:tagged-value-address <- list-value-address curr:list-address)
+;?     (break-if t1:tagged-value-address)
+;?     (reply 0:literal)
+;?   }
+;?   ; else return 1+length(curr.cdr)
+;? ;?   ($print (("recurse\n" literal)))
+;?   (next:list-address <- list-next curr:list-address)
+;?   (sub:integer <- list-length next:list-address)
+;?   (result:integer <- add sub:integer 1:literal)
+;?   (reply result:integer))
+  ; iterative solution
+  (result:integer <- copy 0:literal)
+  { begin
+    ; while curr
+    (t1:tagged-value-address <- list-value-address curr:list-address)
+    (break-unless t1:tagged-value-address)
+    ; ++result
+    (result:integer <- add result:integer 1:literal)
+;?     ($print result:integer)
+;?     ($print (("\n" literal)))
+    ; curr = curr.cdr
+    (curr:list-address <- list-next curr:list-address)
+    (loop)
+  }
+  (reply result:integer))
+
+(init-fn init-channel
+  (default-space:space-address <- new space:literal 30:literal)
+  ; result = new channel
+  (result:channel-address <- new channel:literal)
+  ; result.first-full = 0
+  (full:integer-address <- get-address result:channel-address/deref first-full:offset)
+  (full:integer-address/deref <- copy 0:literal)
+  ; result.first-free = 0
+  (free:integer-address <- get-address result:channel-address/deref first-free:offset)
+  (free:integer-address/deref <- copy 0:literal)
+  ; result.circular-buffer = new tagged-value[arg+1]
+  (capacity:integer <- next-input)
+  (capacity:integer <- add capacity:integer 1:literal)  ; unused slot for full? below
+  (channel-buffer-address:tagged-value-array-address-address <- get-address result:channel-address/deref circular-buffer:offset)
+  (channel-buffer-address:tagged-value-array-address-address/deref <- new tagged-value-array:literal capacity:integer)
+  (reply result:channel-address))
+
+(init-fn capacity
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel <- next-input)
+  (q:tagged-value-array-address <- get chan:channel circular-buffer:offset)
+  (qlen:integer <- length q:tagged-value-array-address/deref)
+  (reply qlen:integer))
+
+(init-fn write
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel-address <- next-input)
+  (val:tagged-value <- next-input)
+  { begin
+    ; block if chan is full
+    (full:boolean <- full? chan:channel-address/deref)
+    (break-unless full:boolean)
+    (full-address:integer-address <- get-address chan:channel-address/deref first-full:offset)
+    (sleep until-location-changes:literal full-address:integer-address/deref)
+  }
+  ; store val
+  (q:tagged-value-array-address <- get chan:channel-address/deref circular-buffer:offset)
+  (free:integer-address <- get-address chan:channel-address/deref first-free:offset)
+  (dest:tagged-value-address <- index-address q:tagged-value-array-address/deref free:integer-address/deref)
+  (dest:tagged-value-address/deref <- copy val:tagged-value)
+  ; increment free
+  (free:integer-address/deref <- add free:integer-address/deref 1:literal)
+  { begin
+    ; wrap free around to 0 if necessary
+    (qlen:integer <- length q:tagged-value-array-address/deref)
+    (remaining?:boolean <- less-than free:integer-address/deref qlen:integer)
+    (break-if remaining?:boolean)
+    (free:integer-address/deref <- copy 0:literal)
+  }
+  (reply chan:channel-address/deref/same-as-arg:0))
+
+(init-fn read
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel-address <- next-input)
+;?   ($dump-channel chan:channel-address) ;? 2
+  { begin
+    ; block if chan is empty
+    (empty:boolean <- empty? chan:channel-address/deref)
+    (break-unless empty:boolean)
+    (free-address:integer-address <- get-address chan:channel-address/deref first-free:offset)
+    (sleep until-location-changes:literal free-address:integer-address/deref)
+  }
+  ; read result
+  (full:integer-address <- get-address chan:channel-address/deref first-full:offset)
+  (q:tagged-value-array-address <- get chan:channel-address/deref circular-buffer:offset)
+  (result:tagged-value <- index q:tagged-value-array-address/deref full:integer-address/deref)
+  ; increment full
+  (full:integer-address/deref <- add full:integer-address/deref 1:literal)
+  { begin
+    ; wrap full around to 0 if necessary
+    (qlen:integer <- length q:tagged-value-array-address/deref)
+    (remaining?:boolean <- less-than full:integer-address/deref qlen:integer)
+    (break-if remaining?:boolean)
+    (full:integer-address/deref <- copy 0:literal)
+  }
+  (reply result:tagged-value chan:channel-address/deref/same-as-arg:0))
+
+; An empty channel has first-empty and first-full both at the same value.
+(init-fn empty?
+  (default-space:space-address <- new space:literal 30:literal)
+  ; return arg.first-full == arg.first-free
+  (chan:channel <- next-input)
+  (full:integer <- get chan:channel first-full:offset)
+  (free:integer <- get chan:channel first-free:offset)
+  (result:boolean <- equal full:integer free:integer)
+  (reply result:boolean))
+
+; A full channel has first-empty just before first-full, wasting one slot.
+; (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)
+(init-fn full?
+  (default-space:space-address <- new space:literal 30:literal)
+  (chan:channel <- next-input)
+  ; curr = chan.first-free + 1
+  (curr:integer <- get chan:channel first-free:offset)
+  (curr:integer <- add curr:integer 1:literal)
+  { begin
+    ; if (curr == chan.capacity) curr = 0
+    (qlen:integer <- capacity chan:channel)
+    (remaining?:boolean <- less-than curr:integer qlen:integer)
+    (break-if remaining?:boolean)
+    (curr:integer <- copy 0:literal)
+  }
+  ; return chan.first-full == curr
+  (full:integer <- get chan:channel first-full:offset)
+  (result:boolean <- equal full:integer curr:integer)
+  (reply result:boolean))
+
+(init-fn string-equal
+  (default-space:space-address <- new space:literal 30:literal)
+  (a:string-address <- next-input)
+  (a-len:integer <- length a:string-address/deref)
+  (b:string-address <- next-input)
+  (b-len:integer <- length b:string-address/deref)
+  ; compare lengths
+  { begin
+    (length-equal?:boolean <- equal a-len:integer b-len:integer)
+    (break-if length-equal?:boolean)
+    (reply nil:literal)
+  }
+  ; compare each corresponding byte
+  (i:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- greater-or-equal i:integer a-len:integer)
+    (break-if done?:boolean)
+    (a2:byte <- index a:string-address/deref i:integer)
+    (b2:byte <- index b:string-address/deref i:integer)
+    { begin
+      (chars-match?:boolean <- equal a2:byte b2:byte)
+      (break-if chars-match?:boolean)
+      (reply nil:literal)
+    }
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+  (reply t:literal)
+)
+
+(init-fn strcat
+  (default-space:space-address <- new space:literal 30:literal)
+  ; result = new string[a.length + b.length]
+  (a:string-address <- next-input)
+  (a-len:integer <- length a:string-address/deref)
+  (b:string-address <- next-input)
+  (b-len:integer <- length b:string-address/deref)
+  (result-len:integer <- add a-len:integer b-len:integer)
+  (result:string-address <- new string:literal result-len:integer)
+  ; copy a into result
+  (result-idx:integer <- copy 0:literal)
+  (i:integer <- copy 0:literal)
+  { begin
+    ; while (i < a.length)
+    (a-done?:boolean <- greater-or-equal i:integer a-len:integer)
+    (break-if a-done?:boolean)
+    ; result[result-idx] = a[i]
+    (out:byte-address <- index-address result:string-address/deref result-idx:integer)
+    (in:byte <- index a:string-address/deref i:integer)
+    (out:byte-address/deref <- copy in:byte)
+    ; ++i
+    (i:integer <- add i:integer 1:literal)
+    ; ++result-idx
+    (result-idx:integer <- add result-idx:integer 1:literal)
+    (loop)
+  }
+  ; copy b into result
+  (i:integer <- copy 0:literal)
+  { begin
+    ; while (i < b.length)
+    (b-done?:boolean <- greater-or-equal i:integer b-len:integer)
+    (break-if b-done?:boolean)
+    ; result[result-idx] = a[i]
+    (out:byte-address <- index-address result:string-address/deref result-idx:integer)
+    (in:byte <- index b:string-address/deref i:integer)
+    (out:byte-address/deref <- copy in:byte)
+    ; ++i
+    (i:integer <- add i:integer 1:literal)
+    ; ++result-idx
+    (result-idx:integer <- add result-idx:integer 1:literal)
+    (loop)
+  }
+  (reply result:string-address))
+
+; replace underscores in first with remaining args
+(init-fn interpolate  ; string-address template, string-address a..
+  (default-space:space-address <- new space:literal 60:literal)
+  (template:string-address <- next-input)
+  ; compute result-len, space to allocate for result
+  (tem-len:integer <- length template:string-address/deref)
+  (result-len:integer <- copy tem-len:integer)
+  { begin
+    ; while arg received
+    (a:string-address arg-received?:boolean <- next-input)
+    (break-unless arg-received?:boolean)
+;?     ($print ("arg now: " literal))
+;?     ($print a:string-address)
+;?     ($print "@":literal)
+;?     ($print a:string-address/deref)  ; todo: test (m on scoped array)
+;?     ($print "\n":literal)
+;? ;?     (assert nil:literal)
+    ; result-len = result-len + arg.length - 1 (for the 'underscore' being replaced)
+    (a-len:integer <- length a:string-address/deref)
+    (result-len:integer <- add result-len:integer a-len:integer)
+    (result-len:integer <- subtract result-len:integer 1:literal)
+;?     ($print ("result-len now: " literal))
+;?     ($print result-len:integer)
+;?     ($print "\n":literal)
+    (loop)
+  }
+  ; rewind to start of non-template args
+  (_ <- input 0:literal)
+  ; result = new string[result-len]
+  (result:string-address <- new string:literal result-len:integer)
+  ; repeatedly copy sections of template and 'holes' into result
+  (result-idx:integer <- copy 0:literal)
+  (i:integer <- copy 0:literal)
+  { begin
+    ; while arg received
+    (a:string-address arg-received?:boolean <- next-input)
+    (break-unless arg-received?:boolean)
+    ; copy template into result until '_'
+    { begin
+      ; while (i < template.length)
+      (tem-done?:boolean <- greater-or-equal i:integer tem-len:integer)
+      (break-if tem-done?:boolean 2:blocks)
+      ; while template[i] != '_'
+      (in:byte <- index template:string-address/deref i:integer)
+      (underscore?:boolean <- equal in:byte ((#\_ literal)))
+      (break-if underscore?:boolean)
+      ; result[result-idx] = template[i]
+      (out:byte-address <- index-address result:string-address/deref result-idx:integer)
+      (out:byte-address/deref <- copy in:byte)
+      ; ++i
+      (i:integer <- add i:integer 1:literal)
+      ; ++result-idx
+      (result-idx:integer <- add result-idx:integer 1:literal)
+      (loop)
+    }
+;?     ($print ("i now: " literal))
+;?     ($print i:integer)
+;?     ($print "\n":literal)
+    ; copy 'a' into result
+    (j:integer <- copy 0:literal)
+    { begin
+      ; while (j < a.length)
+      (arg-done?:boolean <- greater-or-equal j:integer a-len:integer)
+      (break-if arg-done?:boolean)
+      ; result[result-idx] = a[j]
+      (in:byte <- index a:string-address/deref j:integer)
+;?       ($print ("copying: " literal))
+;?       ($print in:byte)
+;?       ($print (" at: " literal))
+;?       ($print result-idx:integer)
+;?       ($print "\n":literal)
+      (out:byte-address <- index-address result:string-address/deref result-idx:integer)
+      (out:byte-address/deref <- copy in:byte)
+      ; ++j
+      (j:integer <- add j:integer 1:literal)
+      ; ++result-idx
+      (result-idx:integer <- add result-idx:integer 1:literal)
+      (loop)
+    }
+    ; skip '_' in template
+    (i:integer <- add i:integer 1:literal)
+;?     ($print ("i now: " literal))
+;?     ($print i:integer)
+;?     ($print "\n":literal)
+    (loop)  ; interpolate next arg
+  }
+  ; done with holes; copy rest of template directly into result
+  { begin
+    ; while (i < template.length)
+    (tem-done?:boolean <- greater-or-equal i:integer tem-len:integer)
+    (break-if tem-done?:boolean)
+    ; result[result-idx] = template[i]
+    (in:byte <- index template:string-address/deref i:integer)
+;?     ($print ("copying: " literal))
+;?     ($print in:byte)
+;?     ($print (" at: " literal))
+;?     ($print result-idx:integer)
+;?     ($print "\n":literal)
+    (out:byte-address <- index-address result:string-address/deref result-idx:integer)
+    (out:byte-address/deref <- copy in:byte)
+    ; ++i
+    (i:integer <- add i:integer 1:literal)
+    ; ++result-idx
+    (result-idx:integer <- add result-idx:integer 1:literal)
+    (loop)
+  }
+  (reply result:string-address))
+
+(init-fn find-next  ; string, character, index -> next index
+  (default-space:space-address <- new space:literal 30:literal)
+  (text:string-address <- next-input)
+  (pattern:character <- next-input)
+  (idx:integer <- next-input)
+  (len:integer <- length text:string-address/deref)
+  { begin
+    (eof?:boolean <- greater-or-equal idx:integer len:integer)
+    (break-if eof?:boolean)
+    (curr:byte <- index text:string-address/deref idx:integer)
+    (found?:boolean <- equal curr:byte pattern:character)
+    (break-if found?:boolean)
+    (idx:integer <- add idx:integer 1:literal)
+    (loop)
+  }
+  (reply idx:integer))
+
+(init-fn find-substring/variant:find-next
+  (default-space:space-address <- new space:literal 30:literal)
+  ; fairly dumb algorithm; used for parsing code and traces
+  (text:string-address <- next-input)
+  (pattern:string-address <- next-input)
+  (idx:integer <- next-input)
+  (first:character <- index pattern:string-address/deref 0:literal)
+  ; repeatedly check for match at current idx
+  (len:integer <- length text:string-address/deref)
+  { begin
+    ; does some unnecessary work checking for substrings even when there isn't enough of text left
+    (eof?:boolean <- greater-or-equal idx:integer len:integer)
+    (break-if eof?:boolean)
+    (found?:boolean <- match-at text:string-address pattern:string-address idx:integer)
+    (break-if found?:boolean)
+    (idx:integer <- add idx:integer 1:literal)
+    ; optimization: skip past indices that definitely won't match
+    (idx:integer <- find-next text:string-address first:character idx:integer)
+    (loop)
+  }
+  (reply idx:integer)
+)
+
+(init-fn match-at
+  (default-space:space-address <- new space:literal 30:literal)
+  ; fairly dumb algorithm; used for parsing code and traces
+  (text:string-address <- next-input)
+  (pattern:string-address <- next-input)
+  (idx:integer <- next-input)
+  (pattern-len:integer <- length pattern:string-address/deref)
+  ; check that there's space left for the pattern
+  { begin
+    (x:integer <- length text:string-address/deref)
+    (x:integer <- subtract x:integer pattern-len:integer)
+    (enough-room?:boolean <- lesser-or-equal idx:integer x:integer)
+    (break-if enough-room?:boolean)
+    (reply nil:literal)
+  }
+  ; check each character of pattern
+  (pattern-idx:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- greater-or-equal pattern-idx:integer pattern-len:integer)
+    (break-if done?:boolean)
+    (c:character <- index text:string-address/deref idx:integer)
+    (exp:character <- index pattern:string-address/deref pattern-idx:integer)
+    { begin
+      (match?:boolean <- equal c:character exp:character)
+      (break-if match?:boolean)
+      (reply nil:literal)
+    }
+    (idx:integer <- add idx:integer 1:literal)
+    (pattern-idx:integer <- add pattern-idx:integer 1:literal)
+    (loop)
+  }
+  (reply t:literal)
+)
+
+(init-fn split  ; string, character -> string-address-array-address
+  (default-space:space-address <- new space:literal 30:literal)
+  (s:string-address <- next-input)
+  (delim:character <- next-input)
+  ; empty string? return empty array
+  (len:integer <- length s:string-address/deref)
+  { begin
+    (empty?:boolean <- equal len:integer 0:literal)
+    (break-unless empty?:boolean)
+    (result:string-address-array-address <- new string-address-array:literal 0:literal)
+    (reply result:string-address-array-address)
+  }
+  ; count #pieces we need room for
+  (count:integer <- copy 1:literal)  ; n delimiters = n+1 pieces
+  (idx:integer <- copy 0:literal)
+  { begin
+    (idx:integer <- find-next s:string-address delim:character idx:integer)
+    (done?:boolean <- greater-or-equal idx:integer len:integer)
+    (break-if done?:boolean)
+    (idx:integer <- add idx:integer 1:literal)
+    (count:integer <- add count:integer 1:literal)
+    (loop)
+  }
+  ; allocate space
+;?   ($print (("alloc: " literal)))
+;?   ($print count:integer)
+;?   ($print (("\n" literal)))
+  (result:string-address-array-address <- new string-address-array:literal count:integer)
+  ; repeatedly copy slices (start..end) until delimiter into result[curr-result]
+  (curr-result:integer <- copy 0:literal)
+  (start:integer <- copy 0:literal)
+  { begin
+    ; while next delim exists
+    (done?:boolean <- greater-or-equal start:integer len:integer)
+    (break-if done?:boolean)
+    (end:integer <- find-next s:string-address delim:character start:integer)
+;?     ($print start:integer) ;? 1
+;?     ($print ((" " literal))) ;? 1
+;?     ($print end:integer) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    ; copy start..end into result[curr-result]
+    (dest:string-address-address <- index-address result:string-address-array-address/deref curr-result:integer)
+    (dest:string-address-address/deref <- string-copy s:string-address start:integer end:integer)
+    ; slide over to next slice
+    (start:integer <- add end:integer 1:literal)
+    (curr-result:integer <- add curr-result:integer 1:literal)
+    (loop)
+  }
+  (reply result:string-address-array-address)
+)
+
+(init-fn split-first-at-substring/variant:split-first  ; string text, string delim -> string first, string rest
+  (default-space:space-address <- new space:literal 30:literal)
+  (text:string-address <- next-input)
+  (delim:string-address <- next-input)
+  ; empty string? return empty strings
+  (len:integer <- length text:string-address/deref)
+  { begin
+    (empty?:boolean <- equal len:integer 0:literal)
+    (break-unless empty?:boolean)
+    (x:string-address <- new "")
+    (y:string-address <- new "")
+    (reply x:string-address y:string-address)
+  }
+  (idx:integer <- find-substring text:string-address delim:string-address 0:literal)
+  (x:string-address <- string-copy text:string-address 0:literal idx:integer)
+  (k:integer <- length delim:string-address/deref)
+  (idx:integer <- add idx:integer k:integer)
+  (y:string-address <- string-copy text:string-address idx:integer len:integer)
+  (reply x:string-address y:string-address)
+)
+
+(init-fn split-first  ; string text, character delim -> string first, string rest
+  (default-space:space-address <- new space:literal 30:literal)
+  (text:string-address <- next-input)
+  (delim:character <- next-input)
+  ; empty string? return empty strings
+  (len:integer <- length text:string-address/deref)
+  { begin
+    (empty?:boolean <- equal len:integer 0:literal)
+    (break-unless empty?:boolean)
+    (x:string-address <- new "")
+    (y:string-address <- new "")
+    (reply x:string-address y:string-address)
+  }
+  (idx:integer <- find-next text:string-address delim:character 0:literal)
+  (x:string-address <- string-copy text:string-address 0:literal idx:integer)
+  (idx:integer <- add idx:integer 1:literal)
+  (y:string-address <- string-copy text:string-address idx:integer len:integer)
+  (reply x:string-address y:string-address)
+)
+
+; todo: make this generic
+(init-fn string-copy  ; buf start end -> address of new array
+  (default-space:space-address <- new space:literal 30:literal)
+  (buf:string-address <- next-input)
+  (start:integer <- next-input)
+  (end:integer <- next-input)
+;?   ($print (("  copy: " literal))) ;? 1
+;?   ($print start:integer) ;? 1
+;?   ($print (("-" literal))) ;? 1
+;?   ($print end:integer) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  ; if end is out of bounds, trim it
+  (len:integer <- length buf:string-address/deref)
+  (end:integer <- min len:integer end:integer)
+  ; allocate space for result
+  (len:integer <- subtract end:integer start:integer)
+  (result:string-address <- new string:literal len:integer)
+  ; copy start..end into result[curr-result]
+  (src-idx:integer <- copy start:integer)
+  (dest-idx:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- greater-or-equal src-idx:integer end:integer)
+    (break-if done?:boolean)
+    (src:character <- index buf:string-address/deref src-idx:integer)
+;?     ($print (("  copying " literal))) ;? 1
+;?     ($print src:character) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (dest:character-address <- index-address result:string-address/deref dest-idx:integer)
+    (dest:character-address/deref <- copy src:character)
+    (src-idx:integer <- add src-idx:integer 1:literal)
+    (dest-idx:integer <- add dest-idx:integer 1:literal)
+    (loop)
+  }
+  (reply result:string-address)
+)
+
+(init-fn min
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:integer <- next-input)
+  (y:integer <- next-input)
+  { begin
+    (return-x?:boolean <- less-than x:integer y:integer)
+    (break-if return-x?:boolean)
+    (reply y:integer)
+  }
+  (reply x:integer)
+)
+
+(init-fn max
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:integer <- next-input)
+  (y:integer <- next-input)
+  { begin
+    (return-x?:boolean <- greater-than x:integer y:integer)
+    (break-if return-x?:boolean)
+    (reply y:integer)
+  }
+  (reply x:integer)
+)
+
+(init-fn init-stream
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:string-address <- next-input)
+  (result:stream-address <- new stream:literal)
+  (x:integer-address <- get-address result:stream-address/deref pointer:offset)
+  (x:integer-address/deref <- copy 0:literal)
+  (y:string-address-address <- get-address result:stream-address/deref data:offset)
+  (y:string-address-address/deref <- copy in:string-address)
+  (reply result:stream-address)
+)
+
+(init-fn rewind-stream
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:stream-address <- next-input)
+  (x:integer-address <- get-address in:stream-address/deref pointer:offset)
+  (x:integer-address/deref <- copy 0:literal)
+  (reply in:stream-address/same-as-arg:0)
+)
+
+(init-fn read-line
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:stream-address <- next-input)
+  (idx:integer-address <- get-address in:stream-address/deref pointer:offset)
+  (s:string-address <- get in:stream-address/deref data:offset)
+;?   ($print (("idx before: " literal))) ;? 1
+;?   ($print idx:integer-address/deref) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (next-idx:integer <- find-next s:string-address ((#\newline literal)) idx:integer-address/deref)
+;?   ($print (("next-idx: " literal))) ;? 1
+;?   ($print next-idx:integer) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (result:string-address <- string-copy s:string-address idx:integer-address/deref next-idx:integer)
+  (idx:integer-address/deref <- add next-idx:integer 1:literal)  ; skip newline
+;?   ($print (("idx now: " literal))) ;? 1
+;?   ($print idx:integer-address/deref) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (reply result:string-address)
+)
+
+(init-fn read-character
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:stream-address <- next-input)
+  (idx:integer-address <- get-address in:stream-address/deref pointer:offset)
+  (s:string-address <- get in:stream-address/deref data:offset)
+  (c:character <- index s:string-address/deref idx:integer-address/deref)
+  (idx:integer-address/deref <- add idx:integer-address/deref 1:literal)
+  (reply c:character)
+)
+
+(init-fn end-of-stream?
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:stream-address <- next-input)
+  (idx:integer <- get in:stream-address/deref pointer:offset)
+  (s:string-address <- get in:stream-address/deref data:offset)
+  (len:integer <- length s:string-address/deref)
+;?   ($print (("eos: " literal))) ;? 1
+;?   ($print len:integer) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+;?   ($print (("idx: " literal))) ;? 1
+;?   ($print idx:integer) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (result:boolean <- greater-or-equal idx:integer len:integer)
+  (reply result:boolean)
+)
+
+(init-fn init-keyboard
+  (default-space:space-address <- new space:literal 30:literal)
+  (result:keyboard-address <- new keyboard:literal)
+  (buf:string-address-address <- get-address result:keyboard-address/deref data:offset)
+  (buf:string-address-address/deref <- next-input)
+  (idx:integer-address <- get-address result:keyboard-address/deref index:offset)
+  (idx:integer-address/deref <- copy 0:literal)
+  (reply result:keyboard-address)
+)
+
+(init-fn read-key
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (break-unless x:keyboard-address)
+    (idx:integer-address <- get-address x:keyboard-address/deref index:offset)
+    (buf:string-address <- get x:keyboard-address/deref data:offset)
+    (max:integer <- length buf:string-address/deref)
+    { begin
+      (done?:boolean <- greater-or-equal idx:integer-address/deref max:integer)
+      (break-unless done?:boolean)
+      (reply ((#\null literal)))
+    }
+    (c:character <- index buf:string-address/deref idx:integer-address/deref)
+    (idx:integer-address/deref <- add idx:integer-address/deref 1:literal)
+    (reply c:character)
+  }
+  ; real keyboard input is infrequent; avoid polling it too much
+  (sleep for-some-cycles:literal 1:literal)
+  (c:character <- read-key-from-host)
+  ; when we read from a real keyboard we print to screen as well
+  { begin
+    (break-unless c:character)
+    (silent?:boolean <- equal screen:terminal-address ((silent literal)))
+    (break-if silent?:boolean)
+;?     ($print (("aaaa\n" literal))) ;? 1
+    (print-character-to-host c:character)
+  }
+  (reply c:character)
+)
+
+(init-fn wait-for-key
+  (default-space:space-address <- new space:literal 30:literal)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (result:character <- read-key k:keyboard-address screen:terminal-address)
+    (loop-unless result:character)
+  }
+  (reply result:character)
+)
+
+(init-fn send-keys-to-stdin
+  (default-space:space-address <- new space:literal 30:literal)
+  (k:keyboard-address <- next-input)
+  (stdin:channel-address <- next-input)
+;?   (c:character <- copy ((#\a literal))) ;? 1
+;?   (curr:tagged-value <- save-type c:character) ;? 1
+;?   (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
+;?   (c:character <- copy ((#\newline literal))) ;? 1
+;?   (curr:tagged-value <- save-type c:character) ;? 1
+;?   (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value) ;? 1
+  { begin
+    (c:character <- read-key k:keyboard-address)
+    (loop-unless c:character)
+    (curr:tagged-value <- save-type c:character)
+    (stdin:channel-address/deref <- write stdin:channel-address curr:tagged-value)
+    (eof?:boolean <- equal c:character ((#\null literal)))
+    (break-if eof?:boolean)
+    (loop)
+  }
+)
+
+; collect characters until newline before sending out
+(init-fn buffer-lines
+  (default-space:space-address <- new space:literal 30:literal)
+  (stdin:channel-address <- next-input)
+  (buffered-stdin:channel-address <- next-input)
+  ; repeat forever
+  { begin
+    (line:buffer-address <- init-buffer 30:literal)
+;?     ($dump-channel 1093:literal) ;? 1
+    ; read characters from stdin until newline, copy into line
+    { begin
+      (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+      (c:character <- maybe-coerce x:tagged-value character:literal)
+      (assert c:character)
+;?       ($print line:buffer-address) ;? 2
+;?       ($print (("\n" literal))) ;? 2
+;?       ($print c:character) ;? 2
+;?       ($print (("\n" literal))) ;? 2
+      ; handle backspace
+      { begin
+        (backspace?:boolean <- equal c:character ((#\backspace literal)))
+        (break-unless backspace?:boolean)
+        (len:integer-address <- get-address line:buffer-address/deref length:offset)
+        ; but only if we need to
+        { begin
+;?           ($print (("backspace: " literal))) ;? 1
+;?           ($print len:integer-address/deref) ;? 1
+;?           ($print (("\n" literal))) ;? 1
+          (zero?:boolean <- lesser-or-equal len:integer-address/deref 0:literal)
+          (break-if zero?:boolean)
+          (len:integer-address/deref <- subtract len:integer-address/deref 1:literal)
+        }
+        (loop 2:blocks)
+      }
+      (line:buffer-address <- append line:buffer-address c:character)
+      (line-done?:boolean <- equal c:character ((#\newline literal)))
+      (break-if line-done?:boolean)
+      (eof?:boolean <- equal c:character ((#\null literal)))
+      (break-if eof?:boolean 2:blocks)
+      (loop)
+    }
+    ; copy line into buffered-stdout
+    (i:integer <- copy 0:literal)
+    (line-contents:string-address <- get line:buffer-address/deref data:offset)
+    (max:integer <- get line:buffer-address/deref length:offset)
+;?     ($print (("len: " literal))) ;? 1
+;?     ($print max:integer) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    { begin
+      (done?:boolean <- greater-or-equal i:integer max:integer)
+      (break-if done?:boolean)
+      (c:character <- index line-contents:string-address/deref i:integer)
+      (curr:tagged-value <- save-type c:character)
+;?       ($dump-channel 1093:literal) ;? 1
+;?       ($start-tracing) ;? 1
+;?       ($print (("bufferout: " literal))) ;? 2
+;?       ($print c:character) ;? 1
+;?       (x:integer <- character-to-integer c:character) ;? 1
+;?       ($print x:integer) ;? 1
+;?       ($print (("\n" literal))) ;? 2
+      (buffered-stdin:channel-address/deref <- write buffered-stdin:channel-address curr:tagged-value)
+;?       ($stop-tracing) ;? 1
+;?       ($dump-channel 1093:literal) ;? 1
+;?       ($quit) ;? 1
+      (i:integer <- add i:integer 1:literal)
+      (loop)
+    }
+    (loop)
+  }
+)
+
+(init-fn clear-screen
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  { begin
+    (break-unless x:terminal-address)
+;?     ($print (("AAA" literal)))
+    (buf:string-address <- get x:terminal-address/deref data:offset)
+    (max:integer <- length buf:string-address/deref)
+    (i:integer <- copy 0:literal)
+    { begin
+      (done?:boolean <- greater-or-equal i:integer max:integer)
+      (break-if done?:boolean)
+      (x:byte-address <- index-address buf:string-address/deref i:integer)
+      (x:byte-address/deref <- copy ((#\space literal)))
+      (i:integer <- add i:integer 1:literal)
+      (loop)
+    }
+    (reply)
+  }
+  (clear-host-screen)
+)
+
+(init-fn cursor
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  (newrow:integer <- next-input)
+  (newcol:integer <- next-input)
+  { begin
+    (break-unless x:terminal-address)
+    (row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
+    (row:integer-address/deref <- copy newrow:integer)
+    (col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
+    (col:integer-address/deref <- copy newcol:integer)
+    (reply)
+  }
+  (cursor-on-host row:integer col:integer)
+)
+
+(init-fn cursor-to-next-line
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  { begin
+    (break-unless x:terminal-address)
+    (row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
+;?     ($print row:integer-address/deref)
+;?     ($print (("\n" literal)))
+    (row:integer-address/deref <- add row:integer-address/deref 1:literal)
+    (col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
+;?     ($print col:integer-address/deref)
+;?     ($print (("\n" literal)))
+    (col:integer-address/deref <- copy 0:literal)
+    (reply)
+  }
+  (cursor-on-host-to-next-line)
+)
+
+(init-fn cursor-down
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+;?   ($print ((#\# literal))) ;? 1
+  (height:integer-address <- get-address x:terminal-address/deref num-rows:offset)
+;?   ($print height:integer-address/deref) ;? 1
+  { begin
+    (break-unless x:terminal-address)
+;?     ($print ((#\% literal))) ;? 1
+    (row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
+;?     ($print (("cursor down: " literal))) ;? 1
+;?     ($print row:integer-address/deref) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    { begin
+      (bottom?:boolean <- greater-or-equal row:integer-address/deref height:integer-address/deref)
+      (break-if bottom?:boolean)
+      (row:integer-address/deref <- add row:integer-address/deref 1:literal)
+;?       ($print ((#\* literal))) ;? 1
+;?       ($print row:integer-address/deref) ;? 1
+    }
+    (reply)
+  }
+  (cursor-down-on-host)
+)
+
+(init-fn cursor-up
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  { begin
+    (break-unless x:terminal-address)
+    (row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
+;?     ($print (("cursor up: " literal))) ;? 1
+;?     ($print row:integer-address/deref) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    { begin
+      (top?:boolean <- lesser-or-equal row:integer-address/deref 0:literal)
+      (break-if top?:boolean)
+      (row:integer-address/deref <- subtract row:integer-address/deref 1:literal)
+    }
+    (reply)
+  }
+  (cursor-up-on-host)
+)
+
+(init-fn cursor-left
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  { begin
+    (break-unless x:terminal-address)
+    (col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
+    { begin
+      (edge?:boolean <- lesser-or-equal col:integer-address/deref 0:literal)
+      (break-if edge?:boolean)
+      (col:integer-address/deref <- subtract col:integer-address/deref 1:literal)
+    }
+    (reply)
+  }
+  (cursor-left-on-host)
+)
+
+(init-fn cursor-right
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  (width:integer-address <- get-address x:terminal-address/deref num-cols:offset)
+  { begin
+    (break-unless x:terminal-address)
+    (col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
+    { begin
+      (edge?:boolean <- lesser-or-equal col:integer-address/deref width:integer-address/deref)
+      (break-if edge?:boolean)
+      (col:integer-address/deref <- add col:integer-address/deref 1:literal)
+    }
+    (reply)
+  }
+  (cursor-right-on-host)
+)
+
+(init-fn replace-character
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  (c:character <- next-input)
+  (print-character x:terminal-address c:character)
+  (cursor-left x:terminal-address)
+)
+
+(init-fn clear-line
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  { begin
+    (break-unless x:terminal-address)
+    (n:integer <- get x:terminal-address/deref num-cols:offset)
+    (col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
+    (orig-col:integer <- copy col:integer-address/deref)
+    ; space over the entire line
+    { begin
+      (done?:boolean <- greater-or-equal col:integer-address/deref n:integer)
+      (break-if done?:boolean)
+      (print-character x:terminal-address ((#\space literal)))  ; implicitly updates 'col'
+      (loop)
+    }
+    ; now back to where the cursor was
+    (col:integer-address/deref <- copy orig-col:integer)
+    (reply)
+  }
+  (clear-line-on-host)
+)
+
+(init-fn print-character
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  (c:character <- next-input)
+  (fg:integer/color <- next-input)
+  (bg:integer/color <- next-input)
+;?   ($print (("printing character to screen " literal)))
+;?   ($print c:character)
+;?   (reply)
+;?   ($print (("\n" literal)))
+  { begin
+    (break-unless x:terminal-address)
+    (row:integer-address <- get-address x:terminal-address/deref cursor-row:offset)
+;?     ($print row:integer-address/deref) ;? 2
+;?     ($print ((", " literal))) ;? 1
+    (col:integer-address <- get-address x:terminal-address/deref cursor-col:offset)
+;?     ($print col:integer-address/deref) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (width:integer <- get x:terminal-address/deref num-cols:offset)
+    (t1:integer <- multiply row:integer-address/deref width:integer)
+    (idx:integer <- add t1:integer col:integer-address/deref)
+    (buf:string-address <- get x:terminal-address/deref data:offset)
+    (cursor:byte-address <- index-address buf:string-address/deref idx:integer)
+    (cursor:byte-address/deref <- copy c:character)  ; todo: newline, etc.
+    (col:integer-address/deref <- add col:integer-address/deref 1:literal)
+    ; we don't rely on any auto-wrap functionality
+    ; maybe die if we go out of screen bounds?
+    (reply)
+  }
+  (print-character-to-host c:character fg:integer/color bg:integer/color)
+)
+
+(init-fn print-string
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  (s:string-address <- next-input)
+  (len:integer <- length s:string-address/deref)
+;?   ($print (("print/string: len: " literal)))
+;?   ($print len:integer)
+;?   ($print (("\n" literal)))
+  (i:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- greater-or-equal i:integer len:integer)
+    (break-if done?:boolean)
+    (c:character <- index s:string-address/deref i:integer)
+    (print-character x:terminal-address c:character)
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+)
+
+(init-fn print-integer
+  (default-space:space-address <- new space:literal 30:literal)
+  (x:terminal-address <- next-input)
+  (n:integer <- next-input)
+  ; todo: other bases besides decimal
+;?   ($print (("AAA " literal)))
+;?   ($print n:integer)
+  (s:string-address <- integer-to-decimal-string n:integer)
+;?   ($print s:string-address)
+  (print-string x:terminal-address s:string-address)
+)
+
+(init-fn init-buffer
+  (default-space:space-address <- new space:literal 30:literal)
+  (result:buffer-address <- new buffer:literal)
+  (len:integer-address <- get-address result:buffer-address/deref length:offset)
+  (len:integer-address/deref <- copy 0:literal)
+  (s:string-address-address <- get-address result:buffer-address/deref data:offset)
+  (capacity:integer <- next-input)
+  (s:string-address-address/deref <- new string:literal capacity:integer)
+  (reply result:buffer-address)
+)
+
+(init-fn grow-buffer
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  ; double buffer size
+  (x:string-address-address <- get-address in:buffer-address/deref data:offset)
+  (oldlen:integer <- length x:string-address-address/deref/deref)
+;?   ($print oldlen:integer) ;? 1
+  (newlen:integer <- multiply oldlen:integer 2:literal)
+;?   ($print newlen:integer) ;? 1
+  (olddata:string-address <- copy x:string-address-address/deref)
+  (x:string-address-address/deref <- new string:literal newlen:integer)
+  ; copy old contents
+  (i:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- greater-or-equal i:integer oldlen:integer)
+    (break-if done?:boolean)
+    (src:byte <- index olddata:string-address/deref i:integer)
+    (dest:byte-address <- index-address x:string-address-address/deref/deref i:integer)
+    (dest:byte-address/deref <- copy src:byte)
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+  (reply in:buffer-address)
+)
+
+(init-fn buffer-full?
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (len:integer <- get in:buffer-address/deref length:offset)
+  (s:string-address <- get in:buffer-address/deref data:offset)
+  (capacity:integer <- length s:string-address/deref)
+  (result:boolean <- greater-or-equal len:integer capacity:integer)
+  (reply result:boolean)
+)
+
+(init-fn buffer-index
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (idx:integer <- next-input)
+  { begin
+    (len:integer <- get in:buffer-address/deref length:offset)
+    (not-too-high?:boolean <- less-than idx:integer len:integer)
+    (not-too-low?:boolean <- greater-or-equal idx:integer 0:literal)
+    (in-bounds?:boolean <- and not-too-low?:boolean not-too-high?:boolean)
+    (break-if in-bounds?:boolean)
+    (assert nil:literal (("buffer-index out of bounds" literal)))
+  }
+  (s:string-address <- get in:buffer-address/deref data:offset)
+  (result:character <- index s:string-address/deref idx:integer)
+  (reply result:character)
+)
+
+(init-fn to-array  ; from buffer
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (len:integer <- get in:buffer-address/deref length:offset)
+  (s:string-address <- get in:buffer-address/deref data:offset)
+  { begin
+    ; test: ctrl-d -> s is nil -> to-array returns nil -> read-expression returns t -> exit repl
+    (break-if s:string-address)
+    (reply nil:literal)
+  }
+  ; we can't just return s because it is usually the wrong length
+  (result:string-address <- new string:literal len:integer)
+  (i:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- greater-or-equal i:integer len:integer)
+    (break-if done?:boolean)
+    (src:byte <- index s:string-address/deref i:integer)
+;?     (foo:integer <- character-to-integer src:byte) ;? 1
+;?     ($print (("a: " literal))) ;? 1
+;?     ($print foo:integer) ;? 1
+;?     ($print ((#\newline literal))) ;? 1
+    (dest:byte-address <- index-address result:string-address/deref i:integer)
+    (dest:byte-address/deref <- copy src:byte)
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+  (reply result:string-address)
+)
+
+(init-fn append
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (c:character <- next-input)
+;?   ($print c:character) ;? 1
+  { begin
+    ; grow buffer if necessary
+    (full?:boolean <- buffer-full? in:buffer-address)
+;?     ($print (("aa\n" literal))) ;? 1
+    (break-unless full?:boolean)
+;?     ($print (("bb\n" literal))) ;? 1
+    (in:buffer-address <- grow-buffer in:buffer-address)
+;?     ($print (("cc\n" literal))) ;? 1
+  }
+  (len:integer-address <- get-address in:buffer-address/deref length:offset)
+  (s:string-address <- get in:buffer-address/deref data:offset)
+  (dest:byte-address <- index-address s:string-address/deref len:integer-address/deref)
+  (dest:byte-address/deref <- copy c:character)
+  (len:integer-address/deref <- add len:integer-address/deref 1:literal)
+  (reply in:buffer-address/same-as-arg:0)
+)
+
+(init-fn last
+  (default-space:space-address <- new space:literal 30:literal)
+  (in:buffer-address <- next-input)
+  (n:integer <- get in:buffer-address/deref length:offset)
+  { begin
+    ; if empty return nil
+    (empty?:boolean <- equal n:integer 0:literal)
+    (break-unless empty?:boolean)
+    (reply nil:literal)
+  }
+  (n:integer <- subtract n:integer 1:literal)
+  (s:string-address <- get in:buffer-address/deref data:offset)
+  (result:character <- index s:string-address/deref n:integer)
+  (reply result:character)
+)
+
+(init-fn integer-to-decimal-string
+  (default-space:space-address <- new space:literal 30:literal)
+  (n:integer <- next-input)
+  ; is it zero?
+  { begin
+    (zero?:boolean <- equal n:integer 0:literal)
+    (break-unless zero?:boolean)
+    (s:string-address <- new "0")
+    (reply s:string-address)
+  }
+  ; save sign
+  (negate-result:boolean <- copy nil:literal)
+  { begin
+    (negative?:boolean <- less-than n:integer 0:literal)
+    (break-unless negative?:boolean)
+;?     ($print (("is negative " literal)))
+    (negate-result:boolean <- copy t:literal)
+    (n:integer <- multiply n:integer -1:literal)
+  }
+  ; add digits from right to left into intermediate buffer
+  (tmp:buffer-address <- init-buffer 30:literal)
+  (zero:character <- copy ((#\0 literal)))
+  (digit-base:integer <- character-to-integer zero:character)
+  { begin
+    (done?:boolean <- equal n:integer 0:literal)
+    (break-if done?:boolean)
+    (n:integer digit:integer <- divide-with-remainder n:integer 10:literal)
+    (digit-codepoint:integer <- add digit-base:integer digit:integer)
+    (c:character <- integer-to-character digit-codepoint:integer)
+    (tmp:buffer-address <- append tmp:buffer-address c:character)
+    (loop)
+  }
+  ; add sign
+  { begin
+    (break-unless negate-result:boolean)
+    (tmp:buffer-address <- append tmp:buffer-address ((#\- literal)))
+  }
+  ; reverse buffer into string result
+  (len:integer <- get tmp:buffer-address/deref length:offset)
+  (buf:string-address <- get tmp:buffer-address/deref data:offset)
+  (result:string-address <- new string:literal len:integer)
+  (i:integer <- subtract len:integer 1:literal)
+  (j:integer <- copy 0:literal)
+  { begin
+    ; while (i >= 0)
+    (done?:boolean <- less-than i:integer 0:literal)
+    (break-if done?:boolean)
+    ; result[j] = tmp[i]
+    (src:byte <- index buf:string-address/deref i:integer)
+    (dest:byte-address <- index-address result:string-address/deref j:integer)
+    (dest:byte-address/deref <- copy src:byte)
+    ; ++i
+    (i:integer <- subtract i:integer 1:literal)
+    ; --j
+    (j:integer <- add j:integer 1:literal)
+    (loop)
+  }
+  (reply result:string-address)
+)
+
+(init-fn send-prints-to-stdout
+  (default-space:space-address <- new space:literal 30:literal)
+  (screen:terminal-address <- next-input)
+  (stdout:channel-address <- next-input)
+;?   (i:integer <- copy 0:literal) ;? 1
+  { begin
+    (x:tagged-value stdout:channel-address/deref <- read stdout:channel-address)
+    (c:character <- maybe-coerce x:tagged-value character:literal)
+    (done?:boolean <- equal c:character ((#\null literal)))
+    (break-if done?:boolean)
+;?     ($print (("printing " literal))) ;? 1
+;?     ($print i:integer) ;? 1
+;?     ($print ((" -- " literal))) ;? 1
+;?     (x:integer <- character-to-integer c:character) ;? 1
+;?     ($print x:integer) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+;?     (i:integer <- add i:integer 1:literal) ;? 1
+    (print-character screen:terminal-address c:character)
+    (loop)
+  }
+)
+
+; remember to call this before you clear the screen or at any other milestone
+; in an interactive program
+(init-fn flush-stdout
+  (default-space:boolean <- copy nil:literal)  ; silence warning, but die if locals used
+  (sleep for-some-cycles:literal 1:literal)
+)
+
+(init-fn init-fake-terminal
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (result:terminal-address <- new terminal:literal)
+  (width:integer-address <- get-address result:terminal-address/deref num-cols:offset)
+  (width:integer-address/deref <- next-input)
+  (height:integer-address <- get-address result:terminal-address/deref num-rows:offset)
+  (height:integer-address/deref <- next-input)
+  (row:integer-address <- get-address result:terminal-address/deref cursor-row:offset)
+  (row:integer-address/deref <- copy 0:literal)
+  (col:integer-address <- get-address result:terminal-address/deref cursor-col:offset)
+  (col:integer-address/deref <- copy 0:literal)
+  (bufsize:integer <- multiply width:integer-address/deref height:integer-address/deref)
+  (buf:string-address-address <- get-address result:terminal-address/deref data:offset)
+  (buf:string-address-address/deref <- new string:literal bufsize:integer)
+  (clear-screen result:terminal-address)
+  (reply result:terminal-address)
+)
+
+(init-fn divides?
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:integer <- next-input)
+  (y:integer <- next-input)
+  (_ remainder:integer <- divide-with-remainder x:integer y:integer)
+  (result:boolean <- equal remainder:integer 0:literal)
+  (reply result:boolean)
+)
+
+; after all system software is loaded:
+;? (= dump-trace* (obj whitelist '("cn0" "cn1")))
+(freeze system-function*)
+)  ; section 100 for system software
+
+;; initialization
+
+(reset)
+(awhen (pos "--" argv)
+  ; batch mode: load all provided files and start at 'main'
+  (map add-code:readfile (cut argv (+ it 1)))
+;?   (set dump-trace*)
+  (run 'main)
+  (if ($.current-charterm) ($.close-charterm))
+  (when ($.graphics-open?) ($.close-viewport Viewport) ($.close-graphics))
+;?   (pr "\nmemory: ")
+;?   (write int-canon.memory*)
+  (prn)
+  (each routine completed-routines*
+    (awhen rep.routine!error
+      (prn "error - " it)
+;?       (prn routine)
+      ))
+)
+
+; repl
+(def run-interactive (stmt)
+  ; careful to avoid re-processing functions and adding noise to traces
+  (= function*!interactive (convert-labels:convert-braces:tokenize-args (list stmt)))
+  (add-next-space-generator function*!interactive 'interactive)
+  (= location*!interactive (assign-names-to-location function*!interactive 'interactive location*!interactive))
+  (replace-names-with-location function*!interactive 'interactive)
+  (= traces* (queue))  ; skip preprocessing
+  (run-more 'interactive))
+
+(when (no cdr.argv)
+  (add-code:readfile "trace.mu")
+  (wipe function*!main)
+  (add-code:readfile "factorial.mu")
+;?   (add-code:readfile "chessboard.mu")  ; takes too long
+  (wipe function*!main)
+  (freeze function*)
+  (load-system-functions)
+  (wipe interactive-commands*)
+  (wipe interactive-traces*)
+  (= interactive-cmdidx* 0)
+  (= traces* (queue))
+;?   (set dump-trace*) ;? 2
+  ; interactive mode
+  (point break
+  (while t
+    (pr interactive-cmdidx*)(pr "> ")
+    (let expr (read)
+      (unless expr (break))
+      (push expr interactive-commands*)
+      (run-interactive expr))
+    (push traces* interactive-traces*)
+    (++ interactive-cmdidx*)
+    )))
+
+(if ($.current-charterm) ($.close-charterm))
+(reset)
+;? (print-times)
diff --git a/archive/0.vm.arc/mu.arc.t b/archive/0.vm.arc/mu.arc.t
new file mode 100644
index 00000000..6c0464f9
--- /dev/null
+++ b/archive/0.vm.arc/mu.arc.t
@@ -0,0 +1,5208 @@
+; Mu: An exploration on making the global structure of programs more accessible.
+;
+;   "Is it a language, or an operating system, or a virtual machine? Mu."
+;   (with apologies to Robert Pirsig: http://en.wikipedia.org/wiki/Mu_%28negative%29#In_popular_culture)
+;
+;; Motivation
+;
+; I want to live in a world where I can have an itch to tweak a program, clone
+; its open-source repository, orient myself on how it's organized, and make
+; the simple change I envisioned, all in an afternoon. This codebase tries to
+; make this possible for its readers. (More details: http://akkartik.name/about)
+;
+; What helps comprehend the global structure of programs? For starters, let's
+; enumerate what doesn't: idiomatic code, adherence to a style guide or naming
+; convention, consistent indentation, API documentation for each class, etc.
+; These conventional considerations improve matters in the small, but don't
+; help understand global organization. They help existing programmers manage
+; day-to-day operations, but they can't turn outsider programmers into
+; insiders. (Elaboration: http://akkartik.name/post/readable-bad)
+;
+; In my experience, two things have improved matters so far: version control
+; and automated tests. Version control lets me rewind back to earlier, simpler
+; times when the codebase was simpler, when its core skeleton was easier to
+; ascertain. Indeed, arguably what came first is by definition the skeleton of
+; a program, modulo major rewrites. Once you understand the skeleton, it
+; becomes tractable to 'play back' later major features one by one. (Previous
+; project that fleshed out this idea: http://akkartik.name/post/wart-layers)
+;
+; The second and biggest boost to comprehension comes from tests. Tests are
+; good for writers for well-understood reasons: they avoid regressions, and
+; they can influence code to be more decoupled and easier to change. In
+; addition, tests are also good for the outsider reader because they permit
+; active reading. If you can't build a program and run its tests it can't help
+; you understand it. It hangs limp at best, and might even be actively
+; misleading. If you can run its tests, however, it comes alive. You can step
+; through scenarios in a debugger. You can add logging and scan logs to make
+; sense of them. You can run what-if scenarios: "why is this line not written
+; like this?" Make a change, rerun tests: "Oh, that's why." (Elaboration:
+; http://akkartik.name/post/literate-programming)
+;
+; However, tests are only useful to the extent that they exist. Think back to
+; your most recent codebase. Do you feel comfortable releasing a new version
+; just because the tests pass? I'm not aware of any such project. There's just
+; too many situations envisaged by the authors that were never encoded in a
+; test. Even disciplined authors can't test for performance or race conditions
+; or fault tolerance. If a line is phrased just so because of some subtle
+; performance consideration, it's hard to communicate to newcomers.
+;
+; This isn't an arcane problem, and it isn't just a matter of altruism. As
+; more and more such implicit considerations proliferate, and as the original
+; authors are replaced by latecomers for day-to-day operations, knowledge is
+; actively forgotten and lost. The once-pristine codebase turns into legacy
+; code that is hard to modify without expensive and stress-inducing
+; regressions.
+;
+; How to write tests for performance, fault tolerance, race conditions, etc.?
+; How can we state and verify that a codepath doesn't ever perform memory
+; allocation, or write to disk? It requires better, more observable primitives
+; than we currently have. Modern operating systems have their roots in the
+; 70s. Their interfaces were not designed to be testable. They provide no way
+; to simulate a full disk, or a specific sequence of writes from different
+; threads. We need something better.
+;
+; This project tries to move, groping, towards that 'something better', a
+; platform that is both thoroughly tested and allows programs written for it
+; to be thoroughly tested. It tries to answer the question:
+;
+;   If Denis Ritchie and Ken Thompson were to set out today to co-design unix
+;   and C, knowing what we know about automated tests, what would they do
+;   differently?
+;
+; To try to impose *some* constraints on this gigantic yak-shave, we'll try to
+; keep both language and OS as simple as possible, focused entirely on
+; permitting more kinds of tests, on first *collecting* all the information
+; about implicit considerations in some form so that readers and tools can
+; have at least some hope of making sense of it.
+;
+; The initial language will be just assembly. We'll try to make it convenient
+; to program in with some simple localized rewrite rules inspired by lisp
+; macros and literate programming. Programmers will have to do their own
+; memory management and register allocation, but we'll provide libraries to
+; help with them.
+;
+; The initial OS will provide just memory management and concurrency
+; primitives. No users or permissions (we don't live on mainframes anymore),
+; no kernel- vs user-mode, no virtual memory or process abstraction, all
+; threads sharing a single address space (use VMs for security and
+; sandboxing). The only use case we care about is getting a test harness to
+; run some code, feed it data through blocking channels, stop it and observe
+; its internals. The code under test is expected to cooperate in such testing,
+; by logging important events for the test harness to observe. (More info:
+; http://akkartik.name/post/tracing-tests)
+;
+; The common thread here is elimination of abstractions, and it's not an
+; accident. Abstractions help insiders manage the evolution of a codebase, but
+; they actively hinder outsiders in understanding it from scratch. This
+; matters, because the funnel to turn outsiders into insiders is critical to
+; the long-term life of a codebase. Perhaps authors should raise their
+; estimation of the costs of abstraction, and go against their instincts for
+; introducing it. That's what I'll be trying to do: question every abstraction
+; before I introduce it. We'll see how it goes.
+
+; ---
+
+;; Getting started
+;
+; Mu is currently built atop Racket and Arc, but this is temporary and
+; contingent. We want to keep our options open, whether to port to a different
+; host language, and easy to rewrite to native code for any platform. So we'll
+; try to avoid 'cheating': relying on the host platform for advanced
+; functionality.
+;
+; Other than that, we'll say no more about the code, and focus in the rest of
+; this file on the scenarios the code cares about.
+
+(selective-load "mu.arc" section-level)
+(ero "running tests in mu.ar.c.t (takes ~30s)")
+;? (quit)
+
+(set allow-raw-addresses*)
+
+(section 20
+
+; Our language is assembly-like in that functions consist of series of
+; statements, and statements consist of an operation and its arguments (input
+; and output).
+;
+;   oarg1, oarg2, ... <- op arg1, arg2, ...
+;
+; Args must be atomic, like an integer or a memory address, they can't be
+; expressions doing arithmetic or function calls. But we can have any number
+; of them.
+;
+; Since we're building on lisp, our code samples won't look quite like the
+; idealized syntax above. For now they will look like this:
+;
+;   (function f [
+;     (oarg1 oarg2 ... <- op arg1 arg2 ...)
+;     ...
+;     ...
+;    ])
+;
+; Each arg/oarg can contain metadata separated by slashes and colons. In this
+; first example below, the only metadata is types: 'integer' for a memory
+; location containing an integer, and 'literal' for a value included directly
+; in code. (Assembly languages traditionally call them 'immediate' operands.)
+; In the future a simple tool will check that the types line up as expected in
+; each op. A different tool might add types where they aren't provided.
+; Instead of a monolithic compiler I want to build simple, lightweight tools
+; that can be combined in various ways, say for using different typecheckers
+; in different subsystems.
+;
+; In our tests we'll define such mu functions using a call to 'add-code', so
+; look for it when reading the code examples. Everything outside 'add-code' is
+; just test-harness details that can be skipped at first.
+
+(reset)
+;? (set dump-trace*)
+(new-trace "literal")
+(add-code
+  '((function main [
+      (1:integer <- copy 23:literal)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 23)
+  (prn "F - 'copy' writes its lone 'arg' after the instruction name to its lone 'oarg' or output arg before the arrow. After this test, the value 23 is stored in memory address 1."))
+;? (reset) ;? 2
+;? (quit) ;? 2
+
+; Our basic arithmetic ops can operate on memory locations or literals.
+; (Ignore hardware details like registers for now.)
+
+(reset)
+(new-trace "add")
+(add-code
+  '((function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (3:integer <- add 1:integer 2:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4))
+  (prn "F - 'add' operates on two addresses"))
+;? (reset) ;? 1
+;? (quit) ;? 1
+
+(reset)
+(new-trace "add-literal")
+(add-code
+  '((function main [
+      (1:integer <- add 2:literal 3:literal)
+     ])))
+(run 'main)
+(when (~is memory*.1 5)
+  (prn "F - ops can take 'literal' operands (but not return them)"))
+
+(reset)
+(new-trace "sub-literal")
+(add-code
+  '((function main [
+      (1:integer <- subtract 1:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 -2)
+  (prn "F - 'subtract'"))
+
+(reset)
+(new-trace "mul-literal")
+(add-code
+  '((function main [
+      (1:integer <- multiply 2:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 6)
+  (prn "F - 'multiply'"))
+
+(reset)
+(new-trace "div-literal")
+(add-code
+  '((function main [
+      (1:integer <- divide 8:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 (/ real.8 3))
+  (prn "F - 'divide'"))
+
+(reset)
+(new-trace "idiv-literal")
+(add-code
+  '((function main [
+      (1:integer 2:integer <- divide-with-remainder 23:literal 6:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 3  2 5))
+  (prn "F - 'divide-with-remainder' performs integer division"))
+
+(reset)
+(new-trace "dummy-oarg")
+;? (set dump-trace*)
+(add-code
+  '((function main [
+      (_ 2:integer <- divide-with-remainder 23:literal 6:literal)
+     ])))
+(run 'main)
+(when (~iso memory* (obj 2 5))
+  (prn "F - '_' oarg can ignore some results"))
+;? (quit)
+
+; Basic boolean operations: and, or, not
+; There are easy ways to encode booleans in binary, but we'll skip past those
+; details for now.
+
+(reset)
+(new-trace "and-literal")
+(add-code
+  '((function main [
+      (1:boolean <- and t:literal nil:literal)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 nil)
+  (prn "F - logical 'and' for booleans"))
+
+; Basic comparison operations
+
+(reset)
+(new-trace "lt-literal")
+(add-code
+  '((function main [
+      (1:boolean <- less-than 4:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 nil)
+  (prn "F - 'less-than' inequality operator"))
+
+(reset)
+(new-trace "le-literal-false")
+(add-code
+  '((function main [
+      (1:boolean <- lesser-or-equal 4:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 nil)
+  (prn "F - 'lesser-or-equal'"))
+
+(reset)
+(new-trace "le-literal-true")
+(add-code
+  '((function main [
+      (1:boolean <- lesser-or-equal 4:literal 4:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 t)
+  (prn "F - 'lesser-or-equal' returns true for equal operands"))
+
+(reset)
+(new-trace "le-literal-true-2")
+(add-code
+  '((function main [
+      (1:boolean <- lesser-or-equal 4:literal 5:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 t)
+  (prn "F - 'lesser-or-equal' - 2"))
+
+; Control flow operations: jump, jump-if, jump-unless
+; These introduce a new type -- 'offset' -- for literals that refer to memory
+; locations relative to the current location.
+
+(reset)
+(new-trace "jump-skip")
+(add-code
+  '((function main [
+      (1:integer <- copy 8:literal)
+      (jump 1:offset)
+      (2:integer <- copy 3:literal)  ; should be skipped
+      (reply)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 8))
+  (prn "F - 'jump' skips some instructions"))
+;? (quit)
+
+(reset)
+(new-trace "jump-target")
+(add-code
+  '((function main [
+      (1:integer <- copy 8:literal)
+      (jump 1:offset)
+      (2:integer <- copy 3:literal)  ; should be skipped
+      (reply)
+      (3:integer <- copy 34:literal)
+     ])))  ; never reached
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 8))
+  (prn "F - 'jump' doesn't skip too many instructions"))
+;? (quit)
+
+(reset)
+(new-trace "jump-if-skip")
+(add-code
+  '((function main [
+      (2:integer <- copy 1:literal)
+      (1:boolean <- equal 1:literal 2:integer)
+      (jump-if 1:boolean 1:offset)
+      (2:integer <- copy 3:literal)
+      (reply)
+      (3:integer <- copy 34:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 t  2 1))
+  (prn "F - 'jump-if' is a conditional 'jump'"))
+
+(reset)
+(new-trace "jump-if-fallthrough")
+(add-code
+  '((function main [
+      (1:boolean <- equal 1:literal 2:literal)
+      (jump-if 3:boolean 1:offset)
+      (2:integer <- copy 3:literal)
+      (reply)
+      (3:integer <- copy 34:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 nil  2 3))
+  (prn "F - if 'jump-if's first arg is false, it doesn't skip any instructions"))
+
+(reset)
+(new-trace "jump-if-backward")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 1:literal)
+      ; loop
+      (2:integer <- add 2:integer 2:integer)
+      (3:boolean <- equal 1:integer 2:integer)
+      (jump-if 3:boolean -3:offset)  ; to loop
+      (4:integer <- copy 3:literal)
+      (reply)
+      (3:integer <- copy 34:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 4  3 nil  4 3))
+  (prn "F - 'jump-if' can take a negative offset to make backward jumps"))
+
+(reset)
+(new-trace "jump-label")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 1:literal)
+      loop
+      (2:integer <- add 2:integer 2:integer)
+      (3:boolean <- equal 1:integer 2:integer)
+      (jump-if 3:boolean loop:offset)
+      (4:integer <- copy 3:literal)
+      (reply)
+      (3:integer <- copy 34:literal)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("-")))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 4  3 nil  4 3))
+  (prn "F - 'jump-if' can take a negative offset to make backward jumps"))
+;? (quit)
+
+; Data movement relies on addressing modes:
+;   'direct' - refers to a memory location; default for most types.
+;   'literal' - directly encoded in the code; implicit for some types like 'offset'.
+
+(reset)
+(new-trace "direct-addressing")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:integer <- copy 1:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 34))
+  (prn "F - 'copy' performs direct addressing"))
+
+; 'Indirect' addressing refers to an address stored in a memory location.
+; Indicated by the metadata '/deref'. Usually requires an address type.
+; In the test below, the memory location 1 contains '2', so an indirect read
+; of location 1 returns the value of location 2.
+
+(reset)
+(new-trace "indirect-addressing")
+(add-code
+  '((function main [
+      (1:integer-address <- copy 2:literal)  ; unsafe; can't do this in general
+      (2:integer <- copy 34:literal)
+      (3:integer <- copy 1:integer-address/deref)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 34  3 34))
+  (prn "F - 'copy' performs indirect addressing"))
+
+; Output args can use indirect addressing. In the test below the value is
+; stored at the location stored in location 1 (i.e. location 2).
+
+(reset)
+(new-trace "indirect-addressing-oarg")
+(add-code
+  '((function main [
+      (1:integer-address <- copy 2:literal)
+      (2:integer <- copy 34:literal)
+      (1:integer-address/deref <- add 2:integer 2:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 36))
+  (prn "F - instructions can perform indirect addressing on output arg"))
+
+;; Compound data types
+;
+; Until now we've dealt with scalar types like integers and booleans and
+; addresses, where mu looks like other assembly languages. In addition, mu
+; provides first-class support for compound types: arrays and and-records.
+;
+; 'get' accesses fields in and-records
+; 'index' accesses indices in arrays
+;
+; Both operations require knowledge about the types being worked on, so all
+; types used in mu programs are defined in a single global system-wide table
+; (see type* in mu.arc for the complete list of types; we'll add to it over
+; time).
+
+; first a sanity check that the table of types is consistent
+(reset)
+(each (typ typeinfo) type*
+  (when typeinfo!and-record
+    (assert (is typeinfo!size (len typeinfo!elems)))
+    (when typeinfo!fields
+      (assert (is typeinfo!size (len typeinfo!fields))))))
+
+(reset)
+(new-trace "get-record")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy nil:literal)
+      (3:boolean <- get 1:integer-boolean-pair 1:offset)
+      (4:integer <- get 1:integer-boolean-pair 0:offset)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 nil  3 nil  4 34))
+  (prn "F - 'get' accesses fields of and-records"))
+;? (quit)
+
+(reset)
+(new-trace "get-indirect")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy nil:literal)
+      (3:integer-boolean-pair-address <- copy 1:literal)
+      (4:boolean <- get 3:integer-boolean-pair-address/deref 1:offset)
+      (5:integer <- get 3:integer-boolean-pair-address/deref 0:offset)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 nil  3 1  4 nil  5 34))
+  (prn "F - 'get' accesses fields of and-record address"))
+
+(reset)
+(new-trace "get-indirect-repeated")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:integer <- copy 35:literal)
+      (3:integer <- copy 36:literal)
+      (4:integer-point-pair-address <- copy 1:literal)  ; unsafe
+      (5:integer-point-pair-address-address <- copy 4:literal)  ; unsafe
+      (6:integer-integer-pair <- get 5:integer-point-pair-address-address/deref/deref 1:offset)
+      (8:integer <- get 5:integer-point-pair-address-address/deref/deref 0:offset)
+     ])))
+(run 'main)
+(when (~memory-contains 6 '(35 36 34))
+  (prn "F - 'get' can deref multiple times"))
+;? (quit)
+
+(reset)
+(new-trace "get-compound-field")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:integer <- copy 35:literal)
+      (3:integer <- copy 36:literal)
+      (4:integer-integer-pair <- get 1:integer-point-pair 1:offset)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 35  3 36  4 35  5 36))
+  (prn "F - 'get' accesses fields spanning multiple locations"))
+
+(reset)
+(new-trace "get-address")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy t:literal)
+      (3:boolean-address <- get-address 1:integer-boolean-pair 1:offset)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 t  3 2))
+  (prn "F - 'get-address' returns address of fields of and-records"))
+
+(reset)
+(new-trace "get-address-indirect")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy t:literal)
+      (3:integer-boolean-pair-address <- copy 1:literal)
+      (4:boolean-address <- get-address 3:integer-boolean-pair-address/deref 1:offset)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 t  3 1  4 2))
+  (prn "F - 'get-address' accesses fields of and-record address"))
+
+(reset)
+(new-trace "index-literal")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer-boolean-pair <- index 1:integer-boolean-pair-array 1:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 23 3 nil  4 24 5 t  6 24 7 t))
+  (prn "F - 'index' accesses indices of arrays"))
+;? (quit)
+
+(reset)
+(new-trace "index-direct")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer <- copy 1:literal)
+      (7:integer-boolean-pair <- index 1:integer-boolean-pair-array 6:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 23 3 nil  4 24 5 t  6 1  7 24 8 t))
+  (prn "F - 'index' accesses indices of arrays"))
+;? (quit)
+
+(reset)
+(new-trace "index-indirect")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer <- copy 1:literal)
+      (7:integer-boolean-pair-array-address <- copy 1:literal)
+      (8:integer-boolean-pair <- index 7:integer-boolean-pair-array-address/deref 6:integer)
+     ])))
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "cvt0" "cvt1")))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 23 3 nil  4 24 5 t  6 1  7 1  8 24 9 t))
+  (prn "F - 'index' accesses indices of array address"))
+;? (quit)
+
+(reset)
+(new-trace "index-indirect-multiple")
+(add-code
+  '((function main [
+      (1:integer <- copy 4:literal)
+      (2:integer <- copy 23:literal)
+      (3:integer <- copy 24:literal)
+      (4:integer <- copy 25:literal)
+      (5:integer <- copy 26:literal)
+      (6:integer-array-address <- copy 1:literal)  ; unsafe
+      (7:integer-array-address-address <- copy 6:literal)  ; unsafe
+      (8:integer <- index 7:integer-array-address-address/deref/deref 1:literal)
+     ])))
+(run 'main)
+(when (~is memory*.8 24)
+  (prn "F - 'index' can deref multiple times"))
+
+(reset)
+(new-trace "index-address")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer <- copy 1:literal)
+      (7:integer-boolean-pair-address <- index-address 1:integer-boolean-pair-array 6:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 23 3 nil  4 24 5 t  6 1  7 4))
+  (prn "F - 'index-address' returns addresses of indices of arrays"))
+
+(reset)
+(new-trace "index-address-indirect")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer <- copy 1:literal)
+      (7:integer-boolean-pair-array-address <- copy 1:literal)
+      (8:integer-boolean-pair-address <- index-address 7:integer-boolean-pair-array-address/deref 6:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 2  2 23 3 nil  4 24 5 t  6 1  7 1  8 4))
+  (prn "F - 'index-address' returns addresses of indices of array addresses"))
+
+; Array values know their length. Record lengths are saved in the types table.
+
+(reset)
+(new-trace "len-array")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer <- length 1:integer-boolean-pair-array)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.6 2)
+  (prn "F - 'length' of array"))
+
+(reset)
+(new-trace "len-array-indirect")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer-address <- copy 1:literal)
+      (7:integer <- length 6:integer-boolean-pair-array-address/deref)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "cvt0" "cvt1")))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.7 2)
+  (prn "F - 'length' of array address"))
+
+; 'sizeof' is a helper to determine the amount of memory required by a type.
+; Only for non-arrays.
+
+(reset)
+(new-trace "sizeof-record")
+(add-code
+  '((function main [
+      (1:integer <- sizeof integer-boolean-pair:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.1 2)
+  (prn "F - 'sizeof' returns space required by arg"))
+
+(reset)
+(new-trace "sizeof-record-not-len")
+(add-code
+  '((function main [
+      (1:integer <- sizeof integer-point-pair:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (is memory*.1 2)
+  (prn "F - 'sizeof' is different from number of elems"))
+
+; Regardless of a type's length, you can move it around just like a primitive.
+
+(reset)
+(new-trace "copy-record")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy nil:literal)
+      (4:boolean <- copy t:literal)
+      (3:integer-boolean-pair <- copy 1:integer-boolean-pair)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 nil  3 34  4 nil))
+  (prn "F - ops can operate on records spanning multiple locations"))
+
+(reset)
+(new-trace "copy-record2")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:integer <- copy 35:literal)
+      (3:integer <- copy 36:literal)
+      (4:integer <- copy 0:literal)
+      (5:integer <- copy 0:literal)
+      (6:integer <- copy 0:literal)
+      (4:integer-point-pair <- copy 1:integer-point-pair)
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "sizeof")))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 35  3 36
+                         ; result
+                         4 34  5 35  6 36))
+  (prn "F - ops can operate on records with fields spanning multiple locations"))
+
+)  ; section 20
+
+(section 100
+
+; A special kind of record is the 'tagged type'. It lets us represent
+; dynamically typed values, which save type information in memory rather than
+; in the code to use them. This will let us do things like create heterogenous
+; lists containing both integers and strings. Tagged values admit two
+; operations:
+;
+;   'save-type' - turns a regular value into a tagged-value of the appropriate type
+;   'maybe-coerce' - turns a tagged value into a regular value if the type matches
+;
+; The payload of a tagged value must occupy just one location. Save pointers
+; to records.
+
+(reset)
+(new-trace "tagged-value")
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "cvt0" "cvt1")))
+(add-code
+  '((function main [
+      (1:type <- copy integer:literal)
+      (2:integer <- copy 34:literal)
+      (3:integer 4:boolean <- maybe-coerce 1:tagged-value integer:literal)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn completed-routines*)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn memory*)
+(when (or (~is memory*.3 34)
+          (~is memory*.4 t))
+  (prn "F - 'maybe-coerce' copies value only if type tag matches"))
+;? (quit)
+
+(reset)
+(new-trace "tagged-value-2")
+;? (set dump-trace*)
+(add-code
+  '((function main [
+      (1:type <- copy integer-address:literal)
+      (2:integer <- copy 34:literal)
+      (3:boolean 4:boolean <- maybe-coerce 1:tagged-value boolean:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (or (~is memory*.3 0)
+          (~is memory*.4 nil))
+  (prn "F - 'maybe-coerce' doesn't copy value when type tag doesn't match"))
+
+(reset)
+(new-trace "save-type")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:tagged-value <- save-type 1:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj  1 34  2 'integer  3 34))
+  (prn "F - 'save-type' saves the type of a value at runtime, turning it into a tagged-value"))
+
+(reset)
+(new-trace "init-tagged-value")
+(add-code
+  '((function main [
+      (1:integer <- copy 34:literal)
+      (2:tagged-value-address <- init-tagged-value integer:literal 1:integer)
+      (3:integer 4:boolean <- maybe-coerce 2:tagged-value-address/deref integer:literal)
+     ])))
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "cvt0" "cvt1" "sizeof")))
+(run 'main)
+;? (prn memory*)
+(when (or (~is memory*.3 34)
+          (~is memory*.4 t))
+  (prn "F - 'init-tagged-value' is the converse of 'maybe-coerce'"))
+;? (quit)
+
+; Now that we can package values together with their types, we can construct a
+; dynamically typed list.
+
+(reset)
+(new-trace "list")
+;? (set dump-trace*)
+(add-code
+  '((function main [
+      ; 1 points at first node: tagged-value (int 34)
+      (1:list-address <- new list:literal)
+      (2:tagged-value-address <- list-value-address 1:list-address)
+      (3:type-address <- get-address 2:tagged-value-address/deref type:offset)
+      (3:type-address/deref <- copy integer:literal)
+      (4:location <- get-address 2:tagged-value-address/deref payload:offset)
+      (4:location/deref <- copy 34:literal)
+      (5:list-address-address <- get-address 1:list-address/deref cdr:offset)
+      (5:list-address-address/deref <- new list:literal)
+      ; 6 points at second node: tagged-value (boolean t)
+      (6:list-address <- copy 5:list-address-address/deref)
+      (7:tagged-value-address <- list-value-address 6:list-address)
+      (8:type-address <- get-address 7:tagged-value-address/deref type:offset)
+      (8:type-address/deref <- copy boolean:literal)
+      (9:location <- get-address 7:tagged-value-address/deref payload:offset)
+      (9:location/deref <- copy t:literal)
+      (10:list-address <- get 6:list-address/deref 1:offset)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let first rep.routine!alloc
+;?     (= dump-trace* (obj whitelist '("run")))
+;?     (set dump-trace*)
+    (run)
+;?     (prn memory*)
+    (each routine completed-routines*
+      (aif rep.routine!error (prn "error - " it)))
+    (when (or (~all first (map memory* '(1 2 3)))
+              (~is memory*.first  'integer)
+              (~is memory*.4 (+ first 1))
+              (~is (memory* (+ first 1))  34)
+              (~is memory*.5 (+ first 2))
+              (let second memory*.6
+                (or
+                  (~is (memory* (+ first 2)) second)
+                  (~all second (map memory* '(6 7 8)))
+                  (~is memory*.second 'boolean)
+                  (~is memory*.9 (+ second 1))
+                  (~is (memory* (+ second 1)) t)
+                  (~is memory*.10 nil))))
+      (prn "F - lists can contain elements of different types"))))
+(run-code test2
+  (10:list-address <- list-next 1:list-address))
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is memory*.10 memory*.6)
+  (prn "F - 'list-next can move a list pointer to the next node"))
+;? (quit)
+
+; 'init-list' takes a variable number of args and constructs a list containing
+; them. Just integers for now.
+
+(reset)
+(new-trace "init-list")
+(add-code
+  '((function main [
+      (1:integer <- init-list 3:literal 4:literal 5:literal)
+     ])))
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "cvt0" "cvt1" "sizeof")))
+(run 'main)
+;? (prn memory*)
+(let first memory*.1
+;?   (prn first)
+  (when (or (~is memory*.first  'integer)
+            (~is (memory* (+ first 1))  3)
+            (let second (memory* (+ first 2))
+;?               (prn second)
+              (or (~is memory*.second 'integer)
+                  (~is (memory* (+ second 1)) 4)
+                  (let third (memory* (+ second 2))
+;?                     (prn third)
+                    (or (~is memory*.third 'integer)
+                        (~is (memory* (+ third 1)) 5)
+                        (~is (memory* (+ third 2) nil)))))))
+    (prn "F - 'init-list' can construct a list of integers")))
+
+)  ; section 100
+
+(section 20
+
+;; Functions
+;
+; Just like the table of types is centralized, functions are conceptualized as
+; a centralized table of operations just like the "primitives" we've seen so
+; far. If you create a function you can call it like any other op.
+
+(reset)
+(new-trace "new-fn")
+(add-code
+  '((function test1 [
+      (3:integer <- add 1:integer 2:integer)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (test1)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4))
+  (prn "F - calling a user-defined function runs its instructions"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-once")
+(add-code
+  '((function test1 [
+      (1:integer <- copy 1:literal)
+     ])
+    (function main [
+      (test1)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(when (~is 2 curr-cycle*)
+  (prn "F - calling a user-defined function runs its instructions exactly once " curr-cycle*))
+;? (quit)
+
+; User-defined functions communicate with their callers through two
+; primitives:
+;
+;   'arg' - to access inputs
+;   'reply' - to return outputs
+
+(reset)
+(new-trace "new-fn-reply")
+(add-code
+  '((function test1 [
+      (3:integer <- add 1:integer 2:integer)
+      (reply)
+      (4:integer <- copy 34:literal)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (test1)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4))
+  (prn "F - 'reply' stops executing the current function"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-reply-nested")
+(add-code
+  '((function test1 [
+      (3:integer <- test2)
+     ])
+    (function test2 [
+      (reply 2:integer)
+     ])
+    (function main [
+      (2:integer <- copy 34:literal)
+      (test1)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 2 34  3 34))
+  (prn "F - 'reply' stops executing any callers as necessary"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-reply-once")
+(add-code
+  '((function test1 [
+      (3:integer <- add 1:integer 2:integer)
+      (reply)
+      (4:integer <- copy 34:literal)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (test1)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(when (~is 5 curr-cycle*)
+  (prn "F - 'reply' executes instructions exactly once " curr-cycle*))
+;? (quit)
+
+(reset)
+(new-trace "reply-increments-caller-pc")
+(add-code
+  '((function callee [
+      (reply)
+     ])
+    (function caller [
+      (1:integer <- copy 0:literal)
+      (2:integer <- copy 0:literal)
+     ])))
+(freeze function*)
+(= routine* (make-routine 'caller))
+(assert (is 0 pc.routine*))
+(push-stack routine* 'callee)  ; pretend call was at first instruction of caller
+(run-for-time-slice 1)
+(when (~is 1 pc.routine*)
+  (prn "F - 'reply' increments pc in caller (to move past calling instruction)"))
+
+(reset)
+(new-trace "new-fn-arg-sequential")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer <- next-input)
+      (3:integer <- add 4:integer 5:integer)
+      (reply)
+      (4:integer <- copy 34:literal)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (test1 1:integer 2:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4
+                         ; test1's temporaries
+                         4 1  5 3))
+  (prn "F - 'arg' accesses in order the operands of the most recent function call (the caller)"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-random-access")
+;? (set dump-trace*)
+(add-code
+  '((function test1 [
+      (5:integer <- input 1:literal)
+      (4:integer <- input 0:literal)
+      (3:integer <- add 4:integer 5:integer)
+      (reply)
+      (4:integer <- copy 34:literal)  ; should never run
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (test1 1:integer 2:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4
+                         ; test's temporaries
+                         4 1  5 3))
+  (prn "F - 'arg' with index can access function call arguments out of order"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-random-then-sequential")
+;? (set dump-trace*)
+(add-code
+  '((function test1 [
+      (_ <- input 1:literal)
+      (1:integer <- next-input)  ; takes next arg after index 1
+     ])  ; should never run
+    (function main [
+      (test1 1:literal 2:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 3))
+  (prn "F - 'arg' with index resets index for later calls"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-status")
+(add-code
+  '((function test1 [
+      (4:integer 5:boolean <- next-input)
+     ])
+    (function main [
+      (test1 1:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 4 1  5 t))
+  (prn "F - 'arg' sets a second oarg when arg exists"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-missing")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer <- next-input)
+     ])
+    (function main [
+      (test1 1:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 4 1))
+  (prn "F - missing 'arg' doesn't cause error"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-missing-2")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer 6:boolean <- next-input)
+     ])
+    (function main [
+      (test1 1:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 4 1  6 nil))
+  (prn "F - missing 'arg' wipes second oarg when provided"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-missing-3")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer <- copy 34:literal)
+      (5:integer 6:boolean <- next-input)
+    ])
+    (function main [
+      (test1 1:literal)
+    ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 4 1  6 nil))
+  (prn "F - missing 'arg' consistently wipes its oarg"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-missing-4")
+(add-code
+  '((function test1 [
+      ; if given two args, adds them; if given one arg, increments
+      (4:integer <- next-input)
+      (5:integer 6:boolean <- next-input)
+      { begin
+        (break-if 6:boolean)
+        (5:integer <- copy 1:literal)
+      }
+      (7:integer <- add 4:integer 5:integer)
+     ])
+    (function main [
+      (test1 34:literal)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 4 34  5 1  6 nil  7 35))
+  (prn "F - function with optional second arg"))
+;? (quit)
+
+(reset)
+(new-trace "new-fn-arg-by-value")
+(add-code
+  '((function test1 [
+      (1:integer <- copy 0:literal)  ; overwrite caller memory
+      (2:integer <- next-input)
+     ])  ; arg not clobbered
+    (function main [
+      (1:integer <- copy 34:literal)
+      (test1 1:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 0  2 34))
+  (prn "F - 'arg' passes by value"))
+
+(reset)
+(new-trace "arg-record")
+(add-code
+  '((function test1 [
+      (4:integer-boolean-pair <- next-input)
+     ])
+    (function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy nil:literal)
+      (test1 1:integer-boolean-pair)
+     ])))
+(run 'main)
+(when (~iso memory* (obj 1 34  2 nil  4 34  5 nil))
+  (prn "F - 'arg' can copy records spanning multiple locations"))
+
+(reset)
+(new-trace "arg-record-indirect")
+;? (set dump-trace*)
+(add-code
+  '((function test1 [
+      (4:integer-boolean-pair <- next-input)
+     ])
+    (function main [
+      (1:integer <- copy 34:literal)
+      (2:boolean <- copy nil:literal)
+      (3:integer-boolean-pair-address <- copy 1:literal)
+      (test1 3:integer-boolean-pair-address/deref)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 34  2 nil  3 1  4 34  5 nil))
+  (prn "F - 'arg' can copy records spanning multiple locations in indirect mode"))
+
+(reset)
+(new-trace "new-fn-reply-oarg")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer <- next-input)
+      (6:integer <- add 4:integer 5:integer)
+      (reply 6:integer)
+      (4:integer <- copy 34:literal)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (3:integer <- test1 1:integer 2:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4
+                         ; test1's temporaries
+                         4 1  5 3  6 4))
+  (prn "F - 'reply' can take aguments that are returned, or written back into output args of caller"))
+
+(reset)
+(new-trace "new-fn-reply-oarg-multiple")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer <- next-input)
+      (6:integer <- add 4:integer 5:integer)
+      (reply 6:integer 5:integer)
+      (4:integer <- copy 34:literal)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (3:integer 7:integer <- test1 1:integer 2:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4    7 3
+                         ; test1's temporaries
+                         4 1  5 3  6 4))
+  (prn "F - 'reply' permits a function to return multiple values at once"))
+
+; 'prepare-reply' is useful for doing cleanup before exiting a function
+(reset)
+(new-trace "new-fn-prepare-reply")
+(add-code
+  '((function test1 [
+      (4:integer <- next-input)
+      (5:integer <- next-input)
+      (6:integer <- add 4:integer 5:integer)
+      (prepare-reply 6:integer 5:integer)
+      (reply)
+      (4:integer <- copy 34:literal)
+     ])
+    (function main [
+      (1:integer <- copy 1:literal)
+      (2:integer <- copy 3:literal)
+      (3:integer 7:integer <- test1 1:integer 2:integer)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory* (obj 1 1  2 3  3 4    7 3
+                         ; test1's temporaries
+                         4 1  5 3  6 4))
+  (prn "F - without args, 'reply' returns values from previous 'prepare-reply'."))
+
+; When you have arguments that are both read from and written to, include them
+; redundantly in both ingredients and results. That'll help tools track what
+; changed.
+
+; To enforce that the result and ingredient must always match, use the
+; 'same-as-arg' property. Results with 'same-as-arg' properties should only be
+; copied to a caller output arg identical to the specified caller arg.
+(reset)
+(new-trace "new-fn-same-as-arg")
+(add-code
+  '((function test1 [
+      ; increment the contents of an address
+      (default-space:space-address <- new space:literal 2:literal)
+      (x:integer-address <- next-input)
+      (x:integer-address/deref <- add x:integer-address/deref 1:literal)
+      (reply x:integer-address/same-as-arg:0)
+    ])
+    (function main [
+      (2:integer-address <- new integer:literal)
+      (2:integer-address/deref <- copy 0:literal)
+      (3:integer-address <- test1 2:integer-address)
+    ])))
+(run 'main)
+(let routine (car completed-routines*)
+;?   (prn rep.routine!error) ;? 1
+  (when (no rep.routine!error)
+    (prn "F - 'same-as-arg' results must be identical to a given input")))
+;? (quit) ;? 2
+
+)  ; section 20
+
+(section 11
+
+;; Structured programming
+;
+; Our jump operators are quite inconvenient to use, so mu provides a
+; lightweight tool called 'convert-braces' to work in a slightly more
+; convenient format with nested braces:
+;
+;   {
+;     some instructions
+;     {
+;       more instructions
+;     }
+;   }
+;
+; Braces are like labels in assembly language, they require no special
+; parsing. The operations 'loop' and 'break' jump to just after the enclosing
+; '{' and '}' respectively.
+;
+; Conditional and unconditional 'loop' and 'break' should give us 80% of the
+; benefits of the control-flow primitives we're used to in other languages,
+; like 'if', 'while', 'for', etc.
+;
+; Compare 'unquoted blocks' using {} with 'quoted blocks' using [] that we've
+; gotten used to seeing. Quoted blocks are used by top-level instructions to
+; provide code without running it.
+
+(reset)
+(new-trace "convert-braces")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("c{0" "c{1")))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                (((3 integer)) <- ((copy)) ((0 literal)))
+                { begin  ; 'begin' is just a hack because racket turns braces into parens
+                  (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
+                  (((break-if)) ((4 boolean)))
+                  (((5 integer)) <- ((copy)) ((0 literal)))
+                }
+                (((reply)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
+              (((jump-if)) ((4 boolean)) ((1 offset)))
+              (((5 integer)) <- ((copy)) ((0 literal)))
+              (((reply)))))
+  (prn "F - convert-braces replaces break-if with a jump-if to after the next close-brace"))
+;? (quit)
+
+(reset)
+(new-trace "convert-braces-empty-block")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("c{0" "c{1")))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                (((3 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((break)))
+                }
+                (((reply)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((0 offset)))
+              (((reply)))))
+  (prn "F - convert-braces works for degenerate blocks"))
+;? (quit)
+
+(reset)
+(new-trace "convert-braces-nested-break")
+(= traces* (queue))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                (((3 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
+                  (((break-if)) ((4 boolean)))
+                  { begin
+                    (((5 integer)) <- ((copy)) ((0 literal)))
+                  }
+                }
+                (((reply)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
+              (((jump-if)) ((4 boolean)) ((1 offset)))
+              (((5 integer)) <- ((copy)) ((0 literal)))
+              (((reply)))))
+  (prn "F - convert-braces balances braces when converting break"))
+
+(reset)
+(new-trace "convert-braces-repeated-jump")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("c{0" "c{1")))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((break)))
+                  (((2 integer)) <- ((copy)) ((0 literal)))
+                }
+                { begin
+                  (((break)))
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                }
+                (((4 integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((1 offset)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((1 offset)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-braces handles jumps on jumps"))
+;? (quit)
+
+(reset)
+(new-trace "convert-braces-nested-loop")
+(= traces* (queue))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                  { begin
+                    (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
+                  }
+                  (((loop-if)) ((4 boolean)))
+                  (((5 integer)) <- ((copy)) ((0 literal)))
+                }
+                (((reply)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 boolean)) <- ((not-equal)) ((1 integer)) ((3 integer)))
+              (((jump-if)) ((4 boolean)) ((-3 offset)))
+              (((5 integer)) <- ((copy)) ((0 literal)))
+              (((reply)))))
+  (prn "F - convert-braces balances braces when converting 'loop'"))
+
+(reset)
+(new-trace "convert-braces-label")
+(= traces* (queue))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                foo
+                (((2 integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              foo
+              (((2 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-braces skips past labels"))
+;? (quit)
+
+(reset)
+(new-trace "convert-braces-label-increments-offset")
+(= traces* (queue))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((break)))
+                  foo
+                }
+                (((2 integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((1 offset)))
+              foo
+              (((2 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-braces treats labels as instructions"))
+;? (quit)
+
+(reset)
+(new-trace "convert-braces-label-increments-offset2")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("c{0" "c{1")))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((break)))
+                  foo
+                }
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((break)))
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                }
+                (((4 integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((1 offset)))
+              foo
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((1 offset)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-braces treats labels as instructions - 2"))
+;? (quit)
+
+(reset)
+(new-trace "break-multiple")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("-")))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  { begin
+                    (((break)) ((2 blocks)))
+                  }
+                  (((2 integer)) <- ((copy)) ((0 literal)))
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                  (((4 integer)) <- ((copy)) ((0 literal)))
+                  (((5 integer)) <- ((copy)) ((0 literal)))
+                }))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((4 offset)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 integer)) <- ((copy)) ((0 literal)))
+              (((5 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - 'break' can take an extra arg with number of nested blocks to exit"))
+;? (quit)
+
+(reset)
+(new-trace "loop")
+;? (set dump-trace*)
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                  (((loop)))
+                }))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((-2 offset)))))
+  (prn "F - 'loop' jumps to start of containing block"))
+;? (quit)
+
+; todo: fuzz-test invariant: convert-braces offsets should be robust to any
+; number of inner blocks inside but not around the loop block.
+
+(reset)
+(new-trace "loop-nested")
+;? (set dump-trace*)
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                (((2 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                  { begin
+                    (((4 integer)) <- ((copy)) ((0 literal)))
+                  }
+                  (((loop)))
+                }))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((4 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((-3 offset)))))
+  (prn "F - 'loop' correctly jumps back past nested braces"))
+
+(reset)
+(new-trace "loop-multiple")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("-")))
+(when (~iso (convert-braces
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                { begin
+                  (((2 integer)) <- ((copy)) ((0 literal)))
+                  (((3 integer)) <- ((copy)) ((0 literal)))
+                  { begin
+                    (((loop)) ((2 blocks)))
+                  }
+                }))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))
+              (((jump)) ((-3 offset)))))
+  (prn "F - 'loop' can take an extra arg with number of nested blocks to exit"))
+;? (quit)
+
+(reset)
+(new-trace "convert-labels")
+(= traces* (queue))
+(when (~iso (convert-labels
+              '(loop
+                (((jump)) ((loop offset)))))
+            '(loop
+              (((jump)) ((-2 offset)))))
+  (prn "F - 'convert-labels' rewrites jumps to labels"))
+
+;; Variables
+;
+; A big convenience high-level languages provide is the ability to name memory
+; locations. In mu, a lightweight tool called 'convert-names' provides this
+; convenience.
+
+(reset)
+(new-trace "convert-names")
+(= traces* (queue))
+;? (set dump-trace*)
+(when (~iso (convert-names
+              '((((x integer)) <- ((copy)) ((0 literal)))
+                (((y integer)) <- ((copy)) ((0 literal)))
+                (((z integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-names renames symbolic names to integer locations"))
+
+(reset)
+(new-trace "convert-names-compound")
+(= traces* (queue))
+(when (~iso (convert-names
+              ; copying 0 into pair is meaningless; just for testing
+              '((((x integer-boolean-pair)) <- ((copy)) ((0 literal)))
+                (((y integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer-boolean-pair)) <- ((copy)) ((0 literal)))
+              (((3 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-names increments integer locations by the size of the type of the previous var"))
+
+(reset)
+(new-trace "convert-names-nil")
+(= traces* (queue))
+;? (set dump-trace*)
+(when (~iso (convert-names
+              '((((x integer)) <- ((copy)) ((0 literal)))
+                (((y integer)) <- ((copy)) ((0 literal)))
+                ; nil location is meaningless; just for testing
+                (((nil integer)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((nil integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-names never renames nil"))
+
+(reset)
+(new-trace "convert-names-string")
+;? (set dump-trace*)
+(when (~iso (convert-names
+              '((((1 integer-address)) <- ((new)) "foo")))
+            '((((1 integer-address)) <- ((new)) "foo")))
+  (prn "convert-names passes through raw strings (just a convenience arg for 'new')"))
+
+(reset)
+(new-trace "convert-names-raw")
+(= traces* (queue))
+(when (~iso (convert-names
+              '((((x integer)) <- ((copy)) ((0 literal)))
+                (((y integer) (raw)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((y integer) (raw)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-names never renames raw operands"))
+
+(reset)
+(new-trace "convert-names-literal")
+(= traces* (queue))
+(when (~iso (convert-names
+              ; meaningless; just for testing
+              '((((x literal)) <- ((copy)) ((0 literal)))))
+            '((((x literal)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-names never renames literals"))
+
+(reset)
+(new-trace "convert-names-literal-2")
+(= traces* (queue))
+(when (~iso (convert-names
+              '((((x boolean)) <- ((copy)) ((x literal)))))
+            '((((1 boolean)) <- ((copy)) ((x literal)))))
+  (prn "F - convert-names never renames literals, even when the name matches a variable"))
+
+; kludgy support for 'fork' below
+(reset)
+(new-trace "convert-names-functions")
+(= traces* (queue))
+(when (~iso (convert-names
+              '((((x integer)) <- ((copy)) ((0 literal)))
+                (((y integer)) <- ((copy)) ((0 literal)))
+                ; meaningless; just for testing
+                (((z fn)) <- ((copy)) ((0 literal)))))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              (((2 integer)) <- ((copy)) ((0 literal)))
+              (((z fn)) <- ((copy)) ((0 literal)))))
+  (prn "F - convert-names never renames fns"))
+
+(reset)
+(new-trace "convert-names-record-fields")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("cn0")))
+(when (~iso (convert-names
+              '((((x integer)) <- ((get)) ((34 integer-boolean-pair)) ((bool offset)))))
+            '((((1 integer)) <- ((get)) ((34 integer-boolean-pair)) ((1 offset)))))
+  (prn "F - convert-names replaces record field offsets"))
+
+(reset)
+(new-trace "convert-names-record-fields-ambiguous")
+(= traces* (queue))
+(when (errsafe (convert-names
+                 '((((bool boolean)) <- ((copy)) ((t literal)))
+                   (((x integer)) <- ((get)) ((34 integer-boolean-pair)) ((bool offset))))))
+  (prn "F - convert-names doesn't allow offsets and variables with the same name in a function"))
+
+(reset)
+(new-trace "convert-names-record-fields-ambiguous-2")
+(= traces* (queue))
+(when (errsafe (convert-names
+                 '((((x integer)) <- ((get)) ((34 integer-boolean-pair)) ((bool offset)))
+                   (((bool boolean)) <- ((copy)) ((t literal))))))
+  (prn "F - convert-names doesn't allow offsets and variables with the same name in a function - 2"))
+
+(reset)
+(new-trace "convert-names-record-fields-indirect")
+(= traces* (queue))
+;? (= dump-trace* (obj whitelist '("cn0")))
+(when (~iso (convert-names
+              '((((x integer)) <- ((get)) ((34 integer-boolean-pair-address) (deref)) ((bool offset)))))
+            '((((1 integer)) <- ((get)) ((34 integer-boolean-pair-address) (deref)) ((1 offset)))))
+  (prn "F - convert-names replaces field offsets for record addresses"))
+;? (quit)
+
+(reset)
+(new-trace "convert-names-record-fields-multiple")
+(= traces* (queue))
+(when (~iso (convert-names
+              '((((2 boolean)) <- ((get)) ((1 integer-boolean-pair)) ((bool offset)))
+                (((3 boolean)) <- ((get)) ((1 integer-boolean-pair)) ((bool offset)))))
+            '((((2 boolean)) <- ((get)) ((1 integer-boolean-pair)) ((1 offset)))
+              (((3 boolean)) <- ((get)) ((1 integer-boolean-pair)) ((1 offset)))))
+  (prn "F - convert-names replaces field offsets with multiple mentions"))
+;? (quit)
+
+(reset)
+(new-trace "convert-names-label")
+(= traces* (queue))
+(when (~iso (convert-names
+              '((((1 integer)) <- ((copy)) ((0 literal)))
+                foo))
+            '((((1 integer)) <- ((copy)) ((0 literal)))
+              foo))
+  (prn "F - convert-names skips past labels"))
+;? (quit)
+
+)  ; section 11
+
+(section 20
+
+; A rudimentary memory allocator. Eventually we want to write this in mu.
+;
+; No deallocation yet; let's see how much code we can build in mu before we
+; feel the need for it.
+
+(reset)
+(new-trace "new-primitive")
+(add-code
+  '((function main [
+      (1:integer-address <- new integer:literal)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+;?     (set dump-trace*)
+    (run)
+;?     (prn memory*)
+    (when (~iso memory*.1 before)
+      (prn "F - 'new' returns current high-water mark"))
+    (when (~iso rep.routine!alloc (+ before 1))
+      (prn "F - 'new' on primitive types increments high-water mark by their size"))))
+;? (quit)
+
+(reset)
+(new-trace "new-array-literal")
+(add-code
+  '((function main [
+      (1:type-array-address <- new type-array:literal 5:literal)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+    (run)
+;?     (prn memory*)
+    (when (~iso memory*.1 before)
+      (prn "F - 'new' on array with literal size returns current high-water mark"))
+    (when (~iso rep.routine!alloc (+ before 6))
+      (prn "F - 'new' on primitive arrays increments high-water mark by their size"))))
+
+(reset)
+(new-trace "new-array-direct")
+(add-code
+  '((function main [
+      (1:integer <- copy 5:literal)
+      (2:type-array-address <- new type-array:literal 1:integer)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+    (run)
+;?     (prn memory*)
+    (when (~iso memory*.2 before)
+      (prn "F - 'new' on array with variable size returns current high-water mark"))
+    (when (~iso rep.routine!alloc (+ before 6))
+      (prn "F - 'new' on primitive arrays increments high-water mark by their (variable) size"))))
+
+(reset)
+(new-trace "new-allocation-chunk")
+(add-code
+  '((function main [
+      (1:integer-address <- new integer:literal)
+     ])))
+; start allocating from address 30, in chunks of 10 locations each
+(= Memory-allocated-until 30
+   Allocation-chunk 10)
+(let routine make-routine!main
+  (assert:is rep.routine!alloc 30)
+  (assert:is rep.routine!alloc-max 40)
+  ; pretend the current chunk is full
+  (= rep.routine!alloc 40)
+  (enq routine running-routines*)
+  (run)
+  (each routine completed-routines*
+    (aif rep.routine!error (prn "error - " it)))
+  (when (~is rep.routine!alloc 41)
+    (prn "F - 'new' can allocate past initial routine memory"))
+  (when (~is rep.routine!alloc-max 50)
+    (prn "F - 'new' updates upper bound for routine memory @rep.routine!alloc-max")))
+
+(reset)
+(new-trace "new-skip")
+(add-code
+  '((function main [
+      (1:integer-boolean-pair-address <- new integer-boolean-pair:literal)
+     ])))
+; start allocating from address 30, in chunks of 10 locations each
+(= Memory-allocated-until 30
+   Allocation-chunk 10)
+(let routine make-routine!main
+  (assert:is rep.routine!alloc 30)
+  (assert:is rep.routine!alloc-max 40)
+  ; pretend the current chunk has just one location left
+  (= rep.routine!alloc 39)
+  (enq routine running-routines*)
+  ; request 2 locations
+  (run)
+  (each routine completed-routines*
+    (aif rep.routine!error (prn "error - " it)))
+  (when (or (~is memory*.1 40)
+            (~is rep.routine!alloc 42)
+            (~is rep.routine!alloc-max 50)
+            (~is Memory-allocated-until 50))
+    (prn "F - 'new' skips past current chunk if insufficient space")))
+
+(reset)
+(new-trace "new-skip-noncontiguous")
+(add-code
+  '((function main [
+      (1:integer-boolean-pair-address <- new integer-boolean-pair:literal)
+     ])))
+; start allocating from address 30, in chunks of 10 locations each
+(= Memory-allocated-until 30
+   Allocation-chunk 10)
+(let routine make-routine!main
+  (assert:is rep.routine!alloc 30)
+  (assert:is rep.routine!alloc-max 40)
+  ; pretend the current chunk has just one location left
+  (= rep.routine!alloc 39)
+  ; pretend we allocated more memory since we created the routine
+  (= Memory-allocated-until 90)
+  (enq routine running-routines*)
+  ; request 2 locations
+  (run)
+  (each routine completed-routines*
+    (aif rep.routine!error (prn "error - " it)))
+  (when (or (~is memory*.1 90)
+            (~is rep.routine!alloc 92)
+            (~is rep.routine!alloc-max 100)
+            (~is Memory-allocated-until 100))
+    (prn "F - 'new' allocates a new chunk if insufficient space")))
+
+(reset)
+(new-trace "new-array-skip-noncontiguous")
+(add-code
+  '((function main [
+      (1:integer-array-address <- new integer-array:literal 4:literal)
+     ])))
+; start allocating from address 30, in chunks of 10 locations each
+(= Memory-allocated-until 30
+   Allocation-chunk 10)
+(let routine make-routine!main
+  (assert:is rep.routine!alloc 30)
+  (assert:is rep.routine!alloc-max 40)
+  ; pretend the current chunk has just one location left
+  (= rep.routine!alloc 39)
+  ; pretend we allocated more memory since we created the routine
+  (= Memory-allocated-until 90)
+  (enq routine running-routines*)
+  ; request 4 locations
+  (run)
+  (each routine completed-routines*
+    (aif rep.routine!error (prn "error - " it)))
+;?   (prn memory*.1) ;? 1
+;?   (prn rep.routine) ;? 1
+;?   (prn Memory-allocated-until) ;? 1
+  (when (or (~is memory*.1 90)
+            (~is rep.routine!alloc 95)
+            (~is rep.routine!alloc-max 100)
+            (~is Memory-allocated-until 100))
+    (prn "F - 'new-array' allocates a new chunk if insufficient space")))
+
+;? (quit) ;? 1
+
+; Even though our memory locations can now have names, the names are all
+; globals, accessible from any function. To isolate functions from their
+; callers we need local variables, and mu provides them using a special
+; variable called default-space. When you initialize such a variable (likely
+; with a call to our just-defined memory allocator) mu interprets memory
+; locations as offsets from its value. If default-space is set to 1000, for
+; example, reads and writes to memory location 1 will really go to 1001.
+;
+; 'default-space' is itself hard-coded to be function-local; it's nil in a new
+; function, and it's restored when functions return to their callers. But the
+; actual space allocation is independent. So you can define closures, or do
+; even more funky things like share locals between two coroutines.
+
+(reset)
+(new-trace "set-default-space")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 2:literal)
+      (1:integer <- copy 23:literal)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+;?     (set dump-trace*)
+    (run)
+;?     (prn memory*)
+    (when (~and (~is 23 memory*.1)
+                (is 23 (memory* (+ before 2))))
+      (prn "F - default-space implicitly modifies variable locations"))))
+;? (quit)
+
+(reset)
+(new-trace "set-default-space-skips-offset")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 2:literal)
+      (1:integer <- copy 23:offset)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+;?     (set dump-trace*)
+    (run)
+;?     (prn memory*)
+    (when (~and (~is 23 memory*.1)
+                (is 23 (memory* (+ before 2))))
+      (prn "F - default-space skips 'offset' types just like literals"))))
+
+(reset)
+(new-trace "default-space-bounds-check")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 2:literal)
+      (2:integer <- copy 23:literal)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(let routine (car completed-routines*)
+  (when (no rep.routine!error)
+    (prn "F - default-space checks bounds")))
+
+(reset)
+(new-trace "default-space-and-get-indirect")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 5:literal)
+      (1:integer-boolean-pair-address <- new integer-boolean-pair:literal)
+      (2:integer-address <- get-address 1:integer-boolean-pair-address/deref 0:offset)
+      (2:integer-address/deref <- copy 34:literal)
+      (3:integer/raw <- get 1:integer-boolean-pair-address/deref 0:offset)
+     ])))
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "cvt0" "cvt1")))
+(run 'main)
+;? (prn memory*)
+;? (prn completed-routines*)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is 34 memory*.3)
+  (prn "F - indirect 'get' works in the presence of default-space"))
+;? (quit)
+
+(reset)
+(new-trace "default-space-and-index-indirect")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 5:literal)
+      (1:integer-array-address <- new integer-array:literal 4:literal)
+      (2:integer-address <- index-address 1:integer-array-address/deref 2:offset)
+      (2:integer-address/deref <- copy 34:literal)
+      (3:integer/raw <- index 1:integer-array-address/deref 2:offset)
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "array-info")))
+(run 'main)
+;? (prn memory*)
+;? (prn completed-routines*)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is 34 memory*.3)
+  (prn "F - indirect 'index' works in the presence of default-space"))
+;? (quit)
+
+(reset)
+(new-trace "convert-names-default-space")
+(= traces* (queue))
+(when (~iso (convert-names
+              '((((x integer)) <- ((copy)) ((4 literal)))
+                (((y integer)) <- ((copy)) ((2 literal)))
+                ; unsafe in general; don't write random values to 'default-space'
+                (((default-space integer)) <- ((add)) ((x integer)) ((y integer)))))
+            '((((1 integer)) <- ((copy)) ((4 literal)))
+              (((2 integer)) <- ((copy)) ((2 literal)))
+              (((default-space integer)) <- ((add)) ((1 integer)) ((2 integer)))))
+  (prn "F - convert-names never renames default-space"))
+
+(reset)
+(new-trace "suppress-default-space")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 2:literal)
+      (1:integer/raw <- copy 23:literal)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+;?     (set dump-trace*)
+    (run)
+;?     (prn memory*)
+    (when (~and (is 23 memory*.1)
+                (~is 23 (memory* (+ before 1))))
+      (prn "F - default-space skipped for locations with metadata 'raw'"))))
+;? (quit)
+
+(reset)
+(new-trace "array-copy-indirect-scoped")
+(add-code
+  '((function main [
+      (10:integer <- copy 30:literal)  ; pretend allocation
+      (default-space:space-address <- copy 10:literal)  ; unsafe
+      (1:integer <- copy 2:literal)  ; raw location 12
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer-boolean-pair-array-address <- copy 12:literal)  ; unsafe
+      (7:integer-boolean-pair-array <- copy 6:integer-boolean-pair-array-address/deref)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("run" "mem" "sizeof")))
+(run 'main)
+;? (prn memory*)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~iso memory*.18 2)  ; variable 7
+  (prn "F - indirect array copy in the presence of 'default-space'"))
+;? (quit)
+
+(reset)
+(new-trace "len-array-indirect-scoped")
+(add-code
+  '((function main [
+      (10:integer <- copy 30:literal)  ; pretend allocation
+      (default-space:space-address <- copy 10:literal)  ; unsafe
+      (1:integer <- copy 2:literal)  ; raw location 12
+      (2:integer <- copy 23:literal)
+      (3:boolean <- copy nil:literal)
+      (4:integer <- copy 24:literal)
+      (5:boolean <- copy t:literal)
+      (6:integer-address <- copy 12:literal)  ; unsafe
+      (7:integer <- length 6:integer-boolean-pair-array-address/deref)
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "addr" "sz" "array-len")))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory*.18 2)
+  (prn "F - 'len' accesses length of array address"))
+;? (quit)
+
+(reset)
+(new-trace "default-space-shared")
+(add-code
+  '((function init-counter [
+      (default-space:space-address <- new space:literal 30:literal)
+      (1:integer <- copy 3:literal)  ; initialize to 3
+      (reply default-space:space-address)
+     ])
+    (function increment-counter [
+      (default-space:space-address <- next-input)
+      (1:integer <- add 1:integer 1:literal)  ; increment
+      (reply 1:integer)
+     ])
+    (function main [
+      (1:space-address <- init-counter)
+      (2:integer <- increment-counter 1:space-address)
+      (3:integer <- increment-counter 1:space-address)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn memory*)
+(when (or (~is memory*.2 4)
+          (~is memory*.3 5))
+  (prn "F - multiple calls to a function can share locals"))
+;? (quit)
+
+(reset)
+(new-trace "default-space-closure")
+(add-code
+  '((function init-counter [
+      (default-space:space-address <- new space:literal 30:literal)
+      (1:integer <- copy 3:literal)  ; initialize to 3
+      (reply default-space:space-address)
+     ])
+    (function increment-counter [
+      (default-space:space-address <- new space:literal 30:literal)
+      (0:space-address <- next-input)  ; share outer space
+      (1:integer/space:1 <- add 1:integer/space:1 1:literal)  ; increment
+      (1:integer <- copy 34:literal)  ; dummy
+      (reply 1:integer/space:1)
+     ])
+    (function main [
+      (1:space-address <- init-counter)
+      (2:integer <- increment-counter 1:space-address)
+      (3:integer <- increment-counter 1:space-address)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn memory*)
+(when (or (~is memory*.2 4)
+          (~is memory*.3 5))
+  (prn "F - closures using /space metadata"))
+;? (quit)
+
+(reset)
+(new-trace "default-space-closure-with-names")
+(add-code
+  '((function init-counter [
+      (default-space:space-address <- new space:literal 30:literal)
+      (x:integer <- copy 23:literal)
+      (y:integer <- copy 3:literal)  ; correct copy of y
+      (reply default-space:space-address)
+     ])
+    (function increment-counter [
+      (default-space:space-address <- new space:literal 30:literal)
+      (0:space-address/names:init-counter <- next-input)  ; outer space must be created by 'init-counter' above
+      (y:integer/space:1 <- add y:integer/space:1 1:literal)  ; increment
+      (y:integer <- copy 34:literal)  ; dummy
+      (reply y:integer/space:1)
+     ])
+    (function main [
+      (1:space-address/names:init-counter <- init-counter)
+      (2:integer <- increment-counter 1:space-address/names:init-counter)
+      (3:integer <- increment-counter 1:space-address/names:init-counter)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn memory*)
+(when (or (~is memory*.2 4)
+          (~is memory*.3 5))
+  (prn "F - /names to name variables in outer spaces"))
+;? (quit)
+
+(reset)
+(new-trace "default-space-shared-with-names")
+(add-code
+  '((function f [
+      (default-space:space-address <- new space:literal 30:literal)
+      (x:integer <- copy 3:literal)
+      (y:integer <- copy 4:literal)
+      (reply default-space:space-address)
+     ])
+    (function g [
+      (default-space:space-address/names:f <- next-input)
+      (y:integer <- add y:integer 1:literal)
+      (x:integer <- add x:integer 2:literal)
+      (reply x:integer y:integer)
+     ])
+    (function main [
+      (1:space-address <- f)
+      (2:integer 3:integer <- g 1:space-address)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (or (~is memory*.2 5)
+          (~is memory*.3 5))
+  (prn "F - override names for the default space"))
+
+(reset)
+(new-trace "default-space-shared-with-extra-names")
+(add-code
+  '((function f [
+      (default-space:space-address <- new space:literal 30:literal)
+      (x:integer <- copy 3:literal)
+      (y:integer <- copy 4:literal)
+      (reply default-space:space-address)
+     ])
+    (function g [
+      (default-space:space-address/names:f <- next-input)
+      (y:integer <- add y:integer 1:literal)
+      (x:integer <- add x:integer 2:literal)
+      (z:integer <- add x:integer y:integer)
+      (reply z:integer)
+     ])
+    (function main [
+      (1:space-address <- f)
+      (2:integer <- g 1:space-address)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is memory*.2 10)
+  (prn "F - shared spaces can add new names"))
+
+(reset)
+(new-trace "default-space-shared-extra-names-dont-overlap-bindings")
+(add-code
+  '((function f [
+      (default-space:space-address <- new space:literal 30:literal)
+      (x:integer <- copy 3:literal)
+      (y:integer <- copy 4:literal)
+      (reply default-space:space-address)
+     ])
+    (function g [
+      (default-space:space-address/names:f <- next-input)
+      (y:integer <- add y:integer 1:literal)
+      (x:integer <- add x:integer 2:literal)
+      (z:integer <- copy 2:literal)
+      (reply x:integer y:integer)
+     ])
+    (function main [
+      (1:space-address <- f)
+      (2:integer 3:integer <- g 1:space-address)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn memory*) ;? 1
+(when (or (~is memory*.2 5)
+          (~is memory*.3 5))
+  (prn "F - new names in shared spaces don't override old ones"))
+;? (quit) ;? 1
+
+)  ; section 20
+
+(section 100
+
+;; Dynamic dispatch
+;
+; Putting it all together, here's how you define generic functions that run
+; different code based on the types of their args.
+
+(reset)
+(new-trace "dispatch-clause")
+;? (set dump-trace*)
+(add-code
+  '((function test1 [
+      ; doesn't matter too much how many locals you allocate space for (here 20)
+      ; if it's slightly too many -- memory is plentiful
+      ; if it's too few -- mu will raise an error
+      (default-space:space-address <- new space:literal 20:literal)
+      (first-arg-box:tagged-value-address <- next-input)
+      ; if given integers, add them
+      { begin
+        (first-arg:integer match?:boolean <- maybe-coerce first-arg-box:tagged-value-address/deref integer:literal)
+        (break-unless match?:boolean)
+        (second-arg-box:tagged-value-address <- next-input)
+        (second-arg:integer <- maybe-coerce second-arg-box:tagged-value-address/deref integer:literal)
+        (result:integer <- add first-arg:integer second-arg:integer)
+        (reply result:integer)
+      }
+      (reply nil:literal)
+     ])
+    (function main [
+      (1:tagged-value-address <- init-tagged-value integer:literal 34:literal)
+      (2:tagged-value-address <- init-tagged-value integer:literal 3:literal)
+      (3:integer <- test1 1:tagged-value-address 2:tagged-value-address)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~is memory*.3 37)
+  (prn "F - an example function that checks that its oarg is an integer"))
+;? (quit)
+
+(reset)
+(new-trace "dispatch-multiple-clauses")
+;? (set dump-trace*)
+(add-code
+  '((function test1 [
+      (default-space:space-address <- new space:literal 20:literal)
+      (first-arg-box:tagged-value-address <- next-input)
+      ; if given integers, add them
+      { begin
+        (first-arg:integer match?:boolean <- maybe-coerce first-arg-box:tagged-value-address/deref integer:literal)
+        (break-unless match?:boolean)
+        (second-arg-box:tagged-value-address <- next-input)
+        (second-arg:integer <- maybe-coerce second-arg-box:tagged-value-address/deref integer:literal)
+        (result:integer <- add first-arg:integer second-arg:integer)
+        (reply result:integer)
+      }
+      ; if given booleans, or them (it's a silly kind of generic function)
+      { begin
+        (first-arg:boolean match?:boolean <- maybe-coerce first-arg-box:tagged-value-address/deref boolean:literal)
+        (break-unless match?:boolean)
+        (second-arg-box:tagged-value-address <- next-input)
+        (second-arg:boolean <- maybe-coerce second-arg-box:tagged-value-address/deref boolean:literal)
+        (result:boolean <- or first-arg:boolean second-arg:boolean)
+        (reply result:integer)
+      }
+      (reply nil:literal)
+     ])
+    (function main [
+      (1:tagged-value-address <- init-tagged-value boolean:literal t:literal)
+      (2:tagged-value-address <- init-tagged-value boolean:literal nil:literal)
+      (3:boolean <- test1 1:tagged-value-address 2:tagged-value-address)
+     ])))
+;? (each stmt function*!test-fn
+;?   (prn "  " stmt))
+(run 'main)
+;? (wipe dump-trace*)
+;? (prn memory*)
+(when (~is memory*.3 t)
+  (prn "F - an example function that can do different things (dispatch) based on the type of its args or oargs"))
+;? (quit)
+
+(reset)
+(new-trace "dispatch-multiple-calls")
+(add-code
+  '((function test1 [
+      (default-space:space-address <- new space:literal 20:literal)
+      (first-arg-box:tagged-value-address <- next-input)
+      ; if given integers, add them
+      { begin
+        (first-arg:integer match?:boolean <- maybe-coerce first-arg-box:tagged-value-address/deref integer:literal)
+        (break-unless match?:boolean)
+        (second-arg-box:tagged-value-address <- next-input)
+        (second-arg:integer <- maybe-coerce second-arg-box:tagged-value-address/deref integer:literal)
+        (result:integer <- add first-arg:integer second-arg:integer)
+        (reply result:integer)
+      }
+      ; if given booleans, or them (it's a silly kind of generic function)
+      { begin
+        (first-arg:boolean match?:boolean <- maybe-coerce first-arg-box:tagged-value-address/deref boolean:literal)
+        (break-unless match?:boolean)
+        (second-arg-box:tagged-value-address <- next-input)
+        (second-arg:boolean <- maybe-coerce second-arg-box:tagged-value-address/deref boolean:literal)
+        (result:boolean <- or first-arg:boolean second-arg:boolean)
+        (reply result:integer)
+      }
+      (reply nil:literal)
+     ])
+    (function main [
+      (1:tagged-value-address <- init-tagged-value boolean:literal t:literal)
+      (2:tagged-value-address <- init-tagged-value boolean:literal nil:literal)
+      (3:boolean <- test1 1:tagged-value-address 2:tagged-value-address)
+      (10:tagged-value-address <- init-tagged-value integer:literal 34:literal)
+      (11:tagged-value-address <- init-tagged-value integer:literal 3:literal)
+      (12:integer <- test1 10:tagged-value-address 11:tagged-value-address)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~and (is memory*.3 t) (is memory*.12 37))
+  (prn "F - different calls can exercise different clauses of the same function"))
+
+; We can also dispatch based on the type of the operands or results at the
+; caller.
+
+(reset)
+(new-trace "dispatch-otype")
+(add-code
+  '((function test1 [
+      (4:type <- otype 0:offset)
+      { begin
+        (5:boolean <- equal 4:type integer:literal)
+        (break-unless 5:boolean)
+        (6:integer <- next-input)
+        (7:integer <- next-input)
+        (8:integer <- add 6:integer 7:integer)
+      }
+      (reply 8:integer)
+     ])
+    (function main [
+      (1:integer <- test1 1:literal 3:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~iso memory*.1 4)
+  (prn "F - an example function that checks that its oarg is an integer"))
+;? (quit)
+
+(reset)
+(new-trace "dispatch-otype-multiple-clauses")
+;? (set dump-trace*)
+(add-code
+  '((function test1 [
+      (4:type <- otype 0:offset)
+      { begin
+        ; integer needed? add args
+        (5:boolean <- equal 4:type integer:literal)
+        (break-unless 5:boolean)
+        (6:integer <- next-input)
+        (7:integer <- next-input)
+        (8:integer <- add 6:integer 7:integer)
+        (reply 8:integer)
+      }
+      { begin
+        ; boolean needed? 'or' args
+        (5:boolean <- equal 4:type boolean:literal)
+        (break-unless 5:boolean 4:offset)
+        (6:boolean <- next-input)
+        (7:boolean <- next-input)
+        (8:boolean <- or 6:boolean 7:boolean)
+        (reply 8:boolean)
+      }])
+    (function main [
+      (1:boolean <- test1 t:literal t:literal)
+     ])))
+;? (each stmt function*!test1
+;?   (prn "  " stmt))
+(run 'main)
+;? (wipe dump-trace*)
+;? (prn memory*)
+(when (~is memory*.1 t)
+  (prn "F - an example function that can do different things (dispatch) based on the type of its args or oargs"))
+;? (quit)
+
+(reset)
+(new-trace "dispatch-otype-multiple-calls")
+(add-code
+  '((function test1 [
+      (4:type <- otype 0:offset)
+      { begin
+        (5:boolean <- equal 4:type integer:literal)
+        (break-unless 5:boolean)
+        (6:integer <- next-input)
+        (7:integer <- next-input)
+        (8:integer <- add 6:integer 7:integer)
+        (reply 8:integer)
+      }
+      { begin
+        (5:boolean <- equal 4:type boolean:literal)
+        (break-unless 5:boolean)
+        (6:boolean <- next-input)
+        (7:boolean <- next-input)
+        (8:boolean <- or 6:boolean 7:boolean)
+        (reply 8:boolean)
+      }])
+    (function main [
+      (1:boolean <- test1 t:literal t:literal)
+      (2:integer <- test1 3:literal 4:literal)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (~and (is memory*.1 t) (is memory*.2 7))
+  (prn "F - different calls can exercise different clauses of the same function"))
+
+)  ; section 100
+
+(section 20
+
+;; Concurrency
+;
+; A rudimentary process scheduler. You can 'run' multiple functions at once,
+; and they share the virtual processor.
+;
+; There's also a 'fork' primitive to let functions create new threads of
+; execution (we call them routines).
+;
+; Eventually we want to allow callers to influence how much of their CPU they
+; give to their 'children', or to rescind a child's running privileges.
+
+(reset)
+(new-trace "scheduler")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 3:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 4:literal)
+     ])))
+(run 'f1 'f2)
+(when (~iso 2 curr-cycle*)
+  (prn "F - scheduler didn't run the right number of instructions: " curr-cycle*))
+(when (~iso memory* (obj 1 3  2 4))
+  (prn "F - scheduler runs multiple functions: " memory*))
+(check-trace-contents "scheduler orders functions correctly"
+  '(("schedule" "f1")
+    ("schedule" "f2")
+  ))
+(check-trace-contents "scheduler orders schedule and run events correctly"
+  '(("schedule" "f1")
+    ("run" "f1 0")
+    ("schedule" "f2")
+    ("run" "f2 0")
+  ))
+
+(reset)
+(new-trace "scheduler-alternate")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+      (2:integer <- copy 0:literal)
+     ])))
+;? (= dump-trace* (obj whitelist '("schedule")))
+(= scheduling-interval* 1)
+(run 'f1 'f2)
+(check-trace-contents "scheduler alternates between routines"
+  '(("run" "f1 0")
+    ("run" "f2 0")
+    ("run" "f1 1")
+    ("run" "f2 1")
+  ))
+
+(reset)
+(new-trace "scheduler-sleep")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+     ])))
+; add one baseline routine to run (empty running-routines* handled below)
+(enq make-routine!f1 running-routines*)
+(assert (is 1 len.running-routines*))
+; sleeping routine
+(let routine make-routine!f2
+  (= rep.routine!sleep '(until 23))
+  (set sleeping-routines*.routine))
+; not yet time for it to wake up
+(= curr-cycle* 23)
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(update-scheduler-state)
+(when (~is 1 len.running-routines*)
+  (prn "F - scheduler lets routines sleep"))
+
+(reset)
+(new-trace "scheduler-wakeup")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+     ])))
+; add one baseline routine to run (empty running-routines* handled below)
+(enq make-routine!f1 running-routines*)
+(assert (is 1 len.running-routines*))
+; sleeping routine
+(let routine make-routine!f2
+  (= rep.routine!sleep '(until 23))
+  (set sleeping-routines*.routine))
+; time for it to wake up
+(= curr-cycle* 24)
+(update-scheduler-state)
+(when (~is 2 len.running-routines*)
+  (prn "F - scheduler wakes up sleeping routines at the right time"))
+
+(reset)
+(new-trace "scheduler-sleep-location")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+     ])))
+; add one baseline routine to run (empty running-routines* handled below)
+(enq make-routine!f1 running-routines*)
+(assert (is 1 len.running-routines*))
+; blocked routine waiting for location 23 to change
+(let routine make-routine!f2
+  (= rep.routine!sleep '(until-location-changes 23 0))
+  (set sleeping-routines*.routine))
+; leave memory location 23 unchanged
+(= memory*.23 0)
+;? (prn memory*)
+;? (prn running-routines*)
+;? (prn sleeping-routines*)
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(update-scheduler-state)
+;? (prn running-routines*)
+;? (prn sleeping-routines*)
+; routine remains blocked
+(when (~is 1 len.running-routines*)
+  (prn "F - scheduler lets routines block on locations"))
+;? (quit)
+
+(reset)
+(new-trace "scheduler-wakeup-location")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+     ])))
+; add one baseline routine to run (empty running-routines* handled below)
+(enq make-routine!f1 running-routines*)
+(assert (is 1 len.running-routines*))
+; blocked routine waiting for location 23 to change
+(let routine make-routine!f2
+  (= rep.routine!sleep '(until-location-changes 23 0))
+  (set sleeping-routines*.routine))
+; change memory location 23
+(= memory*.23 1)
+(update-scheduler-state)
+; routine unblocked
+(when (~is 2 len.running-routines*)
+  (prn "F - scheduler unblocks routines blocked on locations"))
+
+(reset)
+(new-trace "scheduler-skip")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])))
+; running-routines* is empty
+(assert (empty running-routines*))
+; sleeping routine
+(let routine make-routine!f1
+  (= rep.routine!sleep '(until 34))
+  (set sleeping-routines*.routine))
+; long time left for it to wake up
+(= curr-cycle* 0)
+(update-scheduler-state)
+;? (prn curr-cycle*)
+(assert (is curr-cycle* 35))
+(when (~is 1 len.running-routines*)
+  (prn "F - scheduler skips ahead to earliest sleeping routines when nothing to run"))
+
+(reset)
+(new-trace "scheduler-deadlock")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])))
+(assert (empty running-routines*))
+(assert (empty completed-routines*))
+; blocked routine
+(let routine make-routine!f1
+  (= rep.routine!sleep '(until-location-changes 23 0))
+  (set sleeping-routines*.routine))
+; location it's waiting on is 'unchanged'
+(= memory*.23 0)
+(update-scheduler-state)
+(assert (~empty completed-routines*))
+;? (prn completed-routines*)
+(let routine completed-routines*.0
+  (when (~posmatch "deadlock" rep.routine!error)
+    (prn "F - scheduler detects deadlock")))
+;? (quit)
+
+(reset)
+(new-trace "scheduler-deadlock2")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])))
+; running-routines* is empty
+(assert (empty running-routines*))
+; blocked routine
+(let routine make-routine!f1
+  (= rep.routine!sleep '(until-location-changes 23 0))
+  (set sleeping-routines*.routine))
+; but is about to become ready
+(= memory*.23 1)
+(update-scheduler-state)
+(when (~empty completed-routines*)
+  (prn "F - scheduler ignores sleeping but ready threads when detecting deadlock"))
+
+; Helper routines are just to sidestep the deadlock test; they stop running
+; when there's no non-helper routines left to run.
+;
+; Be careful not to overuse them. In particular, the component under test
+; should never run in a helper routine; that'll make interrupting and
+; restarting it very brittle.
+(reset)
+(new-trace "scheduler-helper")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])))
+; just a helper routine
+(= routine* make-routine!f1)
+(set rep.routine*!helper)
+;? (= dump-trace* (obj whitelist '("schedule")))
+(update-scheduler-state)
+(when (or (~empty running-routines*) (~empty sleeping-routines*))
+  (prn "F - scheduler stops when there's only helper routines left"))
+
+(reset)
+(new-trace "scheduler-helper-sleeping")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])))
+; just a helper routine
+(let routine make-routine!f1
+  (set rep.routine!helper)
+  (= rep.routine!sleep '(until-location-changes 23 nil))
+  (set sleeping-routines*.routine))
+;? (= dump-trace* (obj whitelist '("schedule")))
+;? (prn "1 " running-routines*)
+;? (prn sleeping-routines*)
+(update-scheduler-state)
+;? (prn "2 " running-routines*)
+;? (prn sleeping-routines*)
+(when (or (~empty running-routines*) (~empty sleeping-routines*))
+  (prn "F - scheduler stops when there's only sleeping helper routines left"))
+
+(reset)
+(new-trace "scheduler-termination")
+(= traces* (queue))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])))
+; all routines done
+(update-scheduler-state)
+(check-trace-doesnt-contain "scheduler helper check shouldn't trigger unless necessary"
+  '(("schedule" "just helpers left")))
+
+; both running and sleeping helpers
+; running helper and sleeping non-helper
+; sleeping helper and running non-helper
+
+(reset)
+(new-trace "scheduler-account-slice")
+; function running an infinite loop
+(add-code
+  '((function f1 [
+      { begin
+        (1:integer <- copy 0:literal)
+        (loop)
+      }
+     ])))
+(let routine make-routine!f1
+  (= rep.routine!limit 10)
+  (enq routine running-routines*))
+(= scheduling-interval* 20)
+(run)
+(when (or (empty completed-routines*)
+          (~is -10 ((rep completed-routines*.0) 'limit)))
+  (prn "F - when given a low cycle limit, a routine runs to end of time slice"))
+
+(reset)
+(new-trace "scheduler-account-slice-multiple")
+; function running an infinite loop
+(add-code
+  '((function f1 [
+      { begin
+        (1:integer <- copy 0:literal)
+        (loop)
+      }
+     ])))
+(let routine make-routine!f1
+  (= rep.routine!limit 100)
+  (enq routine running-routines*))
+(= scheduling-interval* 20)
+(run)
+(when (or (empty completed-routines*)
+          (~is -0 ((rep completed-routines*.0) 'limit)))
+  (prn "F - when given a high limit, a routine successfully stops after multiple time slices"))
+
+(reset)
+(new-trace "scheduler-account-run-while-asleep")
+(add-code
+    ; f1 needs 4 cycles of sleep time, 4 cycles of work
+  '((function f1 [
+      (sleep for-some-cycles:literal 4:literal)
+      (i:integer <- copy 0:literal)
+      (i:integer <- copy 0:literal)
+      (i:integer <- copy 0:literal)
+      (i:integer <- copy 0:literal)
+     ])))
+(let routine make-routine!f1
+  (= rep.routine!limit 6)  ; enough time excluding sleep
+  (enq routine running-routines*))
+(= scheduling-interval* 1)
+;? (= dump-trace* (obj whitelist '("schedule")))
+(run)
+; if time slept counts against limit, routine doesn't have time to complete
+(when (ran-to-completion 'f1)
+  (prn "F - time slept counts against a routine's cycle limit"))
+;? (quit)
+
+(reset)
+(new-trace "scheduler-account-stop-on-preempt")
+(add-code
+  '((function baseline [
+      (i:integer <- copy 0:literal)
+      { begin
+        (done?:boolean <- greater-or-equal i:integer 10:literal)
+        (break-if done?:boolean)
+        (1:integer <- add i:integer 1:literal)
+        (loop)
+      }
+     ])
+    (function f1 [
+      (i:integer <- copy 0:literal)
+      { begin
+        (done?:boolean <- greater-or-equal i:integer 6:literal)
+        (break-if done?:boolean)
+        (1:integer <- add i:integer 1:literal)
+        (loop)
+      }
+     ])))
+(let routine make-routine!baseline
+  (enq routine running-routines*))
+; now add the routine we care about
+(let routine make-routine!f1
+  (= rep.routine!limit 40)  ; less than 2x time f1 needs to complete
+  (enq routine running-routines*))
+(= scheduling-interval* 1)
+; if baseline's time were to count against f1's limit, it wouldn't be able to
+; complete.
+(when (~ran-to-completion 'f1)
+  (prn "F - preempted time doesn't count against a routine's limit"))
+;? (quit)
+
+(reset)
+(new-trace "scheduler-sleep-timeout")
+(add-code
+  '((function baseline [
+      (i:integer <- copy 0:literal)
+      { begin
+        (done?:boolean <- greater-or-equal i:integer 10:literal)
+        (break-if done?:boolean)
+        (1:integer <- add i:integer 1:literal)
+        (loop)
+      }
+     ])
+    (function f1 [
+      (sleep for-some-cycles:literal 10:literal)  ; less time than baseline would take to run
+     ])))
+; add baseline routine to prevent cycle-skipping
+(let routine make-routine!baseline
+  (enq routine running-routines*))
+; now add the routine we care about
+(let routine make-routine!f1
+  (= rep.routine!limit 4)  ; less time than f1 would take to run
+  (enq routine running-routines*))
+(= scheduling-interval* 1)
+;? (= dump-trace* (obj whitelist '("schedule")))
+(run)
+(when (ran-to-completion 'f1)
+  (prn "F - sleeping routines can time out"))
+;? (quit)
+
+(reset)
+(new-trace "sleep")
+(add-code
+  '((function f1 [
+      (sleep for-some-cycles:literal 1:literal)
+      (1:integer <- copy 0:literal)
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+      (2:integer <- copy 0:literal)
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(run 'f1 'f2)
+(check-trace-contents "scheduler handles sleeping routines"
+  '(("run" "f1 0")
+    ("run" "sleeping until 2")
+    ("schedule" "pushing f1 to sleep queue")
+    ("run" "f2 0")
+    ("run" "f2 1")
+    ("schedule" "waking up f1")
+    ("run" "f1 1")
+    ("run" "f1 2")
+  ))
+
+(reset)
+(new-trace "sleep-long")
+(add-code
+  '((function f1 [
+      (sleep for-some-cycles:literal 20:literal)
+      (1:integer <- copy 0:literal)
+      (1:integer <- copy 0:literal)
+     ])
+    (function f2 [
+      (2:integer <- copy 0:literal)
+      (2:integer <- copy 0:literal)
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(run 'f1 'f2)
+(check-trace-contents "scheduler progresses sleeping routines when there are no routines left to run"
+  '(("run" "f1 0")
+    ("run" "sleeping until 21")
+    ("schedule" "pushing f1 to sleep queue")
+    ("run" "f2 0")
+    ("run" "f2 1")
+    ("schedule" "waking up f1")
+    ("run" "f1 1")
+    ("run" "f1 2")
+  ))
+
+(reset)
+(new-trace "sleep-location")
+(add-code
+  '((function f1 [
+      ; waits for memory location 1 to be set, before computing its successor
+      (1:integer <- copy 0:literal)
+      (sleep until-location-changes:literal 1:integer)
+      (2:integer <- add 1:integer 1:literal)
+     ])
+    (function f2 [
+      (sleep for-some-cycles:literal 30:literal)
+      (1:integer <- copy 3:literal)  ; set to value
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+;? (set dump-trace*)
+(run 'f1 'f2)
+;? (prn int-canon.memory*)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is memory*.2 4)  ; successor of value
+  (prn "F - sleep can block on a memory location"))
+;? (quit)
+
+(reset)
+(new-trace "sleep-scoped-location")
+(add-code
+  '((function f1 [
+      ; waits for memory location 1 to be changed, before computing its successor
+      (10:integer <- copy 5:literal)  ; array of locals
+      (default-space:space-address <- copy 10:literal)
+      (1:integer <- copy 23:literal)  ; really location 12
+      (sleep until-location-changes:literal 1:integer)
+      (2:integer <- add 1:integer 1:literal)
+     ])
+    (function f2 [
+      (sleep for-some-cycles:literal 30:literal)
+      (12:integer <- copy 3:literal)  ; set to value
+     ])))
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(run 'f1 'f2)
+(when (~is memory*.13 4)  ; successor of value
+  (prn "F - sleep can block on a scoped memory location"))
+;? (quit)
+
+(reset)
+(new-trace "fork")
+(add-code
+  '((function f1 [
+      (1:integer <- copy 4:literal)
+     ])
+    (function main [
+      (fork f1:fn)
+     ])))
+(run 'main)
+(when (~iso memory*.1 4)
+  (prn "F - fork works"))
+
+(reset)
+(new-trace "fork-returns-id")
+(add-code
+  '((function f1 [
+      (1:integer <- copy 4:literal)
+     ])
+    (function main [
+      (2:integer <- fork f1:fn)
+     ])))
+(run 'main)
+;? (prn memory*)
+(when (no memory*.2)
+  (prn "F - fork returns a pid for the new routine"))
+
+(reset)
+(new-trace "fork-returns-unique-id")
+(add-code
+  '((function f1 [
+      (1:integer <- copy 4:literal)
+     ])
+    (function main [
+      (2:integer <- fork f1:fn)
+      (3:integer <- fork f1:fn)
+     ])))
+(run 'main)
+(when (or (no memory*.2)
+          (no memory*.3)
+          (is memory*.2 memory*.3))
+  (prn "F - fork returns a unique pid everytime"))
+
+(reset)
+(new-trace "fork-with-args")
+(add-code
+  '((function f1 [
+      (2:integer <- next-input)
+     ])
+    (function main [
+      (fork f1:fn nil:literal/globals nil:literal/limit 4:literal)
+     ])))
+(run 'main)
+(when (~iso memory*.2 4)
+  (prn "F - fork can pass args"))
+
+(reset)
+(new-trace "fork-copies-args")
+(add-code
+  '((function f1 [
+      (2:integer <- next-input)
+     ])
+    (function main [
+      (default-space:space-address <- new space:literal 5:literal)
+      (x:integer <- copy 4:literal)
+      (fork f1:fn nil:literal/globals nil:literal/limit x:integer)
+      (x:integer <- copy 0:literal)  ; should be ignored
+     ])))
+(run 'main)
+(when (~iso memory*.2 4)
+  (prn "F - fork passes args by value"))
+
+(reset)
+(new-trace "fork-global")
+(add-code
+  '((function f1 [
+      (1:integer/raw <- copy 2:integer/space:global)
+     ])
+    (function main [
+      (default-space:space-address <- new space:literal 5:literal)
+      (2:integer <- copy 4:literal)
+      (fork f1:fn default-space:space-address/globals nil:literal/limit)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error (prn "error - " it)))
+(when (~iso memory*.1 4)
+  (prn "F - fork can take a space of global variables to access"))
+
+(reset)
+(new-trace "fork-limit")
+(add-code
+  '((function f1 [
+      { begin
+        (loop)
+      }
+     ])
+    (function main [
+      (fork f1:fn nil:literal/globals 30:literal/limit)
+     ])))
+(= scheduling-interval* 5)
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error (prn "error - " it)))
+(when (ran-to-completion 'f1)
+  (prn "F - fork can specify a maximum cycle limit"))
+
+(reset)
+(new-trace "fork-then-wait")
+(add-code
+  '((function f1 [
+      { begin
+        (loop)
+      }
+     ])
+    (function main [
+      (1:integer/routine-id <- fork f1:fn nil:literal/globals 30:literal/limit)
+      (sleep until-routine-done:literal 1:integer/routine-id)
+      (2:integer <- copy 34:literal)
+     ])))
+(= scheduling-interval* 5)
+;? (= dump-trace* (obj whitelist '("schedule")))
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error (prn "error - " it)))
+(check-trace-contents "scheduler orders functions correctly"
+  '(("schedule" "pushing main to sleep queue")
+    ("schedule" "scheduling f1")
+    ("schedule" "ran out of time")
+    ("schedule" "waking up main")
+  ))
+;? (quit)
+
+; todo: Haven't yet written several tests
+;   that restarting a routine works
+;     when it died
+;     when it timed out
+;     when it completed
+;   running multiple routines in tandem
+; first example using these features: read-move-incomplete in chessboard-cursor.arc.t
+
+; The scheduler needs to keep track of the call stack for each routine.
+; Eventually we'll want to save this information in mu's address space itself,
+; along with the types array, the magic buffers for args and oargs, and so on.
+;
+; Eventually we want the right stack-management primitives to build delimited
+; continuations in mu.
+
+; Routines can throw errors.
+(reset)
+(new-trace "array-bounds-check")
+(add-code
+  '((function main [
+      (1:integer <- copy 2:literal)
+      (2:integer <- copy 23:literal)
+      (3:integer <- copy 24:literal)
+      (4:integer <- index 1:integer-array 2:literal)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(let routine (car completed-routines*)
+  (when (no rep.routine!error)
+    (prn "F - 'index' throws an error if out of bounds")))
+
+)  ; section 20
+
+(section 100
+
+;; Synchronization
+;
+; Mu synchronizes using channels rather than locks, like Erlang and Go.
+;
+; The two ends of a channel will usually belong to different routines, but
+; each end should only be used by a single one. Don't try to read from or
+; write to it from multiple routines at once.
+;
+; To avoid locking, writer and reader will never write to the same location.
+; So channels will include fields in pairs, one for the writer and one for the
+; reader.
+
+; The core circular buffer contains values at index 'first-full' up to (but
+; not including) index 'first-empty'. The reader always modifies it at
+; first-full, while the writer always modifies it at first-empty.
+(reset)
+(new-trace "channel-new")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer <- get 1:channel-address/deref first-full:offset)
+      (3:integer <- get 1:channel-address/deref first-free:offset)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (or (~is 0 memory*.2)
+          (~is 0 memory*.3))
+  (prn "F - 'init-channel' initializes 'first-full and 'first-free to 0"))
+
+(reset)
+(new-trace "channel-write")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (5:integer <- get 1:channel-address/deref first-full:offset)
+      (6:integer <- get 1:channel-address/deref first-free:offset)
+     ])))
+;? (prn function*!write)
+;? (set dump-trace*)
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "array-len" "cvt0" "cvt1")))
+;? (= dump-trace* (obj whitelist '("jump")))
+;? (= dump-trace* (obj whitelist '("run" "reply")))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn canon.memory*)
+(when (or (~is 0 memory*.5)
+          (~is 1 memory*.6))
+  (prn "F - 'write' enqueues item to channel"))
+;? (quit)
+
+(reset)
+(new-trace "channel-read")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (5:tagged-value 1:channel-address/deref <- read 1:channel-address)
+      (7:integer <- maybe-coerce 5:tagged-value integer:literal)
+      (8:integer <- get 1:channel-address/deref first-full:offset)
+      (9:integer <- get 1:channel-address/deref first-free:offset)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "array-len" "cvt0" "cvt1")))
+(run 'main)
+;? (prn int-canon.memory*)
+(when (~is memory*.7 34)
+  (prn "F - 'read' returns written value"))
+(when (or (~is 1 memory*.8)
+          (~is 1 memory*.9))
+  (prn "F - 'read' dequeues item from channel"))
+
+(reset)
+(new-trace "channel-write-wrap")
+(add-code
+  '((function main [
+      ; channel with 1 slot
+      (1:channel-address <- init-channel 1:literal)
+      ; write a value
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      ; first-free will now be 1
+      (5:integer <- get 1:channel-address/deref first-free:offset)
+      ; read one value
+      (_ 1:channel-address/deref <- read 1:channel-address)
+      ; write a second value; verify that first-free wraps around to 0.
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (6:integer <- get 1:channel-address/deref first-free:offset)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "array-len" "cvt0" "cvt1")))
+(run 'main)
+;? (prn canon.memory*)
+(when (or (~is 1 memory*.5)
+          (~is 0 memory*.6))
+  (prn "F - 'write' can wrap pointer back to start"))
+
+(reset)
+(new-trace "channel-read-wrap")
+(add-code
+  '((function main [
+      ; channel with 1 slot
+      (1:channel-address <- init-channel 1:literal)
+      ; write a value
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      ; read one value
+      (_ 1:channel-address/deref <- read 1:channel-address)
+      ; first-full will now be 1
+      (5:integer <- get 1:channel-address/deref first-full:offset)
+      ; write a second value
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      ; read second value; verify that first-full wraps around to 0.
+      (_ 1:channel-address/deref <- read 1:channel-address)
+      (6:integer <- get 1:channel-address/deref first-full:offset)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj blacklist '("sz" "mem" "addr" "array-len" "cvt0" "cvt1")))
+(run 'main)
+;? (prn canon.memory*)
+(when (or (~is 1 memory*.5)
+          (~is 0 memory*.6))
+  (prn "F - 'read' can wrap pointer back to start"))
+
+(reset)
+(new-trace "channel-new-empty-not-full")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:boolean <- empty? 1:channel-address/deref)
+      (3:boolean <- full? 1:channel-address/deref)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (or (~is t memory*.2)
+          (~is nil memory*.3))
+  (prn "F - a new channel is always empty, never full"))
+
+(reset)
+(new-trace "channel-write-not-empty")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (5:boolean <- empty? 1:channel-address/deref)
+      (6:boolean <- full? 1:channel-address/deref)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (or (~is nil memory*.5)
+          (~is nil memory*.6))
+  (prn "F - a channel after writing is never empty"))
+
+(reset)
+(new-trace "channel-write-full")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 1:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (5:boolean <- empty? 1:channel-address/deref)
+      (6:boolean <- full? 1:channel-address/deref)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (or (~is nil memory*.5)
+          (~is t memory*.6))
+  (prn "F - a channel after writing may be full"))
+
+(reset)
+(new-trace "channel-read-not-full")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (_ 1:channel-address/deref <- read 1:channel-address)
+      (5:boolean <- empty? 1:channel-address/deref)
+      (6:boolean <- full? 1:channel-address/deref)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (or (~is nil memory*.5)
+          (~is nil memory*.6))
+  (prn "F - a channel after reading is never full"))
+
+(reset)
+(new-trace "channel-read-empty")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      (_ 1:channel-address/deref <- read 1:channel-address)
+      (5:boolean <- empty? 1:channel-address/deref)
+      (6:boolean <- full? 1:channel-address/deref)
+     ])))
+;? (set dump-trace*)
+(run 'main)
+;? (prn memory*)
+(when (or (~is t memory*.5)
+          (~is nil memory*.6))
+  (prn "F - a channel after reading may be empty"))
+
+; The key property of channels; writing to a full channel blocks the current
+; routine until it creates space. Ditto reading from an empty channel.
+
+(reset)
+(new-trace "channel-read-block")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 3:literal)
+      ; channel is empty, but receives a read
+      (2:tagged-value 1:channel-address/deref <- read 1:channel-address)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("run" "schedule")))
+(run 'main)
+;? (prn int-canon.memory*)
+;? (prn sleeping-routines*)
+;? (prn completed-routines*)
+; read should cause the routine to sleep, and
+; the sole sleeping routine should trigger the deadlock detector
+(let routine (car completed-routines*)
+  (when (or (no routine)
+            (no rep.routine!error)
+            (~posmatch "deadlock" rep.routine!error))
+    (prn "F - 'read' on empty channel blocks (puts the routine to sleep until the channel gets data)")))
+;? (quit)
+
+(reset)
+(new-trace "channel-write-block")
+(add-code
+  '((function main [
+      (1:channel-address <- init-channel 1:literal)
+      (2:integer <- copy 34:literal)
+      (3:tagged-value <- save-type 2:integer)
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+      ; channel has capacity 1, but receives a second write
+      (1:channel-address/deref <- write 1:channel-address 3:tagged-value)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("run" "schedule" "addr")))
+(run 'main)
+;? (prn int-canon.memory*)
+;? (prn running-routines*)
+;? (prn sleeping-routines*)
+;? (prn completed-routines*)
+; second write should cause the routine to sleep, and
+; the sole sleeping routine should trigger the deadlock detector
+(let routine (car completed-routines*)
+  (when (or (no routine)
+            (no rep.routine!error)
+            (~posmatch "deadlock" rep.routine!error))
+    (prn "F - 'write' on full channel blocks (puts the routine to sleep until the channel gets data)")))
+;? (quit)
+
+(reset)
+(new-trace "channel-handoff")
+(add-code
+  '((function consumer [
+      (default-space:space-address <- new space:literal 30:literal)
+      (chan:channel-address <- init-channel 3:literal)  ; create a channel
+      (fork producer:fn nil:literal/globals nil:literal/limit chan:channel-address)  ; fork a routine to produce a value in it
+      (1:tagged-value/raw <- read chan:channel-address)  ; wait for input on channel
+     ])
+    (function producer [
+      (default-space:space-address <- new space:literal 30:literal)
+      (n:integer <- copy 24:literal)
+      (ochan:channel-address <- next-input)
+      (x:tagged-value <- save-type n:integer)
+      (ochan:channel-address/deref <- write ochan:channel-address x:tagged-value)
+     ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("schedule" "run" "addr")))
+;? (= dump-trace* (obj whitelist '("-")))
+(run 'consumer)
+;? (prn memory*)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is 24 memory*.2)  ; location 1 contains tagged-value x above
+  (prn "F - channels are meant to be shared between routines"))
+;? (quit)
+
+(reset)
+(new-trace "channel-handoff-routine")
+(add-code
+  '((function consumer [
+      (default-space:space-address <- new space:literal 30:literal)
+      (1:channel-address <- init-channel 3:literal)  ; create a channel
+      (fork producer:fn default-space:space-address/globals nil:literal/limit)  ; pass it as a global to another routine
+      (1:tagged-value/raw <- read 1:channel-address)  ; wait for input on channel
+     ])
+    (function producer [
+      (default-space:space-address <- new space:literal 30:literal)
+      (n:integer <- copy 24:literal)
+      (x:tagged-value <- save-type n:integer)
+      (1:channel-address/space:global/deref <- write 1:channel-address/space:global x:tagged-value)
+     ])))
+(run 'consumer)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is 24 memory*.2)  ; location 1 contains tagged-value x above
+  (prn "F - channels are meant to be shared between routines"))
+
+)  ; section 100
+
+(section 10
+
+;; Separating concerns
+;
+; Lightweight tools can also operate on quoted lists of statements surrounded
+; by square brackets. In the example below, we mimic Go's 'defer' keyword
+; using 'convert-quotes'. It lets us write code anywhere in a function, but
+; have it run just before the function exits. Great for keeping code to
+; reclaim memory or other resources close to the code to allocate it. (C++
+; programmers know this as RAII.) We'll use 'defer' when we build a memory
+; deallocation routine like C's 'free'.
+;
+; More powerful reorderings are also possible like in Literate Programming or
+; Aspect-Oriented Programming; one advantage of prohibiting arbitrarily nested
+; code is that we can naturally name 'join points' wherever we want.
+
+(reset)
+(new-trace "convert-quotes-defer")
+(= traces* (queue))
+(when (~iso (convert-quotes
+              '((1:integer <- copy 4:literal)
+                (defer [
+                         (3:integer <- copy 6:literal)
+                       ])
+                (2:integer <- copy 5:literal)))
+            '((1:integer <- copy 4:literal)
+              (2:integer <- copy 5:literal)
+              (3:integer <- copy 6:literal)))
+  (prn "F - convert-quotes can handle 'defer'"))
+
+(reset)
+(new-trace "convert-quotes-defer-reply")
+(= traces* (queue))
+(when (~iso (convert-quotes
+              '((1:integer <- copy 0:literal)
+                (defer [
+                         (5:integer <- copy 0:literal)
+                       ])
+                (2:integer <- copy 0:literal)
+                (reply)
+                (3:integer <- copy 0:literal)
+                (4:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              (5:integer <- copy 0:literal)
+              (reply)
+              (3:integer <- copy 0:literal)
+              (4:integer <- copy 0:literal)
+              (5:integer <- copy 0:literal)))
+  (prn "F - convert-quotes inserts code at early exits"))
+
+(reset)
+(new-trace "convert-quotes-defer-reply-arg")
+(= traces* (queue))
+(when (~iso (convert-quotes
+              '((1:integer <- copy 0:literal)
+                (defer [
+                         (5:integer <- copy 0:literal)
+                       ])
+                (2:integer <- copy 0:literal)
+                (reply 2:literal)
+                (3:integer <- copy 0:literal)
+                (4:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              (prepare-reply 2:literal)
+              (5:integer <- copy 0:literal)
+              (reply)
+              (3:integer <- copy 0:literal)
+              (4:integer <- copy 0:literal)
+              (5:integer <- copy 0:literal)))
+  (prn "F - convert-quotes inserts code at early exits"))
+
+(reset)
+(new-trace "convert-quotes-label")
+(= traces* (queue))
+(when (~iso (convert-quotes
+              '((1:integer <- copy 4:literal)
+                foo
+                (2:integer <- copy 5:literal)))
+            '((1:integer <- copy 4:literal)
+              foo
+              (2:integer <- copy 5:literal)))
+  (prn "F - convert-quotes can handle labels"))
+
+(reset)
+(new-trace "before")
+(= traces* (queue))
+(add-code
+  '((before label1 [
+     (2:integer <- copy 0:literal)
+    ])))
+(when (~iso (as cons before*!label1)
+            '(; fragment
+              (
+                (2:integer <- copy 0:literal))))
+  (prn "F - 'before' records fragments of code to insert before labels"))
+
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (3:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              label1
+              (3:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert fragments before labels"))
+
+(reset)
+(new-trace "before-multiple")
+(= traces* (queue))
+(add-code
+  '((before label1 [
+      (2:integer <- copy 0:literal)
+     ])
+    (before label1 [
+      (3:integer <- copy 0:literal)
+     ])))
+(when (~iso (as cons before*!label1)
+            '(; fragment
+              (
+                (2:integer <- copy 0:literal))
+              (
+                (3:integer <- copy 0:literal))))
+  (prn "F - 'before' records fragments in order"))
+
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (4:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              (3:integer <- copy 0:literal)
+              label1
+              (4:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert multiple fragments in order before label"))
+
+(reset)
+(new-trace "before-scoped")
+(= traces* (queue))
+(add-code
+  '((before f/label1 [  ; label1 only inside function f
+     (2:integer <- copy 0:literal)
+    ])))
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (3:integer <- copy 0:literal))
+              'f)
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              label1
+              (3:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert fragments before labels just in specified functions"))
+
+(reset)
+(new-trace "before-scoped2")
+(= traces* (queue))
+(add-code
+  '((before f/label1 [  ; label1 only inside function f
+      (2:integer <- copy 0:literal)
+     ])))
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (3:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              label1
+              (3:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' ignores labels not in specified functions"))
+
+(reset)
+(new-trace "after")
+(= traces* (queue))
+(add-code
+  '((after label1 [
+      (2:integer <- copy 0:literal)
+     ])))
+(when (~iso (as cons after*!label1)
+            '(; fragment
+              (
+                (2:integer <- copy 0:literal))))
+  (prn "F - 'after' records fragments of code to insert after labels"))
+
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (3:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              label1
+              (2:integer <- copy 0:literal)
+              (3:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert fragments after labels"))
+
+(reset)
+(new-trace "after-multiple")
+(= traces* (queue))
+(add-code
+  '((after label1 [
+      (2:integer <- copy 0:literal)
+     ])
+    (after label1 [
+      (3:integer <- copy 0:literal)
+     ])))
+(when (~iso (as cons after*!label1)
+            '(; fragment
+              (
+                (3:integer <- copy 0:literal))
+              (
+                (2:integer <- copy 0:literal))))
+  (prn "F - 'after' records fragments in *reverse* order"))
+
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (4:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              label1
+              (3:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              (4:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert multiple fragments in order after label"))
+
+(reset)
+(new-trace "before-after")
+(= traces* (queue))
+(add-code
+  '((before label1 [
+      (2:integer <- copy 0:literal)
+     ])
+    (after label1 [
+      (3:integer <- copy 0:literal)
+     ])))
+(when (and (~iso (as cons before*!label1)
+                 '(; fragment
+                   (
+                     (2:integer <- copy 0:literal))))
+           (~iso (as cons after*!label1)
+                 '(; fragment
+                   (
+                     (3:integer <- copy 0:literal)))))
+  (prn "F - 'before' and 'after' fragments work together"))
+
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (4:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              label1
+              (3:integer <- copy 0:literal)
+              (4:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert multiple fragments around label"))
+
+(reset)
+(new-trace "before-after-multiple")
+(= traces* (queue))
+(add-code
+  '((before label1 [
+      (2:integer <- copy 0:literal)
+      (3:integer <- copy 0:literal)
+     ])
+    (after label1 [
+      (4:integer <- copy 0:literal)
+     ])
+    (before label1 [
+      (5:integer <- copy 0:literal)
+     ])
+    (after label1 [
+      (6:integer <- copy 0:literal)
+      (7:integer <- copy 0:literal)
+     ])))
+(when (or (~iso (as cons before*!label1)
+                '(; fragment
+                  (
+                    (2:integer <- copy 0:literal)
+                    (3:integer <- copy 0:literal))
+                  (
+                    (5:integer <- copy 0:literal))))
+          (~iso (as cons after*!label1)
+                '(; fragment
+                  (
+                    (6:integer <- copy 0:literal)
+                    (7:integer <- copy 0:literal))
+                  (
+                    (4:integer <- copy 0:literal)))))
+  (prn "F - multiple 'before' and 'after' fragments at once"))
+
+(when (~iso (insert-code
+              '((1:integer <- copy 0:literal)
+                label1
+                (8:integer <- copy 0:literal)))
+            '((1:integer <- copy 0:literal)
+              (2:integer <- copy 0:literal)
+              (3:integer <- copy 0:literal)
+              (5:integer <- copy 0:literal)
+              label1
+              (6:integer <- copy 0:literal)
+              (7:integer <- copy 0:literal)
+              (4:integer <- copy 0:literal)
+              (8:integer <- copy 0:literal)))
+  (prn "F - 'insert-code' can insert multiple fragments around label - 2"))
+
+(reset)
+(new-trace "before-after-independent")
+(= traces* (queue))
+(when (~iso (do
+              (reset)
+              (add-code
+                '((before label1 [
+                    (2:integer <- copy 0:literal)
+                   ])
+                  (after label1 [
+                    (3:integer <- copy 0:literal)
+                   ])
+                  (before label1 [
+                    (4:integer <- copy 0:literal)
+                   ])
+                  (after label1 [
+                    (5:integer <- copy 0:literal)
+                   ])))
+              (list before*!label1 after*!label1))
+            (do
+              (reset)
+              (add-code
+                '((before label1 [
+                    (2:integer <- copy 0:literal)
+                   ])
+                  (before label1 [
+                    (4:integer <- copy 0:literal)
+                   ])
+                  (after label1 [
+                    (3:integer <- copy 0:literal)
+                   ])
+                  (after label1 [
+                    (5:integer <- copy 0:literal)
+                   ])))
+              (list before*!label1 after*!label1)))
+  (prn "F - order matters between 'before' and between 'after' fragments, but not *across* 'before' and 'after' fragments"))
+
+(reset)
+(new-trace "before-after-braces")
+(= traces* (queue))
+(= function* (table))
+(add-code
+  '((after label1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function f1 [
+      { begin
+        label1
+      }
+     ])))
+;? (= dump-trace* (obj whitelist '("cn0")))
+(freeze function*)
+(when (~iso function*!f1
+            '(label1
+              (((1 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - before/after works inside blocks"))
+
+(reset)
+(new-trace "before-after-any-order")
+(= traces* (queue))
+(= function* (table))
+(add-code
+  '((function f1 [
+      { begin
+        label1
+      }
+     ])
+    (after label1 [
+       (1:integer <- copy 0:literal)
+     ])))
+(freeze function*)
+(when (~iso function*!f1
+            '(label1
+              (((1 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - before/after can come after the function they need to modify"))
+;? (quit)
+
+(reset)
+(new-trace "multiple-defs")
+(= traces* (queue))
+(= function* (table))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function f1 [
+      (2:integer <- copy 0:literal)
+     ])))
+(freeze function*)
+(when (~iso function*!f1
+            '((((2 integer)) <- ((copy)) ((0 literal)))
+              (((1 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - multiple 'def' of the same function add clauses"))
+
+(reset)
+(new-trace "def!")
+(= traces* (queue))
+(= function* (table))
+(add-code
+  '((function f1 [
+      (1:integer <- copy 0:literal)
+     ])
+    (function! f1 [
+      (2:integer <- copy 0:literal)
+     ])))
+(freeze function*)
+(when (~iso function*!f1
+            '((((2 integer)) <- ((copy)) ((0 literal)))))
+  (prn "F - 'def!' clears all previous clauses"))
+
+)  ; section 10
+
+;; ---
+
+(section 100
+
+; String utilities
+
+(reset)
+(new-trace "string-new")
+(add-code
+  '((function main [
+      (1:string-address <- new string:literal 5:literal)
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+    (run)
+    (when (~iso rep.routine!alloc (+ before 5 1))
+      (prn "F - 'new' allocates arrays of bytes for strings"))))
+
+; Convenience: initialize strings using string literals
+(reset)
+(new-trace "string-literal")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello")
+     ])))
+(let routine make-routine!main
+  (enq routine running-routines*)
+  (let before rep.routine!alloc
+;?     (set dump-trace*)
+;?     (= dump-trace* (obj whitelist '("schedule" "run" "addr")))
+    (run)
+    (when (~iso rep.routine!alloc (+ before 5 1))
+      (prn "F - 'new' allocates arrays of bytes for string literals"))
+    (when (~memory-contains-array before "hello")
+      (prn "F - 'new' initializes allocated memory to string literal"))))
+
+(reset)
+(new-trace "string-equal")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello")
+      (2:string-address <- new "hello")
+      (3:boolean <- string-equal 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 t)
+  (prn "F - 'string-equal'"))
+
+(reset)
+(new-trace "string-equal-empty")
+(add-code
+  '((function main [
+      (1:string-address <- new "")
+      (2:string-address <- new "")
+      (3:boolean <- string-equal 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 t)
+  (prn "F - 'string-equal' works on empty strings"))
+
+(reset)
+(new-trace "string-equal-compare-with-empty")
+(add-code
+  '((function main [
+      (1:string-address <- new "a")
+      (2:string-address <- new "")
+      (3:boolean <- string-equal 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 nil)
+  (prn "F - 'string-equal' compares correctly with empty strings"))
+
+(reset)
+(new-trace "string-equal-compares-length")
+(add-code
+  '((function main [
+      (1:string-address <- new "a")
+      (2:string-address <- new "ab")
+      (3:boolean <- string-equal 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 nil)
+  (prn "F - 'string-equal' handles differing lengths"))
+
+(reset)
+(new-trace "string-equal-compares-initial-element")
+(add-code
+  '((function main [
+      (1:string-address <- new "aa")
+      (2:string-address <- new "ba")
+      (3:boolean <- string-equal 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 nil)
+  (prn "F - 'string-equal' handles inequal final byte"))
+
+(reset)
+(new-trace "string-equal-compares-final-element")
+(add-code
+  '((function main [
+      (1:string-address <- new "ab")
+      (2:string-address <- new "aa")
+      (3:boolean <- string-equal 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 nil)
+  (prn "F - 'string-equal' handles inequal final byte"))
+
+(reset)
+(new-trace "string-equal-reflexive")
+(add-code
+  '((function main [
+      (1:string-address <- new "ab")
+      (3:boolean <- string-equal 1:string-address 1:string-address)
+     ])))
+(run 'main)
+(when (~iso memory*.3 t)
+  (prn "F - 'string-equal' handles identical pointer"))
+
+(reset)
+(new-trace "strcat")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello,")
+      (2:string-address <- new " world!")
+      (3:string-address <- strcat 1:string-address 2:string-address)
+     ])))
+;? (= dump-trace* (obj whitelist '("run"))) ;? 1
+(run 'main)
+(when (~memory-contains-array memory*.3 "hello, world!")
+  (prn "F - 'strcat' concatenates strings"))
+;? (quit) ;? 1
+
+(reset)
+(new-trace "interpolate")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello, _!")
+      (2:string-address <- new "abc")
+      (3:string-address <- interpolate 1:string-address 2:string-address)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(when (~memory-contains-array memory*.3 "hello, abc!")
+  (prn "F - 'interpolate' splices strings"))
+
+(reset)
+(new-trace "interpolate-empty")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello!")
+      (2:string-address <- new "abc")
+      (3:string-address <- interpolate 1:string-address 2:string-address)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(when (~memory-contains-array memory*.3 "hello!")
+  (prn "F - 'interpolate' without underscore returns template"))
+
+(reset)
+(new-trace "interpolate-at-start")
+(add-code
+  '((function main [
+      (1:string-address <- new "_, hello!")
+      (2:string-address <- new "abc")
+      (3:string-address <- interpolate 1:string-address 2:string-address)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(when (~memory-contains-array memory*.3 "abc, hello")
+  (prn "F - 'interpolate' splices strings at start"))
+
+(reset)
+(new-trace "interpolate-at-end")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello, _")
+      (2:string-address <- new "abc")
+      (3:string-address <- interpolate 1:string-address 2:string-address)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(when (~memory-contains-array memory*.3 "hello, abc")
+  (prn "F - 'interpolate' splices strings at start"))
+
+(reset)
+(new-trace "interpolate-varargs")
+(add-code
+  '((function main [
+      (1:string-address <- new "hello, _, _, and _!")
+      (2:string-address <- new "abc")
+      (3:string-address <- new "def")
+      (4:string-address <- new "ghi")
+      (5:string-address <- interpolate 1:string-address 2:string-address 3:string-address 4:string-address)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+;? (= dump-trace* (obj whitelist '("run" "array-info")))
+;? (set dump-trace*)
+(run 'main)
+;? (quit)
+;? (up i 1 (+ 1 (memory* memory*.5))
+;?   (prn (memory* (+ memory*.5 i))))
+(when (~memory-contains-array memory*.5 "hello, abc, def, and ghi!")
+  (prn "F - 'interpolate' splices in any number of strings"))
+
+(reset)
+(new-trace "string-find-next")
+(add-code
+  '((function main [
+      (1:string-address <- new "a/b")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.2 1)
+  (prn "F - 'find-next' finds first location of a character"))
+
+(reset)
+(new-trace "string-find-next-empty")
+(add-code
+  '((function main [
+      (1:string-address <- new "")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 0:literal)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~is memory*.2 0)
+  (prn "F - 'find-next' finds first location of a character"))
+
+(reset)
+(new-trace "string-find-next-initial")
+(add-code
+  '((function main [
+      (1:string-address <- new "/abc")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.2 0)
+  (prn "F - 'find-next' handles prefix match"))
+
+(reset)
+(new-trace "string-find-next-final")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc/")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 0:literal)
+     ])))
+(run 'main)
+;? (prn memory*.2)
+(when (~is memory*.2 3)
+  (prn "F - 'find-next' handles suffix match"))
+
+(reset)
+(new-trace "string-find-next-missing")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 0:literal)
+     ])))
+(run 'main)
+;? (prn memory*.2)
+(when (~is memory*.2 3)
+  (prn "F - 'find-next' handles no match"))
+
+(reset)
+(new-trace "string-find-next-invalid-index")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 4:literal)
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn memory*.2)
+(when (~is memory*.2 4)
+  (prn "F - 'find-next' skips invalid index (past end of string)"))
+
+(reset)
+(new-trace "string-find-next-first")
+(add-code
+  '((function main [
+      (1:string-address <- new "ab/c/")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.2 2)
+  (prn "F - 'find-next' finds first of multiple options"))
+
+(reset)
+(new-trace "string-find-next-second")
+(add-code
+  '((function main [
+      (1:string-address <- new "ab/c/")
+      (2:integer <- find-next 1:string-address ((#\/ literal)) 3:literal)
+     ])))
+(run 'main)
+(when (~is memory*.2 4)
+  (prn "F - 'find-next' finds second of multiple options"))
+
+(reset)
+(new-trace "match-at")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "ab")
+      (3:boolean <- match-at 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 t)
+  (prn "F - 'match-at' matches substring at given index"))
+
+(reset)
+(new-trace "match-at-reflexive")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (3:boolean <- match-at 1:string-address 1:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 t)
+  (prn "F - 'match-at' always matches a string at itself at index 0"))
+
+(reset)
+(new-trace "match-at-outside-bounds")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "a")
+      (3:boolean <- match-at 1:string-address 2:string-address 4:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 nil)
+  (prn "F - 'match-at' always fails to match outside the bounds of the text"))
+
+(reset)
+(new-trace "match-at-empty-pattern")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "")
+      (3:boolean <- match-at 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 t)
+  (prn "F - 'match-at' always matches empty pattern"))
+
+(reset)
+(new-trace "match-at-empty-pattern-outside-bounds")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "")
+      (3:boolean <- match-at 1:string-address 2:string-address 4:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 nil)
+  (prn "F - 'match-at' matches empty pattern -- unless index is out of bounds"))
+
+(reset)
+(new-trace "match-at-empty-text")
+(add-code
+  '((function main [
+      (1:string-address <- new "")
+      (2:string-address <- new "abc")
+      (3:boolean <- match-at 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 nil)
+  (prn "F - 'match-at' never matches empty text"))
+
+(reset)
+(new-trace "match-at-empty-against-empty")
+(add-code
+  '((function main [
+      (1:string-address <- new "")
+      (3:boolean <- match-at 1:string-address 1:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 t)
+  (prn "F - 'match-at' never matches empty text -- unless pattern is also empty"))
+
+(reset)
+(new-trace "match-at-inside-bounds")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "bc")
+      (3:boolean <- match-at 1:string-address 2:string-address 1:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 t)
+  (prn "F - 'match-at' matches inner substring"))
+
+(reset)
+(new-trace "match-at-inside-bounds-2")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "bc")
+      (3:boolean <- match-at 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 nil)
+  (prn "F - 'match-at' matches inner substring - 2"))
+
+(reset)
+(new-trace "find-substring")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "bc")
+      (3:integer <- find-substring 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+;? (prn memory*.3) ;? 1
+(when (~is memory*.3 1)
+  (prn "F - 'find-substring' returns index of match"))
+
+(reset)
+(new-trace "find-substring-2")
+(add-code
+  '((function main [
+      (1:string-address <- new "abcd")
+      (2:string-address <- new "bc")
+      (3:integer <- find-substring 1:string-address 2:string-address 1:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 1)
+  (prn "F - 'find-substring' returns provided index if it matches"))
+
+(reset)
+(new-trace "find-substring-no-match")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- new "bd")
+      (3:integer <- find-substring 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 3)
+  (prn "F - 'find-substring' returns out-of-bounds index on no-match"))
+
+(reset)
+(new-trace "find-substring-suffix-match")
+(add-code
+  '((function main [
+      (1:string-address <- new "abcd")
+      (2:string-address <- new "cd")
+      (3:integer <- find-substring 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 2)
+  (prn "F - 'find-substring' returns provided index if it matches"))
+
+(reset)
+(new-trace "find-substring-suffix-match-2")
+(add-code
+  '((function main [
+      (1:string-address <- new "abcd")
+      (2:string-address <- new "cde")
+      (3:integer <- find-substring 1:string-address 2:string-address 0:literal)
+     ])))
+(run 'main)
+(when (~is memory*.3 4)
+  (prn "F - 'find-substring' returns provided index if it matches"))
+
+;? (quit) ;? 1
+
+(reset)
+(new-trace "string-split")
+(add-code
+  '((function main [
+      (1:string-address <- new "a/b")
+      (2:string-address-array-address <- split 1:string-address ((#\/ literal)))
+     ])))
+;? (set dump-trace*)
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(let base memory*.2
+;?   (prn base " " memory*.base)
+  (when (or (~is memory*.base 2)
+;?             (do1 nil prn.111)
+            (~memory-contains-array (memory* (+ base 1)) "a")
+;?             (do1 nil prn.111)
+            (~memory-contains-array (memory* (+ base 2)) "b"))
+    (prn "F - 'split' cuts string at delimiter")))
+
+(reset)
+(new-trace "string-split2")
+(add-code
+  '((function main [
+      (1:string-address <- new "a/b/c")
+      (2:string-address-array-address <- split 1:string-address ((#\/ literal)))
+     ])))
+;? (set dump-trace*)
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(let base memory*.2
+;?   (prn base " " memory*.base)
+  (when (or (~is memory*.base 3)
+;?             (do1 nil prn.111)
+            (~memory-contains-array (memory* (+ base 1)) "a")
+;?             (do1 nil prn.111)
+            (~memory-contains-array (memory* (+ base 2)) "b")
+;?             (do1 nil prn.111)
+            (~memory-contains-array (memory* (+ base 3)) "c"))
+    (prn "F - 'split' cuts string at two delimiters")))
+
+(reset)
+(new-trace "string-split-missing")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address-array-address <- split 1:string-address ((#\/ literal)))
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(let base memory*.2
+  (when (or (~is memory*.base 1)
+            (~memory-contains-array (memory* (+ base 1)) "abc"))
+    (prn "F - 'split' handles missing delimiter")))
+
+(reset)
+(new-trace "string-split-empty")
+(add-code
+  '((function main [
+      (1:string-address <- new "")
+      (2:string-address-array-address <- split 1:string-address ((#\/ literal)))
+     ])))
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(let base memory*.2
+;?   (prn base " " memory*.base)
+  (when (~is memory*.base 0)
+    (prn "F - 'split' handles empty string")))
+
+(reset)
+(new-trace "string-split-empty-piece")
+(add-code
+  '((function main [
+      (1:string-address <- new "a/b//c")
+      (2:string-address-array-address <- split 1:string-address ((#\/ literal)))
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(let base memory*.2
+  (when (or (~is memory*.base 4)
+            (~memory-contains-array (memory* (+ base 1)) "a")
+            (~memory-contains-array (memory* (+ base 2)) "b")
+            (~memory-contains-array (memory* (+ base 3)) "")
+            (~memory-contains-array (memory* (+ base 4)) "c"))
+    (prn "F - 'split' cuts string at two delimiters")))
+;? (quit) ;? 1
+
+(reset)
+(new-trace "string-split-first")
+(add-code
+  '((function main [
+      (1:string-address <- new "a/b")
+      (2:string-address 3:string-address <- split-first 1:string-address ((#\/ literal)))
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (or (~memory-contains-array memory*.2 "a")
+          (~memory-contains-array memory*.3 "b"))
+  (prn "F - 'split-first' cuts string at first occurrence of delimiter"))
+
+(reset)
+(new-trace "string-split-first-at-substring")
+(add-code
+  '((function main [
+      (1:string-address <- new "a//b")
+      (2:string-address <- new "//")
+      (3:string-address 4:string-address <- split-first-at-substring 1:string-address 2:string-address)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn int-canon.memory*) ;? 1
+(when (or (~memory-contains-array memory*.3 "a")
+          (~memory-contains-array memory*.4 "b"))
+  (prn "F - 'split-first-at-substring' is like split-first but with a string delimiter"))
+
+(reset)
+(new-trace "string-copy")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- string-copy 1:string-address 1:literal 3:literal)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~memory-contains-array memory*.2 "bc")
+  (prn "F - 'string-copy' returns a copy of a substring"))
+
+(reset)
+(new-trace "string-copy-out-of-bounds")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- string-copy 1:string-address 2:literal 4:literal)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~memory-contains-array memory*.2 "c")
+  (prn "F - 'string-copy' stops at bounds"))
+
+(reset)
+(new-trace "string-copy-out-of-bounds-2")
+(add-code
+  '((function main [
+      (1:string-address <- new "abc")
+      (2:string-address <- string-copy 1:string-address 3:literal 3:literal)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+(when (~memory-contains-array memory*.2 "")
+  (prn "F - 'string-copy' returns empty string when range is out of bounds"))
+
+(reset)
+(new-trace "min")
+(add-code
+  '((function main [
+      (1:integer <- min 3:literal 4:literal)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (aif rep.routine!error (prn "error - " it)))
+;? (prn int-canon.memory*) ;? 1
+(when (~is memory*.1 3)
+  (prn "F - 'min' returns smaller of two numbers"))
+
+;? (quit) ;? 2
+
+(reset)
+(new-trace "integer-to-decimal-string")
+(add-code
+  '((function main [
+      (1:string-address/raw <- integer-to-decimal-string 34:literal)
+    ])))
+;? (set dump-trace*)
+;? (= dump-trace* (obj whitelist '("run")))
+(run 'main)
+(let base memory*.1
+  (when (~memory-contains-array base "34")
+    (prn "F - converting integer to decimal string")))
+
+(reset)
+(new-trace "integer-to-decimal-string-zero")
+(add-code
+  '((function main [
+      (1:string-address/raw <- integer-to-decimal-string 0:literal)
+    ])))
+(run 'main)
+(let base memory*.1
+  (when (~memory-contains-array base "0")
+    (prn "F - converting zero to decimal string")))
+
+(reset)
+(new-trace "integer-to-decimal-string-negative")
+(add-code
+  '((function main [
+      (1:string-address/raw <- integer-to-decimal-string -237:literal)
+    ])))
+(run 'main)
+(let base memory*.1
+  (when (~memory-contains-array base "-237")
+    (prn "F - converting negative integer to decimal string")))
+
+; fake screen for tests; prints go to a string
+(reset)
+(new-trace "fake-screen-empty")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal/capacity)
+      (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+      (5:string-address/raw <- get screen:terminal-address/deref data:offset)
+     ])))
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~memory-contains-array memory*.5
+          (+ "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "))
+  (prn "F - fake screen starts out with all spaces"))
+
+; fake keyboard for tests; must initialize keys in advance
+(reset)
+(new-trace "fake-keyboard")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "foo")
+      (x:keyboard-address <- init-keyboard s:string-address)
+      (1:character-address/raw <- read-key x:keyboard-address)
+     ])))
+(run 'main)
+(when (~is memory*.1 #\f)
+  (prn "F - 'read-key' reads character from provided 'fake keyboard' string"))
+
+; fake keyboard for tests; must initialize keys in advance
+(reset)
+(new-trace "fake-keyboard2")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "foo")
+      (x:keyboard-address <- init-keyboard s:string-address)
+      (1:character-address/raw <- read-key x:keyboard-address)
+      (1:character-address/raw <- read-key x:keyboard-address)
+     ])))
+(run 'main)
+(when (~is memory*.1 #\o)
+  (prn "F - 'read-key' advances cursor in provided string"))
+
+; to receive input line by line, run send-keys-buffered-to-stdin
+(reset)
+(new-trace "buffer-stdin-until-newline")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "foo")
+      (k:keyboard-address <- init-keyboard s:string-address)
+      (stdin:channel-address <- init-channel 1:literal)
+      (fork send-keys-to-stdin:fn nil:literal/globals nil:literal/limit k:keyboard-address stdin:channel-address)
+      (buffered-stdin:channel-address <- init-channel 1:literal)
+      (r:integer/routine <- fork buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+      (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+      (5:string-address/raw <- get screen:terminal-address/deref data:offset)
+      (fork-helper send-prints-to-stdout:fn nil:literal/globals nil:literal/limit screen:terminal-address buffered-stdin:channel-address)
+      (sleep until-routine-done:literal r:integer/routine)
+    ])))
+;? (set dump-trace*) ;? 3
+;? (= dump-trace* (obj whitelist '("schedule" "run"))) ;? 0
+(run 'main)
+;? (prn int-canon.memory*) ;? 0
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~memory-contains-array memory*.5
+          (+ "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "))
+  (prn "F - 'buffer-lines' prints nothing until newline is encountered"))
+;? (quit) ;? 3
+
+(reset)
+(new-trace "print-buffered-contents-on-newline")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "foo\nline2")
+      (k:keyboard-address <- init-keyboard s:string-address)
+      (stdin:channel-address <- init-channel 1:literal)
+      (fork send-keys-to-stdin:fn nil:literal/globals nil:literal/limit k:keyboard-address stdin:channel-address)
+      (buffered-stdin:channel-address <- init-channel 1:literal)
+      (r:integer/routine <- fork buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+      (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+      (5:string-address/raw <- get screen:terminal-address/deref data:offset)
+      (fork-helper send-prints-to-stdout:fn nil:literal/globals nil:literal/limit screen:terminal-address buffered-stdin:channel-address)
+      (sleep until-routine-done:literal r:integer/routine)
+    ])))
+;? (= dump-trace* (obj whitelist '("schedule" "run"))) ;? 1
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~memory-contains-array memory*.5
+          (+ "foo\n                "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "))
+  (prn "F - 'buffer-lines' prints lines to screen"))
+
+(reset)
+(new-trace "print-buffered-contents-right-at-newline")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "foo\n")
+      (k:keyboard-address <- init-keyboard s:string-address)
+      (stdin:channel-address <- init-channel 1:literal)
+      (fork send-keys-to-stdin:fn nil:literal/globals nil:literal/limit k:keyboard-address stdin:channel-address)
+      (buffered-stdin:channel-address <- init-channel 1:literal)
+      (r:integer/routine <- fork buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+      (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+      (5:string-address/raw <- get screen:terminal-address/deref data:offset)
+      (fork-helper send-prints-to-stdout:fn nil:literal/globals nil:literal/limit screen:terminal-address buffered-stdin:channel-address)
+      (sleep until-routine-done:literal r:integer/routine)
+      ; hack: give helper some time to finish printing
+      (sleep for-some-cycles:literal 500:literal)
+    ])))
+;? (= dump-trace* (obj whitelist '("schedule" "run"))) ;? 1
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~memory-contains-array memory*.5
+          (+ "foo\n                "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "))
+  (prn "F - 'buffer-lines' prints lines to screen immediately on newline"))
+
+(reset)
+(new-trace "buffered-contents-skip-backspace")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "fooa\b\nline2")
+      (k:keyboard-address <- init-keyboard s:string-address)
+      (stdin:channel-address <- init-channel 1:literal)
+      (fork send-keys-to-stdin:fn nil:literal/globals nil:literal/limit k:keyboard-address stdin:channel-address)
+      (buffered-stdin:channel-address <- init-channel 1:literal)
+      (r:integer/routine <- fork buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+      (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+      (5:string-address/raw <- get screen:terminal-address/deref data:offset)
+      (fork-helper send-prints-to-stdout:fn nil:literal/globals nil:literal/limit screen:terminal-address buffered-stdin:channel-address)
+      (sleep until-routine-done:literal r:integer/routine)
+    ])))
+;? (= dump-trace* (obj whitelist '("schedule" "run"))) ;? 1
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~memory-contains-array memory*.5
+          (+ "foo\n                "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "))
+  (prn "F - 'buffer-lines' handles backspace"))
+
+(reset)
+(new-trace "buffered-contents-ignore-excess-backspace")
+(add-code
+  '((function main [
+      (default-space:space-address <- new space:literal 30:literal)
+      (s:string-address <- new "a\b\bfoo\n")
+      (k:keyboard-address <- init-keyboard s:string-address)
+      (stdin:channel-address <- init-channel 1:literal)
+      (fork send-keys-to-stdin:fn nil:literal/globals nil:literal/limit k:keyboard-address stdin:channel-address)
+      (buffered-stdin:channel-address <- init-channel 1:literal)
+      (r:integer/routine <- fork buffer-lines:fn nil:literal/globals nil:literal/limit stdin:channel-address buffered-stdin:channel-address)
+      (screen:terminal-address <- init-fake-terminal 20:literal 10:literal)
+      (5:string-address/raw <- get screen:terminal-address/deref data:offset)
+      (fork-helper send-prints-to-stdout:fn nil:literal/globals nil:literal/limit screen:terminal-address buffered-stdin:channel-address)
+      (sleep until-routine-done:literal r:integer/routine)
+      ; hack: give helper some time to finish printing
+      (sleep for-some-cycles:literal 500:literal)
+    ])))
+;? (= dump-trace* (obj whitelist '("schedule" "run"))) ;? 1
+(run 'main)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+;? (prn memory*.5) ;? 1
+(when (~memory-contains-array memory*.5
+          (+ "foo\n                "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "
+             "                    "))
+  (prn "F - 'buffer-lines' ignores backspace when there's nothing to backspace over"))
+
+)  ; section 100
+
+(reset)
+(new-trace "parse-and-record")
+(add-code
+  '((and-record foo [
+      x:string
+      y:integer
+      z:boolean
+     ])))
+(when (~iso type*!foo (obj size 3  and-record t  elems '((string) (integer) (boolean))  fields '(x y z)))
+  (prn "F - 'add-code' can add new and-records"))
+
+;; unit tests for various helpers
+
+; tokenize-args
+(prn "== tokenize-args")
+(assert:iso '((a b) (c d))
+            (tokenize-arg 'a:b/c:d))
+; numbers are not symbols
+(assert:iso '((a b) (1 d))
+            (tokenize-arg 'a:b/1:d))
+; special symbols are skipped
+(assert:iso '<-
+            (tokenize-arg '<-))
+(assert:iso '_
+            (tokenize-arg '_))
+
+; idempotent
+(assert:iso (tokenize-arg:tokenize-arg 'a:b/c:d)
+            (tokenize-arg              'a:b/c:d))
+
+; support labels
+(assert:iso '((((default-space space-address)) <- ((new)) ((space literal)) ((30 literal)))
+              foo)
+            (tokenize-args
+              '((default-space:space-address <- new space:literal 30:literal)
+                foo)))
+
+; support braces
+(assert:iso '((((default-space space-address)) <- ((new)) ((space literal)) ((30 literal)))
+              foo
+              { begin
+                bar
+                (((a b)) <- ((op)) ((c d)) ((e f)))
+              })
+            (tokenize-args
+              '((default-space:space-address <- new space:literal 30:literal)
+                foo
+                { begin
+                  bar
+                  (a:b <- op c:d e:f)
+                })))
+
+; space
+(prn "== space")
+(reset)
+(when (~iso 0 (space '((4 integer))))
+  (prn "F - 'space' is 0 by default"))
+(when (~iso 1 (space '((4 integer) (space 1))))
+  (prn "F - 'space' picks up space when available"))
+(when (~iso 'global (space '((4 integer) (space global))))
+  (prn "F - 'space' understands routine-global space"))
+
+; absolutize
+(prn "== absolutize")
+(reset)
+(when (~iso '((4 integer)) (absolutize '((4 integer))))
+  (prn "F - 'absolutize' works without routine"))
+(= routine* make-routine!foo)
+(when (~iso '((4 integer)) (absolutize '((4 integer))))
+  (prn "F - 'absolutize' works without default-space"))
+(= rep.routine*!call-stack.0!default-space 10)
+(= memory*.10 5)  ; bounds check for default-space
+(when (~iso '((15 integer) (raw))
+            (absolutize '((4 integer))))
+  (prn "F - 'absolutize' works with default-space"))
+(absolutize '((5 integer)))
+(when (~posmatch "no room" rep.routine*!error)
+  (prn "F - 'absolutize' checks against default-space bounds"))
+(when (~iso '((_ integer)) (absolutize '((_ integer))))
+  (prn "F - 'absolutize' passes dummy args right through"))
+(when (~iso '((default-space integer)) (absolutize '((default-space integer))))
+  (prn "F - 'absolutize' passes 'default-space' right through"))
+
+(= memory*.20 5)  ; pretend array
+(= rep.routine*!globals 20)  ; provide it to routine global
+(when (~iso '((22 integer) (raw))
+            (absolutize '((1 integer) (space global))))
+  (prn "F - 'absolutize' handles variables in the global space"))
+
+; deref
+(prn "== deref")
+(reset)
+(= memory*.3 4)
+(when (~iso '((4 integer))
+            (deref '((3 integer-address)
+                     (deref))))
+  (prn "F - 'deref' handles simple addresses"))
+(when (~iso '((4 integer) (deref))
+            (deref '((3 integer-address)
+                     (deref)
+                     (deref))))
+  (prn "F - 'deref' deletes just one deref"))
+(= memory*.4 5)
+(when (~iso '((5 integer))
+            (deref:deref '((3 integer-address-address)
+                           (deref)
+                           (deref))))
+  (prn "F - 'deref' can be chained"))
+(when (~iso '((5 integer) (foo))
+            (deref:deref '((3 integer-address-address)
+                           (deref)
+                           (foo)
+                           (deref))))
+  (prn "F - 'deref' skips junk"))
+
+; addr
+(prn "== addr")
+(reset)
+(= routine* nil)
+;? (prn 111)
+(when (~is 4 (addr '((4 integer))))
+  (prn "F - directly addressed operands are their own address"))
+;? (quit)
+(when (~is 4 (addr '((4 integer-address))))
+  (prn "F - directly addressed operands are their own address - 2"))
+(when (~is 4 (addr '((4 literal))))
+  (prn "F - 'addr' doesn't understand literals"))
+;? (prn 201)
+(= memory*.4 23)
+;? (prn 202)
+(when (~is 23 (addr '((4 integer-address) (deref))))
+  (prn "F - 'addr' works with indirectly-addressed 'deref'"))
+;? (quit)
+(= memory*.3 4)
+(when (~is 23 (addr '((3 integer-address-address) (deref) (deref))))
+  (prn "F - 'addr' works with multiple 'deref'"))
+
+(= routine* make-routine!foo)
+(when (~is 4 (addr '((4 integer))))
+  (prn "F - directly addressed operands are their own address inside routines"))
+(when (~is 4 (addr '((4 integer-address))))
+  (prn "F - directly addressed operands are their own address inside routines - 2"))
+(when (~is 4 (addr '((4 literal))))
+  (prn "F - 'addr' doesn't understand literals inside routines"))
+(= memory*.4 23)
+(when (~is 23 (addr '((4 integer-address) (deref))))
+  (prn "F - 'addr' works with indirectly-addressed 'deref' inside routines"))
+
+;? (prn 301)
+(= rep.routine*!call-stack.0!default-space 10)
+;? (prn 302)
+(= memory*.10 5)  ; bounds check for default-space
+;? (prn 303)
+(when (~is 15 (addr '((4 integer))))
+  (prn "F - directly addressed operands in routines add default-space"))
+;? (quit)
+(when (~is 15 (addr '((4 integer-address))))
+  (prn "F - directly addressed operands in routines add default-space - 2"))
+(when (~is 15 (addr '((4 literal))))
+  (prn "F - 'addr' doesn't understand literals"))
+(= memory*.15 23)
+(when (~is 23 (addr '((4 integer-address) (deref))))
+  (prn "F - 'addr' adds default-space before 'deref', not after"))
+;? (quit)
+
+; array-len
+(prn "== array-len")
+(reset)
+(= memory*.35 4)
+(when (~is 4 (array-len '((35 integer-boolean-pair-array))))
+  (prn "F - 'array-len'"))
+(= memory*.34 35)
+(when (~is 4 (array-len '((34 integer-boolean-pair-array-address) (deref))))
+  (prn "F - 'array-len'"))
+;? (quit)
+
+; sizeof
+(prn "== sizeof")
+(reset)
+;? (set dump-trace*)
+;? (prn 401)
+(when (~is 1 (sizeof '((_ integer))))
+  (prn "F - 'sizeof' works on primitives"))
+(when (~is 1 (sizeof '((_ integer-address))))
+  (prn "F - 'sizeof' works on addresses"))
+(when (~is 2 (sizeof '((_ integer-boolean-pair))))
+  (prn "F - 'sizeof' works on and-records"))
+(when (~is 3 (sizeof '((_ integer-point-pair))))
+  (prn "F - 'sizeof' works on and-records with and-record fields"))
+
+;? (prn 410)
+(when (~is 1 (sizeof '((34 integer))))
+  (prn "F - 'sizeof' works on primitive operands"))
+(when (~is 1 (sizeof '((34 integer-address))))
+  (prn "F - 'sizeof' works on address operands"))
+(when (~is 2 (sizeof '((34 integer-boolean-pair))))
+  (prn "F - 'sizeof' works on and-record operands"))
+(when (~is 3 (sizeof '((34 integer-point-pair))))
+  (prn "F - 'sizeof' works on and-record operands with and-record fields"))
+(when (~is 2 (sizeof '((34 integer-boolean-pair-address) (deref))))
+  (prn "F - 'sizeof' works on pointers to and-records"))
+(= memory*.35 4)  ; size of array
+(= memory*.34 35)
+;? (= dump-trace* (obj whitelist '("sizeof" "array-len")))
+(when (~is 9 (sizeof '((34 integer-boolean-pair-array-address) (deref))))
+  (prn "F - 'sizeof' works on pointers to arrays"))
+;? (quit)
+
+;? (prn 420)
+(= memory*.4 23)
+(when (~is 24 (sizeof '((4 integer-array))))
+  (prn "F - 'sizeof' reads array lengths from memory"))
+(= memory*.3 4)
+(when (~is 24 (sizeof '((3 integer-array-address) (deref))))
+  (prn "F - 'sizeof' handles pointers to arrays"))
+(= memory*.15 34)
+(= routine* make-routine!foo)
+(when (~is 24 (sizeof '((4 integer-array))))
+  (prn "F - 'sizeof' reads array lengths from memory inside routines"))
+(= rep.routine*!call-stack.0!default-space 10)
+(= memory*.10 5)  ; bounds check for default-space
+(when (~is 35 (sizeof '((4 integer-array))))
+  (prn "F - 'sizeof' reads array lengths from memory using default-space"))
+(= memory*.35 4)  ; size of array
+(= memory*.15 35)
+;? (= dump-trace* (obj whitelist '("sizeof")))
+(aif rep.routine*!error (prn "error - " it))
+(when (~is 9 (sizeof '((4 integer-boolean-pair-array-address) (deref))))
+  (prn "F - 'sizeof' works on pointers to arrays using default-space"))
+;? (quit)
+
+; m
+(prn "== m")
+(reset)
+(when (~is 4 (m '((4 literal))))
+  (prn "F - 'm' avoids reading memory for literals"))
+(when (~is 4 (m '((4 offset))))
+  (prn "F - 'm' avoids reading memory for offsets"))
+(= memory*.4 34)
+(when (~is 34 (m '((4 integer))))
+  (prn "F - 'm' reads memory for simple types"))
+(= memory*.3 4)
+(when (~is 34 (m '((3 integer-address) (deref))))
+  (prn "F - 'm' redirects addresses"))
+(= memory*.2 3)
+(when (~is 34 (m '((2 integer-address-address) (deref) (deref))))
+  (prn "F - 'm' multiply redirects addresses"))
+(when (~iso (annotate 'record '(34 nil)) (m '((4 integer-boolean-pair))))
+  (prn "F - 'm' supports compound records"))
+(= memory*.5 35)
+(= memory*.6 36)
+(when (~iso (annotate 'record '(34 35 36)) (m '((4 integer-point-pair))))
+  (prn "F - 'm' supports records with compound fields"))
+(when (~iso (annotate 'record '(34 35 36)) (m '((3 integer-point-pair-address) (deref))))
+  (prn "F - 'm' supports indirect access to records"))
+(= memory*.4 2)
+(when (~iso (annotate 'record '(2 35 36)) (m '((4 integer-array))))
+  (prn "F - 'm' supports access to arrays"))
+(when (~iso (annotate 'record '(2 35 36)) (m '((3 integer-array-address) (deref))))
+  (prn "F - 'm' supports indirect access to arrays"))
+
+(= routine* make-routine!foo)
+(= memory*.10 5)  ; fake array
+(= memory*.12 34)
+(= rep.routine*!globals 10)
+(when (~iso 34 (m '((1 integer) (space global))))
+  (prn "F - 'm' supports access to per-routine globals"))
+
+; setm
+(prn "== setm")
+(reset)
+(setm '((4 integer)) 34)
+(when (~is 34 memory*.4)
+  (prn "F - 'setm' writes primitives to memory"))
+(setm '((3 integer-address)) 4)
+(when (~is 4 memory*.3)
+  (prn "F - 'setm' writes addresses to memory"))
+(setm '((3 integer-address) (deref)) 35)
+(when (~is 35 memory*.4)
+  (prn "F - 'setm' redirects writes"))
+(= memory*.2 3)
+(setm '((2 integer-address-address) (deref) (deref)) 36)
+(when (~is 36 memory*.4)
+  (prn "F - 'setm' multiply redirects writes"))
+;? (prn 505)
+(setm '((4 integer-integer-pair)) (annotate 'record '(23 24)))
+(when (~memory-contains 4 '(23 24))
+  (prn "F - 'setm' writes compound records"))
+(assert (is memory*.7 nil))
+;? (prn 506)
+(setm '((7 integer-point-pair)) (annotate 'record '(23 24 25)))
+(when (~memory-contains 7 '(23 24 25))
+  (prn "F - 'setm' writes records with compound fields"))
+(= routine* make-routine!foo)
+(setm '((4 integer-point-pair)) (annotate 'record '(33 34)))
+(when (~posmatch "incorrect size" rep.routine*!error)
+  (prn "F - 'setm' checks size of target"))
+(wipe routine*)
+(setm '((3 integer-point-pair-address) (deref)) (annotate 'record '(43 44 45)))
+(when (~memory-contains 4 '(43 44 45))
+  (prn "F - 'setm' supports indirect writes to records"))
+(setm '((2 integer-point-pair-address-address) (deref) (deref)) (annotate 'record '(53 54 55)))
+(when (~memory-contains 4 '(53 54 55))
+  (prn "F - 'setm' supports multiply indirect writes to records"))
+(setm '((4 integer-array)) (annotate 'record '(2 31 32)))
+(when (~memory-contains 4 '(2 31 32))
+  (prn "F - 'setm' writes arrays"))
+(setm '((3 integer-array-address) (deref)) (annotate 'record '(2 41 42)))
+(when (~memory-contains 4 '(2 41 42))
+  (prn "F - 'setm' supports indirect writes to arrays"))
+(= routine* make-routine!foo)
+(setm '((4 integer-array)) (annotate 'record '(2 31 32 33)))
+(when (~posmatch "invalid array" rep.routine*!error)
+  (prn "F - 'setm' checks that array written is well-formed"))
+(= routine* make-routine!foo)
+;? (prn 111)
+;? (= dump-trace* (obj whitelist '("sizeof" "mem")))
+(setm '((4 integer-boolean-pair-array)) (annotate 'record '(2 31 nil 32 nil 33)))
+(when (~posmatch "invalid array" rep.routine*!error)
+  (prn "F - 'setm' checks that array of records is well-formed"))
+(= routine* make-routine!foo)
+;? (prn 222)
+(setm '((4 integer-boolean-pair-array)) (annotate 'record '(2 31 nil 32 nil)))
+(when (posmatch "invalid array" rep.routine*!error)
+  (prn "F - 'setm' checks that array of records is well-formed - 2"))
+(wipe routine*)
+
+(reset)  ; end file with this to persist the trace for the final test
diff --git a/archive/0.vm.arc/mu.arc.t.html b/archive/0.vm.arc/mu.arc.t.html
new file mode 100644
index 00000000..dd641472
--- /dev/null
+++ b/archive/0.vm.arc/mu.arc.t.html
@@ -0,0 +1,4154 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>mu.arc.t</title>
+<meta name="Generator" content="Vim/7.4">
+<meta name="plugin-version" content="vim7.4_v1">
+<meta name="syntax" content="scheme">
+<meta name="settings" content="use_css,pre_wrap,no_foldcolumn,expand_tabs,prevent_copy=">
+<meta name="colorscheme" content="minimal">
+<style type="text/css">
+<!--
+pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #000000; }
+body { font-family: monospace; color: #aaaaaa; background-color: #000000; }
+a { color:#4444ff; }
+* { font-size: 1em; }
+.Global { color: #00af87; }
+.SalientComment { color: #00ffff; }
+.CommentedCode { color: #666666; }
+.Mu, .Mu .Normal, .Mu .Constant { color: #eeeeee; }
+.Op { color: #ff8888; }
+.Delimiter { color: #600060; }
+.Normal { color: #aaaaaa; }
+.Comment { color: #8080ff; }
+.Constant, .MuConstant { color: #008080; }
+.Identifier { color: #008080; }
+-->
+</style>
+
+<script type='text/javascript'>
+<!--
+
+-->
+</script>
+</head>
+<body>
+<pre id='vimCodeElement'>
+<span class="Comment">; Mu: An exploration on making the global structure of programs more accessible.</span>
+<span class="Comment">;</span>
+<span class="Comment">;   &quot;Is it a language, or an operating system, or a virtual machine? Mu.&quot;</span>
+<span class="Comment">;   (with apologies to Robert Pirsig: <a href="http://en.wikipedia.org/wiki/Mu_%28negative%29#In_popular_culture">http://en.wikipedia.org/wiki/Mu_%28negative%29#In_popular_culture</a>)</span>
+<span class="Comment">;</span>
+<span class="SalientComment">;; Motivation</span>
+<span class="Comment">;</span>
+<span class="Comment">; I want to live in a world where I can have an itch to tweak a program, clone</span>
+<span class="Comment">; its open-source repository, orient myself on how it's organized, and make</span>
+<span class="Comment">; the simple change I envisioned, all in an afternoon. This codebase tries to</span>
+<span class="Comment">; make this possible for its readers. (More details: <a href="http://akkartik.name/about">http://akkartik.name/about</a>)</span>
+<span class="Comment">;</span>
+<span class="Comment">; What helps comprehend the global structure of programs? For starters, let's</span>
+<span class="Comment">; enumerate what doesn't: idiomatic code, adherence to a style guide or naming</span>
+<span class="Comment">; convention, consistent indentation, API documentation for each class, etc.</span>
+<span class="Comment">; These conventional considerations improve matters in the small, but don't</span>
+<span class="Comment">; help understand global organization. They help existing programmers manage</span>
+<span class="Comment">; day-to-day operations, but they can't turn outsider programmers into</span>
+<span class="Comment">; insiders. (Elaboration: <a href="http://akkartik.name/post/readable-bad">http://akkartik.name/post/readable-bad</a>)</span>
+<span class="Comment">;</span>
+<span class="Comment">; In my experience, two things have improved matters so far: version control</span>
+<span class="Comment">; and automated tests. Version control lets me rewind back to earlier, simpler</span>
+<span class="Comment">; times when the codebase was simpler, when its core skeleton was easier to</span>
+<span class="Comment">; ascertain. Indeed, arguably what came first is by definition the skeleton of</span>
+<span class="Comment">; a program, modulo major rewrites. Once you understand the skeleton, it</span>
+<span class="Comment">; becomes tractable to 'play back' later major features one by one. (Previous</span>
+<span class="Comment">; project that fleshed out this idea: <a href="http://akkartik.name/post/wart-layers">http://akkartik.name/post/wart-layers</a>)</span>
+<span class="Comment">;</span>
+<span class="Comment">; The second and biggest boost to comprehension comes from tests. Tests are</span>
+<span class="Comment">; good for writers for well-understood reasons: they avoid regressions, and</span>
+<span class="Comment">; they can influence code to be more decoupled and easier to change. In</span>
+<span class="Comment">; addition, tests are also good for the outsider reader because they permit</span>
+<span class="Comment">; active reading. If you can't build a program and run its tests it can't help</span>
+<span class="Comment">; you understand it. It hangs limp at best, and might even be actively</span>
+<span class="Comment">; misleading. If you can run its tests, however, it comes alive. You can step</span>
+<span class="Comment">; through scenarios in a debugger. You can add logging and scan logs to make</span>
+<span class="Comment">; sense of them. You can run what-if scenarios: &quot;why is this line not written</span>
+<span class="Comment">; like this?&quot; Make a change, rerun tests: &quot;Oh, that's why.&quot; (Elaboration:</span>
+<span class="Comment">; <a href="http://akkartik.name/post/literate-programming">http://akkartik.name/post/literate-programming</a>)</span>
+<span class="Comment">;</span>
+<span class="Comment">; However, tests are only useful to the extent that they exist. Think back to</span>
+<span class="Comment">; your most recent codebase. Do you feel comfortable releasing a new version</span>
+<span class="Comment">; just because the tests pass? I'm not aware of any such project. There's just</span>
+<span class="Comment">; too many situations envisaged by the authors that were never encoded in a</span>
+<span class="Comment">; test. Even disciplined authors can't test for performance or race conditions</span>
+<span class="Comment">; or fault tolerance. If a line is phrased just so because of some subtle</span>
+<span class="Comment">; performance consideration, it's hard to communicate to newcomers.</span>
+<span class="Comment">;</span>
+<span class="Comment">; This isn't an arcane problem, and it isn't just a matter of altruism. As</span>
+<span class="Comment">; more and more such implicit considerations proliferate, and as the original</span>
+<span class="Comment">; authors are replaced by latecomers for day-to-day operations, knowledge is</span>
+<span class="Comment">; actively forgotten and lost. The once-pristine codebase turns into legacy</span>
+<span class="Comment">; code that is hard to modify without expensive and stress-inducing</span>
+<span class="Comment">; regressions.</span>
+<span class="Comment">;</span>
+<span class="Comment">; How to write tests for performance, fault tolerance, race conditions, etc.?</span>
+<span class="Comment">; How can we state and verify that a codepath doesn't ever perform memory</span>
+<span class="Comment">; allocation, or write to disk? It requires better, more observable primitives</span>
+<span class="Comment">; than we currently have. Modern operating systems have their roots in the</span>
+<span class="Comment">; 70s. Their interfaces were not designed to be testable. They provide no way</span>
+<span class="Comment">; to simulate a full disk, or a specific sequence of writes from different</span>
+<span class="Comment">; threads. We need something better.</span>
+<span class="Comment">;</span>
+<span class="Comment">; This project tries to move, groping, towards that 'something better', a</span>
+<span class="Comment">; platform that is both thoroughly tested and allows programs written for it</span>
+<span class="Comment">; to be thoroughly tested. It tries to answer the question:</span>
+<span class="Comment">;</span>
+<span class="Comment">;   If Denis Ritchie and Ken Thompson were to set out today to co-design unix</span>
+<span class="Comment">;   and C, knowing what we know about automated tests, what would they do</span>
+<span class="Comment">;   differently?</span>
+<span class="Comment">;</span>
+<span class="Comment">; To try to impose *some* constraints on this gigantic yak-shave, we'll try to</span>
+<span class="Comment">; keep both language and OS as simple as possible, focused entirely on</span>
+<span class="Comment">; permitting more kinds of tests, on first *collecting* all the information</span>
+<span class="Comment">; about implicit considerations in some form so that readers and tools can</span>
+<span class="Comment">; have at least some hope of making sense of it.</span>
+<span class="Comment">;</span>
+<span class="Comment">; The initial language will be just assembly. We'll try to make it convenient</span>
+<span class="Comment">; to program in with some simple localized rewrite rules inspired by lisp</span>
+<span class="Comment">; macros and literate programming. Programmers will have to do their own</span>
+<span class="Comment">; memory management and register allocation, but we'll provide libraries to</span>
+<span class="Comment">; help with them.</span>
+<span class="Comment">;</span>
+<span class="Comment">; The initial OS will provide just memory management and concurrency</span>
+<span class="Comment">; primitives. No users or permissions (we don't live on mainframes anymore),</span>
+<span class="Comment">; no kernel- vs user-mode, no virtual memory or process abstraction, all</span>
+<span class="Comment">; threads sharing a single address space (use VMs for security and</span>
+<span class="Comment">; sandboxing). The only use case we care about is getting a test harness to</span>
+<span class="Comment">; run some code, feed it data through blocking channels, stop it and observe</span>
+<span class="Comment">; its internals. The code under test is expected to cooperate in such testing,</span>
+<span class="Comment">; by logging important events for the test harness to observe. (More info:</span>
+<span class="Comment">; <a href="http://akkartik.name/post/tracing-tests">http://akkartik.name/post/tracing-tests</a>)</span>
+<span class="Comment">;</span>
+<span class="Comment">; The common thread here is elimination of abstractions, and it's not an</span>
+<span class="Comment">; accident. Abstractions help insiders manage the evolution of a codebase, but</span>
+<span class="Comment">; they actively hinder outsiders in understanding it from scratch. This</span>
+<span class="Comment">; matters, because the funnel to turn outsiders into insiders is critical to</span>
+<span class="Comment">; the long-term life of a codebase. Perhaps authors should raise their</span>
+<span class="Comment">; estimation of the costs of abstraction, and go against their instincts for</span>
+<span class="Comment">; introducing it. That's what I'll be trying to do: question every abstraction</span>
+<span class="Comment">; before I introduce it. We'll see how it goes.</span>
+
+<span class="Comment">; ---</span>
+
+<span class="SalientComment">;; Getting started</span>
+<span class="Comment">;</span>
+<span class="Comment">; Mu is currently built atop Racket and Arc, but this is temporary and</span>
+<span class="Comment">; contingent. We want to keep our options open, whether to port to a different</span>
+<span class="Comment">; host language, and easy to rewrite to native code for any platform. So we'll</span>
+<span class="Comment">; try to avoid 'cheating': relying on the host platform for advanced</span>
+<span class="Comment">; functionality.</span>
+<span class="Comment">;</span>
+<span class="Comment">; Other than that, we'll say no more about the code, and focus in the rest of</span>
+<span class="Comment">; this file on the scenarios the code cares about.</span>
+
+<span class="Delimiter">(</span>selective-load <span class="Constant">&quot;mu.arc&quot;</span> section-level<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">20</span>
+
+<span class="Comment">; Our language is assembly-like in that functions consist of series of</span>
+<span class="Comment">; statements, and statements consist of an operation and its arguments (input</span>
+<span class="Comment">; and output).</span>
+<span class="Comment">;</span>
+<span class="Comment">;   oarg1, oarg2, ... <span class="Op">&lt;-</span> op arg1, arg2, ...</span>
+<span class="Comment">;</span>
+<span class="Comment">; Args must be atomic, like an integer or a memory address, they can't be</span>
+<span class="Comment">; expressions doing arithmetic or function calls. But we can have any number</span>
+<span class="Comment">; of them.</span>
+<span class="Comment">;</span>
+<span class="Comment">; Since we're building on lisp, our code samples won't look quite like the</span>
+<span class="Comment">; idealized syntax above. For now they will look like this:</span>
+<span class="Comment">;</span>
+<span class="Comment">;   (function f [</span>
+<span class="Comment">;     (oarg1 oarg2 ... <span class="Op">&lt;-</span> op arg1 arg2 ...)</span>
+<span class="Comment">;     ...</span>
+<span class="Comment">;     ...</span>
+<span class="Comment">;    ])</span>
+<span class="Comment">;</span>
+<span class="Comment">; Each arg/oarg can contain metadata separated by slashes and colons. In this</span>
+<span class="Comment">; first example below, the only metadata is types: 'integer' for a memory</span>
+<span class="Comment">; location containing an integer, and 'literal' for a value included directly</span>
+<span class="Comment">; in code. (Assembly languages traditionally call them 'immediate' operands.)</span>
+<span class="Comment">; In the future a simple tool will check that the types line up as expected in</span>
+<span class="Comment">; each op. A different tool might add types where they aren't provided.</span>
+<span class="Comment">; Instead of a monolithic compiler I want to build simple, lightweight tools</span>
+<span class="Comment">; that can be combined in various ways, say for using different typecheckers</span>
+<span class="Comment">; in different subsystems.</span>
+<span class="Comment">;</span>
+<span class="Comment">; In our tests we'll define such mu functions using a call to 'add-code', so</span>
+<span class="Comment">; look for it when reading the code examples. Everything outside 'add-code' is</span>
+<span class="Comment">; just test-harness details that can be skipped at first.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">23</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'copy' writes its lone 'arg' after the instruction name to its lone 'oarg' or output arg before the arrow. After this test, the value 23 is stored in memory address 1.&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; Our basic arithmetic ops can operate on memory locations or literals.</span>
+<span class="Comment">; (Ignore hardware details like registers for now.)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;add&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'add' operates on two addresses&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;add-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> add <span class="MuConstant">2</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">5</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - ops can take 'literal' operands (but not return them)&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sub-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> subtract <span class="MuConstant">1</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">-2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'subtract'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;mul-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> multiply <span class="MuConstant">2</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">6</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'multiply'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;div-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> divide <span class="MuConstant">8</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Delimiter">(</span>/ real.8 <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'divide'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;idiv-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Constant">2</span>:integer <span class="Op">&lt;-</span> divide-with-remainder <span class="MuConstant">23</span>:literal <span class="MuConstant">6</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">3</span>  <span class="Constant">2</span> <span class="Constant">5</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'divide-with-remainder' performs integer division&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dummy-oarg&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Constant">2</span>:integer <span class="Op">&lt;-</span> divide-with-remainder <span class="MuConstant">23</span>:literal <span class="MuConstant">6</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">2</span> <span class="Constant">5</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - '_' oarg can ignore some results&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; Basic boolean operations: and, or, not</span>
+<span class="Comment">; There are easy ways to encode booleans in binary, but we'll skip past those</span>
+<span class="Comment">; details for now.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;and-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> and <span class="MuConstant">t</span>:literal <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> nil<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - logical 'and' for booleans&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; Basic comparison operations</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;lt-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> less-than <span class="MuConstant">4</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> nil<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'less-than' inequality operator&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;le-literal-false&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> lesser-or-equal <span class="MuConstant">4</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> nil<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'lesser-or-equal'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;le-literal-true&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> lesser-or-equal <span class="MuConstant">4</span>:literal <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> t<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'lesser-or-equal' returns true for equal operands&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;le-literal-true-2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> lesser-or-equal <span class="MuConstant">4</span>:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> t<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'lesser-or-equal' - 2&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; Control flow operations: jump, jump-if, jump-unless</span>
+<span class="Comment">; These introduce a new type -- 'offset' -- for literals that refer to memory</span>
+<span class="Comment">; locations relative to the current location.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;jump-skip&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">8</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">jump</span> <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; should be skipped</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">8</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'jump' skips some instructions&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;jump-target&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">8</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">jump</span> <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; should be skipped</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>  <span class="Comment">; never reached</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">8</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'jump' doesn't skip too many instructions&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;jump-if-skip&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> equal <span class="MuConstant">1</span>:literal <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">jump-if</span> <span class="Constant">1</span>:boolean <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> t  <span class="Constant">2</span> <span class="Constant">1</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'jump-if' is a conditional 'jump'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;jump-if-fallthrough&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> equal <span class="MuConstant">1</span>:literal <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">jump-if</span> <span class="Constant">3</span>:boolean <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> nil  <span class="Constant">2</span> <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - if 'jump-if's first arg is false, it doesn't skip any instructions&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;jump-if-backward&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Comment">; loop</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">2</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">jump-if</span> <span class="Constant">3</span>:boolean <span class="MuConstant">-3</span>:offset<span class="Delimiter">)</span>  <span class="Comment">; to loop</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">4</span>  <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'jump-if' can take a negative offset to make backward jumps&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;jump-label&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Identifier">loop</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">2</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">jump-if</span> <span class="Constant">3</span>:boolean <span class="Identifier">loop</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;-&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">4</span>  <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'jump-if' can take a negative offset to make backward jumps&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; Data movement relies on addressing modes:</span>
+<span class="Comment">;   'direct' - refers to a memory location; default for most types.</span>
+<span class="Comment">;   'literal' - directly encoded in the code; implicit for some types like 'offset'.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;direct-addressing&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'copy' performs direct addressing&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; 'Indirect' addressing refers to an address stored in a memory location.</span>
+<span class="Comment">; Indicated by the metadata 'deref'. Usually requires an address type.</span>
+<span class="Comment">; In the test below, the memory location 1 contains '2', so an indirect read</span>
+<span class="Comment">; of location 1 returns the value of location 2.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;indirect-addressing&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer-address <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe; can't do this in general</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="Constant">1</span>:integer-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">34</span>  <span class="Constant">3</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'copy' performs indirect addressing&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; Output args can use indirect addressing. In the test below the value is</span>
+<span class="Comment">; stored at the location stored in location 1 (i.e. location 2).</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;indirect-addressing-oarg&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer-address <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer-address/deref <span class="Op">&lt;-</span> add <span class="Constant">2</span>:integer <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">36</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - instructions can perform indirect addressing on output arg&quot;</span><span class="Delimiter">))</span>
+
+<span class="SalientComment">;; Compound data types</span>
+<span class="Comment">;</span>
+<span class="Comment">; Until now we've dealt with scalar types like integers and booleans and</span>
+<span class="Comment">; addresses, where mu looks like other assembly languages. In addition, mu</span>
+<span class="Comment">; provides first-class support for compound types: arrays and and-records.</span>
+<span class="Comment">;</span>
+<span class="Comment">; 'get' accesses fields in and-records</span>
+<span class="Comment">; 'index' accesses indices in arrays</span>
+<span class="Comment">;</span>
+<span class="Comment">; Both operations require knowledge about the types being worked on, so all</span>
+<span class="Comment">; types used in mu programs are defined in a single global system-wide table</span>
+<span class="Comment">; (see type* in mu.arc for the complete list of types; we'll add to it over</span>
+<span class="Comment">; time).</span>
+
+<span class="Comment">; first a sanity check that the table of types is consistent</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each <span class="Delimiter">(</span>typ typeinfo<span class="Delimiter">)</span> <span class="Global">type*</span>
+  <span class="Delimiter">(</span>when typeinfo!and-record
+    <span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is typeinfo!size <span class="Delimiter">(</span>len typeinfo!elems<span class="Delimiter">)))</span>
+    <span class="Delimiter">(</span>when typeinfo!fields
+      <span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is typeinfo!size <span class="Delimiter">(</span>len typeinfo!fields<span class="Delimiter">))))))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;get-record&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> get <span class="Constant">1</span>:integer-boolean-pair <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:integer-boolean-pair <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> nil  <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'get' accesses fields of and-records&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;get-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer-boolean-pair-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:boolean <span class="Op">&lt;-</span> get <span class="Constant">3</span>:integer-boolean-pair-address/deref <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">3</span>:integer-boolean-pair-address/deref <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> nil  <span class="Constant">3</span> <span class="Constant">1</span>  <span class="Constant">4</span> nil  <span class="Constant">5</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'get' accesses fields of and-record address&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;get-indirect-repeated&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">35</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">36</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer-point-pair-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer-point-pair-address-address <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer-integer-pair <span class="Op">&lt;-</span> get <span class="Constant">5</span>:integer-point-pair-address-address/deref/deref <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">5</span>:integer-point-pair-address-address/deref/deref <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">6</span> <span class="Delimiter">'(</span><span class="Constant">35</span> <span class="Constant">36</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'get' can deref multiple times&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;get-compound-field&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">35</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">36</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer-integer-pair <span class="Op">&lt;-</span> get <span class="Constant">1</span>:integer-point-pair <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> <span class="Constant">35</span>  <span class="Constant">3</span> <span class="Constant">36</span>  <span class="Constant">4</span> <span class="Constant">35</span>  <span class="Constant">5</span> <span class="Constant">36</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'get' accesses fields spanning multiple locations&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;get-address&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean-address <span class="Op">&lt;-</span> get-address <span class="Constant">1</span>:integer-boolean-pair <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> t  <span class="Constant">3</span> <span class="Constant">2</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'get-address' returns address of fields of and-records&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;get-address-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer-boolean-pair-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:boolean-address <span class="Op">&lt;-</span> get-address <span class="Constant">3</span>:integer-boolean-pair-address/deref <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> t  <span class="Constant">3</span> <span class="Constant">1</span>  <span class="Constant">4</span> <span class="Constant">2</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'get-address' accesses fields of and-record address&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;index-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer-boolean-pair <span class="Op">&lt;-</span> index <span class="Constant">1</span>:integer-boolean-pair-array <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">23</span> <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">24</span> <span class="Constant">5</span> t  <span class="Constant">6</span> <span class="Constant">24</span> <span class="Constant">7</span> t<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index' accesses indices of arrays&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;index-direct&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer-boolean-pair <span class="Op">&lt;-</span> index <span class="Constant">1</span>:integer-boolean-pair-array <span class="Constant">6</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">23</span> <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">24</span> <span class="Constant">5</span> t  <span class="Constant">6</span> <span class="Constant">1</span>  <span class="Constant">7</span> <span class="Constant">24</span> <span class="Constant">8</span> t<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index' accesses indices of arrays&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;index-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer-boolean-pair-array-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer-boolean-pair <span class="Op">&lt;-</span> index <span class="Constant">7</span>:integer-boolean-pair-array-address/deref <span class="Constant">6</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">23</span> <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">24</span> <span class="Constant">5</span> t  <span class="Constant">6</span> <span class="Constant">1</span>  <span class="Constant">7</span> <span class="Constant">1</span>  <span class="Constant">8</span> <span class="Constant">24</span> <span class="Constant">9</span> t<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index' accesses indices of array address&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;index-indirect-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">25</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">26</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer-array-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer-array-address-address <span class="Op">&lt;-</span> copy <span class="MuConstant">6</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> index <span class="Constant">7</span>:integer-array-address-address/deref/deref <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.8</span> <span class="Constant">24</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index' can deref multiple times&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;index-address&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer-boolean-pair-address <span class="Op">&lt;-</span> index-address <span class="Constant">1</span>:integer-boolean-pair-array <span class="Constant">6</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">23</span> <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">24</span> <span class="Constant">5</span> t  <span class="Constant">6</span> <span class="Constant">1</span>  <span class="Constant">7</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index-address' returns addresses of indices of arrays&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;index-address-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer-boolean-pair-array-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer-boolean-pair-address <span class="Op">&lt;-</span> index-address <span class="Constant">7</span>:integer-boolean-pair-array-address/deref <span class="Constant">6</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">2</span>  <span class="Constant">2</span> <span class="Constant">23</span> <span class="Constant">3</span> nil  <span class="Constant">4</span> <span class="Constant">24</span> <span class="Constant">5</span> t  <span class="Constant">6</span> <span class="Constant">1</span>  <span class="Constant">7</span> <span class="Constant">1</span>  <span class="Constant">8</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index-address' returns addresses of indices of array addresses&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; Array values know their length. Record lengths are saved in the types table.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;len-array&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> length <span class="Constant">1</span>:integer-boolean-pair-array<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.6</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'length' of array&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;len-array-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> length <span class="Constant">6</span>:integer-boolean-pair-array-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.7</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'length' of array address&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; 'sizeof' is a helper to determine the amount of memory required by a type.</span>
+<span class="Comment">; Only for non-arrays.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sizeof-record&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> sizeof integer-boolean-pair:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' returns space required by arg&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sizeof-record-not-len&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> sizeof integer-point-pair:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>is <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' is different from number of elems&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; Regardless of a type's length, you can move it around just like a primitive.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;copy-record&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer-boolean-pair <span class="Op">&lt;-</span> copy <span class="Constant">1</span>:integer-boolean-pair<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> nil  <span class="Constant">3</span> <span class="Constant">34</span>  <span class="Constant">4</span> nil<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - ops can operate on records spanning multiple locations&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;copy-record2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">35</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">36</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer-point-pair <span class="Op">&lt;-</span> copy <span class="Constant">1</span>:integer-point-pair<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;sizeof&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> <span class="Constant">35</span>  <span class="Constant">3</span> <span class="Constant">36</span>
+                       <span class="Comment">; result</span>
+                       <span class="Constant">4</span> <span class="Constant">34</span>  <span class="Constant">5</span> <span class="Constant">35</span>  <span class="Constant">6</span> <span class="Constant">36</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - ops can operate on records with fields spanning multiple locations&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 20</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">100</span>
+
+<span class="Comment">; A special kind of record is the 'tagged type'. It lets us represent</span>
+<span class="Comment">; dynamically typed values, which save type information in memory rather than</span>
+<span class="Comment">; in the code to use them. This will let us do things like create heterogenous</span>
+<span class="Comment">; lists containing both integers and strings. Tagged values admit two</span>
+<span class="Comment">; operations:</span>
+<span class="Comment">;</span>
+<span class="Comment">;   'save-type' - turns a regular value into a tagged-value of the appropriate type</span>
+<span class="Comment">;   'maybe-coerce' - turns a tagged value into a regular value if the type matches</span>
+<span class="Comment">;</span>
+<span class="Comment">; The payload of a tagged value must occupy just one location. Save pointers</span>
+<span class="Comment">; to records.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;tagged-value&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:type <span class="Op">&lt;-</span> copy integer:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Constant">4</span>:boolean <span class="Op">&lt;-</span> maybe-coerce <span class="Constant">1</span>:tagged-value integer:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn completed-routines*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.4</span> t<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'maybe-coerce' copies value only if type tag matches&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;tagged-value-2&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:type <span class="Op">&lt;-</span> copy integer-address:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Constant">4</span>:boolean <span class="Op">&lt;-</span> maybe-coerce <span class="Constant">1</span>:tagged-value boolean:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">0</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.4</span> nil<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'maybe-coerce' doesn't copy value when type tag doesn't match&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;save-type&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj  <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> <span class="Delimiter">'</span>integer  <span class="Constant">3</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'save-type' saves the type of a value at runtime, turning it into a tagged-value&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;init-tagged-value&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value integer:literal <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Constant">4</span>:boolean <span class="Op">&lt;-</span> maybe-coerce <span class="Constant">2</span>:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;cvt0&quot; &quot;cvt1&quot; &quot;sizeof&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.4</span> t<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'init-tagged-value' is the converse of 'maybe-coerce'&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; Now that we can package values together with their types, we can construct a</span>
+<span class="Comment">; dynamically typed list.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;list&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Comment">; 1 points at first node: tagged-value (int 34)</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:list-address <span class="Op">&lt;-</span> new list:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value-address <span class="Op">&lt;-</span> list-value-address <span class="Constant">1</span>:list-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:type-address <span class="Op">&lt;-</span> get-address <span class="Constant">2</span>:tagged-value-address/deref type:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:type-address/deref <span class="Op">&lt;-</span> copy integer:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:location <span class="Op">&lt;-</span> get-address <span class="Constant">2</span>:tagged-value-address/deref payload:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:location/deref <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:list-address-address <span class="Op">&lt;-</span> get-address <span class="Constant">1</span>:list-address/deref cdr:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:list-address-address/deref <span class="Op">&lt;-</span> new list:literal<span class="Delimiter">)</span></span>
+      <span class="Comment">; 6 points at second node: tagged-value (boolean t)</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:list-address <span class="Op">&lt;-</span> copy <span class="Constant">5</span>:list-address-address/deref<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:tagged-value-address <span class="Op">&lt;-</span> list-value-address <span class="Constant">6</span>:list-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:type-address <span class="Op">&lt;-</span> get-address <span class="Constant">7</span>:tagged-value-address/deref type:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:type-address/deref <span class="Op">&lt;-</span> copy boolean:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">9</span>:location <span class="Op">&lt;-</span> get-address <span class="Constant">7</span>:tagged-value-address/deref payload:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">9</span>:location/deref <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">10</span>:list-address <span class="Op">&lt;-</span> get <span class="Constant">6</span>:list-address/deref <span class="MuConstant">1</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> first rep.routine!alloc
+<span class="CommentedCode">;?     (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="CommentedCode">;?     (set dump-trace*)</span>
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+      <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~all first <span class="Delimiter">(</span>map <span class="Global">memory*</span> <span class="Delimiter">'(</span><span class="Constant">1</span> <span class="Constant">2</span> <span class="Constant">3</span><span class="Delimiter">)))</span>
+            <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.first  <span class="Delimiter">'</span>integer<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Delimiter">(</span>+ first <span class="Constant">1</span><span class="Delimiter">))</span>
+            <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ first <span class="Constant">1</span><span class="Delimiter">))</span>  <span class="Constant">34</span><span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.5</span> <span class="Delimiter">(</span>+ first <span class="Constant">2</span><span class="Delimiter">))</span>
+            <span class="Delimiter">(</span><span class="Normal">let</span> second <span class="Global">memory*</span><span class="Constant">.6</span>
+              <span class="Delimiter">(</span><span class="Normal">or</span>
+                <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ first <span class="Constant">2</span><span class="Delimiter">))</span> second<span class="Delimiter">)</span>
+                <span class="Delimiter">(</span>~all second <span class="Delimiter">(</span>map <span class="Global">memory*</span> <span class="Delimiter">'(</span><span class="Constant">6</span> <span class="Constant">7</span> <span class="Constant">8</span><span class="Delimiter">)))</span>
+                <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.second <span class="Delimiter">'</span>boolean<span class="Delimiter">)</span>
+                <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.9</span> <span class="Delimiter">(</span>+ second <span class="Constant">1</span><span class="Delimiter">))</span>
+                <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ second <span class="Constant">1</span><span class="Delimiter">))</span> t<span class="Delimiter">)</span>
+                <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.10</span> nil<span class="Delimiter">))))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - lists can contain elements of different types&quot;</span><span class="Delimiter">))))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">10</span>:list-address <span class="Op">&lt;-</span> list-next <span class="Constant">1</span>:list-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>test2<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.10</span> <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'list-next can move a list pointer to the next node&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; 'init-list' takes a variable number of args and constructs a list containing</span>
+<span class="Comment">; them. Just integers for now.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;init-list&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> init-list <span class="MuConstant">3</span>:literal <span class="MuConstant">4</span>:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;cvt0&quot; &quot;cvt1&quot; &quot;sizeof&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> first <span class="Global">memory*</span><span class="Constant">.1</span>
+<span class="CommentedCode">;?   (prn first)</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.first  <span class="Delimiter">'</span>integer<span class="Delimiter">)</span>
+          <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ first <span class="Constant">1</span><span class="Delimiter">))</span>  <span class="Constant">3</span><span class="Delimiter">)</span>
+          <span class="Delimiter">(</span><span class="Normal">let</span> second <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ first <span class="Constant">2</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;?             (prn second)</span>
+            <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.second <span class="Delimiter">'</span>integer<span class="Delimiter">)</span>
+                <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ second <span class="Constant">1</span><span class="Delimiter">))</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+                <span class="Delimiter">(</span><span class="Normal">let</span> third <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ second <span class="Constant">2</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;?                   (prn third)</span>
+                  <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.third <span class="Delimiter">'</span>integer<span class="Delimiter">)</span>
+                      <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ third <span class="Constant">1</span><span class="Delimiter">))</span> <span class="Constant">5</span><span class="Delimiter">)</span>
+                      <span class="Delimiter">(</span>~is <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ third <span class="Constant">2</span><span class="Delimiter">)</span> nil<span class="Delimiter">)))))))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'init-list' can construct a list of integers&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 100</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">20</span>
+
+<span class="SalientComment">;; Functions</span>
+<span class="Comment">;</span>
+<span class="Comment">; Just like the table of types is centralized, functions are conceptualized as</span>
+<span class="Comment">; a centralized table of operations just like the &quot;primitives&quot; we've seen so</span>
+<span class="Comment">; far. If you create a function you can call it like any other op.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - calling a user-defined function runs its instructions&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-once&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">2</span> <span class="Global">curr-cycle*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - calling a user-defined function runs its instructions exactly once &quot;</span> <span class="Global">curr-cycle*</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; User-defined functions communicate with their callers through two</span>
+<span class="Comment">; primitives:</span>
+<span class="Comment">;</span>
+<span class="Comment">;   'arg' - to access inputs</span>
+<span class="Comment">;   'reply' - to return outputs</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-reply&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'reply' stops executing the current function&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-reply-nested&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> test2<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function test2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">2</span> <span class="Constant">34</span>  <span class="Constant">3</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'reply' stops executing any callers as necessary&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-reply-once&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">5</span> <span class="Global">curr-cycle*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'reply' executes instructions exactly once &quot;</span> <span class="Global">curr-cycle*</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;reply-increments-caller-pc&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function callee <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function caller <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>freeze <span class="Global">function*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> <span class="Delimiter">(</span>make-routine <span class="Delimiter">'</span>caller<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Constant">0</span> pc.routine*<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>push-stack <span class="Global">routine*</span> <span class="Delimiter">'</span>callee<span class="Delimiter">)</span>  <span class="Comment">; pretend call was at first instruction of caller</span>
+<span class="Delimiter">(</span>run-for-time-slice <span class="Constant">1</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> pc.routine*<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'reply' should increment pc in caller (to move past calling instruction)&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-sequential&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">4</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span>
+                       <span class="Comment">; test1's temporaries</span>
+                       <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">5</span> <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' accesses in order the operands of the most recent function call (the caller)&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-random-access&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">input</span> <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">input</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">4</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; should never run</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span>
+                       <span class="Comment">; test's temporaries</span>
+                       <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">5</span> <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' with index can access function call arguments out of order&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-random-then-sequential&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Op">&lt;-</span> <span class="Identifier">input</span> <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span>  <span class="Comment">; takes next arg after index 1</span></span>
+     <span class="Delimiter">])</span>  <span class="Comment">; should never run</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="MuConstant">1</span>:literal <span class="MuConstant">2</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' with index resets index for later calls&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-status&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">5</span> t<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' sets a second oarg when arg exists&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-missing&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">4</span> <span class="Constant">1</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - missing 'arg' doesn't cause error&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-missing-2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">6</span> nil<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - missing 'arg' wipes second oarg when provided&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-missing-3&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+    <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+    <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">6</span> nil<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - missing 'arg' consistently wipes its oarg&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-missing-4&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Comment">; if given two args, adds them; if given one arg, increments</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-if</span> <span class="Constant">6</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      }
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">4</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">4</span> <span class="Constant">34</span>  <span class="Constant">5</span> <span class="Constant">1</span>  <span class="Constant">6</span> nil  <span class="Constant">7</span> <span class="Constant">35</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - function with optional second arg&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-arg-by-value&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; overwrite caller memory</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>  <span class="Comment">; arg not clobbered</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">0</span>  <span class="Constant">2</span> <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' passes by value&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;arg-record&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer-boolean-pair <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="Constant">1</span>:integer-boolean-pair<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> nil  <span class="Constant">4</span> <span class="Constant">34</span>  <span class="Constant">5</span> nil<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' can copy records spanning multiple locations&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;arg-record-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer-boolean-pair <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer-boolean-pair-address <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>test1 <span class="Constant">3</span>:integer-boolean-pair-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">34</span>  <span class="Constant">2</span> nil  <span class="Constant">3</span> <span class="Constant">1</span>  <span class="Constant">4</span> <span class="Constant">34</span>  <span class="Constant">5</span> nil<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'arg' can copy records spanning multiple locations in indirect mode&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-reply-oarg&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">4</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">6</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> test1 <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span>
+                       <span class="Comment">; test1's temporaries</span>
+                       <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">5</span> <span class="Constant">3</span>  <span class="Constant">6</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'reply' can take aguments that are returned, or written back into output args of caller&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-reply-oarg-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">4</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">6</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Constant">7</span>:integer <span class="Op">&lt;-</span> test1 <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span>    <span class="Constant">7</span> <span class="Constant">3</span>
+                         <span class="Comment">; test1's temporaries</span>
+                         <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">5</span> <span class="Constant">3</span>  <span class="Constant">6</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'reply' permits a function to return multiple values at once&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-fn-prepare-reply&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">4</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>prepare-reply <span class="Constant">6</span>:integer <span class="Constant">5</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Constant">7</span>:integer <span class="Op">&lt;-</span> test1 <span class="Constant">1</span>:integer <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">1</span>  <span class="Constant">2</span> <span class="Constant">3</span>  <span class="Constant">3</span> <span class="Constant">4</span>    <span class="Constant">7</span> <span class="Constant">3</span>
+                         <span class="Comment">; test1's temporaries</span>
+                         <span class="Constant">4</span> <span class="Constant">1</span>  <span class="Constant">5</span> <span class="Constant">3</span>  <span class="Constant">6</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - without args, 'reply' returns values from previous 'prepare-reply'.&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 20</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">11</span>
+
+<span class="SalientComment">;; Structured programming</span>
+<span class="Comment">;</span>
+<span class="Comment">; Our jump operators are quite inconvenient to use, so mu provides a</span>
+<span class="Comment">; lightweight tool called 'convert-braces' to work in a slightly more</span>
+<span class="Comment">; convenient format with nested braces:</span>
+<span class="Comment">;</span>
+<span class="Comment">;   {</span>
+<span class="Comment">;     some instructions</span>
+<span class="Comment">;     {</span>
+<span class="Comment">;       more instructions</span>
+<span class="Comment">;     }</span>
+<span class="Comment">;   }</span>
+<span class="Comment">;</span>
+<span class="Comment">; Braces are like labels in assembly language, they require no special</span>
+<span class="Comment">; parsing. The operations 'loop' and 'break' jump to just after the enclosing</span>
+<span class="Comment">; '{' and '}' respectively.</span>
+<span class="Comment">;</span>
+<span class="Comment">; Conditional and unconditional 'loop' and 'break' should give us 80% of the</span>
+<span class="Comment">; benefits of the control-flow primitives we're used to in other languages,</span>
+<span class="Comment">; like 'if', 'while', 'for', etc.</span>
+<span class="Comment">;</span>
+<span class="Comment">; Compare 'unquoted blocks' using {} with 'quoted blocks' using [] that we've</span>
+<span class="Comment">; gotten used to seeing. Quoted blocks are used by top-level instructions to</span>
+<span class="Comment">; provide code without running it.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;c{0&quot; &quot;c{1&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>  <span class="Comment">; 'begin' is just a hack because racket turns braces into parens</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>not-equal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">3</span> integer<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break-if</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">4</span> boolean<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>not-equal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">3</span> integer<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump-if</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces replaces break-if with a jump-if to after the next close-brace&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-empty-block&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;c{0&quot; &quot;c{1&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">)))</span></span>
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces works for degenerate blocks&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-nested-break&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>not-equal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">3</span> integer<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break-if</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">4</span> boolean<span class="Delimiter">)))</span></span>
+                { <span class="CommentedCode">begin</span>
+                  <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                }
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>not-equal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">3</span> integer<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump-if</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces balances braces when converting break&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-repeated-jump&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;c{0&quot; &quot;c{1&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              }
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces handles jumps on jumps&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-nested-loop&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                { <span class="CommentedCode">begin</span>
+                  <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>not-equal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">3</span> integer<span class="Delimiter">)))</span></span>
+                }
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">loop-if</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">4</span> boolean<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>not-equal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">3</span> integer<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump-if</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">4</span> boolean<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">-3</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">reply</span><span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces balances braces when converting 'loop'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-label&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              foo
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            foo
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces skips past labels&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-label-increments-offset&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">)))</span></span>
+                foo
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span>
+            foo
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces treats labels as instructions&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-braces-label-increments-offset2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;c{0&quot; &quot;c{1&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">)))</span></span>
+                foo
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              }
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            foo
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-braces treats labels as instructions - 2&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;break-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;-&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                { <span class="CommentedCode">begin</span>
+                  <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">break</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">2</span> blocks<span class="Delimiter">)))</span></span>
+                }
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              }<span class="Delimiter">))</span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">4</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'break' can take an extra arg with number of nested blocks to exit&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;loop&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">loop</span><span class="Delimiter">)))</span></span>
+              }<span class="Delimiter">))</span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">-2</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'loop' jumps to start of containing block&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; todo: fuzz-test invariant: convert-braces offsets should be robust to any</span>
+<span class="Comment">; number of inner blocks inside but not around the loop block.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;loop-nested&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                { <span class="CommentedCode">begin</span>
+                  <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                }
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">loop</span><span class="Delimiter">)))</span></span>
+              }<span class="Delimiter">))</span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">-3</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'loop' correctly jumps back past nested braces&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;loop-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;-&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-braces
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              { <span class="CommentedCode">begin</span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+                { <span class="CommentedCode">begin</span>
+                  <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">loop</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">2</span> blocks<span class="Delimiter">)))</span></span>
+                }
+              }<span class="Delimiter">))</span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">-3</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'loop' can take an extra arg with number of nested blocks to exit&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-labels&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-labels
+            <span class="Mu"><span class="Delimiter">'(</span><span class="Identifier">loop</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Identifier">loop</span> offset<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'(</span><span class="Identifier">loop</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Identifier">jump</span><span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">-2</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'convert-labels' rewrites jumps to labels&quot;</span><span class="Delimiter">))</span>
+
+<span class="SalientComment">;; Variables</span>
+<span class="Comment">;</span>
+<span class="Comment">; A big convenience high-level languages provide is the ability to name memory</span>
+<span class="Comment">; locations. In mu, a lightweight tool called 'convert-names' provides this</span>
+<span class="Comment">; convenience.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>z integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names renames symbolic names to integer locations&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-compound&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Comment">; copying 0 into pair is meaningless; just for testing</span>
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer-boolean-pair<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names increments integer locations by the size of the type of the previous var&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-nil&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Comment">; nil location is meaningless; just for testing</span>
+              <span class="Mu"><span class="Delimiter">(((</span>nil integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span>nil integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names never renames nil&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-string&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer-address<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>new<span class="Delimiter">))</span> <span class="Constant">&quot;foo&quot;</span><span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer-address<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>new<span class="Delimiter">))</span> <span class="Constant">&quot;foo&quot;</span><span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;convert-names passes through raw strings (just a convenience arg for 'new')&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-raw&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>raw<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>raw<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names never renames raw operands&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Comment">; meaningless; just for testing</span>
+            <span class="Mu"><span class="Delimiter">'((((</span>x literal<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span>x literal<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names never renames literals&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-literal-2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span>x literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span>x literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names never renames literals, even when the name matches a variable&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; kludgy support for 'fork' below</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-functions&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Comment">; meaningless; just for testing</span>
+              <span class="Mu"><span class="Delimiter">(((</span>z fn<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span>z fn<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names never renames fns&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-record-fields&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;cn0&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">34</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span>bool offset<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">34</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names replaces record field offsets&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-record-fields-ambiguous&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>errsafe <span class="Delimiter">(</span>convert-names
+               <span class="Mu"><span class="Delimiter">'((((</span>bool boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">t</span> literal<span class="Delimiter">)))</span></span>
+                 <span class="Mu"><span class="Delimiter">(((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">34</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span>bool offset<span class="Delimiter">))))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names doesn't allow offsets and variables with the same name in a function&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-record-fields-ambiguous-2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>errsafe <span class="Delimiter">(</span>convert-names
+               <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">34</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span>bool offset<span class="Delimiter">)))</span></span>
+                 <span class="Mu"><span class="Delimiter">(((</span>bool boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">t</span> literal<span class="Delimiter">))))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names doesn't allow offsets and variables with the same name in a function - 2&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-record-fields-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;cn0&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">34</span> integer-boolean-pair-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Delimiter">((</span>bool offset<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">34</span> integer-boolean-pair-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names replaces field offsets for record addresses&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-record-fields-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">2</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span>bool offset<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span>bool offset<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">2</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">3</span> boolean<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>get<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer-boolean-pair<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">1</span> offset<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names replaces field offsets with multiple mentions&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-label&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+              foo<span class="Delimiter">))</span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            foo<span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names skips past labels&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 11</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">20</span>
+
+<span class="Comment">; A rudimentary memory allocator. Eventually we want to write this in mu.</span>
+<span class="Comment">;</span>
+<span class="Comment">; No deallocation yet; let's see how much code we can build in mu before we</span>
+<span class="Comment">; feel the need for it.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-primitive&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer-address <span class="Op">&lt;-</span> new integer:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+<span class="CommentedCode">;?     (set dump-trace*)</span>
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.1</span> before<span class="Delimiter">)</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' returns current high-water mark&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso rep.routine!alloc <span class="Delimiter">(</span>+ before <span class="Constant">1</span><span class="Delimiter">))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' on primitive types increments high-water mark by their size&quot;</span><span class="Delimiter">))))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-array-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:type-array-address <span class="Op">&lt;-</span> new type-array:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.1</span> before<span class="Delimiter">)</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' on array with literal size returns current high-water mark&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso rep.routine!alloc <span class="Delimiter">(</span>+ before <span class="Constant">6</span><span class="Delimiter">))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' on primitive arrays increments high-water mark by their size&quot;</span><span class="Delimiter">))))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;new-array-direct&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:type-array-address <span class="Op">&lt;-</span> new type-array:literal <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.2</span> before<span class="Delimiter">)</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' on array with variable size returns current high-water mark&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso rep.routine!alloc <span class="Delimiter">(</span>+ before <span class="Constant">6</span><span class="Delimiter">))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' on primitive arrays increments high-water mark by their (variable) size&quot;</span><span class="Delimiter">))))</span>
+
+<span class="Comment">; Even though our memory locations can now have names, the names are all</span>
+<span class="Comment">; globals, accessible from any function. To isolate functions from their</span>
+<span class="Comment">; callers we need local variables, and mu provides them using a special</span>
+<span class="Comment">; variable called default-space. When you initialize such a variable (likely</span>
+<span class="Comment">; with a call to our just-defined memory allocator) mu interprets memory</span>
+<span class="Comment">; locations as offsets from its value. If default-space is set to 1000, for</span>
+<span class="Comment">; example, reads and writes to memory location 1 will really go to 1001.</span>
+<span class="Comment">;</span>
+<span class="Comment">; 'default-space' is itself hard-coded to be function-local; it's nil in a new</span>
+<span class="Comment">; function, and it's restored when functions return to their callers. But the</span>
+<span class="Comment">; actual space allocation is independent. So you can define closures, or do</span>
+<span class="Comment">; even more funky things like share locals between two coroutines.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;set-default-space&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+<span class="CommentedCode">;?     (set dump-trace*)</span>
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~and <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Global">memory*</span><span class="Constant">.1</span><span class="Delimiter">)</span>
+              <span class="Delimiter">(</span>is <span class="Constant">23</span> <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ before <span class="Constant">2</span><span class="Delimiter">))))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - default-space implicitly modifies variable locations&quot;</span><span class="Delimiter">))))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;set-default-space-skips-offset&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+<span class="CommentedCode">;?     (set dump-trace*)</span>
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~and <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Global">memory*</span><span class="Constant">.1</span><span class="Delimiter">)</span>
+              <span class="Delimiter">(</span>is <span class="Constant">23</span> <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ before <span class="Constant">2</span><span class="Delimiter">))))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - default-space skips 'offset' types just like literals&quot;</span><span class="Delimiter">))))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;default-space-bounds-check&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine <span class="Delimiter">(</span>car <span class="Global">completed-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>no rep.routine!error<span class="Delimiter">)</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - default-space checks bounds&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;default-space-and-get-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer-boolean-pair-address <span class="Op">&lt;-</span> new integer-boolean-pair:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer-address <span class="Op">&lt;-</span> get-address <span class="Constant">1</span>:integer-boolean-pair-address/deref <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer-address/deref <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer/raw <span class="Op">&lt;-</span> get <span class="Constant">1</span>:integer-boolean-pair-address/deref <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="CommentedCode">;? (prn completed-routines*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">34</span> <span class="Global">memory*</span><span class="Constant">.3</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - indirect 'get' works in the presence of default-space&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;default-space-and-index-indirect&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer-array-address <span class="Op">&lt;-</span> new integer-array:literal <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer-address <span class="Op">&lt;-</span> index-address <span class="Constant">1</span>:integer-array-address/deref <span class="MuConstant">2</span>:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer-address/deref <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer/raw <span class="Op">&lt;-</span> index <span class="Constant">1</span>:integer-array-address/deref <span class="MuConstant">2</span>:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;array-info&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="CommentedCode">;? (prn completed-routines*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">34</span> <span class="Global">memory*</span><span class="Constant">.3</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - indirect 'index' works in the presence of default-space&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-names-default-space&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-names
+            <span class="Mu"><span class="Delimiter">'((((</span>x integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">4</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Mu"><span class="Delimiter">(((</span>y integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">2</span> literal<span class="Delimiter">)))</span></span>
+              <span class="Comment">; unsafe in general; don't write random values to 'default-space'</span>
+              <span class="Mu"><span class="Delimiter">(((</span>default-space integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>add<span class="Delimiter">))</span> <span class="Delimiter">((</span>x integer<span class="Delimiter">))</span> <span class="Delimiter">((</span>y integer<span class="Delimiter">)))))</span></span>
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">4</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">2</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span>default-space integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>add<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="Constant">2</span> integer<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-names never renames default-space&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;suppress-default-space&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer/raw <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+<span class="CommentedCode">;?     (set dump-trace*)</span>
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+<span class="CommentedCode">;?     (prn memory*)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~and <span class="Delimiter">(</span>is <span class="Constant">23</span> <span class="Global">memory*</span><span class="Constant">.1</span><span class="Delimiter">)</span>
+              <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ before <span class="Constant">1</span><span class="Delimiter">))))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - default-space skipped for locations with metadata 'raw'&quot;</span><span class="Delimiter">))))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;array-copy-indirect-scoped&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">10</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; pretend allocation</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> copy <span class="MuConstant">10</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; raw location 12</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer-boolean-pair-array-address <span class="Op">&lt;-</span> copy <span class="MuConstant">12</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer-boolean-pair-array <span class="Op">&lt;-</span> copy <span class="Constant">6</span>:integer-boolean-pair-array-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;m&quot; &quot;sizeof&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.18</span> <span class="Constant">2</span><span class="Delimiter">)</span>  <span class="Comment">; variable 7</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - indirect array copy in the presence of 'default-space'&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;len-array-indirect-scoped&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">10</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; pretend allocation</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> copy <span class="MuConstant">10</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; raw location 12</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> copy <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer-address <span class="Op">&lt;-</span> copy <span class="MuConstant">12</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; unsafe</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> length <span class="Constant">6</span>:integer-boolean-pair-array-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;addr&quot; &quot;sz&quot; &quot;array-len&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.18</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'len' accesses length of array address&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;default-space-shared&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function init-counter <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; initialize to 3</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> default-space:space-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function increment-counter <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; increment</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:space-address <span class="Op">&lt;-</span> init-counter<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> increment-counter <span class="Constant">1</span>:space-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> increment-counter <span class="Constant">1</span>:space-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">5</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - multiple calls to a function can share locals&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;default-space-closure&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function init-counter <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; initialize to 3</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> default-space:space-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function increment-counter <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">0</span>:space-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span>  <span class="Comment">; share outer space</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer/space:1 <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer/space:1 <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; increment</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; dummy</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">1</span>:integer/space:1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:space-address <span class="Op">&lt;-</span> init-counter<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> increment-counter <span class="Constant">1</span>:space-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> increment-counter <span class="Constant">1</span>:space-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">5</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - multiple calls to a function can share locals&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;default-space-closure-with-names&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function init-counter <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>x:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>y:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; correct copy of y</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> default-space:space-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function increment-counter <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">0</span>:space-address/names:init-counter <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span>  <span class="Comment">; outer space must be created by 'init-counter' above</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>y:integer/space:1 <span class="Op">&lt;-</span> add y:integer/space:1 <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; increment</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>y:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; dummy</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> y:integer/space:1<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:space-address/names:init-counter <span class="Op">&lt;-</span> init-counter<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> increment-counter <span class="Constant">1</span>:space-address/names:init-counter<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> increment-counter <span class="Constant">1</span>:space-address/names:init-counter<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">5</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - multiple calls to a function can share locals&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 20</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">100</span>
+
+<span class="SalientComment">;; Dynamic dispatch</span>
+<span class="Comment">;</span>
+<span class="Comment">; Putting it all together, here's how you define generic functions that run</span>
+<span class="Comment">; different code based on the types of their args.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dispatch-clause&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Comment">; doesn't matter too much how many locals you allocate space for (here 20)</span>
+      <span class="Comment">; if it's slightly too many -- memory is plentiful</span>
+      <span class="Comment">; if it's too few -- mu will raise an error</span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">20</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>first-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Comment">; if given integers, add them</span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span>first-arg:integer match?:boolean <span class="Op">&lt;-</span> maybe-coerce first-arg-box:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> match?:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg:integer <span class="Op">&lt;-</span> maybe-coerce second-arg-box:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>result:integer <span class="Op">&lt;-</span> add first-arg:integer second-arg:integer<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> result:integer<span class="Delimiter">)</span></span>
+      }
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value integer:literal <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value integer:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> test1 <span class="Constant">1</span>:tagged-value-address <span class="Constant">2</span>:tagged-value-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">37</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - an example function that checks that its oarg is an integer&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dispatch-multiple-clauses&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">20</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>first-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Comment">; if given integers, add them</span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span>first-arg:integer match?:boolean <span class="Op">&lt;-</span> maybe-coerce first-arg-box:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> match?:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg:integer <span class="Op">&lt;-</span> maybe-coerce second-arg-box:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>result:integer <span class="Op">&lt;-</span> add first-arg:integer second-arg:integer<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> result:integer<span class="Delimiter">)</span></span>
+      }
+      <span class="Comment">; if given booleans, or them (it's a silly kind of generic function)</span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span>first-arg:boolean match?:boolean <span class="Op">&lt;-</span> maybe-coerce first-arg-box:tagged-value-address/deref boolean:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> match?:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg:boolean <span class="Op">&lt;-</span> maybe-coerce second-arg-box:tagged-value-address/deref boolean:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>result:boolean <span class="Op">&lt;-</span> or first-arg:boolean second-arg:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> result:integer<span class="Delimiter">)</span></span>
+      }
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value boolean:literal <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value boolean:literal <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> test1 <span class="Constant">1</span>:tagged-value-address <span class="Constant">2</span>:tagged-value-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (each stmt function*!test-fn</span>
+<span class="CommentedCode">;?   (prn &quot;  &quot; stmt))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (wipe dump-trace*)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.3</span> t<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - an example function that can do different things (dispatch) based on the type of its args or oargs&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dispatch-multiple-calls&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">20</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>first-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Comment">; if given integers, add them</span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span>first-arg:integer match?:boolean <span class="Op">&lt;-</span> maybe-coerce first-arg-box:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> match?:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg:integer <span class="Op">&lt;-</span> maybe-coerce second-arg-box:tagged-value-address/deref integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>result:integer <span class="Op">&lt;-</span> add first-arg:integer second-arg:integer<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> result:integer<span class="Delimiter">)</span></span>
+      }
+      <span class="Comment">; if given booleans, or them (it's a silly kind of generic function)</span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span>first-arg:boolean match?:boolean <span class="Op">&lt;-</span> maybe-coerce first-arg-box:tagged-value-address/deref boolean:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> match?:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg-box:tagged-value-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>second-arg:boolean <span class="Op">&lt;-</span> maybe-coerce second-arg-box:tagged-value-address/deref boolean:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span>result:boolean <span class="Op">&lt;-</span> or first-arg:boolean second-arg:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> result:integer<span class="Delimiter">)</span></span>
+      }
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value boolean:literal <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value boolean:literal <span class="MuConstant">nil</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> test1 <span class="Constant">1</span>:tagged-value-address <span class="Constant">2</span>:tagged-value-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">10</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value integer:literal <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">11</span>:tagged-value-address <span class="Op">&lt;-</span> init-tagged-value integer:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">12</span>:integer <span class="Op">&lt;-</span> test1 <span class="Constant">10</span>:tagged-value-address <span class="Constant">11</span>:tagged-value-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~and <span class="Delimiter">(</span>is <span class="Global">memory*</span><span class="Constant">.3</span> t<span class="Delimiter">)</span> <span class="Delimiter">(</span>is <span class="Global">memory*</span><span class="Constant">.12</span> <span class="Constant">37</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - different calls can exercise different clauses of the same function&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; We can also dispatch based on the type of the operands or results at the</span>
+<span class="Comment">; caller.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dispatch-otype&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:type <span class="Op">&lt;-</span> otype <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">4</span>:type integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> <span class="Constant">5</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">6</span>:integer <span class="Constant">7</span>:integer<span class="Delimiter">)</span></span>
+      }
+      <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">8</span>:integer<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> test1 <span class="MuConstant">1</span>:literal <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - an example function that checks that its oarg is an integer&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dispatch-otype-multiple-clauses&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:type <span class="Op">&lt;-</span> otype <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Comment">; integer needed? add args</span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">4</span>:type integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> <span class="Constant">5</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">6</span>:integer <span class="Constant">7</span>:integer<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">8</span>:integer<span class="Delimiter">)</span></span>
+      }
+      { <span class="CommentedCode">begin</span>
+        <span class="Comment">; boolean needed? 'or' args</span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">4</span>:type boolean:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> <span class="Constant">5</span>:boolean <span class="MuConstant">4</span>:offset<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:boolean <span class="Op">&lt;-</span> or <span class="Constant">6</span>:boolean <span class="Constant">7</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">8</span>:boolean<span class="Delimiter">)</span></span>
+      }<span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> test1 <span class="MuConstant">t</span>:literal <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (each stmt function*!test1</span>
+<span class="CommentedCode">;?   (prn &quot;  &quot; stmt))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (wipe dump-trace*)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.1</span> t<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - an example function that can do different things (dispatch) based on the type of its args or oargs&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;dispatch-otype-multiple-calls&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function test1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:type <span class="Op">&lt;-</span> otype <span class="MuConstant">0</span>:offset<span class="Delimiter">)</span></span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">4</span>:type integer:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> <span class="Constant">5</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">6</span>:integer <span class="Constant">7</span>:integer<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">8</span>:integer<span class="Delimiter">)</span></span>
+      }
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> equal <span class="Constant">4</span>:type boolean:literal<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">break-unless</span> <span class="Constant">5</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:boolean <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:boolean <span class="Op">&lt;-</span> or <span class="Constant">6</span>:boolean <span class="Constant">7</span>:boolean<span class="Delimiter">)</span></span>
+        <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="Constant">8</span>:boolean<span class="Delimiter">)</span></span>
+      }<span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:boolean <span class="Op">&lt;-</span> test1 <span class="MuConstant">t</span>:literal <span class="MuConstant">t</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> test1 <span class="MuConstant">3</span>:literal <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~and <span class="Delimiter">(</span>is <span class="Global">memory*</span><span class="Constant">.1</span> t<span class="Delimiter">)</span> <span class="Delimiter">(</span>is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">7</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - different calls can exercise different clauses of the same function&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 100</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">20</span>
+
+<span class="SalientComment">;; Concurrency</span>
+<span class="Comment">;</span>
+<span class="Comment">; A rudimentary process scheduler. You can 'run' multiple functions at once,</span>
+<span class="Comment">; and they share the virtual processor.</span>
+<span class="Comment">;</span>
+<span class="Comment">; There's also a 'fork' primitive to let functions create new threads of</span>
+<span class="Comment">; execution (we call them routines).</span>
+<span class="Comment">;</span>
+<span class="Comment">; Eventually we want to allow callers to influence how much of their CPU they</span>
+<span class="Comment">; give to their 'children', or to rescind a child's running privileges.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1 <span class="Delimiter">'</span>f2<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>when <span class="Delimiter">(</span>~iso <span class="Constant">2</span> <span class="Global">curr-cycle*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler didn't run the right number of instructions: &quot;</span> <span class="Global">curr-cycle*</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span> <span class="Delimiter">(</span>obj <span class="Constant">1</span> <span class="Constant">3</span>  <span class="Constant">2</span> <span class="Constant">4</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler runs multiple functions: &quot;</span> <span class="Global">memory*</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>check-trace-contents <span class="Constant">&quot;scheduler orders functions correctly&quot;</span>
+  <span class="Delimiter">'((</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;f1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;f2&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">))</span>
+<span class="Delimiter">(</span>check-trace-contents <span class="Constant">&quot;scheduler orders schedule and run events correctly&quot;</span>
+  <span class="Delimiter">'((</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;f1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;f2&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 0&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-alternate&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>= <span class="Global">scheduling-interval*</span> <span class="Constant">1</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1 <span class="Delimiter">'</span>f2<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>check-trace-contents <span class="Constant">&quot;scheduler alternates between routines&quot;</span>
+  <span class="Delimiter">'((</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 1&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-sleep&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Comment">; add one baseline routine to run (empty running-routines* handled below)</span>
+<span class="Delimiter">(</span>enq make-routine!f1 <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">))</span>
+<span class="Comment">; sleeping routine</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f2
+  <span class="Mu"><span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>for-some-cycles <span class="Constant">23</span><span class="Delimiter">))</span></span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; not yet time for it to wake up</span>
+<span class="Delimiter">(</span>= <span class="Global">curr-cycle*</span> <span class="Constant">23</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler lets routines sleep&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-wakeup&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Comment">; add one baseline routine to run (empty running-routines* handled below)</span>
+<span class="Delimiter">(</span>enq make-routine!f1 <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">))</span>
+<span class="Comment">; sleeping routine</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f2
+  <span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>for-some-cycles <span class="Constant">23</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; time for it to wake up</span>
+<span class="Delimiter">(</span>= <span class="Global">curr-cycle*</span> <span class="Constant">24</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">2</span> len.running-routines*<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler wakes up sleeping routines at the right time&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-sleep-location&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Comment">; add one baseline routine to run (empty running-routines* handled below)</span>
+<span class="Delimiter">(</span>enq make-routine!f1 <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">))</span>
+<span class="Comment">; blocked routine waiting for location 23 to change</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f2
+  <span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>until-location-changes <span class="Constant">23</span> <span class="Constant">0</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; leave memory location 23 unchanged</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.23</span> <span class="Constant">0</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="CommentedCode">;? (prn running-routines*)</span>
+<span class="CommentedCode">;? (prn sleeping-routines*)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn running-routines*)</span>
+<span class="CommentedCode">;? (prn sleeping-routines*)</span>
+<span class="Comment">; routine remains blocked</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler lets routines block on locations&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-wakeup-location&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Comment">; add one baseline routine to run (empty running-routines* handled below)</span>
+<span class="Delimiter">(</span>enq make-routine!f1 <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">))</span>
+<span class="Comment">; blocked routine waiting for location 23 to change</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f2
+  <span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>until-location-changes <span class="Constant">23</span> <span class="Constant">0</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; change memory location 23</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.23</span> <span class="Constant">1</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="Comment">; routine unblocked</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">2</span> len.running-routines*<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler unblocks routines blocked on locations&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-skip&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Comment">; running-routines* is empty</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>empty <span class="Global">running-routines*</span><span class="Delimiter">))</span>
+<span class="Comment">; sleeping routine</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f1
+  <span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>for-some-cycles <span class="Constant">34</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; long time left for it to wake up</span>
+<span class="Delimiter">(</span>= <span class="Global">curr-cycle*</span> <span class="Constant">0</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Global">curr-cycle*</span> <span class="Constant">35</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> len.running-routines*<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler skips ahead to earliest sleeping routines when nothing to run&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-deadlock&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>empty <span class="Global">running-routines*</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>empty <span class="Global">completed-routines*</span><span class="Delimiter">))</span>
+<span class="Comment">; blocked routine</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f1
+  <span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>until-location-changes <span class="Constant">23</span> <span class="Constant">0</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; location it's waiting on is 'unchanged'</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.23</span> <span class="Constant">0</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>~empty <span class="Global">completed-routines*</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (prn completed-routines*)</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine <span class="Global">completed-routines*</span><span class="Constant">.0</span>
+  <span class="Delimiter">(</span>when <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;deadlock&quot;</span> rep.routine!error<span class="Delimiter">)</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler detects deadlock&quot;</span><span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;scheduler-deadlock2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Comment">; running-routines* is empty</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>empty <span class="Global">running-routines*</span><span class="Delimiter">))</span>
+<span class="Comment">; blocked routine</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!f1
+  <span class="Delimiter">(</span>= rep.routine!sleep <span class="Delimiter">'(</span>until-location-changes <span class="Constant">23</span> <span class="Constant">0</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>set <span class="Global">sleeping-routines*</span>.routine<span class="Delimiter">))</span>
+<span class="Comment">; but is about to become ready</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.23</span> <span class="Constant">1</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>update-scheduler-state<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>when <span class="Delimiter">(</span>~empty <span class="Global">completed-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - scheduler ignores sleeping but ready threads when detecting deadlock&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sleep&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>sleep for-some-cycles:literal <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1 <span class="Delimiter">'</span>f2<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>check-trace-contents <span class="Constant">&quot;scheduler handles sleeping routines&quot;</span>
+  <span class="Delimiter">'((</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;sleeping until 2&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;pushing f1 to sleep queue&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;waking up f1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 2&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sleep-long&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>sleep for-some-cycles:literal <span class="MuConstant">20</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1 <span class="Delimiter">'</span>f2<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>check-trace-contents <span class="Constant">&quot;scheduler progresses sleeping routines when there are no routines left to run&quot;</span>
+  <span class="Delimiter">'((</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;sleeping until 21&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;pushing f1 to sleep queue&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 0&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f2 1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;schedule&quot;</span> <span class="Constant">&quot;waking up f1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 1&quot;</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Constant">&quot;run&quot;</span> <span class="Constant">&quot;f1 2&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sleep-location&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Comment">; waits for memory location 1 to be set, before computing its successor</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>sleep until-location-changes:literal <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>sleep for-some-cycles:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; set to value</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1 <span class="Delimiter">'</span>f2<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn int-canon.memory*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>  <span class="Comment">; successor of value</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - sleep can block on a memory location&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;sleep-scoped-location&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Comment">; waits for memory location 1 to be changed, before computing its successor</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">10</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; array of locals</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> copy <span class="MuConstant">10</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; really location 12</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>sleep until-location-changes:literal <span class="Constant">1</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> add <span class="Constant">1</span>:integer <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>sleep for-some-cycles:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">12</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; set to value</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1 <span class="Delimiter">'</span>f2<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.13</span> <span class="Constant">4</span><span class="Delimiter">)</span>  <span class="Comment">; successor of value</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - sleep can block on a scoped memory location&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;fork&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>fork f2:fn<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - fork works&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;fork-with-args&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>fork f2:fn <span class="MuConstant">nil</span>:literal <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - fork can pass args&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;fork-copies-args&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>x:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>fork f2:fn <span class="MuConstant">nil</span>:literal x:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>x:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; should be ignored</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f2 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>f1<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - fork passes args by value&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;fork-global&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer/raw <span class="Op">&lt;-</span> copy <span class="Constant">2</span>:integer/space:global<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>fork f1:fn default-space:space-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>awhen rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">memory*</span><span class="Constant">.1</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - fork can take a space of global variables to access&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; The scheduler needs to keep track of the call stack for each routine.</span>
+<span class="Comment">; Eventually we'll want to save this information in mu's address space itself,</span>
+<span class="Comment">; along with the types array, the magic buffers for args and oargs, and so on.</span>
+<span class="Comment">;</span>
+<span class="Comment">; Eventually we want the right stack-management primitives to build delimited</span>
+<span class="Comment">; continuations in mu.</span>
+
+<span class="Comment">; Routines can throw errors.</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;array-bounds-check&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">23</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> index <span class="Constant">1</span>:integer-array <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine <span class="Delimiter">(</span>car <span class="Global">completed-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>no rep.routine!error<span class="Delimiter">)</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'index' throws an error if out of bounds&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 20</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">100</span>
+
+<span class="SalientComment">;; Synchronization</span>
+<span class="Comment">;</span>
+<span class="Comment">; Mu synchronizes using channels rather than locks, like Erlang and Go.</span>
+<span class="Comment">;</span>
+<span class="Comment">; The two ends of a channel will usually belong to different routines, but</span>
+<span class="Comment">; each end should only be used by a single one. Don't try to read from or</span>
+<span class="Comment">; write to it from multiple routines at once.</span>
+<span class="Comment">;</span>
+<span class="Comment">; To avoid locking, writer and reader will never write to the same location.</span>
+<span class="Comment">; So channels will include fields in pairs, one for the writer and one for the</span>
+<span class="Comment">; reader.</span>
+
+<span class="Comment">; The core circular buffer contains values at index 'first-full' up to (but</span>
+<span class="Comment">; not including) index 'first-empty'. The reader always modifies it at</span>
+<span class="Comment">; first-full, while the writer always modifies it at first-empty.</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-new&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-full:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-free:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Constant">0</span> <span class="Global">memory*</span><span class="Constant">.2</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Constant">0</span> <span class="Global">memory*</span><span class="Constant">.3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'init-channel' initializes 'first-full and 'first-free to 0&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-write&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-full:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-free:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (prn function*!write)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;array-len&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;jump&quot;)))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;reply&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (prn canon.memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Constant">0</span> <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'write' enqueues item to channel&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-read&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:tagged-value <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> maybe-coerce <span class="Constant">5</span>:tagged-value integer:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-full:offset<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">9</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-free:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;array-len&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn int-canon.memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.7</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'read' returns written value&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Global">memory*</span><span class="Constant">.8</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Global">memory*</span><span class="Constant">.9</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'read' dequeues item from channel&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-write-wrap&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Comment">; channel with 1 slot</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Comment">; write a value</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Comment">; first-free will now be 1</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-free:offset<span class="Delimiter">)</span></span>
+      <span class="Comment">; read one value</span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+      <span class="Comment">; write a second value; verify that first-free wraps around to 0.</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-free:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;array-len&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn canon.memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Constant">0</span> <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'write' can wrap pointer back to start&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-read-wrap&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Comment">; channel with 1 slot</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Comment">; write a value</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Comment">; read one value</span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+      <span class="Comment">; first-full will now be 1</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-full:offset<span class="Delimiter">)</span></span>
+      <span class="Comment">; write a second value</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Comment">; read second value; verify that first-full wraps around to 0.</span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> get <span class="Constant">1</span>:channel-address/deref first-full:offset<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj blacklist '(&quot;sz&quot; &quot;m&quot; &quot;setm&quot; &quot;addr&quot; &quot;array-len&quot; &quot;cvt0&quot; &quot;cvt1&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn canon.memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is <span class="Constant">0</span> <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'read' can wrap pointer back to start&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-new-empty-not-full&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:boolean <span class="Op">&lt;-</span> empty? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:boolean <span class="Op">&lt;-</span> full? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is t <span class="Global">memory*</span><span class="Constant">.2</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.3</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - a new channel is always empty, never full&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-write-not-empty&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> empty? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> full? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - a channel after writing is never empty&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-write-full&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> empty? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> full? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is t <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - a channel after writing may be full&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-read-not-full&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> empty? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> full? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - a channel after reading is never full&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-read-empty&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>_ <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:boolean <span class="Op">&lt;-</span> empty? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:boolean <span class="Op">&lt;-</span> full? <span class="Constant">1</span>:channel-address/deref<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is t <span class="Global">memory*</span><span class="Constant">.5</span><span class="Delimiter">)</span>
+        <span class="Delimiter">(</span>~is nil <span class="Global">memory*</span><span class="Constant">.6</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - a channel after reading may be empty&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; The key property of channels; writing to a full channel blocks the current</span>
+<span class="Comment">; routine until it creates space. Ditto reading from an empty channel.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-read-block&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Comment">; channel is empty, but receives a read</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:tagged-value <span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn int-canon.memory*)</span>
+<span class="CommentedCode">;? (prn sleeping-routines*)</span>
+<span class="CommentedCode">;? (prn completed-routines*)</span>
+<span class="Comment">; read should cause the routine to sleep, and</span>
+<span class="Comment">; the sole sleeping routine should trigger the deadlock detector</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine <span class="Delimiter">(</span>car <span class="Global">completed-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>when <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>no routine<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>no rep.routine!error<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;deadlock&quot;</span> rep.routine!error<span class="Delimiter">))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'read' on empty channel blocks (puts the routine to sleep until the channel gets data)&quot;</span><span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-write-block&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">1</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">34</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:tagged-value <span class="Op">&lt;-</span> save-type <span class="Constant">2</span>:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+      <span class="Comment">; channel has capacity 1, but receives a second write</span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address <span class="Constant">3</span>:tagged-value<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;schedule&quot; &quot;addr&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn int-canon.memory*)</span>
+<span class="CommentedCode">;? (prn running-routines*)</span>
+<span class="CommentedCode">;? (prn sleeping-routines*)</span>
+<span class="CommentedCode">;? (prn completed-routines*)</span>
+<span class="Comment">; second write should cause the routine to sleep, and</span>
+<span class="Comment">; the sole sleeping routine should trigger the deadlock detector</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine <span class="Delimiter">(</span>car <span class="Global">completed-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>when <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>no routine<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>no rep.routine!error<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;deadlock&quot;</span> rep.routine!error<span class="Delimiter">))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'write' on full channel blocks (puts the routine to sleep until the channel gets data)&quot;</span><span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-handoff&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function consumer <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>chan:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; create a channel</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>fork producer:fn <span class="MuConstant">nil</span>:literal chan:channel-address<span class="Delimiter">)</span>  <span class="Comment">; fork a routine to produce a value in it</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:tagged-value/raw <span class="Op">&lt;-</span> read chan:channel-address<span class="Delimiter">)</span>  <span class="Comment">; wait for input on channel</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function producer <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>n:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>ochan:channel-address <span class="Op">&lt;-</span> <span class="Identifier">next-input</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>x:tagged-value <span class="Op">&lt;-</span> save-type n:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>ochan:channel-address/deref <span class="Op">&lt;-</span> write ochan:channel-address x:tagged-value<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;schedule&quot; &quot;run&quot; &quot;addr&quot;)))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;-&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>consumer<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">24</span> <span class="Global">memory*</span><span class="Constant">.2</span><span class="Delimiter">)</span>  <span class="Comment">; location 1 contains tagged-value x above</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - channels are meant to be shared between routines&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;channel-handoff-routine&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function consumer <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address <span class="Op">&lt;-</span> init-channel <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span>  <span class="Comment">; create a channel</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>fork producer:fn default-space:space-address<span class="Delimiter">)</span>  <span class="Comment">; pass it as a global to another routine</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:tagged-value/raw <span class="Op">&lt;-</span> read <span class="Constant">1</span>:channel-address<span class="Delimiter">)</span>  <span class="Comment">; wait for input on channel</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function producer <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>n:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">24</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span>x:tagged-value <span class="Op">&lt;-</span> save-type n:integer<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:channel-address/space:global/deref <span class="Op">&lt;-</span> write <span class="Constant">1</span>:channel-address/space:global x:tagged-value<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>consumer<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">24</span> <span class="Global">memory*</span><span class="Constant">.2</span><span class="Delimiter">)</span>  <span class="Comment">; location 1 contains tagged-value x above</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - channels are meant to be shared between routines&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 100</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">10</span>
+
+<span class="SalientComment">;; Separating concerns</span>
+<span class="Comment">;</span>
+<span class="Comment">; Lightweight tools can also operate on quoted lists of statements surrounded</span>
+<span class="Comment">; by square brackets. In the example below, we mimic Go's 'defer' keyword</span>
+<span class="Comment">; using 'convert-quotes'. It lets us write code anywhere in a function, but</span>
+<span class="Comment">; have it run just before the function exits. Great for keeping code to</span>
+<span class="Comment">; reclaim memory or other resources close to the code to allocate it. (C++</span>
+<span class="Comment">; programmers know this as RAII.) We'll use 'defer' when we build a memory</span>
+<span class="Comment">; deallocation routine like C's 'free'.</span>
+<span class="Comment">;</span>
+<span class="Comment">; More powerful reorderings are also possible like in Literate Programming or</span>
+<span class="Comment">; Aspect-Oriented Programming; one advantage of prohibiting arbitrarily nested</span>
+<span class="Comment">; code is that we can naturally name 'join points' wherever we want.</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-quotes-defer&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-quotes
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span>defer <span class="Delimiter">[</span></span>
+                       <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">6</span>:literal<span class="Delimiter">)</span></span>
+                     <span class="Delimiter">])</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">5</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">6</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-quotes can handle 'defer'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-quotes-defer-reply&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-quotes
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span>defer <span class="Delimiter">[</span></span>
+                       <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                     <span class="Delimiter">])</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-quotes inserts code at early exits&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-quotes-defer-reply-arg&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-quotes
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span>defer <span class="Delimiter">[</span></span>
+                       <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                     <span class="Delimiter">])</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span> <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span>prepare-reply <span class="MuConstant">2</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Identifier">reply</span><span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-quotes inserts code at early exits&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;convert-quotes-label&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>convert-quotes
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+              foo
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">5</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+            foo
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">5</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - convert-quotes can handle labels&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>before label1 <span class="Delimiter">[</span></span>
+     <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+    <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">before*</span>!label1<span class="Delimiter">)</span>
+          <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+            <span class="Delimiter">(</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'before' records fragments of code to insert before labels&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert fragments before labels&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>before label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>before label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">before*</span>!label1<span class="Delimiter">)</span>
+          <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+            <span class="Delimiter">(</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))</span></span>
+            <span class="Delimiter">(</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'before' records fragments in order&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert multiple fragments in order before label&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-scoped&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>before f/label1 <span class="Delimiter">[</span>  <span class="Comment">; label1 only inside function f</span></span>
+     <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+    <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))</span></span>
+            <span class="Delimiter">'</span>f<span class="Delimiter">)</span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert fragments before labels just in specified functions&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-scoped2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>before f/label1 <span class="Delimiter">[</span>  <span class="Comment">; label1 only inside function f</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' ignores labels not in specified functions&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;after&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">after*</span>!label1<span class="Delimiter">)</span>
+          <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+            <span class="Delimiter">(</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'after' records fragments of code to insert after labels&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert fragments after labels&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;after-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">after*</span>!label1<span class="Delimiter">)</span>
+          <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+            <span class="Delimiter">(</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))</span></span>
+            <span class="Delimiter">(</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'after' records fragments in *reverse* order&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert multiple fragments in order after label&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-after&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>before label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">and</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">before*</span>!label1<span class="Delimiter">)</span>
+               <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+                 <span class="Delimiter">(</span>
+                   <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))))</span></span>
+         <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">after*</span>!label1<span class="Delimiter">)</span>
+               <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+                 <span class="Delimiter">(</span>
+                   <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'before' and 'after' fragments work together&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert multiple fragments around label&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-after-multiple&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>before label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>before label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">before*</span>!label1<span class="Delimiter">)</span>
+              <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+                <span class="Delimiter">(</span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))</span></span>
+                <span class="Delimiter">(</span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))))</span></span>
+        <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>as cons <span class="Global">after*</span>!label1<span class="Delimiter">)</span>
+              <span class="Delimiter">'(</span><span class="Comment">; fragment</span>
+                <span class="Delimiter">(</span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">))</span></span>
+                <span class="Delimiter">(</span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - multiple 'before' and 'after' fragments at once&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>insert-code
+            <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+              <span class="Mu">label1</span>
+              <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+          <span class="Mu"><span class="Delimiter">'((</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu">label1</span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">6</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">7</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+            <span class="Mu"><span class="Delimiter">(</span><span class="Constant">8</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'insert-code' can insert multiple fragments around label - 2&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-after-independent&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span><span class="Normal">do</span>
+            <span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>add-code
+              <span class="Mu"><span class="Delimiter">'((</span>before label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])</span>
+                <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])</span>
+                <span class="Mu"><span class="Delimiter">(</span>before label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])</span>
+                <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])))</span>
+            <span class="Delimiter">(</span>list <span class="Global">before*</span>!label1 <span class="Global">after*</span>!label1<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span><span class="Normal">do</span>
+            <span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>add-code
+              <span class="Mu"><span class="Delimiter">'((</span>before label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])</span>
+                <span class="Mu"><span class="Delimiter">(</span>before label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])</span>
+                <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])</span>
+                <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+                  <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+                 <span class="Delimiter">])))</span>
+            <span class="Delimiter">(</span>list <span class="Global">before*</span>!label1 <span class="Global">after*</span>!label1<span class="Delimiter">)))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - order matters between 'before' and between 'after' fragments, but not *across* 'before' and 'after' fragments&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-after-braces&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">function*</span> <span class="Delimiter">(</span>table<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>after label1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f1 <span class="Delimiter">[</span></span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu">label1</span>
+      }
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;cn0&quot;)))</span>
+<span class="Delimiter">(</span>freeze <span class="Global">function*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">function*</span>!f1
+          <span class="Mu"><span class="Delimiter">'(</span>label1</span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - before/after works inside blocks&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;before-after-any-order&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">function*</span> <span class="Delimiter">(</span>table<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      { <span class="CommentedCode">begin</span>
+        <span class="Mu">label1</span>
+      }
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>after label1 <span class="Delimiter">[</span></span>
+       <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>freeze <span class="Global">function*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">function*</span>!f1
+          <span class="Mu"><span class="Delimiter">'(</span>label1</span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - before/after can come after the function they need to modify&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;multiple-defs&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">function*</span> <span class="Delimiter">(</span>table<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>freeze <span class="Global">function*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">function*</span>!f1
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))</span></span>
+            <span class="Mu"><span class="Delimiter">(((</span><span class="Constant">1</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - multiple 'def' of the same function add clauses&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;def!&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">traces*</span> <span class="Delimiter">(</span>queue<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">function*</span> <span class="Delimiter">(</span>table<span class="Delimiter">))</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])</span>
+    <span class="Mu"><span class="Delimiter">(</span>function! f1 <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> copy <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>freeze <span class="Global">function*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">function*</span>!f1
+          <span class="Mu"><span class="Delimiter">'((((</span><span class="Constant">2</span> integer<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>copy<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">0</span> literal<span class="Delimiter">)))))</span></span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'def!' clears all previous clauses&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 10</span>
+
+<span class="SalientComment">;; ---</span>
+
+<span class="Delimiter">(</span>section <span class="Constant">100</span>  <span class="Comment">; string utilities</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-new&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new string:literal <span class="MuConstant">5</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso rep.routine!alloc <span class="Delimiter">(</span>+ before <span class="Constant">5</span> <span class="Constant">1</span><span class="Delimiter">))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' allocates arrays of bytes for strings&quot;</span><span class="Delimiter">))))</span>
+
+<span class="Comment">; Convenience: initialize strings using string literals</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-literal&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;hello&quot;</span><span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> routine make-routine!main
+  <span class="Delimiter">(</span>enq routine <span class="Global">running-routines*</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span><span class="Normal">let</span> before rep.routine!alloc
+<span class="CommentedCode">;?     (set dump-trace*)</span>
+<span class="CommentedCode">;?     (= dump-trace* (obj whitelist '(&quot;schedule&quot; &quot;run&quot; &quot;addr&quot;)))</span>
+    <span class="Delimiter">(</span>run<span class="Delimiter">)</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso rep.routine!alloc <span class="Delimiter">(</span>+ before <span class="Constant">5</span> <span class="Constant">1</span><span class="Delimiter">))</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' allocates arrays of bytes for string literals&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array before <span class="Constant">&quot;hello&quot;</span><span class="Delimiter">)</span>
+      <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'new' initializes allocated memory to string literal&quot;</span><span class="Delimiter">))))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;strcat&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;hello,&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot; world!&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:string-address <span class="Op">&lt;-</span> strcat <span class="Constant">1</span>:string-address <span class="Constant">2</span>:string-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">&quot;hello, world!&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'strcat' concatenates strings&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;interpolate&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;hello, _!&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:string-address <span class="Op">&lt;-</span> interpolate <span class="Constant">1</span>:string-address <span class="Constant">2</span>:string-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">&quot;hello, abc!&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'interpolate' splices strings&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;interpolate-empty&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;hello!&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:string-address <span class="Op">&lt;-</span> interpolate <span class="Constant">1</span>:string-address <span class="Constant">2</span>:string-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">&quot;hello!&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'interpolate' without underscore returns template&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;interpolate-at-start&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;_, hello!&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:string-address <span class="Op">&lt;-</span> interpolate <span class="Constant">1</span>:string-address <span class="Constant">2</span>:string-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">&quot;abc, hello&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'interpolate' splices strings at start&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;interpolate-at-end&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;hello, _&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:string-address <span class="Op">&lt;-</span> interpolate <span class="Constant">1</span>:string-address <span class="Constant">2</span>:string-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">&quot;hello, abc&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'interpolate' splices strings at start&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;interpolate-varargs&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;hello, _, _, and _!&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">3</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;def&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">4</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;ghi&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">5</span>:string-address <span class="Op">&lt;-</span> interpolate <span class="Constant">1</span>:string-address <span class="Constant">2</span>:string-address <span class="Constant">3</span>:string-address <span class="Constant">4</span>:string-address<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot; &quot;array-info&quot;)))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (quit)</span>
+<span class="CommentedCode">;? (up i 1 (+ 1 (memory* memory*.5))</span>
+<span class="CommentedCode">;?   (prn (memory* (+ memory*.5 i))))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains-array <span class="Global">memory*</span><span class="Constant">.5</span> <span class="Constant">&quot;hello, abc, def, and ghi!&quot;</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'interpolate' splices in any number of strings&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;a/b&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">1</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' finds first location of a character&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-empty&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">0</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' finds first location of a character&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-initial&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;/abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">0</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' handles prefix match&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-final&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc/&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*.2)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">3</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' handles suffix match&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-missing&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn memory*.2)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">3</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' handles no match&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-invalid-index&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">4</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="CommentedCode">;? (prn memory*.2)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' skips invalid index (past end of string)&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-first&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;ab/c/&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">0</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' finds first of multiple options&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-find-next-second&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;ab/c/&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:integer <span class="Op">&lt;-</span> find-next <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">))</span> <span class="MuConstant">3</span>:literal<span class="Delimiter">)</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'find-next' finds second of multiple options&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-split&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;a/b&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address-array-address <span class="Op">&lt;-</span> split <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">)))</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> base <span class="Global">memory*</span><span class="Constant">.2</span>
+<span class="CommentedCode">;?   (prn base &quot; &quot; memory*.base)</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.base <span class="Constant">2</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;?           (do1 nil prn.111)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">1</span><span class="Delimiter">))</span> <span class="Constant">&quot;a&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;?           (do1 nil prn.111)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">2</span><span class="Delimiter">))</span> <span class="Constant">&quot;b&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'split' cuts string at delimiter&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-split2&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;a/b/c&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address-array-address <span class="Op">&lt;-</span> split <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">)))</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> base <span class="Global">memory*</span><span class="Constant">.2</span>
+<span class="CommentedCode">;?   (prn base &quot; &quot; memory*.base)</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.base <span class="Constant">3</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;?           (do1 nil prn.111)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">1</span><span class="Delimiter">))</span> <span class="Constant">&quot;a&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;?           (do1 nil prn.111)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">2</span><span class="Delimiter">))</span> <span class="Constant">&quot;b&quot;</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;?           (do1 nil prn.111)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">3</span><span class="Delimiter">))</span> <span class="Constant">&quot;c&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'split' cuts string at two delimiters&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-split-missing&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address-array-address <span class="Op">&lt;-</span> split <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">)))</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> base <span class="Global">memory*</span><span class="Constant">.2</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.base <span class="Constant">1</span><span class="Delimiter">)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">1</span><span class="Delimiter">))</span> <span class="Constant">&quot;abc&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'split' handles missing delimiter&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-split-empty&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address-array-address <span class="Op">&lt;-</span> split <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">)))</span></span>
+     <span class="Delimiter">])))</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;run&quot;)))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> base <span class="Global">memory*</span><span class="Constant">.2</span>
+<span class="CommentedCode">;?   (prn base &quot; &quot; memory*.base)</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.base <span class="Constant">0</span><span class="Delimiter">)</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'split' handles empty string&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;string-split-empty-piece&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Mu"><span class="Delimiter">'((</span>function main <span class="Delimiter">[</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">1</span>:string-address <span class="Op">&lt;-</span> new <span class="Constant">&quot;a/b//c&quot;</span><span class="Delimiter">)</span></span>
+      <span class="Mu"><span class="Delimiter">(</span><span class="Constant">2</span>:string-address-array-address <span class="Op">&lt;-</span> split <span class="Constant">1</span>:string-address <span class="Delimiter">((</span><span class="MuConstant">#\/</span> literal<span class="Delimiter">)))</span></span>
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span>run <span class="Delimiter">'</span>main<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>each routine <span class="Global">completed-routines*</span>
+  <span class="Delimiter">(</span>aif rep.routine!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">let</span> base <span class="Global">memory*</span><span class="Constant">.2</span>
+  <span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span><span class="Normal">or</span> <span class="Delimiter">(</span>~is <span class="Global">memory*</span>.base <span class="Constant">4</span><span class="Delimiter">)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">1</span><span class="Delimiter">))</span> <span class="Constant">&quot;a&quot;</span><span class="Delimiter">)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">2</span><span class="Delimiter">))</span> <span class="Constant">&quot;b&quot;</span><span class="Delimiter">)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">3</span><span class="Delimiter">))</span> <span class="Constant">&quot;&quot;</span><span class="Delimiter">)</span>
+          <span class="Delimiter">(</span>~memory-contains-array <span class="Delimiter">(</span><span class="Global">memory*</span> <span class="Delimiter">(</span>+ base <span class="Constant">4</span><span class="Delimiter">))</span> <span class="Constant">&quot;c&quot;</span><span class="Delimiter">))</span>
+    <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'split' cuts string at two delimiters&quot;</span><span class="Delimiter">)))</span>
+
+<span class="Delimiter">)</span>  <span class="Comment">; section 100 for string utilities</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>new-trace <span class="Constant">&quot;parse-and-record&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>add-code
+  <span class="Delimiter">'((</span>and-record foo <span class="Delimiter">[</span>
+      x:string
+      y:integer
+      z:boolean
+     <span class="Delimiter">])))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Global">type*</span>!foo <span class="Delimiter">(</span>obj size <span class="Constant">3</span>  and-record t  elems <span class="Delimiter">'((</span>string<span class="Delimiter">)</span> <span class="Delimiter">(</span>integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>boolean<span class="Delimiter">))</span>  <span class="Normal">fields</span> <span class="Delimiter">'(</span>x y z<span class="Delimiter">)))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'add-code' can add new and-records&quot;</span><span class="Delimiter">))</span>
+
+<span class="SalientComment">;; unit tests for various helpers</span>
+
+<span class="Comment">; tokenize-args</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== tokenize-args&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>assert:iso <span class="Delimiter">'((</span>a b<span class="Delimiter">)</span> <span class="Delimiter">(</span>c d<span class="Delimiter">))</span>
+            <span class="Delimiter">(</span>tokenize-arg <span class="Delimiter">'</span>a:b/c:d<span class="Delimiter">))</span>
+<span class="Comment">; numbers are not symbols</span>
+<span class="Delimiter">(</span>assert:iso <span class="Delimiter">'((</span>a b<span class="Delimiter">)</span> <span class="Delimiter">(</span><span class="Constant">1</span> d<span class="Delimiter">))</span>
+            <span class="Delimiter">(</span>tokenize-arg <span class="Delimiter">'</span>a:b/1:d<span class="Delimiter">))</span>
+<span class="Comment">; special symbols are skipped</span>
+<span class="Mu"><span class="Delimiter">(</span>assert:iso <span class="Delimiter">'</span><span class="Op">&lt;-</span></span>
+            <span class="Mu"><span class="Delimiter">(</span>tokenize-arg <span class="Delimiter">'</span><span class="Op">&lt;-</span><span class="Delimiter">))</span></span>
+<span class="Delimiter">(</span>assert:iso <span class="Delimiter">'</span>_
+            <span class="Delimiter">(</span>tokenize-arg <span class="Delimiter">'</span>_<span class="Delimiter">))</span>
+
+<span class="Comment">; idempotent</span>
+<span class="Delimiter">(</span>assert:iso <span class="Delimiter">(</span>tokenize-arg:tokenize-arg <span class="Delimiter">'</span>a:b/c:d<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>tokenize-arg              <span class="Delimiter">'</span>a:b/c:d<span class="Delimiter">))</span>
+
+<span class="Comment">; support labels</span>
+<span class="Mu"><span class="Delimiter">(</span>assert:iso <span class="Delimiter">'((((</span>default-space space-address<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>new<span class="Delimiter">))</span> <span class="Delimiter">((</span>space literal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">30</span> literal<span class="Delimiter">)))</span></span>
+              foo<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>tokenize-args
+              <span class="Mu"><span class="Delimiter">'((</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+                foo<span class="Delimiter">)))</span>
+
+<span class="Comment">; support braces</span>
+<span class="Mu"><span class="Delimiter">(</span>assert:iso <span class="Delimiter">'((((</span>default-space space-address<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>new<span class="Delimiter">))</span> <span class="Delimiter">((</span>space literal<span class="Delimiter">))</span> <span class="Delimiter">((</span><span class="MuConstant">30</span> literal<span class="Delimiter">)))</span></span>
+              foo
+              { <span class="CommentedCode">begin</span>
+                bar
+                <span class="Mu"><span class="Delimiter">(((</span>a b<span class="Delimiter">))</span> <span class="Op">&lt;-</span> <span class="Delimiter">((</span>op<span class="Delimiter">))</span> <span class="Delimiter">((</span>c d<span class="Delimiter">))</span> <span class="Delimiter">((</span>e f<span class="Delimiter">)))</span></span>
+              }<span class="Delimiter">)</span>
+            <span class="Delimiter">(</span>tokenize-args
+              <span class="Mu"><span class="Delimiter">'((</span>default-space:space-address <span class="Op">&lt;-</span> new space:literal <span class="MuConstant">30</span>:literal<span class="Delimiter">)</span></span>
+                foo
+                { <span class="CommentedCode">begin</span>
+                  bar
+                  <span class="Mu"><span class="Delimiter">(</span>a:b <span class="Op">&lt;-</span> op c:d e:f<span class="Delimiter">)</span></span>
+                }<span class="Delimiter">)))</span>
+
+<span class="Comment">; space</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== space&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Constant">0</span> <span class="Delimiter">(</span>space <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'space' is 0 by default&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Constant">1</span> <span class="Delimiter">(</span>space <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>space <span class="Constant">1</span><span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'space' picks up space when available&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'</span>global <span class="Delimiter">(</span>space <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>space global<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'space' understands routine-global space&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; absolutize</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== absolutize&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Delimiter">(</span>absolutize <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'absolutize' works without routine&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Delimiter">(</span>absolutize <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'absolutize' works without default-space&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= rep.routine*!call-stack.0!default-space <span class="Constant">10</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.10</span> <span class="Constant">5</span><span class="Delimiter">)</span>  <span class="Comment">; bounds check for default-space</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">15</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>raw<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span>absolutize <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'absolutize' works with default-space&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>absolutize <span class="Delimiter">'((</span><span class="Constant">5</span> integer<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;no room&quot;</span> rep.routine*!error<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'absolutize' checks against default-space bounds&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span>_ integer<span class="Delimiter">))</span> <span class="Delimiter">(</span>absolutize <span class="Delimiter">'((</span>_ integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'absolutize' passes dummy args right through&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.20</span> <span class="Constant">5</span><span class="Delimiter">)</span>  <span class="Comment">; pretend array</span>
+<span class="Delimiter">(</span>= rep.routine*!globals <span class="Constant">20</span><span class="Delimiter">)</span>  <span class="Comment">; provide it to routine global</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">22</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>raw<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span>absolutize <span class="Delimiter">'((</span><span class="Constant">1</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>space global<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'absolutize' handles variables in the global space&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; deref</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== deref&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span>deref <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address<span class="Delimiter">)</span>
+                   <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'deref' handles simple addresses&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span>deref <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address<span class="Delimiter">)</span>
+                   <span class="Delimiter">(</span>deref<span class="Delimiter">)</span>
+                   <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'deref' deletes just one deref&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Constant">5</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">5</span> integer<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span>deref:deref <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address-address<span class="Delimiter">)</span>
+                         <span class="Delimiter">(</span>deref<span class="Delimiter">)</span>
+                         <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'deref' can be chained&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">'((</span><span class="Constant">5</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>foo<span class="Delimiter">))</span>
+          <span class="Delimiter">(</span>deref:deref <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address-address<span class="Delimiter">)</span>
+                         <span class="Delimiter">(</span>deref<span class="Delimiter">)</span>
+                         <span class="Delimiter">(</span>foo<span class="Delimiter">)</span>
+                         <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'deref' skips junk&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; addr</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== addr&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> nil<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn 111)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - directly addressed operands are their own address&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer-address<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - directly addressed operands are their own address - 2&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="MuConstant">4</span> literal<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' doesn't understand literals&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (prn 201)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Constant">23</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn 202)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' works with indirectly-addressed 'deref'&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' works with multiple 'deref'&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - directly addressed operands are their own address inside routines&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer-address<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - directly addressed operands are their own address inside routines - 2&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="MuConstant">4</span> literal<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' doesn't understand literals inside routines&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Constant">23</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' works with indirectly-addressed 'deref' inside routines&quot;</span><span class="Delimiter">))</span>
+
+<span class="CommentedCode">;? (prn 301)</span>
+<span class="Delimiter">(</span>= rep.routine*!call-stack.0!default-space <span class="Constant">10</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn 302)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.10</span> <span class="Constant">5</span><span class="Delimiter">)</span>  <span class="Comment">; bounds check for default-space</span>
+<span class="CommentedCode">;? (prn 303)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">15</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - directly addressed operands in routines add default-space&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">15</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer-address<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - directly addressed operands in routines add default-space - 2&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">15</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="MuConstant">4</span> literal<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' doesn't understand literals&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.15</span> <span class="Constant">23</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">23</span> <span class="Delimiter">(</span>addr <span class="Delimiter">'((</span><span class="Constant">4</span> integer-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'addr' adds default-space before 'deref', not after&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; array-len</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== array-len&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.35</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>array-len <span class="Delimiter">'((</span><span class="Constant">35</span> integer-boolean-pair-array<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'array-len'&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.34</span> <span class="Constant">35</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>array-len <span class="Delimiter">'((</span><span class="Constant">34</span> integer-boolean-pair-array-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'array-len'&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; sizeof</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== sizeof&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (set dump-trace*)</span>
+<span class="CommentedCode">;? (prn 401)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span>_ integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on primitives&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span>_ integer-address<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on addresses&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">2</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span>_ integer-boolean-pair<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on and-records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">3</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span>_ integer-point-pair<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on and-records with and-record fields&quot;</span><span class="Delimiter">))</span>
+
+<span class="CommentedCode">;? (prn 410)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">34</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on primitive operands&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">1</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">34</span> integer-address<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on address operands&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">2</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">34</span> integer-boolean-pair<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on and-record operands&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">3</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">34</span> integer-point-pair<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on and-record operands with and-record fields&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">2</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">34</span> integer-boolean-pair-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on pointers to and-records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.35</span> <span class="Constant">4</span><span class="Delimiter">)</span>  <span class="Comment">; size of array</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.34</span> <span class="Constant">35</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;sizeof&quot; &quot;array-len&quot;)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">9</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">34</span> integer-boolean-pair-array-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on pointers to arrays&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="CommentedCode">;? (prn 420)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Constant">23</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">24</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">4</span> integer-array<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' reads array lengths from memory&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">24</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">3</span> integer-array-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' handles pointers to arrays&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.15</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">24</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">4</span> integer-array<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' reads array lengths from memory inside routines&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= rep.routine*!call-stack.0!default-space <span class="Constant">10</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.10</span> <span class="Constant">5</span><span class="Delimiter">)</span>  <span class="Comment">; bounds check for default-space</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">35</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">4</span> integer-array<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' reads array lengths from memory using default-space&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.35</span> <span class="Constant">4</span><span class="Delimiter">)</span>  <span class="Comment">; size of array</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.15</span> <span class="Constant">35</span><span class="Delimiter">)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;sizeof&quot;)))</span>
+<span class="Delimiter">(</span>aif rep.routine*!error <span class="Delimiter">(</span>prn <span class="Constant">&quot;error - &quot;</span> it<span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">9</span> <span class="Delimiter">(</span>sizeof <span class="Delimiter">'((</span><span class="Constant">4</span> integer-boolean-pair-array-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'sizeof' works on pointers to arrays using default-space&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (quit)</span>
+
+<span class="Comment">; m</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== m&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="MuConstant">4</span> literal<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' avoids reading memory for literals&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="MuConstant">4</span> offset<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' avoids reading memory for offsets&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">34</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' reads memory for simple types&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.3</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">34</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' redirects addresses&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">3</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">34</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">2</span> integer-address-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' multiply redirects addresses&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">34</span> nil<span class="Delimiter">))</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">4</span> integer-boolean-pair<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' supports compound records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.5</span> <span class="Constant">35</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.6</span> <span class="Constant">36</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">34</span> <span class="Constant">35</span> <span class="Constant">36</span><span class="Delimiter">))</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">4</span> integer-point-pair<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' supports records with compound fields&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">34</span> <span class="Constant">35</span> <span class="Constant">36</span><span class="Delimiter">))</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">3</span> integer-point-pair-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' supports indirect access to records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.4</span> <span class="Constant">2</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">35</span> <span class="Constant">36</span><span class="Delimiter">))</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">4</span> integer-array<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' supports access to arrays&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">35</span> <span class="Constant">36</span><span class="Delimiter">))</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">3</span> integer-array-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' supports indirect access to arrays&quot;</span><span class="Delimiter">))</span>
+
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.10</span> <span class="Constant">5</span><span class="Delimiter">)</span>  <span class="Comment">; fake array</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.12</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>= rep.routine*!globals <span class="Constant">10</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~iso <span class="Constant">34</span> <span class="Delimiter">(</span>m <span class="Delimiter">'((</span><span class="Constant">1</span> integer<span class="Delimiter">)</span> <span class="Delimiter">(</span>space global<span class="Delimiter">))))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'm' supports access to per-routine globals&quot;</span><span class="Delimiter">))</span>
+
+<span class="Comment">; setm</span>
+<span class="Delimiter">(</span>prn <span class="Constant">&quot;== setm&quot;</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer<span class="Delimiter">))</span> <span class="Constant">34</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">34</span> <span class="Global">memory*</span><span class="Constant">.4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' writes primitives to memory&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address<span class="Delimiter">))</span> <span class="Constant">4</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">4</span> <span class="Global">memory*</span><span class="Constant">.3</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' writes addresses to memory&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">3</span> integer-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Constant">35</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">35</span> <span class="Global">memory*</span><span class="Constant">.4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' redirects writes&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">memory*</span><span class="Constant">.2</span> <span class="Constant">3</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">2</span> integer-address-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Constant">36</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~is <span class="Constant">36</span> <span class="Global">memory*</span><span class="Constant">.4</span><span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' multiply redirects writes&quot;</span><span class="Delimiter">))</span>
+<span class="CommentedCode">;? (prn 505)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer-integer-pair<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">23</span> <span class="Constant">24</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">4</span> <span class="Delimiter">'(</span><span class="Constant">23</span> <span class="Constant">24</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' writes compound records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>assert <span class="Delimiter">(</span>is <span class="Global">memory*</span><span class="Constant">.7</span> nil<span class="Delimiter">))</span>
+<span class="CommentedCode">;? (prn 506)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">7</span> integer-point-pair<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">23</span> <span class="Constant">24</span> <span class="Constant">25</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">7</span> <span class="Delimiter">'(</span><span class="Constant">23</span> <span class="Constant">24</span> <span class="Constant">25</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' writes records with compound fields&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer-point-pair<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">33</span> <span class="Constant">34</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;incorrect size&quot;</span> rep.routine*!error<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' checks size of target&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>wipe <span class="Global">routine*</span><span class="Delimiter">)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">3</span> integer-point-pair-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">43</span> <span class="Constant">44</span> <span class="Constant">45</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">4</span> <span class="Delimiter">'(</span><span class="Constant">43</span> <span class="Constant">44</span> <span class="Constant">45</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' supports indirect writes to records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">2</span> integer-point-pair-address-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">53</span> <span class="Constant">54</span> <span class="Constant">55</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">4</span> <span class="Delimiter">'(</span><span class="Constant">53</span> <span class="Constant">54</span> <span class="Constant">55</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' supports multiply indirect writes to records&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer-array<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">31</span> <span class="Constant">32</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">4</span> <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">31</span> <span class="Constant">32</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' writes arrays&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">3</span> integer-array-address<span class="Delimiter">)</span> <span class="Delimiter">(</span>deref<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">41</span> <span class="Constant">42</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~memory-contains <span class="Constant">4</span> <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">41</span> <span class="Constant">42</span><span class="Delimiter">))</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' supports indirect writes to arrays&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer-array<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">31</span> <span class="Constant">32</span> <span class="Constant">33</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;invalid array&quot;</span> rep.routine*!error<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' checks that array written is well-formed&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn 111)</span>
+<span class="CommentedCode">;? (= dump-trace* (obj whitelist '(&quot;sizeof&quot; &quot;setm&quot;)))</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer-boolean-pair-array<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">31</span> nil <span class="Constant">32</span> nil <span class="Constant">33</span><span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>~posmatch <span class="Constant">&quot;invalid array&quot;</span> rep.routine*!error<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' checks that array of records is well-formed&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>= <span class="Global">routine*</span> make-routine!foo<span class="Delimiter">)</span>
+<span class="CommentedCode">;? (prn 222)</span>
+<span class="Delimiter">(</span>setm <span class="Delimiter">'((</span><span class="Constant">4</span> integer-boolean-pair-array<span class="Delimiter">))</span> <span class="Delimiter">(</span>annotate <span class="Delimiter">'</span>record <span class="Delimiter">'(</span><span class="Constant">2</span> <span class="Constant">31</span> nil <span class="Constant">32</span> nil<span class="Delimiter">)))</span>
+<span class="Delimiter">(</span><span class="Normal">if</span> <span class="Delimiter">(</span>posmatch <span class="Constant">&quot;invalid array&quot;</span> rep.routine*!error<span class="Delimiter">)</span>
+  <span class="Delimiter">(</span>prn <span class="Constant">&quot;F - 'setm' checks that array of records is well-formed - 2&quot;</span><span class="Delimiter">))</span>
+<span class="Delimiter">(</span>wipe <span class="Global">routine*</span><span class="Delimiter">)</span>
+
+<span class="Delimiter">(</span>reset<span class="Delimiter">)</span>  <span class="Comment">; end file with this to persist the trace for the final test</span>
+</pre>
+</body>
+</html>
+<!-- vim: set foldmethod=manual : -->
diff --git a/archive/0.vm.arc/render.vim b/archive/0.vm.arc/render.vim
new file mode 100644
index 00000000..f005f48b
--- /dev/null
+++ b/archive/0.vm.arc/render.vim
@@ -0,0 +1,93 @@
+" Highlight current matches (:help matchadd()) in html files.
+" Run this after TOhtml.vim converts your source file to html.
+
+" from $VIMRUNTIME/syntax/2html.vim
+let s:cterm_color = {
+	\   0: "#000000", 1: "#c00000", 2: "#008000", 3: "#804000",
+	\   4: "#0000c0", 5: "#c000c0", 6: "#008080", 7: "#c0c0c0",
+	\   8: "#808080", 9: "#ff6060", 10: "#00ff00", 11: "#ffff00",
+	\   12: "#8080ff", 13: "#ff40ff", 14: "#00ffff", 15: "#ffffff"
+	\ }
+if &t_Co == 256
+  call extend(s:cterm_color, {
+	\   16: "#000000", 17: "#00005f", 18: "#000087", 19: "#0000af",
+	\   20: "#0000d7", 21: "#0000ff", 22: "#005f00", 23: "#005f5f",
+	\   24: "#005f87", 25: "#005faf", 26: "#005fd7", 27: "#005fff",
+	\   28: "#008700", 29: "#00875f", 30: "#008787", 31: "#0087af",
+	\   32: "#0087d7", 33: "#0087ff", 34: "#00af00", 35: "#00af5f",
+	\   36: "#00af87", 37: "#00afaf", 38: "#00afd7", 39: "#00afff",
+	\   40: "#00d700", 41: "#00d75f", 42: "#00d787", 43: "#00d7af",
+	\   44: "#00d7d7", 45: "#00d7ff", 46: "#00ff00", 47: "#00ff5f",
+	\   48: "#00ff87", 49: "#00ffaf", 50: "#00ffd7", 51: "#00ffff",
+	\   52: "#5f0000", 53: "#5f005f", 54: "#5f0087", 55: "#5f00af",
+	\   56: "#5f00d7", 57: "#5f00ff", 58: "#5f5f00", 59: "#5f5f5f",
+	\   60: "#5f5f87", 61: "#5f5faf", 62: "#5f5fd7", 63: "#5f5fff",
+	\   64: "#5f8700"
+	\ })
+  call extend(s:cterm_color, {
+	\   65: "#5f875f", 66: "#5f8787", 67: "#5f87af", 68: "#5f87d7",
+	\   69: "#5f87ff", 70: "#5faf00", 71: "#5faf5f", 72: "#5faf87",
+	\   73: "#5fafaf", 74: "#5fafd7", 75: "#5fafff", 76: "#5fd700",
+	\   77: "#5fd75f", 78: "#5fd787", 79: "#5fd7af", 80: "#5fd7d7",
+	\   81: "#5fd7ff", 82: "#5fff00", 83: "#5fff5f", 84: "#5fff87",
+	\   85: "#5fffaf", 86: "#5fffd7", 87: "#5fffff", 88: "#870000",
+	\   89: "#87005f", 90: "#870087", 91: "#8700af", 92: "#8700d7",
+	\   93: "#8700ff", 94: "#875f00", 95: "#875f5f", 96: "#875f87",
+	\   97: "#875faf", 98: "#875fd7", 99: "#875fff", 100: "#878700",
+	\   101: "#87875f", 102: "#878787", 103: "#8787af", 104: "#8787d7",
+	\   105: "#8787ff", 106: "#87af00", 107: "#87af5f", 108: "#87af87",
+	\   109: "#87afaf", 110: "#87afd7", 111: "#87afff", 112: "#87d700"
+	\ })
+  call extend(s:cterm_color, {
+	\   113: "#87d75f", 114: "#87d787", 115: "#87d7af", 116: "#87d7d7",
+	\   117: "#87d7ff", 118: "#87ff00", 119: "#87ff5f", 120: "#87ff87",
+	\   121: "#87ffaf", 122: "#87ffd7", 123: "#87ffff", 124: "#af0000",
+	\   125: "#af005f", 126: "#af0087", 127: "#af00af", 128: "#af00d7",
+	\   129: "#af00ff", 130: "#af5f00", 131: "#af5f5f", 132: "#af5f87",
+	\   133: "#af5faf", 134: "#af5fd7", 135: "#af5fff", 136: "#af8700",
+	\   137: "#af875f", 138: "#af8787", 139: "#af87af", 140: "#af87d7",
+	\   141: "#af87ff", 142: "#afaf00", 143: "#afaf5f", 144: "#afaf87",
+	\   145: "#afafaf", 146: "#afafd7", 147: "#afafff", 148: "#afd700",
+	\   149: "#afd75f", 150: "#afd787", 151: "#afd7af", 152: "#afd7d7",
+	\   153: "#afd7ff", 154: "#afff00", 155: "#afff5f", 156: "#afff87",
+	\   157: "#afffaf", 158: "#afffd7"
+	\ })
+  call extend(s:cterm_color, {
+	\   159: "#afffff", 160: "#d70000", 161: "#d7005f", 162: "#d70087",
+	\   163: "#d700af", 164: "#d700d7", 165: "#d700ff", 166: "#d75f00",
+	\   167: "#d75f5f", 168: "#d75f87", 169: "#d75faf", 170: "#d75fd7",
+	\   171: "#d75fff", 172: "#d78700", 173: "#d7875f", 174: "#d78787",
+	\   175: "#d787af", 176: "#d787d7", 177: "#d787ff", 178: "#d7af00",
+	\   179: "#d7af5f", 180: "#d7af87", 181: "#d7afaf", 182: "#d7afd7",
+	\   183: "#d7afff", 184: "#d7d700", 185: "#d7d75f", 186: "#d7d787",
+	\   187: "#d7d7af", 188: "#d7d7d7", 189: "#d7d7ff", 190: "#d7ff00",
+	\   191: "#d7ff5f", 192: "#d7ff87", 193: "#d7ffaf", 194: "#d7ffd7",
+	\   195: "#d7ffff", 196: "#ff0000", 197: "#ff005f", 198: "#ff0087",
+	\   199: "#ff00af", 200: "#ff00d7", 201: "#ff00ff", 202: "#ff5f00",
+	\   203: "#ff5f5f", 204: "#ff5f87"
+	\ })
+  call extend(s:cterm_color, {
+	\   205: "#ff5faf", 206: "#ff5fd7", 207: "#ff5fff", 208: "#ff8700",
+	\   209: "#ff875f", 210: "#ff8787", 211: "#ff87af", 212: "#ff87d7",
+	\   213: "#ff87ff", 214: "#ffaf00", 215: "#ffaf5f", 216: "#ffaf87",
+	\   217: "#ffafaf", 218: "#ffafd7", 219: "#ffafff", 220: "#ffd700",
+	\   221: "#ffd75f", 222: "#ffd787", 223: "#ffd7af", 224: "#ffd7d7",
+	\   225: "#ffd7ff", 226: "#ffff00", 227: "#ffff5f", 228: "#ffff87",
+	\   229: "#ffffaf", 230: "#ffffd7", 231: "#ffffff", 232: "#080808",
+	\   233: "#121212", 234: "#1c1c1c", 235: "#262626", 236: "#303030",
+	\   237: "#3a3a3a", 238: "#444444", 239: "#4e4e4e", 240: "#585858",
+	\   241: "#626262", 242: "#6c6c6c", 243: "#767676", 244: "#808080",
+	\   245: "#8a8a8a", 246: "#949494", 247: "#9e9e9e", 248: "#a8a8a8",
+	\   249: "#b2b2b2", 250: "#bcbcbc", 251: "#c6c6c6", 252: "#d0d0d0",
+	\   253: "#dadada", 254: "#e4e4e4", 255: "#eeeeee"
+	\ })
+endif
+
+set isk+=-
+redir > /tmp/highlight
+  for matchinfo in getmatches()
+    if !has_key(matchinfo, 'pattern') | continue | endif
+    echo "%s,".matchinfo.pattern.",<span style='color:".s:cterm_color[str2nr(synIDattr(hlID(matchinfo.group), 'fg'))]."'>&</span>,g"
+  endfor
+redir END
+so /tmp/highlight
diff --git a/archive/0.vm.arc/scratch.vim b/archive/0.vm.arc/scratch.vim
new file mode 100644
index 00000000..83b05539
--- /dev/null
+++ b/archive/0.vm.arc/scratch.vim
@@ -0,0 +1,50 @@
+" random commands used interactively to build mu.arc.t.html
+
+TOhtml
+%s,<.*&lt;-.*,<span class="Mu">&</span>,gc
+%s/Special">&lt;/Op">\&lt;/g
+%s, &lt;-, <span class="Op">&</span>,gc
+%s/Constant[^>]*>[^>]*>[: ]literal/Mu&/gc
+%s/Constant[^>]*>[^>]*>[: ]offset/Mu&/gc
+%s,\<nil literal,<span class="MuConstant">t</span> literal,gc
+%s,\<t literal,<span class="MuConstant">t</span> literal,gc
+%s,\<nil:literal\>,<span class="MuConstant">nil</span>:literal,gc
+%s,\<t:literal\>,<span class="MuConstant">t</span>:literal,gc
+
+map ` :s,[^ ].*,<span class="Mu">&</span>,<CR>
+/function.*[
+"b = `/<Up><Up><Enter>n
+map ; @b
+/jump
+/break
+/reply
+/loop
+/sleep
+/fork
+/defer
+/label1
+/before.*[
+/after.*[
+
+  " supercedes
+  %s,<.*break.*,<span class="Mu">&</span>,gc
+  %s,<.*continue.*,<span class="Mu">&</span>,gc
+  %s,<.*reply.*,<span class="Mu">&</span>,gc
+  %s,<.*jump.*,<span class="Mu">&</span>,gc
+  %s,<.*main.*,<span class="Mu">&</span>,gc
+  %s,<.*test1.*,<span class="Mu">&</span>,gc
+  %s,<.*test2.*,<span class="Mu">&</span>,gc
+  %s,<.*f1.*,<span class="Mu">&</span>,gc
+  %s,<.*f2.*,<span class="Mu">&</span>,gc
+
+pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #000000; }
+body { font-family: monospace; color: #aaaaaa; background-color: #000000; }
+a { color:#4444ff; }
+* { font-size: 1em; }
+.Constant, .MuConstant { color: #008080; }
+.Comment { color: #8080ff; }
+.Delimiter { color: #600060; }
+.Normal { color: #aaaaaa; }
+.Mu, .Mu .Normal, .Mu .Constant { color: #ffffff; }
+.Op { color: #ff8888; }
+.CommentedCode { color: #666666; }
diff --git a/archive/0.vm.arc/stdin.mu b/archive/0.vm.arc/stdin.mu
new file mode 100644
index 00000000..87598667
--- /dev/null
+++ b/archive/0.vm.arc/stdin.mu
@@ -0,0 +1,27 @@
+; reads and prints keys until you hit 'q'
+; no need to hit 'enter', and 'enter' has no special meaning
+; dies if you wait a while, because so far we never free memory
+(function main [
+  (default-space:space-address <- new space:literal 30:literal)
+  (cursor-mode)
+  ; hook up stdin
+  (stdin:channel-address <- init-channel 1:literal)
+;?   ($print (("main: stdin is " literal)))
+;?   ($print stdin:channel-address)
+;?   ($print (("\n" literal)))
+  (fork-helper send-keys-to-stdin:fn nil:literal/globals nil:literal/limit nil:literal/keyboard stdin:channel-address)
+  ; now read characters from stdin until a 'q' is typed
+  ($print (("? " literal)))
+  { begin
+    (x:tagged-value stdin:channel-address/deref <- read stdin:channel-address)
+    (c:character <- maybe-coerce x:tagged-value character:literal)
+;?     ($print (("main: stdin is " literal)))
+;?     ($print stdin:channel-address)
+;?     ($print (("\n" literal)))
+;?     ($print (("check: " literal)))
+;?     ($print c:character)
+    (done?:boolean <- equal c:character ((#\q literal)))
+    (break-if done?:boolean)
+    (loop)
+  }
+])
diff --git a/archive/0.vm.arc/tangle.mu b/archive/0.vm.arc/tangle.mu
new file mode 100644
index 00000000..3e73dd89
--- /dev/null
+++ b/archive/0.vm.arc/tangle.mu
@@ -0,0 +1,35 @@
+; To demonstrate tangle directives, we'll construct a factorial function with
+; separate base and recursive cases. Compare factorial.mu.
+; This isn't a very realistic example, just a simple demonstration of
+; possibilities.
+
+(function factorial [
+  (default-space:space-address <- new space:literal 30:literal)
+  (n:integer <- next-input)
+  { begin
+    base-case
+  }
+  recursive-case
+])
+
+(after base-case [
+  ; if n=0 return 1
+  (zero?:boolean <- equal n:integer 0:literal)
+  (break-unless zero?:boolean)
+  (reply 1:literal)
+])
+
+(after recursive-case [
+  ; return n*factorial(n-1)
+  (x:integer <- subtract n:integer 1:literal)
+  (subresult:integer <- factorial x:integer)
+  (result:integer <- multiply subresult:integer n:integer)
+  (reply result:integer)
+])
+
+(function main [
+  (1:integer <- factorial 5:literal)
+  ($print (("result: " literal)))
+  (print-integer nil:literal/terminal 1:integer)
+  (print-character nil:literal/terminal ((#\newline literal)))
+])
diff --git a/archive/0.vm.arc/trace.arc.t b/archive/0.vm.arc/trace.arc.t
new file mode 100644
index 00000000..6dcebe0a
--- /dev/null
+++ b/archive/0.vm.arc/trace.arc.t
@@ -0,0 +1,1659 @@
+(selective-load "mu.arc" section-level)
+(test-only-settings)
+(add-code:readfile "trace.mu")
+(ero "running tests in trace.arc.t (takes ~10 mins)")
+(freeze function*)
+(load-system-functions)
+
+(reset2)
+(new-trace "print-trace")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"schedule: main
+run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
+run: main 0: 1 => ((1 integer))
+mem: ((1 integer)): 1 <= 1
+run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
+run: main 1: 3 => ((2 integer))
+mem: ((2 integer)): 2 <= 3
+run: main 2: (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))
+mem: ((1 integer)) => 1
+mem: ((2 integer)) => 3
+run: main 2: 4 => ((3 integer))
+mem: ((3 integer)): 3 <= 4
+schedule:  done with routine")
+  (s:stream-address <- init-stream x:string-address)
+  (traces:instruction-trace-address-array-address <- parse-traces s:stream-address)
+  (screen:terminal-address <- init-fake-terminal 70:literal 15:literal)
+  (browser-state:space-address <- browser-state traces:instruction-trace-address-array-address 30:literal/screen-height)
+  (print-traces-collapsed browser-state:space-address screen:terminal-address)
+  (1:string-address/raw <- get screen:terminal-address/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+;? (prn memory*.1)
+(when (~screen-contains memory*.1 70
+         (+ "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - print-traces-collapsed works"))
+;? (quit) ;? 1
+
+(reset2)
+(new-trace "print-trace-from-middle-of-screen")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"schedule: main
+run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
+run: main 0: 1 => ((1 integer))
+mem: ((1 integer)): 1 <= 1
+run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
+run: main 1: 3 => ((2 integer))
+mem: ((2 integer)): 2 <= 3
+run: main 2: (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))
+mem: ((1 integer)) => 1
+mem: ((2 integer)) => 3
+run: main 2: 4 => ((3 integer))
+mem: ((3 integer)): 3 <= 4
+schedule:  done with routine")
+  (s:stream-address <- init-stream x:string-address)
+  (traces:instruction-trace-address-array-address <- parse-traces s:stream-address)
+  (1:terminal-address/raw <- init-fake-terminal 70:literal 15:literal)
+  ; position the cursor away from top of screen
+  (cursor-down 1:terminal-address/raw)
+  (cursor-down 1:terminal-address/raw)
+  (browser-state:space-address <- browser-state traces:instruction-trace-address-array-address 30:literal/screen-height)
+  (print-traces-collapsed browser-state:space-address 1:terminal-address/raw traces:instruction-trace-address-array-address)
+  (2:string-address/raw <- get 1:terminal-address/raw/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.2 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - print-traces-collapsed works anywhere on the screen"))
+(run-code main2
+  (print-character 1:terminal-address/raw ((#\* literal))))
+(when (~screen-contains memory*.2 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "
+            "*                                                                     "))
+  (prn "F - print-traces-collapsed leaves cursor at next line"))
+
+(reset2)
+(new-trace "process-key-move-up-down")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"schedule: main
+run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
+run: main 0: 1 => ((1 integer))
+mem: ((1 integer)): 1 <= 1
+run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
+run: main 1: 3 => ((2 integer))
+mem: ((2 integer)): 2 <= 3
+run: main 2: (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))
+mem: ((1 integer)) => 1
+mem: ((2 integer)) => 3
+run: main 2: 4 => ((3 integer))
+mem: ((3 integer)): 3 <= 4
+schedule:  done with routine")
+  (s:stream-address <- init-stream x:string-address)
+  (1:instruction-trace-address-array-address/raw <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 70:literal 15:literal)
+  ; position the cursor away from top of screen
+  (cursor-down 2:terminal-address/raw)
+  (cursor-down 2:terminal-address/raw)
+  (3:space-address/raw <- browser-state 1:instruction-trace-address-array-address/raw 30:literal/screen-height)
+  ; draw trace
+  (print-traces-collapsed 3:space-address/raw/browser-state 2:terminal-address/raw 1:instruction-trace-address-array-address/raw)
+  ; move cursor up
+  ; we have no way yet to test special keys like up-arrow
+  (s:string-address <- new "k")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  ; draw cursor
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "* main/ 2 : 4 => ((3 integer))                                        "))
+            ;^cursor
+  (prn "F - process-key can move up the cursor"))
+(run-code main2
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; reset previous cursor
+  (replace-character 2:terminal-address/raw ((#\+ literal)))
+  ; move cursor up 3 more lines
+  (s:string-address <- new "kkk")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+; cursor is now at line 3
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "* main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            ;^cursor
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key can move up multiple times"))
+; try to move cursor up thrice more
+(run-code main3
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (replace-character 2:terminal-address/raw ((#\+ literal)))
+  (s:string-address <- new "kkk")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+; cursor doesn't go beyond the first line printed
+; stuff on screen before browser-state was initialized is inviolate
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "* main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            ;^cursor
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key doesn't move above bounds"))
+; now move cursor down 4 times
+(run-code main4
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (replace-character 2:terminal-address/raw ((#\+ literal)))
+  (s:string-address <- new "jjjj")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "* main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            ;^cursor
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key can move down multiple times"))
+; try to move cursor down 4 more times
+(run-code main5
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (replace-character 2:terminal-address/raw ((#\+ literal)))
+  (s:string-address <- new "jjjj")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "
+            "*                                                                     "))
+  (prn "F - process-key doesn't move below bounds"))
+
+(reset2)
+(new-trace "process-key-expand")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"schedule: main
+run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
+run: main 0: 1 => ((1 integer))
+mem: ((1 integer)): 1 <= 1
+run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
+run: main 1: 3 => ((2 integer))
+mem: ((2 integer)): 2 <= 3
+run: main 2: (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))
+mem: ((1 integer)) => 1
+mem: ((2 integer)) => 3
+run: main 2: 4 => ((3 integer))
+mem: ((3 integer)): 3 <= 4
+schedule:  done with routine")
+  (s:stream-address <- init-stream x:string-address)
+  (1:instruction-trace-address-array-address/raw <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 70:literal 15:literal)
+  ; position the cursor away from top of screen
+  (cursor-down 2:terminal-address/raw)
+  (cursor-down 2:terminal-address/raw)
+  (3:space-address/raw <- browser-state 1:instruction-trace-address-array-address/raw 30:literal/screen-height)
+  ; draw trace
+  (print-traces-collapsed 3:space-address/raw/browser-state 2:terminal-address/raw 1:instruction-trace-address-array-address/raw)
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key: before expand"))
+(run-code main2
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; move cursor to final line and expand
+  (s:string-address <- new "k\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+; final line is expanded
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "- main/ 2 : 4 => ((3 integer))                                        "
+            "   mem : ((3 integer)): 3 <= 4                                        "
+            "   schedule :  done with routine                                      "))
+  (prn "F - process-key expands the trace index at cursor on <enter>"))
+; and cursor should remain on the top-level line
+(run-code main3
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "* main/ 2 : 4 => ((3 integer))                                        "
+            ;^cursor
+            "   mem : ((3 integer)): 3 <= 4                                        "
+            "   schedule :  done with routine                                      "))
+  (prn "F - process-key positions cursor at start of trace index after expanding"))
+
+(reset2)
+(new-trace "process-key-expand-nonlast")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"schedule: main
+run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
+run: main 0: 1 => ((1 integer))
+mem: ((1 integer)): 1 <= 1
+run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
+run: main 1: 3 => ((2 integer))
+mem: ((2 integer)): 2 <= 3
+run: main 2: (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))
+mem: ((1 integer)) => 1
+mem: ((2 integer)) => 3
+run: main 2: 4 => ((3 integer))
+mem: ((3 integer)): 3 <= 4
+schedule:  done with routine")
+  (s:stream-address <- init-stream x:string-address)
+  (1:instruction-trace-address-array-address/raw <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 70:literal 15:literal)
+  ; position the cursor away from top of screen
+  (cursor-down 2:terminal-address/raw)
+  (cursor-down 2:terminal-address/raw)
+  (3:space-address/raw <- browser-state 1:instruction-trace-address-array-address/raw 30:literal/screen-height)
+  ; draw trace
+  (print-traces-collapsed 3:space-address/raw/browser-state 2:terminal-address/raw 1:instruction-trace-address-array-address/raw)
+  ; expand penultimate line
+  (s:string-address <- new "kk\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "- main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "   mem : ((1 integer)) => 1                                           "
+            "   mem : ((2 integer)) => 3                                           "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key: expanding a line continues to print lines after it"))
+
+(reset2)
+(new-trace "process-key-expanded")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"schedule: main
+run: main 0: (((1 integer)) <- ((copy)) ((1 literal)))
+run: main 0: 1 => ((1 integer))
+mem: ((1 integer)): 1 <= 1
+mem: ((1 integer)): 1 <= 1
+run: main 1: (((2 integer)) <- ((copy)) ((3 literal)))
+run: main 1: 3 => ((2 integer))
+mem: ((2 integer)): 2 <= 3
+run: main 2: (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))
+mem: ((1 integer)) => 1
+mem: ((2 integer)) => 3
+run: main 2: 4 => ((3 integer))
+mem: ((3 integer)): 3 <= 4
+schedule:  done with routine")
+  (s:stream-address <- init-stream x:string-address)
+  (1:instruction-trace-address-array-address/raw <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 70:literal 15:literal)
+  ; position the cursor away from top of screen
+  (cursor-down 2:terminal-address/raw)
+  (cursor-down 2:terminal-address/raw)
+  (3:space-address/raw <- browser-state 1:instruction-trace-address-array-address/raw 30:literal/screen-height)
+  ; draw trace
+  (print-traces-collapsed 3:space-address/raw/browser-state 2:terminal-address/raw 1:instruction-trace-address-array-address/raw)
+  ; expand penultimate line, then move one line down and draw cursor
+  (s:string-address <- new "kk\nj")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; cursor should be at next top-level 'run' line
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "- main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "   mem : ((1 integer)) => 1                                           "
+            "   mem : ((2 integer)) => 3                                           "
+            "* main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key: navigation moves between top-level trace indices only"))
+(run-code main2
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; reset previous cursor
+  (replace-character 2:terminal-address/raw ((#\+ literal)))
+  ; move cursor back up one line
+  (s:string-address <- new "k")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  ; show cursor
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; cursor should be back at the top of the expanded line
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "* main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "   mem : ((1 integer)) => 1                                           "
+            "   mem : ((2 integer)) => 3                                           "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key: navigation moves between top-level indices only - 2"))
+(run-code main3
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; reset previous cursor
+  (replace-character 2:terminal-address/raw ((#\+ literal)))
+  ; press enter
+  (s:string-address <- new "\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; expanded trace should now be collapsed
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "+ main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "+ main/ 2 : 4 => ((3 integer))                                        "
+            "                                                                      "
+            "                                                                      "))
+  (prn "F - process-key: process-key collapses trace indices correctly after moving around"))
+(run-code main4
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; move up a few lines, expand, then move down and expand again
+  (s:string-address <- new "kkk\njjj\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   (replace-character 2:terminal-address/raw ((#\* literal))) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; first expand should have no effect
+(when (~screen-contains memory*.4 70
+         (+ "                                                                      "
+            "                                                                      "
+            "+ main/ 0 : (((1 integer)) <- ((copy)) ((1 literal)))                 "
+            "+ main/ 0 : 1 => ((1 integer))                                        "
+            "+ main/ 1 : (((2 integer)) <- ((copy)) ((3 literal)))                 "
+            "+ main/ 1 : 3 => ((2 integer))                                        "
+            "- main/ 2 : (((3 integer)) <- ((add)) ((1 integer)) ((2 integer)))    "
+            "   mem : ((1 integer)) => 1                                           "
+            "   mem : ((2 integer)) => 3                                           "
+            "+ main/ 2 : 4 => ((3 integer))                                        "))
+  (prn "F - process-key: process-key collapses the previously expanded trace index when expanding elsewhere"))
+
+;; manage screen height
+
+(reset2)
+(new-trace "trace-paginate")
+(run-code main
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"run: main 0: a b c
+mem: 0 a
+run: main 1: d e f
+mem: 1 a
+mem: 1 b
+mem: 1 c
+mem: 1 d
+mem: 1 e
+run: main 2: g hi
+run: main 3: j
+mem: 3 a
+run: main 4: k
+run: main 5: l
+run: main 6: m
+run: main 7: n")
+  (s:stream-address <- init-stream x:string-address)
+  (traces:instruction-trace-address-array-address <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 17:literal 15:literal)
+  (3:space-address/raw/browser-state <- browser-state traces:instruction-trace-address-array-address 3:literal/screen-height)
+  (print-traces-collapsed 3:space-address/raw/browser-state 2:terminal-address/raw)
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+)
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; screen shows a subset of collapsed trace lines
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "+ main/ 1 : d e f"
+            "+ main/ 2 : g hi "))
+  (prn "F - print-traces-collapsed can show just one 'page' of a larger trace"))
+
+; expand top line
+(run-code main2
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "kkk\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; screen shows just first trace line fully expanded
+(when (~screen-contains memory*.4 17
+         (+ "- main/ 0 : a b c"
+            "   mem : 0 a     "
+            "+ main/ 1 : d e f"
+            "                 "))
+  (prn "F - expanding doesn't print past end of page"))
+(run-code main2-2
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+; screen shows part of the second trace line expanded
+(when (~screen-contains memory*.4 17
+         (+ "* main/ 0 : a b c"
+            "   mem : 0 a     "
+            "+ main/ 1 : d e f"
+            "                 "))
+  (prn "F - cursor at right place after expand"))
+
+; expand line below without first collapsing previously expanded line
+(run-code main3
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; reset previous cursor
+  (replace-character 2:terminal-address/raw ((#\- literal)))
+  (s:string-address <- new "j\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; screen shows part of the second trace line expanded
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - expanding below expanded line respects screen/page height"))
+(run-code main3-2
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+  )
+; screen shows part of the second trace line expanded
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "* main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - cursor at right place after expand below"))
+
+; expand line *above* without first collapsing previously expanded line
+(run-code main4
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; reset previous cursor
+  (replace-character 2:terminal-address/raw ((#\- literal)))
+  (s:string-address <- new "k\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; screen again shows first trace line expanded
+(when (~screen-contains memory*.4 17
+         (+ "- main/ 0 : a b c"
+            "   mem : 0 a     "
+            "+ main/ 1 : d e f"
+            "                 "))
+  (prn "F - expanding above expanded line respects screen/page height"))
+;? (quit) ;? 1
+
+; collapse everything and hit page-down
+; again, we can't yet check for special keys like 'page-down so we'll use
+; upper-case J and K for moving a page down or up, respectively.
+(run-code main5
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "\nJ")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; screen shows second page of traces
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "+ main/ 4 : k    "
+            "+ main/ 5 : l    "
+            "                 "))
+  (prn "F - 'page-down' skips to next page after this one"))
+;? (quit) ;? 1
+
+; move cursor down, then page-down
+(run-code main6
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "jJ")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; page-down behaves the same regardless of where the cursor was
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 6 : m    "
+            "+ main/ 7 : n    "
+            "                 "))
+  (prn "F - 'page-down' skips to same place regardless of cursor position"))
+
+; try to page-down past end of trace
+(run-code main7
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "J")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; no change
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 6 : m    "
+            "+ main/ 7 : n    "
+            "                 "))
+  (prn "F - 'page-down' skips to same place regardless of cursor position"))
+
+; now page-up
+(run-code main8
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; precisely undoes previous page-down
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "+ main/ 4 : k    "
+            "+ main/ 5 : l    "
+            "                 "))
+  (prn "F - 'page-up' on partial page behaves as if page was full"))
+
+;; back to page 1, expand a line
+(run-code main9
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "Kkk\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   (print-character 2:terminal-address/raw ((#\* literal))) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; now we have an expanded line
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - intermediate state after expanding a line"))
+
+; next page
+(run-code main10
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "J")
+  (k:keyboard-address <- init-keyboard s:string-address)
+;?   ($start-tracing) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; no lines skipped, page with just inner traces
+(when (~screen-contains memory*.4 17
+         (+ "   mem : 1 b     "
+            "   mem : 1 c     "
+            "   mem : 1 d     "
+            "                 "
+            "                 "))
+  (prn "F - page down continues existing expanded line"))
+
+; next page
+(run-code main11
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "J")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+; page with partial inner trace and more collapsed
+(when (~screen-contains memory*.4 17
+         (+ "   mem : 1 e     "
+            "+ main/ 2 : g hi "
+            "+ main/ 3 : j    "
+            "                 "
+            "                 "))
+  (prn "F - page down shows collapsed lines after continued expanded line at top of page"))
+;? (quit) ;? 1
+
+; page-up through an expanded line
+(run-code main12
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "   mem : 1 b     "
+            "   mem : 1 c     "
+            "   mem : 1 d     "
+            "                 "
+            "                 "))
+  (prn "F - page up understands expanded lines"))
+
+;; page up scenarios
+; skip ones starting at top of trace for now
+; page-up scenario 2
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f  <- top of page
+;   mem: 1 a
+;   mem: 1 b
+;   mem: 1 c
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi
+; + run: main 3: j      <- bottom of page
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main13
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+;?   ($print first-index-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+;?   ($print first-index-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 3:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy -1:literal)
+  (expanded-children:integer/space:1 <- copy -1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "+ main/ 1 : d e f"
+            "+ main/ 2 : g hi "))
+  (prn "F - page-up 2"))
+
+; page-up scenario 3
+; + run: main 0: a b c
+;   mem: 0 a
+; - run: main 1: d e f  <- top of page
+;   mem: 1 a
+;   mem: 1 b            <- bottom of page
+;   mem: 1 c
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main14pre
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -1:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 1:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "   mem : 1 b     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 3: initial print-page state"))
+(run-code main14post
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 0:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 0:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 3: expected post page-up state"))
+;? (quit) ;? 1
+(run-code main14
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -1:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 1:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+;?   ($start-tracing) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 3"))
+;? (quit) ;? 1
+
+; page-up scenario 4
+; + run: main 0: a b c
+;   mem: 0 a
+; - run: main 1: d e f
+;   mem: 1 a
+;   mem: 1 b
+;   mem: 1 c            <- top of page
+;   mem: 1 d
+;   mem: 1 e            <- bottom of page
+; + run: main 2: g hi
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main15
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 2:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 4:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "   mem : 1 b     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 4"))
+
+; page-up scenario 5
+; + run: main 0: a b c
+;   mem: 0 a
+; - run: main 1: d e f
+;   mem: 1 a            <- top of page
+;   mem: 1 b
+;   mem: 1 c            <- bottom of page
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main16pre
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 0:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 2:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+;?   ($print cursor-row:integer/space:1) ;? 1
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+;?   ($print cursor-row:integer/space:1) ;? 1
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "   mem : 1 a     "
+            "   mem : 1 b     "
+            "   mem : 1 c     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 5: initial print-page state"))
+(run-code main16
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 0:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 2:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+;?   ($dump-browser-state 3:space-address/raw/browser-state) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 5"))
+
+; page-up scenario 6
+; + run: main 0: a b c
+;   mem: 0 a
+; - run: main 1: d e f
+;   mem: 1 a
+;   mem: 1 b            <- top of page
+;   mem: 1 c
+;   mem: 1 d            <- bottom of page
+;   mem: 1 e
+; + run: main 2: g hi
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main17
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 1:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 3:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 5:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "- main/ 1 : d e f"
+            "   mem : 1 a     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 6"))
+
+; page-up scenario 7
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f  <- top of page
+;   mem: 1 a
+;   mem: 1 b
+;   mem: 1 c
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi
+; - run: main 3: j      <- bottom of page
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main18
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 3:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -1:literal)
+  (expanded-index:integer/space:1 <- copy 3:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "+ main/ 1 : d e f"
+            "+ main/ 2 : g hi "
+            "                 "))
+  (prn "F - page-up 7 - expanded index starts below bottom"))
+;? (quit) ;? 1
+
+; page-up scenario 8
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f  <- top of page
+;   mem: 1 a
+;   mem: 1 b
+;   mem: 1 c
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi
+; + run: main 3: j      <- bottom of page
+;   mem: 3 a
+; - run: main 4: k
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main19
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 3:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -1:literal)
+  (expanded-index:integer/space:1 <- copy 4:literal)
+  (expanded-children:integer/space:1 <- copy 0:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 0 : a b c"
+            "+ main/ 1 : d e f"
+            "+ main/ 2 : g hi "
+            "                 "))
+  (prn "F - page-up 8 - expanded index starts below top - 2"))
+
+; page-up scenario 9
+; - run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+;   mem: 1 a
+;   mem: 1 b
+;   mem: 1 c
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi
+; + run: main 3: j      <- top of page
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l      <- bottom of page
+; + run: main 6: m
+; + run: main 7: n
+(run-code main20
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 3:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 5:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 0:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "   mem : 0 a     "
+            "+ main/ 1 : d e f"
+            "+ main/ 2 : g hi "
+            "                 "))
+  (prn "F - page-up 9 - expanded index overlaps target page"))
+
+; page-up scenario 10
+; - run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+;   mem: 1 a
+;   mem: 1 b
+;   mem: 1 c
+;   mem: 1 d
+;   mem: 1 e
+; + run: main 2: g hi   <- top of page
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k      <- bottom of page
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main21pre
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 2:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 4:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 0:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+;?   ($start-tracing) ;? 2
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 2 : g hi "
+            "+ main/ 3 : j    "
+            "+ main/ 4 : k    "
+            "                 "
+            "                 "))
+  (prn "F - page-up 10: initial print-page state"))
+;? (quit) ;? 1
+(run-code main21
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 2:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 4:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 0:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "- main/ 0 : a b c"
+            "   mem : 0 a     "
+            "+ main/ 1 : d e f"
+            "                 "
+            "                 "))
+  (prn "F - page-up 10 - expanded index overlaps target page - 2"))
+;? (quit) ;? 2
+
+(reset2)
+(new-trace "trace-paginate2")
+; page-up scenario 11
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+; - run: main 2: g hi
+;   mem: 2 a
+; + run: main 3: j      <- top of page
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l      <- bottom of page
+; + run: main 6: m
+; + run: main 7: n
+(run-code main22
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"run: main 0: a b c
+mem: 0 a
+run: main 1: d e f
+run: main 2: g hi
+mem: 2 a
+run: main 3: j
+mem: 3 a
+run: main 4: k
+run: main 5: l
+run: main 6: m
+run: main 7: n")
+  (s:stream-address <- init-stream x:string-address)
+  (traces:instruction-trace-address-array-address <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 17:literal 15:literal)
+  (3:space-address/raw/browser-state <- browser-state traces:instruction-trace-address-array-address 3:literal/screen-height)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+  (first-index-on-page:integer/space:1 <- copy 3:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 5:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 2:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 1 : d e f"
+            "- main/ 2 : g hi "
+            "   mem : 2 a     "
+            "                 "
+            "                 "))
+  (prn "F - page-up 11 - expanded index overlaps target page - 3"))
+
+; page-up scenario 12
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+; - run: main 2: g hi
+;   mem: 2 a
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k      <- top of page
+; + run: main 5: l
+; + run: main 6: m      <- bottom of page
+; + run: main 7: n
+(run-code main23
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 4:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 6:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 2:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "- main/ 2 : g hi "
+            "   mem : 2 a     "
+            "+ main/ 3 : j    "
+            "                 "))
+  (prn "F - page-up 12 - expanded index overlaps target page - 4"))
+
+; page-up scenario 13
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+; - run: main 2: g hi
+;   mem: 2 a
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k
+; + run: main 5: l
+; + run: main 6: m      <- top of page
+; + run: main 7: n      <- bottom of page
+(run-code main24
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 6:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 7:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 2:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (s:string-address <- new "K")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "+ main/ 4 : k    "
+            "+ main/ 5 : l    "
+            "                 "))
+  (prn "F - page-up 13 - expanded index far above target page"))
+
+(run-code main25
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (s:string-address <- new "kk\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "- main/ 4 : k    "
+            "+ main/ 5 : l    "
+            "                 "))
+  (prn "F - process-key expands a trace index on any page"))
+(run-code main26
+  (replace-character 2:terminal-address/raw ((#\* literal)))
+)
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "* main/ 4 : k    "
+            "+ main/ 5 : l    "
+            "                 "))
+  (prn "F - process-key resets the cursor after expand"))
+;? (quit) ;? 1
+
+(run-code main27
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  ; reset previous cursor
+  (replace-character 2:terminal-address/raw ((#\- literal)))
+  (s:string-address <- new "j\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "+ main/ 4 : k    "
+            "- main/ 5 : l    "
+            "                 "))
+  (prn "F - process-key expands a trace index on any page when there's an expanded trace index above it on the same page"))
+
+; expand scenario
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+; - run: main 2: g hi
+;   mem: 2 a              <- top of page
+; + run: main 3: j
+;   mem: 3 a
+; + run: main 4: k        <- bottom of page
+; + run: main 5: l
+; + run: main 6: m
+; + run: main 7: n
+(run-code main28
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 2:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 0:literal)
+  (last-index-on-page:integer/space:1 <- copy 4:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 2:literal)
+  (expanded-children:integer/space:1 <- copy 1:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+  (s:string-address <- new "kk\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   (replace-character 2:terminal-address/raw ((#\* literal))) ;? 2
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+;?          (+ "   mem : 2 a     "  ; after print-page
+;?             "+ main/ 3 : j    "
+;?             "+ main/ 4 : k    "
+;?             "                 "))
+         (+ "+ main/ 2 : g hi "
+            "- main/ 3 : j    "
+            "   mem : 3 a     "
+            "                 "))
+;?          (+ "- main/ 3 : j    "  ; alternative interpretation in case the above isn't intuitive
+;?             "   mem : 3 a     "
+;?          (+ "- main/ 4 : k    "
+;?             "                 "))
+  (prn "F - process-key expands trace index on a page that starts with a partial expanded trace"))
+
+(reset2)
+(new-trace "trace-paginate3")
+; expand scenario
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+;   mem: 1 a
+;   mem: 1 b              <- top of page
+;   mem: 1 c
+; + run: main 2: g hi     <- bottom of page
+;   mem: 2 a
+; + run: main 3: j
+; + run: main 4: k
+; + run: main 5: l
+(run-code main29
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (x:string-address <- new
+"run: main 0: a b c
+mem: 0 a
+run: main 1: d e f
+mem: 1 a
+mem: 1 b
+mem: 1 c
+run: main 2: g hi
+mem: 2 a
+run: main 3: j
+run: main 4: k
+run: main 5: l")
+  (s:stream-address <- init-stream x:string-address)
+  (traces:instruction-trace-address-array-address <- parse-traces s:stream-address)
+  (2:terminal-address/raw <- init-fake-terminal 17:literal 15:literal)
+  (3:space-address/raw/browser-state <- browser-state traces:instruction-trace-address-array-address 3:literal/screen-height)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (4:string-address/raw <- get 2:terminal-address/raw/deref data:offset)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 1:literal)
+  (last-index-on-page:integer/space:1 <- copy 3:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 3:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+;?   (replace-character 2:terminal-address/raw ((#\* literal))) ;? 1
+  (s:string-address <- new "k\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+;?          (+ "   mem : 1 b     "  ; after print-page
+;?             "   mem : 1 c     "
+;?             "+ main/ 2 : g hi "
+;?             "*                "
+;?             "                 "))
+         (+ "+ main/ 1 : d e f"
+            "- main/ 2 : g hi "
+            "   mem : 2 a     "
+            "                 "
+            "                 "))
+  (prn "F - process-key expands trace index on a page that starts with a partial expanded trace - 2"))
+
+; expand scenario
+; + run: main 0: a b c
+;   mem: 0 a
+; + run: main 1: d e f
+;   mem: 1 a              <- top of page
+;   mem: 1 b
+;   mem: 1 c              <- bottom of page
+; + run: main 2: g hi
+;   mem: 2 a
+; + run: main 3: j
+; + run: main 4: k
+; + run: main 5: l
+(run-code main30
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  (first-index-on-page:integer/space:1 <- copy 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy 0:literal)
+  (last-index-on-page:integer/space:1 <- copy 1:literal)
+  (last-subindex-on-page:integer/space:1 <- copy 2:literal)
+  (expanded-index:integer/space:1 <- copy 1:literal)
+  (expanded-children:integer/space:1 <- copy 3:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+  (s:string-address <- new "k\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   (replace-character 2:terminal-address/raw ((#\* literal))) ;? 1
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+;?          (+ "   mem : 1 a     "  ; after print-page
+;?             "   mem : 1 b     "
+;?             "   mem : 1 c     "
+;?             "*                "))
+         (+ "+ main/ 1 : d e f"
+            "+ main/ 2 : g hi "
+            "+ main/ 3 : j    "))
+  (prn "F - process-key expands trace index on a page with only subindex lines"))
+
+(run-code main31
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  ; reinitialize
+  (first-index-on-page:integer/space:1 <- copy 0:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 2:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy -1:literal)
+  (expanded-children:integer/space:1 <- copy -1:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+;?   (replace-character 2:terminal-address/raw ((#\* literal))) ;? 1
+  (s:string-address <- new "Jjj\n")
+  (k:keyboard-address <- init-keyboard s:string-address)
+;?   ($print (("test: first subindex " literal))) ;? 1
+;?   ($print first-subindex-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   ($print (("test: first subindex 2 " literal))) ;? 1
+;?   ($print first-subindex-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   ($print (("test: first subindex 3 " literal))) ;? 1
+;?   ($print first-subindex-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+;?   ($print (("test: first subindex 4 " literal))) ;? 1
+;?   ($print first-subindex-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+(when (~screen-contains memory*.4 17
+         (+ "+ main/ 3 : j    "
+            "+ main/ 4 : k    "
+            "- main/ 5 : l    "
+            "                 "
+            "                 "))
+  (prn "F - process-key expands final index of trace at bottom of page"))
+
+(run-code main32
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- copy 3:space-address/raw/browser-state)
+  ; reinitialize
+  (first-index-on-page:integer/space:1 <- copy 0:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (last-index-on-page:integer/space:1 <- copy 2:literal)
+  (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+  (expanded-index:integer/space:1 <- copy -1:literal)
+  (expanded-children:integer/space:1 <- copy -1:literal)
+  (to-top 0:space-address/browser-state 2:terminal-address/raw)
+  (print-page 0:space-address/browser-state 2:terminal-address/raw)
+;?   (replace-character 2:terminal-address/raw ((#\* literal))) ;? 1
+  (s:string-address <- new "kk\nJjj")
+  (k:keyboard-address <- init-keyboard s:string-address)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (process-key 3:space-address/raw/browser-state k:keyboard-address 2:terminal-address/raw)
+  (5:integer-address/raw <- get-address 2:terminal-address/raw/deref cursor-row:offset)
+  )
+(each routine completed-routines*
+  (awhen rep.routine!error
+    (prn "error - " it)))
+;? (prn (memory* memory*.5)) ;? 1
+(when (~is 3 (memory* memory*.5))
+  (prn "F - key movement stays within screen bounds, even when no next trace on page"))
+
+(reset2)
+;? (print-times) ;? 3
diff --git a/archive/0.vm.arc/trace.mu b/archive/0.vm.arc/trace.mu
new file mode 100644
index 00000000..eba9b477
--- /dev/null
+++ b/archive/0.vm.arc/trace.mu
@@ -0,0 +1,1092 @@
+(and-record trace [
+  label:string-address
+  contents:string-address
+])
+(address trace-address (trace))
+(array trace-address-array (trace-address))
+(address trace-address-array-address (trace-address-array))
+(address trace-address-array-address-address (trace-address-array-address))
+
+(and-record instruction-trace [
+  call-stack:string-address-array-address
+  pc:string-address  ; should be integer?
+  instruction:string-address
+  children:trace-address-array-address
+])
+(address instruction-trace-address (instruction-trace))
+(array instruction-trace-address-array (instruction-trace-address))
+(address instruction-trace-address-array-address (instruction-trace-address-array))
+
+(function parse-traces [  ; stream-address -> instruction-trace-address-array-address
+  (default-space:space-address <- new space:literal 30:literal)
+;?   ($print (("parse-traces\n" literal))) ;? 2
+  (in:stream-address <- next-input)
+  ; check input size
+  ($print (("counting lines\n" literal)))
+  (n:integer <- copy 0:literal)
+  { begin
+    (done?:boolean <- end-of-stream? in:stream-address)
+    (break-if done?:boolean)
+;?     ($start-tracing) ;? 1
+    (c:character <- read-character in:stream-address)
+    { begin
+      (newline?:boolean <- equal c:character ((#\newline literal)))
+      (break-unless newline?:boolean)
+      (n:integer <- add n:integer 1:literal)
+      { begin
+;?         (print?:boolean <- divides? n:integer 100:literal)
+;?         (break-unless print?:boolean)
+        ($print ((" " literal)))
+        ($print n:integer)
+        ($print (("\n" literal)))
+      }
+    }
+;?     ($quit) ;? 1
+    (loop)
+  }
+  ($print n:integer)
+  ($print ((" lines\n" literal)))
+  (in:stream-address <- rewind-stream in:stream-address)
+  ; prepare result
+  (result:buffer-address <- init-buffer 30:literal)
+  (curr-tail:instruction-trace-address <- copy nil:literal)
+  (ch:buffer-address <- init-buffer 5:literal)  ; accumulator for traces between instructions
+  (run:string-address/const <- new "run")
+  ($print (("parsing\n" literal)))
+  (n:integer <- copy 0:literal)
+  ; reading each line from 'in'
+  { begin
+    next-line
+    (done?:boolean <- end-of-stream? in:stream-address)
+;?     ($print done?:boolean) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (break-if done?:boolean)
+    ; parse next line as a generic trace
+    (line:string-address <- read-line in:stream-address)
+    { begin
+      (n:integer <- add n:integer 1:literal)
+      (print?:boolean <- divides? n:integer 100:literal)
+      (break-unless print?:boolean)
+      ($print ((" " literal)))
+      ($print n:integer)
+      ($print (("\n" literal)))
+    }
+;?     (print-string nil:literal/terminal line:string-address) ;? 1
+    (f:trace-address <- parse-trace line:string-address)
+    (l:string-address <- get f:trace-address/deref label:offset)
+    { begin
+      ; if it's an instruction trace with label 'run'
+      (inst?:boolean <- string-equal l:string-address run:string-address/const)
+      (break-unless inst?:boolean)
+      ; add accumulated traces to curr-tail
+      { begin
+        (break-unless curr-tail:instruction-trace-address)
+        (c:trace-address-array-address-address <- get-address curr-tail:instruction-trace-address/deref children:offset)
+        (c:trace-address-array-address-address/deref <- to-array ch:buffer-address)
+        ; clear 'ch'
+        (ch:buffer-address <- init-buffer 5:literal)
+      }
+      ; append a new curr-tail to result
+      (curr-tail:instruction-trace-address <- parse-instruction-trace f:trace-address)
+      (result:buffer-address <- append result:buffer-address curr-tail:instruction-trace-address)
+      (jump next-line:offset)  ; loop
+    }
+    ; otherwise accumulate trace
+    (loop-unless curr-tail:instruction-trace-address)
+    (ch:buffer-address <- append ch:buffer-address f:trace-address)
+    (loop)
+  }
+  ; add accumulated traces to final curr-tail
+  ; todo: test
+  { begin
+    (break-unless curr-tail:instruction-trace-address)
+    (c:trace-address-array-address-address <- get-address curr-tail:instruction-trace-address/deref children:offset)
+    (c:trace-address-array-address-address/deref <- to-array ch:buffer-address)
+  }
+  (s:instruction-trace-address-array-address <- to-array result:buffer-address)
+  (reply s:instruction-trace-address-array-address)
+])
+
+(function parse-instruction-trace [  ; trace-address -> instruction-trace-address
+  (default-space:space-address <- new space:literal 30:literal)
+;?   ($print (("parse-instruction-trace\n" literal))) ;? 1
+  (in:trace-address <- next-input)
+  (buf:string-address <- get in:trace-address/deref contents:offset)
+;?   (print-string nil:literal buf:string-address) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (result:instruction-trace-address <- new instruction-trace:literal)
+  (f1:string-address rest:string-address <- split-first buf:string-address ((#\space literal)))
+;?   ($print (("call-stack: " literal))) ;? 1
+;?   (print-string nil:literal f1:string-address) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (cs:string-address-array-address-address <- get-address result:instruction-trace-address/deref call-stack:offset)
+  (cs:string-address-array-address-address/deref <- split f1:string-address ((#\/ literal)))
+  (p:string-address-address <- get-address result:instruction-trace-address/deref pc:offset)
+  (delim:string-address <- new ": ")
+  (p:string-address-address/deref rest:string-address <- split-first-at-substring rest:string-address delim:string-address)
+  (inst:string-address-address <- get-address result:instruction-trace-address/deref instruction:offset)
+  (inst:string-address-address/deref <- copy rest:string-address)
+  (reply result:instruction-trace-address)
+])
+
+(function parse-trace [  ; string-address -> trace-address
+  (default-space:space-address <- new space:literal 30:literal)
+;?   ($print (("parse-trace\n" literal))) ;? 1
+  (in:string-address <- next-input)
+  (result:trace-address <- new trace:literal)
+  (delim:string-address <- new ": ")
+  (first:string-address rest:string-address <- split-first-at-substring in:string-address delim:string-address)
+  (l:string-address-address <- get-address result:trace-address/deref label:offset)
+  (l:string-address-address/deref <- copy first:string-address)
+  (c:string-address-address <- get-address result:trace-address/deref contents:offset)
+  (c:string-address-address/deref <- copy rest:string-address)
+  (reply result:trace-address)
+])
+
+(function print-trace [
+  (default-space:space-address <- new space:literal 30:literal)
+  (screen:terminal-address <- next-input)
+  (x:trace-address <- next-input)
+  (l:string-address <- get x:trace-address/deref label:offset)
+  (clear-line screen:terminal-address)
+  (print-string screen:terminal-address l:string-address)
+  (print-character screen:terminal-address ((#\space literal)))
+  (print-character screen:terminal-address ((#\: literal)))
+  (print-character screen:terminal-address ((#\space literal)))
+  (c:string-address <- get x:trace-address/deref contents:offset)
+  (print-string screen:terminal-address c:string-address)
+])
+
+(function print-instruction-trace-parent [
+  (default-space:space-address <- new space:literal 30:literal)
+  (screen:terminal-address <- next-input)
+  (x:instruction-trace-address <- next-input)
+  (0:space-address/names:browser-state <- next-input)
+  (clear-line screen:terminal-address)
+  (print-character screen:terminal-address ((#\- literal)))
+  (print-character screen:terminal-address ((#\space literal)))
+  ; print call stack
+  (c:string-address-array-address <- get x:instruction-trace-address/deref call-stack:offset)
+  (i:integer <- copy 0:literal)
+  (len:integer <- length c:string-address-array-address/deref)
+  { begin
+    (done?:boolean <- greater-or-equal i:integer len:integer)
+    (break-if done?:boolean)
+    (s:string-address <- index c:string-address-array-address/deref i:integer)
+    (print-string screen:terminal-address s:string-address)
+    (print-character screen:terminal-address ((#\/ literal)))
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+  ; print pc
+  (print-character screen:terminal-address ((#\space literal)))
+  (p:string-address <- get x:instruction-trace-address/deref pc:offset)
+  (print-string screen:terminal-address p:string-address)
+  ; print instruction
+  (print-character screen:terminal-address ((#\space literal)))
+  (print-character screen:terminal-address ((#\: literal)))
+  (print-character screen:terminal-address ((#\space literal)))
+  (i:string-address <- get x:instruction-trace-address/deref instruction:offset)
+  (print-string screen:terminal-address i:string-address)
+  (add-line 0:space-address/browser-state screen:terminal-address)
+])
+
+(function print-instruction-trace [
+  (default-space:space-address <- new space:literal 30:literal)
+  (screen:terminal-address <- next-input)
+  (x:instruction-trace-address <- next-input)
+  (0:space-address/names:browser-state <- next-input)
+  (print-instruction-trace-parent screen:terminal-address x:instruction-trace-address 0:space-address/browser-state)
+  ; print children
+  (ch:trace-address-array-address <- get x:instruction-trace-address/deref children:offset)
+  (i:integer <- copy 0:literal)
+  { begin
+    ; todo: test
+    (break-if ch:trace-address-array-address)
+    (reply)
+  }
+  (len:integer <- length ch:trace-address-array-address/deref)
+  (expanded-children:integer/space:1 <- copy len:integer)
+  { begin
+;?     ($print (("i: " literal))) ;? 1
+;?     ($print i:integer) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    ; until done with trace
+    (done?:boolean <- greater-or-equal i:integer len:integer)
+    (break-if done?:boolean)
+    ; or screen ends
+    (screen-done?:boolean <- greater-or-equal cursor-row:integer/space:1 screen-height:integer/space:1)
+    (break-if screen-done?:boolean)
+    (t:trace-address <- index ch:trace-address-array-address/deref i:integer)
+    (print-character screen:terminal-address ((#\space literal)))
+    (print-character screen:terminal-address ((#\space literal)))
+    (print-character screen:terminal-address ((#\space literal)))
+    (print-trace screen:terminal-address t:trace-address)
+    (add-line 0:space-address/browser-state screen:terminal-address)
+    (last-subindex-on-page:integer/space:1 <- copy i:integer)
+;?     ($print (("subindex: " literal))) ;? 1
+;?     ($print last-subindex-on-page:integer/space:1) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+])
+
+(function print-instruction-trace-collapsed [
+  (default-space:space-address <- new space:literal 30:literal)
+  (screen:terminal <- next-input)
+  (x:instruction-trace-address <- next-input)
+  (browser-state:space-address <- next-input)
+  (clear-line screen:terminal-address)
+  (print-character screen:terminal-address ((#\+ literal)))
+  (print-character screen:terminal-address ((#\space literal)))
+  ; print call stack
+  (c:string-address-array-address <- get x:instruction-trace-address/deref call-stack:offset)
+  (i:integer <- copy 0:literal)
+  (len:integer <- length c:string-address-array-address/deref)
+  { begin
+    (done?:boolean <- greater-or-equal i:integer len:integer)
+    (break-if done?:boolean)
+    (s:string-address <- index c:string-address-array-address/deref i:integer)
+    (print-string screen:terminal-address s:string-address)
+;?     (print-character screen:terminal-address ((#\space literal)))
+    (print-character screen:terminal-address ((#\/ literal)))
+;?     (print-character screen:terminal-address ((#\space literal)))
+    (i:integer <- add i:integer 1:literal)
+    (loop)
+  }
+  ; print pc
+  (print-character screen:terminal-address ((#\space literal)))
+  (p:string-address <- get x:instruction-trace-address/deref pc:offset)
+  (print-string screen:terminal-address p:string-address)
+  ; print instruction
+  (print-character screen:terminal-address ((#\space literal)))
+  (print-character screen:terminal-address ((#\: literal)))
+  (print-character screen:terminal-address ((#\space literal)))
+  (i:string-address <- get x:instruction-trace-address/deref instruction:offset)
+  (print-string screen:terminal-address i:string-address)
+  (add-line browser-state:space-address screen:terminal-address)
+])
+
+(function instruction-trace-num-children [
+  (default-space:space-address <- new space:literal 30:literal)
+  (traces:instruction-trace-address-array-address <- next-input)
+  (index:integer <- next-input)
+  (tr:instruction-trace-address <- index traces:instruction-trace-address-array-address/deref index:integer)
+  (tr-children:trace-address-array-address <- get tr:instruction-trace-address/deref children:offset)
+  (n:integer <- length tr-children:instruction-trace-address-array-address/deref)
+  (reply n:integer)
+])
+
+;; data structure
+(function browser-state [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ; trace state
+  (traces:instruction-trace-address-array-address <- next-input)  ; the ground truth being rendered
+  (expanded-index:integer <- copy -1:literal)  ; currently trace browser only ever shows one item expanded
+  (expanded-children:integer <- copy -1:literal)
+  (first-index-on-page:integer <- copy 0:literal)  ; 'outer' line with label 'run'
+  (first-subindex-on-page:integer <- copy -2:literal)  ; 'inner' line with other labels; -2 or lower => not expanded; -1 => expanded and include parent; 0 => expanded and start at first child
+  (last-index-on-page:integer <- copy 0:literal)
+  (last-subindex-on-page:integer <- copy -2:literal)
+  ; screen state
+  (screen-height:integer <- next-input)  ; 'hardware' limitation
+  (app-height:integer <- copy 0:literal)  ; area of the screen we're responsible for; can't be larger than screen-height
+  (printed-height:integer <- copy 0:literal)  ; part of screen that currently has text; can't be larger than app-height
+  (cursor-row:integer <- copy 0:literal)  ; position of cursor on screen; can't be larger than printed-height + 1
+  (reply default-space:space-address)
+])
+
+(function $dump-browser-state [
+  (default-space:space-address/names:browser-state <- next-input)
+  ($print expanded-index:integer)
+  ($print (("*" literal)))
+  ($print expanded-children:integer)
+  ($print ((": " literal)))
+  ($print first-index-on-page:integer)
+  ($print (("/" literal)))
+  ($print first-subindex-on-page:integer)
+  ($print ((" => " literal)))
+  ($print last-index-on-page:integer)
+  ($print (("/" literal)))
+  ($print last-subindex-on-page:integer)
+  ($print (("\n" literal)))
+  ($print cursor-row:integer)
+  ($print ((" " literal)))
+  ($print printed-height:integer)
+  ($print ((" " literal)))
+  ($print app-height:integer)
+  ($print ((" " literal)))
+  ($print screen-height:integer)
+  ($print (("\n" literal)))
+])
+
+(function down [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  ; if at expanded, skip past nested lines
+  { begin
+    (no-expanded?:boolean <- less-than expanded-index:integer/space:1 0:literal)
+    (break-if no-expanded?:boolean)
+    (at-expanded?:boolean <- equal cursor-row:integer/space:1 expanded-index:integer/space:1)
+    (break-unless at-expanded?:boolean)
+;?     ($print (("down: at expanded index\n" literal))) ;? 1
+    (n:integer <- instruction-trace-num-children traces:instruction-trace-address-array-address/space:1 expanded-index:integer/space:1)
+    (n:integer <- add n:integer 1:literal)
+    (i:integer <- copy 0:literal)
+    { begin
+      (done?:boolean <- greater-or-equal i:integer n:integer)
+      (break-if done?:boolean)
+      (at-bottom?:boolean <- greater-or-equal cursor-row:integer/space:1 printed-height:integer/space:1)
+      (break-if at-bottom?:boolean)
+;?       ($print (("down: incrementing\n" literal))) ;? 1
+      (cursor-row:integer/space:1 <- add cursor-row:integer/space:1 1:literal)
+      (cursor-down screen:terminal-address)
+      (i:integer <- add i:integer 1:literal)
+      (loop)
+    }
+    (reply)
+  }
+  ; if not at bottom, move cursor down
+  { begin
+    (at-bottom?:boolean <- greater-or-equal cursor-row:integer/space:1 printed-height:integer/space:1)
+    (break-if at-bottom?:boolean)
+    (cursor-row:integer/space:1 <- add cursor-row:integer/space:1 1:literal)
+    (cursor-down screen:terminal-address)
+  }
+])
+
+(function up [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  ; if at expanded, skip past nested lines
+  { begin
+    (no-expanded?:boolean <- less-than expanded-index:integer/space:1 0:literal)
+    (break-if no-expanded?:boolean)
+    (n:integer <- instruction-trace-num-children traces:instruction-trace-address-array-address/space:1 expanded-index:integer/space:1)
+    (n:integer <- add n:integer 1:literal)
+    (cursor-row-below-expanded:integer <- add expanded-index:integer/space:1 n:integer)
+    (just-below-expanded?:boolean <- equal cursor-row:integer/space:1 cursor-row-below-expanded:integer)
+    (break-unless just-below-expanded?:boolean)
+    (i:integer <- copy 0:literal)
+    { begin
+      (done?:boolean <- greater-or-equal i:integer n:integer)
+      (break-if done?:boolean)
+      (at-top?:boolean <- lesser-or-equal cursor-row:integer/space:1 0:literal)
+      (break-if at-top?:boolean)
+      (cursor-row:integer/space:1 <- subtract cursor-row:integer/space:1 1:literal)
+      (cursor-up screen:terminal-address)
+      (i:integer <- add i:integer 1:literal)
+      (loop)
+    }
+    (reply)
+  }
+  ; if not at top, move cursor up
+  { begin
+    (at-top?:boolean <- lesser-or-equal cursor-row:integer/space:1 0:literal)
+    (break-if at-top?:boolean)
+    (cursor-row:integer/space:1 <- subtract cursor-row:integer/space:1 1:literal)
+    (cursor-up screen:terminal-address)
+  }
+])
+
+(function to-bottom [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (at-bottom?:boolean <- greater-or-equal cursor-row:integer/space:1 printed-height:integer/space:1)
+    (break-if at-bottom?:boolean)
+    (down 0:space-address screen:terminal-address)
+    (loop)
+  }
+])
+
+(function to-top [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (at-top?:boolean <- lesser-or-equal cursor-row:integer/space:1 0:literal)
+    (break-if at-top?:boolean)
+    (up 0:space-address screen:terminal-address)
+    (loop)
+  }
+])
+
+(function back-to [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  (target-row:integer <- next-input)
+;?   ($print (("before back-to: " literal))) ;? 1
+;?   ($print cursor-row:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  { begin
+    (below-target?:boolean <- greater-than cursor-row:integer/space:1 target-row:integer)
+    (break-unless below-target?:boolean)
+;?     ($print (("below target\n" literal))) ;? 1
+    (up 0:space-address screen:terminal-address)
+    (loop)
+  }
+  { begin
+    (above-target?:boolean <- less-than cursor-row:integer/space:1 target-row:integer)
+    (break-unless above-target?:boolean)
+;?     ($print (("above target\n" literal))) ;? 1
+    (down 0:space-address screen:terminal-address)
+    (loop)
+  }
+;?   ($print (("after back-to: " literal))) ;? 1
+;?   ($print cursor-row:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+])
+
+(function add-line [  ; move down, adding line if necessary
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (at-bottom?:boolean <- greater-or-equal cursor-row:integer/space:1 printed-height:integer/space:1)
+    (break-unless at-bottom?:boolean)
+    { begin
+      (screen-full?:boolean <- greater-or-equal app-height:integer/space:1 screen-height:integer/space:1)
+      (break-unless screen-full?:boolean)
+      (cursor-to-next-line screen:terminal-address)
+      (cursor-up screen:terminal-address)
+      (reply)
+    }
+    (printed-height:integer/space:1 <- add printed-height:integer/space:1 1:literal)
+    ; update app-height if necessary
+    { begin
+      (grow-max?:boolean <- greater-than printed-height:integer/space:1 app-height:integer/space:1)
+      (break-unless grow-max?:boolean)
+      (app-height:integer/space:1 <- copy printed-height:integer/space:1)
+    }
+  }
+  (cursor-row:integer/space:1 <- add cursor-row:integer/space:1 1:literal)
+  (cursor-to-next-line screen:terminal-address)
+])
+
+;; initial screen state
+(function print-traces-collapsed [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+;?   ($print (("print traces collapsed\n" literal))) ;? 1
+  (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address 0:literal/from)
+  (clear-rest-of-page 0:space-address/browser-state screen:terminal-address)
+])
+
+(function print-traces-collapsed-from [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  (trace-index:integer <- next-input)
+  (limit-index:integer <- next-input)  ; print until this index (exclusive)
+  ; compute bound
+  (max:integer <- length traces:instruction-trace-address-array-address/space:1/deref)
+  { begin
+    (break-unless limit-index:integer)
+    (max:integer <- min max:integer limit-index:integer)
+  }
+  ; print remaining traces collapsed
+  { begin
+    ; until trace ends
+    (trace-done?:boolean <- greater-or-equal trace-index:integer max:integer)
+    (break-if trace-done?:boolean)
+    ; or screen ends
+    (screen-done?:boolean <- greater-or-equal cursor-row:integer/space:1 screen-height:integer/space:1)
+    (break-if screen-done?:boolean)
+;?     ($print (("screen not done\n" literal))) ;? 1
+    ; continue printing trace lines
+    (tr:instruction-trace-address <- index traces:instruction-trace-address-array-address/space:1/deref trace-index:integer)
+    (last-index-on-page:integer/space:1 <- copy trace-index:integer)
+;?     ($print (("setting last index: " literal))) ;? 1
+;?     ($print last-index-on-page:integer/space:1) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (last-subindex-on-page:integer/space:1 <- copy -2:literal)
+    (print-instruction-trace-collapsed screen:terminal-address tr:instruction-trace-address 0:space-address/browser-state)
+    (trace-index:integer <- add trace-index:integer 1:literal)
+    (loop)
+  }
+])
+
+(function clear-rest-of-page [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  { begin
+    (done?:boolean <- greater-or-equal cursor-row:integer/space:1 app-height:integer/space:1)
+    (break-if done?:boolean)
+    (clear-line screen:terminal-address)
+    (down 0:space-address/browser-state screen:terminal-address)
+    (loop)
+  }
+])
+
+(function print-page [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+;?   ($dump-browser-state 0:space-address/browser-state) ;? 3
+  ; if top inside expanded index, complete existing trace
+  (first-full-index:integer <- copy first-index-on-page:integer/space:1)
+  { begin
+    (screen-done?:boolean <- greater-or-equal cursor-row:integer/space:1 screen-height:integer/space:1)
+    (break-unless screen-done?:boolean)
+    (reply)
+  }
+;?   ($print (("\nAAA\n" literal))) ;? 4
+  { begin
+    (partial-trace?:boolean <- equal first-index-on-page:integer/space:1 expanded-index:integer/space:1)
+    (break-unless partial-trace?:boolean)
+;?   ($print (("AAA: partial\n" literal))) ;? 4
+    (first-full-index:integer <- add first-full-index:integer 1:literal)
+    (tr:instruction-trace-address <- index traces:instruction-trace-address-array-address/space:1/deref first-index-on-page:integer/space:1)
+    { begin
+      (print-parent?:boolean <- equal first-subindex-on-page:integer/space:1 -1:literal)
+      (break-unless print-parent?:boolean)
+      (print-instruction-trace-parent screen:terminal-address tr:instruction-trace-address 0:space-address/browser-state)
+    }
+    (ch:trace-address-array-address <- get tr:instruction-trace-address/deref children:offset)
+    (i:integer <- max first-subindex-on-page:integer/space:1 0:literal)
+    ; print any remaining data in the currently expanded trace
+    { begin
+      ; until done with trace
+      (done?:boolean <- greater-or-equal i:integer expanded-children:integer/space:1)
+      (break-if done?:boolean)
+      ; or screen ends
+      (screen-done?:boolean <- greater-or-equal cursor-row:integer/space:1 screen-height:integer/space:1)
+      (break-if screen-done?:boolean)
+;?       ($print (("AAA printing subtrace\n" literal))) ;? 3
+      (t:trace-address <- index ch:trace-address-array-address/deref i:integer)
+      (print-character screen:terminal-address ((#\space literal)))
+      (print-character screen:terminal-address ((#\space literal)))
+      (print-character screen:terminal-address ((#\space literal)))
+      (print-trace screen:terminal-address t:trace-address)
+      (add-line 0:space-address/browser-state screen:terminal-address)
+      (last-subindex-on-page:integer/space:1 <- copy i:integer)
+      (i:integer <- add i:integer 1:literal)
+      (loop)
+    }
+  }
+;?   ($print (("AAA 3: " literal))) ;? 5
+;?   ($print cursor-row:integer/space:1) ;? 4
+;?   ($print (("\n" literal))) ;? 4
+  { begin
+    (screen-done?:boolean <- greater-or-equal cursor-row:integer/space:1 screen-height:integer/space:1)
+    (break-unless screen-done?:boolean)
+    (reply)
+  }
+;?   ($print (("AAA 4\n" literal))) ;? 5
+  { begin
+    (has-expanded?:boolean <- greater-or-equal expanded-index:integer/space:1 0:literal)
+    (break-if has-expanded?:boolean)
+;?     ($print (("AAA 5a\n" literal))) ;? 4
+    (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address first-full-index:integer)
+    (clear-rest-of-page 0:space-address/browser-state screen:terminal-address)
+    (reply)
+  }
+  { begin
+    (below-expanded?:boolean <- greater-than first-full-index:integer expanded-index:integer/space:1)
+    (break-unless below-expanded?:boolean)
+;?     ($print (("AAA 5b\n" literal))) ;? 4
+    (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address first-full-index:integer)
+    (clear-rest-of-page 0:space-address/browser-state screen:terminal-address)
+    (reply)
+  }
+  ; trace has an expanded index and it's below first-full-index
+  ; print traces collapsed until expanded index
+;?   ($print (("AAA 5c\n" literal))) ;? 4
+  (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address first-full-index:integer expanded-index:integer/space:1/until)
+  ; if room, start printing expanded index
+  { begin
+    (done?:boolean <- greater-or-equal cursor-row:integer/space:1 screen-height:integer/space:1)
+    (break-if done?:boolean)
+    (tr:instruction-trace-address <- index traces:instruction-trace-address-array-address/space:1/deref expanded-index:integer/space:1)
+    (print-instruction-trace screen:terminal-address tr:instruction-trace-address 0:space-address/browser-state)
+    (clear-rest-of-page 0:space-address/browser-state screen:terminal-address)
+  }
+])
+
+(function cursor-row-to-trace-index [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (n:integer/screen <- next-input)
+;?   ($print (("to trace index: first subindex " literal))) ;? 1
+;?   ($print first-subindex-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+;?   ($print (("cursor-to-index: n " literal))) ;? 2
+;?   ($print n:integer) ;? 2
+;?   ($print (("\n" literal))) ;? 2
+;?   ($print (("cursor-to-index: first index " literal))) ;? 2
+;?   ($print first-index-on-page:integer/space:1) ;? 2
+;?   ($print (("\n" literal))) ;? 2
+  (simple-result:integer <- add first-index-on-page:integer/space:1 n:integer)
+;?   ($print (("cursor-to-index: simple result " literal))) ;? 2
+;?   ($print simple-result:integer) ;? 2
+;?   ($print (("\n" literal))) ;? 2
+  ; no row expanded? no munging needed
+  { begin
+    (has-expanded?:boolean <- greater-or-equal expanded-index:integer/space:1 0:literal)
+    (break-if has-expanded?:boolean)
+    (reply simple-result:integer)
+  }
+  ; expanded row above current page? no munging needed
+  { begin
+    (below-expanded?:boolean <- less-than expanded-index:integer/space:1 first-index-on-page:integer/space:1)
+    (break-unless below-expanded?:boolean)
+    (reply simple-result:integer)
+  }
+  ; expanded row at top of current page and partial?
+  { begin
+    (expanded-at-top?:boolean <- equal first-index-on-page:integer/space:1 expanded-index:integer/space:1)
+;?     ($print (("cursor-to-index: first subindex " literal))) ;? 2
+;?     ($print first-subindex-on-page:integer/space:1) ;? 2
+;?     ($print (("\n" literal))) ;? 2
+    (partial-at-top?:boolean <- greater-or-equal first-subindex-on-page:integer/space:1 0:literal)
+;?     ($print (("AAA\n" literal))) ;? 1
+    (partial-expanded-at-top?:boolean <- and expanded-at-top?:boolean partial-at-top?:boolean)
+    (break-unless partial-expanded-at-top?:boolean)
+;?     ($print (("expanded child at top of page\n" literal))) ;? 2
+    (expanded-children-on-page:integer <- subtract expanded-children:integer/space:1 first-subindex-on-page:integer/space:1)
+    (result:integer <- subtract simple-result:integer expanded-children-on-page:integer)
+    (result:integer <- add result:integer 1:literal)
+    (result:integer <- max result:integer first-index-on-page:integer/space:1)
+    (reply result:integer)
+  }
+  ; expanded row is below current page? no munging needed
+  { begin
+    (above-expanded?:boolean <- lesser-or-equal last-index-on-page:integer/space:1 expanded-index:integer/space:1 )
+    (break-unless above-expanded?:boolean)
+    (reply simple-result:integer)
+  }
+  (expanded-index-cursor-row:integer <- subtract expanded-index:integer/space:1 first-index-on-page:integer/space:1)
+  ; cursor is above expanded index? no munging needed
+  { begin
+    (above-expanded?:boolean <- lesser-or-equal cursor-row:integer/space:1 expanded-index-cursor-row:integer)
+    (break-unless above-expanded?:boolean)
+    (reply simple-result:integer)
+  }
+  (result:integer/index <- subtract simple-result:integer expanded-children:integer/space:1)
+  (reply result:integer/index)
+])
+
+(function back-to-index [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (screen:terminal-address <- next-input)
+  (target-index:integer <- next-input)
+;?   ($print (("back-to-index: target " literal))) ;? 3
+;?   ($print target-index:integer) ;? 3
+;?   ($print (("\n" literal))) ;? 3
+;?   ($print (("back-to-index: first subindex " literal))) ;? 1
+;?   ($print first-subindex-on-page:integer/space:1) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  ; scan up until top, or *before* target-index (to skip expanded children)
+  { begin
+;?     ($print cursor-row:integer/space:1) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (at-top?:boolean <- equal cursor-row:integer/space:1 0:literal)
+    (break-if at-top?:boolean)
+    (index:integer <- cursor-row-to-trace-index 0:space-address/browser-state cursor-row:integer/space:1)
+;?     ($print cursor-row:integer/space:1) ;? 3
+;?     ($print ((" " literal))) ;? 3
+;?     ($print index:integer) ;? 3
+;?     ($print (("\n" literal))) ;? 3
+    (done?:boolean <- less-than index:integer target-index:integer)
+    (break-if done?:boolean)
+    (up 0:space-address screen:terminal-address)
+    (loop)
+  }
+  ; now if we're before target-index, down 1
+;?   ($print (("final down?\n" literal))) ;? 1
+  (index:integer <- cursor-row-to-trace-index 0:space-address/browser-state cursor-row:integer/space:1)
+;?   ($print (("done scanning; cursor at row " literal))) ;? 2
+;?   ($print cursor-row:integer/space:1) ;? 2
+;?   ($print ((", which is index " literal))) ;? 2
+;?   ($print index:integer) ;? 2
+;?   ($print (("\n" literal))) ;? 2
+  { begin
+    (at-target?:boolean <- greater-or-equal index:integer target-index:integer)
+    (break-if at-target?:boolean)
+;?     ($print (("down 1\n" literal))) ;? 2
+    ; above expanded
+    (down 0:space-address screen:terminal-address)
+  }
+])
+
+;; pagination helpers
+(function at-first-page [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)  ; read-only
+  (result:boolean <- lesser-or-equal first-index-on-page:integer/space:1 0:literal)
+  { begin
+    (break-if result:boolean)
+    (reply nil:literal)
+  }
+  (expanded?:boolean <- equal expanded-index:integer/space:1 0:literal)
+  { begin
+    (break-if expanded?:boolean)
+    (reply t:literal)
+  }
+  ; if first subindex is 0, the top-level line is on a previous page
+  (result:boolean <- less-than first-subindex-on-page:integer/space:1 0:literal)
+  (reply result:boolean)
+])
+
+(function at-final-page [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)  ; read-only
+  (len:integer <- length traces:instruction-trace-address-array-address/space:1/deref)
+  (final-index:integer <- subtract len:integer 1:literal)
+  (result:boolean <- greater-or-equal last-index-on-page:integer/space:1 final-index:integer)
+  { begin
+    (break-if result:boolean)
+    (reply nil:literal)
+  }
+  (last-trace-expanded?:boolean <- equal expanded-index:integer/space:1 len:integer)
+  { begin
+    (break-if last-trace-expanded?:boolean)
+    (reply t:literal)
+  }
+  (result:boolean <- greater-or-equal last-subindex-on-page:integer/space:1 expanded-children:integer/space:1)
+  (reply result:boolean)
+])
+
+(function next-page [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  { begin
+;?     ($print (("expanded: " literal))) ;? 3
+;?     ($print expanded-index:integer/space:1) ;? 3
+;?     ($print ((" last index: " literal))) ;? 3
+;?     ($print last-index-on-page:integer/space:1) ;? 3
+;?     ($print (("\n" literal))) ;? 3
+    (last-index-expanded?:boolean <- equal expanded-index:integer/space:1 last-index-on-page:integer/space:1)
+    (break-unless last-index-expanded?:boolean)
+    ; expanded
+;?     ($print (("last expanded\n" literal))) ;? 3
+    { begin
+      (expanded-index-done?:boolean <- equal expanded-children:integer/space:1 last-subindex-on-page:integer/space:1)
+      (break-if expanded-index-done?:boolean 2:blocks)
+;?       ($print (("children left\n" literal))) ;? 3
+      ; children left to open
+      (first-index-on-page:integer/space:1 <- copy last-index-on-page:integer/space:1)
+      (first-subindex-on-page:integer/space:1 <- add last-subindex-on-page:integer/space:1 1:literal)
+      (reply)
+    }
+  }
+  (first-index-on-page:integer/space:1 <- add last-index-on-page:integer/space:1 1:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+])
+
+(function previous-page [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+;?   ($print (("before: " literal))) ;? 2
+;?   ($print first-index-on-page:integer/space:1) ;? 2
+;?   ($print ((" " literal))) ;? 2
+;?   ($print first-subindex-on-page:integer/space:1) ;? 2
+;?   ($print (("\n" literal))) ;? 2
+  ; easy case: no expanded-index
+  (jump-unless expanded-index:integer/space:1)
+;?   ($print (("b\n" literal))) ;? 4
+  (x:boolean <- less-than expanded-index:integer/space:1 0:literal)
+  (jump-if x:boolean easy-case:offset)
+  ; easy case: expanded-index lies below top of current page
+;?   ($print (("c\n" literal))) ;? 4
+  (x:boolean <- greater-than expanded-index:integer/space:1 first-index-on-page:integer/space:1)
+  (jump-if x:boolean easy-case:offset)
+  ; easy case: expanded-index *starts* at top of current page
+;?   ($print (("d\n" literal))) ;? 5
+  (top-of-screen-inside-expanded:boolean <- equal expanded-index:integer/space:1 first-index-on-page:integer/space:1)
+  (y:boolean <- lesser-or-equal first-subindex-on-page:integer/space:1 -1:literal)
+  (y:boolean <- and top-of-screen-inside-expanded:boolean y:boolean)
+  (jump-if y:boolean easy-case:offset)
+  ; easy case: expanded-index too far up for previous page
+;?   ($print (("e\n" literal))) ;? 5
+  (delta-to-expanded:integer <- subtract first-index-on-page:integer/space:1 expanded-index:integer/space:1)
+;?   ($print delta-to-expanded:integer) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  (x:boolean <- greater-than delta-to-expanded:integer screen-height:integer/space:1)
+  (jump-if x:boolean easy-case:offset)
+;?   ($print (("f\n" literal))) ;? 5
+  ; tough case: expanded index overlaps current and/or previous page
+  (lines-remaining-to-decrement:integer <- copy screen-height:integer/space:1)
+  ; a) scroll to just below expanded-index if necessary
+  (below-expanded-index:integer <- add expanded-index:integer/space:1 1:literal)
+  { begin
+    (done?:boolean <- done-scrolling-up default-space:space-address)
+    (break-if done?:boolean)
+    (done?:boolean <- lesser-or-equal first-index-on-page:integer/space:1 below-expanded-index:integer)
+    (break-if done?:boolean)
+;?     ($print (("g\n" literal))) ;? 2
+    (first-index-on-page:integer/space:1 <- subtract first-index-on-page:integer/space:1 1:literal)
+    (lines-remaining-to-decrement:integer <- subtract lines-remaining-to-decrement:integer 1:literal)
+    (loop)
+  }
+  { begin
+;?     ($print (("h\n" literal))) ;? 2
+    (x:boolean <- equal first-index-on-page:integer/space:1 below-expanded-index:integer)
+    (break-unless x:boolean)
+    (first-index-on-page:integer/space:1 <- copy expanded-index:integer/space:1)
+    (first-subindex-on-page:integer/space:1 <- subtract expanded-children:integer/space:1 1:literal)
+    (lines-remaining-to-decrement:integer <- subtract lines-remaining-to-decrement:integer 1:literal)
+  }
+  ; b) scroll through expanded-children if necessary
+  { begin
+    (done?:boolean <- done-scrolling-up default-space:space-address)
+    (break-if done?:boolean)
+    (done?:boolean <- less-than first-subindex-on-page:integer/space:1 0:literal)
+    (break-if done?:boolean)
+;?     ($print (("i\n" literal))) ;? 2
+    (first-subindex-on-page:integer/space:1 <- subtract first-subindex-on-page:integer/space:1 1:literal)
+    (lines-remaining-to-decrement:integer <- subtract lines-remaining-to-decrement:integer 1:literal)
+    (loop)
+  }
+  ; c) jump past expanded-index parent if necessary
+;?   ($print (("j\n" literal))) ;? 2
+  { begin
+    (done?:boolean <- done-scrolling-up default-space:space-address)
+    (break-if done?:boolean)
+;?     ($print (("k\n" literal))) ;? 2
+    (first-index-on-page:integer/space:1 <- subtract first-index-on-page:integer/space:1 1:literal)
+    (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+    (lines-remaining-to-decrement:integer <- subtract lines-remaining-to-decrement:integer 1:literal)
+  }
+  ; d) scroll up before expanded-index if necessary
+;?   ($print (("l\n" literal))) ;? 2
+  { begin
+    (done?:boolean <- done-scrolling-up default-space:space-address)
+    (break-if done?:boolean)
+;?     ($print (("m\n" literal))) ;? 2
+    (first-index-on-page:integer/space:1 <- subtract first-index-on-page:integer/space:1 1:literal)
+    (lines-remaining-to-decrement:integer <- subtract lines-remaining-to-decrement:integer 1:literal)
+    (loop)
+  }
+  (reply)
+  easy-case
+  (first-index-on-page:integer/space:1 <- subtract first-index-on-page:integer/space:1 screen-height:integer/space:1)
+  (first-index-on-page:integer/space:1 <- max first-index-on-page:integer/space:1 0:literal)
+  (first-subindex-on-page:integer/space:1 <- copy -2:literal)
+])
+
+(function done-scrolling-up [
+  (default-space:space-address/names:previous-page <- next-input)
+  (0:space-address/names:browser-state <- copy 0:space-address)  ; just to wire up names for space/1
+  (at-top-of-screen?:boolean <- lesser-or-equal lines-remaining-to-decrement:integer 0:literal)
+  (jump-if at-top-of-screen?:boolean done:offset)
+  (at-first-index:boolean <- lesser-or-equal first-index-on-page:integer/space:1 0:literal)
+  (at-first-subindex:boolean <- lesser-or-equal first-subindex-on-page:integer/space:1 -1:literal)
+  (trace-done?:boolean <- and at-first-index:boolean at-first-subindex:boolean)
+  (jump-if trace-done?:boolean done:offset)
+  (reply nil:literal)
+  done
+  (reply t:literal)
+])
+
+;; modify screen state in response to a single key
+(function process-key [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  (0:space-address/names:browser-state <- next-input)
+  (k:keyboard-address <- next-input)
+  (screen:terminal-address <- next-input)
+  (c:character <- read-key k:keyboard-address silent:literal/terminal)
+  { begin
+    ; no key yet
+    (break-if c:character)
+    (reply nil:literal)
+  }
+;?   ($print (("key pressed: " literal))) ;? 1
+;?   ($write c:character) ;? 1
+;?   ($print (("\n" literal))) ;? 1
+  { begin
+    ; user quit
+    (q-pressed?:boolean <- equal c:character ((#\q literal)))
+    (end-of-fake-keyboard-input?:boolean <- equal c:character ((#\null literal)))
+    (quit?:boolean <- or q-pressed?:boolean end-of-fake-keyboard-input?:boolean)
+    (break-unless quit?:boolean)
+    (reply t:literal)
+  }
+  ; up/down navigation
+  { begin
+    (up?:boolean <- equal c:character ((up literal)))
+    (k?:boolean <- equal c:character ((#\k literal)))
+    (up?:boolean <- or up?:boolean k?:boolean)
+    (break-unless up?:boolean)
+    (up 0:space-address/browser-state screen:terminal-address)
+    (reply nil:literal)
+  }
+  { begin
+    (down?:boolean <- equal c:character ((down literal)))
+    (j?:boolean <- equal c:character ((#\j literal)))
+    (down?:boolean <- or down?:boolean j?:boolean)
+    (break-unless down?:boolean)
+    (down 0:space-address/browser-state screen:terminal-address)
+    (reply nil:literal)
+  }
+  ; page up/page down
+  { begin
+    ; if page-up pressed
+    (page-up?:boolean <- equal c:character ((pgup literal)))
+    (K?:boolean <- equal c:character ((#\K literal)))
+    (page-up?:boolean <- or page-up?:boolean K?:boolean)
+    (break-unless page-up?:boolean)
+    ; if we're not already at start of trace
+    (first-page?:boolean <- at-first-page 0:space-address/browser-state)
+    (break-if first-page?:boolean)
+    ; move cursor to top of screen
+    (to-top 0:space-address/browser-state screen:terminal-address)
+    ; switch browser state
+    (previous-page 0:space-address/browser-state)
+;?     ($dump-browser-state 0:space-address) ;? 3
+    ; redraw
+    (print-page 0:space-address/browser-state screen:terminal-address)
+    (reply nil:literal)
+  }
+  { begin
+    ; if page-down pressed
+    (page-down?:boolean <- equal c:character ((pgdn literal)))
+    (J?:boolean <- equal c:character ((#\J literal)))
+    (page-down?:boolean <- or page-down?:boolean J?:boolean)
+    (break-unless page-down?:boolean)
+    ; if we're not already at end of trace
+    (final-page?:boolean <- at-final-page 0:space-address/browser-state)
+    (break-if final-page?:boolean)
+    ; move cursor to top of screen
+    (to-top 0:space-address/browser-state screen:terminal-address)
+;?     ($print (("before: " literal))) ;? 1
+;?     ($print first-index-on-page:integer/space:1) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    ; switch browser state
+    (next-page 0:space-address/browser-state)
+;?     ($print (("after: " literal))) ;? 1
+;?     ($print first-index-on-page:integer/space:1) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    ; redraw
+    (print-page 0:space-address/browser-state screen:terminal-address)
+    ; move cursor back to top of screen
+    (to-top 0:space-address/browser-state screen:terminal-address)
+    (reply nil:literal)
+  }
+  ; enter: expand/collapse current row
+  { begin
+    (toggle?:boolean <- equal c:character ((#\newline literal)))
+    (break-unless toggle?:boolean)
+;?     ($print (("expand: first subindex " literal))) ;? 1
+;?     ($print first-subindex-on-page:integer/space:1) ;? 1
+;?     ($print (("\n" literal))) ;? 1
+    (original-cursor-row:integer <- copy cursor-row:integer/space:1)
+;?     ($print (("cursor starts at row " literal))) ;? 6
+;?     ($print original-cursor-row:integer) ;? 7
+;?     ($print (("\n" literal))) ;? 7
+    (original-trace-index:integer <- cursor-row-to-trace-index 0:space-address/browser-state original-cursor-row:integer)
+;?     ($print (("which maps to index " literal))) ;? 7
+;?     ($print original-trace-index:integer) ;? 9
+;?     ($print (("\n" literal))) ;? 9
+    ; is expanded-index already set?
+    { begin
+      (expanded?:boolean <- greater-or-equal expanded-index:integer/space:1 0:literal)
+      (break-unless expanded?:boolean)
+      (too-early?:boolean <- less-than expanded-index:integer/space:1 first-index-on-page:integer/space:1)
+      (break-if too-early?:boolean)
+      (too-late?:boolean <- greater-than expanded-index:integer/space:1 last-index-on-page:integer/space:1)
+      (break-if too-late?:boolean)
+      ; expanded-index is now on this page
+;?       ($print (("expanded index on this page\n" literal))) ;? 6
+      { begin
+        ; are we at the expanded row?
+        (at-expanded?:boolean <- equal original-trace-index:integer expanded-index:integer/space:1)
+        (break-unless at-expanded?:boolean)
+;?         ($print (("at expanded index\n" literal))) ;? 5
+        ; print remaining lines collapsed and return
+        (back-to-index 0:space-address/browser-state screen:terminal-address expanded-index:integer/space:1)
+        (expanded-index:integer/space:1 <- copy -1:literal)
+        (expanded-children:integer/space:1 <- copy -1:literal)
+        (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address original-trace-index:integer)
+        (clear-rest-of-page 0:space-address/browser-state screen:terminal-address)
+        (back-to 0:space-address/browser-state screen:terminal-address original-cursor-row:integer)
+        (reply nil:literal)
+      }
+      ; are we below the expanded row?
+      { begin
+        (below-expanded?:boolean <- greater-than original-trace-index:integer expanded-index:integer/space:1)
+        (break-unless below-expanded?:boolean)
+;?         ($print (("below expanded index\n" literal))) ;? 6
+        (back-to-index 0:space-address/browser-state screen:terminal-address expanded-index:integer/space:1)
+;?         ($print (("scanning up to row " literal))) ;? 3
+;?         ($print cursor-row:integer/space:1) ;? 3
+;?         ($print (("\n" literal))) ;? 3
+        ; print traces collapsed until just before original row
+        (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address expanded-index:integer/space:1 original-trace-index:integer/until)
+        ; fall through
+      }
+    }
+    ; expand original row and print traces below it
+;?     ($print (("done collapsing previously expanded index\n" literal))) ;? 6
+    (expanded-index:integer/space:1 <- copy original-trace-index:integer)
+    (last-index-on-page:integer/space:1 <- copy original-trace-index:integer)
+    (tr:instruction-trace-address <- index traces:instruction-trace-address-array-address/space:1/deref original-trace-index:integer)
+;?     ($print (("expanded\n" literal))) ;? 6
+    (print-instruction-trace screen:terminal-address tr:instruction-trace-address 0:space-address/browser-state)
+    (next-index:integer <- add original-trace-index:integer 1:literal)
+;?     ($print (("printing collapsed lines from " literal))) ;? 7
+;?     ($print next-index:integer) ;? 8
+;?     ($print (("\n" literal))) ;? 8
+    (print-traces-collapsed-from 0:space-address/browser-state screen:terminal-address next-index:integer)
+;?     ($print (("clearing rest of page\n" literal))) ;? 6
+    (clear-rest-of-page 0:space-address/browser-state screen:terminal-address)
+;?     ($print (("moving cursor back up\n" literal))) ;? 6
+    (back-to-index 0:space-address/browser-state screen:terminal-address original-trace-index:integer)
+;?     ($print (("returning\n" literal))) ;? 5
+    (reply nil:literal)
+  }
+  (reply nil:literal)
+])
+
+(function browse-trace [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ($print (("parsing trace... (might take a while, depending on how long the trace is)\n" literal)))
+  (x:string-address <- next-input)
+  (screen-height:integer <- next-input)
+;?   (print-string nil:literal/terminal x:string-address) ;? 1
+  (s:stream-address <- init-stream x:string-address)
+  (traces:instruction-trace-address-array-address <- parse-traces s:stream-address)
+  (0:space-address/names:browser-state <- browser-state traces:instruction-trace-address-array-address screen-height:integer)
+  (cursor-mode)
+  (print-traces-collapsed 0:space-address/browser-state nil:literal/terminal)
+  { begin
+    (quit?:boolean <- process-key 0:space-address/browser-state nil:literal/keyboard nil:literal/terminal)
+    (break-if quit?:boolean)
+    (loop)
+  }
+  ; move cursor to bottom before exiting
+  (to-bottom 0:space-address/browser-state nil:literal/terminal)
+  (retro-mode)
+])
+
+(function main [
+  (default-space:space-address <- new space:literal 30:literal/capacity)
+  ($print (("loading trace.. (takes ~10s)\n" literal)))
+  (x:string-address <- new
+"run: main 0: a b c
+mem: 0
+run: main 1: d e f
+mem: 1
+mem: 1
+mem: 1
+mem: 1
+mem: 1
+run: main 2: g hi
+run: main 3: j
+mem: 3
+run: main 4: k
+run: main 5: l
+run: main 6: m
+run: main 7: n
+run: main 8: o")
+  (browse-trace x:string-address 3:literal/screen-height)
+])
diff --git a/archive/0.vm.arc/vimrc.vim b/archive/0.vm.arc/vimrc.vim
new file mode 100644
index 00000000..d2a65146
--- /dev/null
+++ b/archive/0.vm.arc/vimrc.vim
@@ -0,0 +1,8 @@
+syntax sync minlines=999
+
+function! HighlightMuInArc()
+  set ft=mu
+  syntax keyword muHack begin | highlight link muHack CommentedCode
+  syntax match muHack "[()]" | highlight link muHack CommentedCode
+endfunction
+autocmd BufRead,BufNewFile *.mu call HighlightMuInArc()
diff --git a/archive/0.vm.arc/x.mu b/archive/0.vm.arc/x.mu
new file mode 100644
index 00000000..778298a8
--- /dev/null
+++ b/archive/0.vm.arc/x.mu
@@ -0,0 +1,6 @@
+(function main [
+  (x:integer <- copy 1:literal)
+  (y:integer <- copy 3:literal)
+  (z:integer <- add x:integer y:integer)
+  ($dump-memory)
+])