https://github.com/akkartik/mu/blob/main/shell/environment.mu
   1 # The top-level data structure for the Mu shell.
   2 #
   3 # vim:textwidth&
   4 # It would be nice for tests to use a narrower screen than the standard 0x80 of
   5 # 1024 pixels with 8px-wide graphemes. But it complicates rendering logic to
   6 # make width configurable, so we just use longer lines than usual.
   7 
   8 type environment {
   9   globals: global-table
  10   sandbox: sandbox
  11   # some state for a modal dialog for navigating between globals
  12   partial-global-name: (handle gap-buffer)
  13   go-modal-error: (handle array byte)
  14   #
  15   cursor-in-globals?: boolean
  16   cursor-in-go-modal?: boolean
  17 }
  18 
  19 # Here's a sample usage session and what it will look like on the screen.
  20 fn test-environment {
  21   var env-storage: environment
  22   var env/esi: (addr environment) <- address env-storage
  23   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
  24   # setup: screen
  25   var screen-on-stack: screen
  26   var screen/edi: (addr screen) <- address screen-on-stack
  27   initialize-screen screen, 0x80/width, 0x30/height, 0/no-pixel-graphics
  28   # type some code into sandbox
  29   type-in env, screen, "(+ 3 4)"  # we don't have any global definitions here, so no macros
  30   # run code in sandbox
  31   edit-environment env, 0x13/ctrl-s, 0/no-disk
  32   render-environment screen, env
  33   #                                                         | global definitions                                                                 | sandbox
  34   # top row blank for now
  35   check-screen-row                     screen,         0/y, "                                                                                                                                ", "F - test-environment/0"
  36   check-screen-row                     screen,         1/y, "                                                                                      screen:                                   ", "F - test-environment/1"
  37   check-background-color-in-screen-row screen, 0/bg,   2/y, "                                                                                        ........                                ", "F - test-environment/2"
  38   check-background-color-in-screen-row screen, 0/bg,   3/y, "                                                                                        ........                                ", "F - test-environment/3"
  39   check-background-color-in-screen-row screen, 0/bg,   4/y, "                                                                                        ........                                ", "F - test-environment/4"
  40   check-screen-row                     screen,         5/y, "                                                                                                                                ", "F - test-environment/5"
  41   check-screen-row                     screen,         6/y, "                                                                                      keyboard:                                 ", "F - test-environment/6"
  42   check-background-color-in-screen-row screen, 0/bg,   6/y, "                                                                                                ................                ", "F - test-environment/6-2"
  43   check-screen-row                     screen,         7/y, "                                                                                                                                ", "F - test-environment/7"
  44   check-screen-row                     screen,         8/y, "                                                                                      (+ 3 4)                                   ", "F - test-environment/8"
  45   check-screen-row                     screen,         9/y, "                                                                                      ...                       trace depth: 4  ", "F - test-environment/9"
  46   check-screen-row                     screen,       0xa/y, "                                                                                      => 7                                      ", "F - test-environment/10"
  47   check-screen-row                     screen,       0xb/y, "                                                                                                                                ", "F - test-environment/11"
  48   check-screen-row                     screen,       0xc/y, "                                                                                                                                ", "F - test-environment/12"
  49   check-screen-row                     screen,       0xd/y, "                                                                                                                                ", "F - test-environment/13"
  50   check-screen-row                     screen,       0xe/y, "                                                                                                                                ", "F - test-environment/14"
  51   # bottom row is for a wordstar-style menu
  52   check-screen-row                     screen,      0x2f/y, " ^r  run main   ^s  run sandbox   ^g  go to   ^m  to trace   ^a  <<   ^b  <word   ^f  word>   ^e  >>                            ", "F - test-environment/15"
  53 }
  54 
  55 fn test-definition-in-environment {
  56   var env-storage: environment
  57   var env/esi: (addr environment) <- address env-storage
  58   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
  59   # setup: screen
  60   var screen-on-stack: screen
  61   var screen/edi: (addr screen) <- address screen-on-stack
  62   initialize-screen screen, 0x80/width, 0x30/height, 0/no-pixel-graphics
  63   # define a global on the right (sandbox) side
  64   type-in env, screen, "(define f 42)"
  65   edit-environment env, 0x13/ctrl-s, 0/no-disk
  66   render-environment screen, env
  67   #                                                         | global definitions                                                                 | sandbox
  68   check-screen-row                     screen,         0/y, "                                                                                                                                ", "F - test-definition-in-environment/0"
  69   # global definition is now on the left side
  70   check-screen-row                     screen,         1/y, "                                           (define f 42)                              screen:                                   ", "F - test-definition-in-environment/1"
  71   check-background-color-in-screen-row screen, 0/bg,   2/y, "                                                                                        ........                                ", "F - test-definition-in-environment/2"
  72   check-background-color-in-screen-row screen, 0/bg,   3/y, "                                                                                        ........                                ", "F - test-definition-in-environment/3"
  73   check-background-color-in-screen-row screen, 0/bg,   4/y, "                                                                                        ........                                ", "F - test-definition-in-environment/4"
  74   check-screen-row                     screen,         5/y, "                                                                                                                                ", "F - test-definition-in-environment/4"
  75   check-screen-row                     screen,         6/y, "                                                                                      keyboard:                                 ", "F - test-definition-in-environment/5"
  76   check-background-color-in-screen-row screen, 0/bg,   6/y, "                                                                                                ................                ", "F - test-definition-in-environment/5-2"
  77   check-screen-row                     screen,         7/y, "                                                                                                                                ", "F - test-definition-in-environment/6"
  78   check-screen-row                     screen,         8/y, "                                                                                                                                ", "F - test-definition-in-environment/7"
  79   # you can still see the trace on the right for what you just added to the left
  80   check-screen-row                     screen,         9/y, "                                                                                      ...                       trace depth: 4  ", "F - test-definition-in-environment/8"
  81 }
  82 
  83 # helper for testing
  84 fn type-in self: (addr environment), screen: (addr screen), keys: (addr array byte) {
  85   # clear the buffer
  86   edit-environment self, 0x15/ctrl-u, 0/no-disk
  87   render-environment screen, self
  88   # type in all the keys
  89   var input-stream-storage: (stream byte 0x40/capacity)
  90   var input-stream/ecx: (addr stream byte) <- address input-stream-storage
  91   write input-stream, keys
  92   {
  93     var done?/eax: boolean <- stream-empty? input-stream
  94     compare done?, 0/false
  95     break-if-!=
  96     var key/eax: grapheme <- read-grapheme input-stream
  97     edit-environment self, key, 0/no-disk
  98     render-environment screen, self
  99     loop
 100   }
 101 }
 102 
 103 fn initialize-environment _self: (addr environment), fake-screen-width: int, fake-screen-height: int {
 104   var self/esi: (addr environment) <- copy _self
 105   var globals/eax: (addr global-table) <- get self, globals
 106   initialize-globals globals
 107   var sandbox/eax: (addr sandbox) <- get self, sandbox
 108   initialize-sandbox sandbox, fake-screen-width, fake-screen-height
 109   var partial-global-name-ah/eax: (addr handle gap-buffer) <- get self, partial-global-name
 110   allocate partial-global-name-ah
 111   var partial-global-name/eax: (addr gap-buffer) <- lookup *partial-global-name-ah
 112   initialize-gap-buffer partial-global-name, 0x40/global-name-capacity
 113 }
 114 
 115 fn render-environment screen: (addr screen), _self: (addr environment) {
 116   # globals layout: 1 char padding, 41 code, 1 padding, 41 code, 1 padding =  85
 117   # sandbox layout: 1 padding, 41 code, 1 padding                          =  43
 118   #                                                                  total = 128 chars
 119   var self/esi: (addr environment) <- copy _self
 120   var cursor-in-globals-a/eax: (addr boolean) <- get self, cursor-in-globals?
 121   var cursor-in-globals?/eax: boolean <- copy *cursor-in-globals-a
 122   var globals/ecx: (addr global-table) <- get self, globals
 123   render-globals screen, globals, cursor-in-globals?
 124   var sandbox/edx: (addr sandbox) <- get self, sandbox
 125   var cursor-in-sandbox?/ebx: boolean <- copy 1/true
 126   cursor-in-sandbox? <- subtract cursor-in-globals?
 127   render-sandbox screen, sandbox, 0x55/sandbox-left-margin, 0/sandbox-top-margin, 0x80/screen-width, 0x2f/screen-height-without-menu, cursor-in-sandbox?
 128   # modal if necessary
 129   {
 130     var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 131     compare *cursor-in-go-modal-a, 0/false
 132     break-if-=
 133     render-go-modal screen, self
 134     render-go-modal-menu screen, self
 135     return
 136   }
 137   # render menu
 138   {
 139     var cursor-in-globals?/eax: (addr boolean) <- get self, cursor-in-globals?
 140     compare *cursor-in-globals?, 0/false
 141     break-if-=
 142     render-globals-menu screen, globals
 143     return
 144   }
 145   render-sandbox-menu screen, sandbox
 146 }
 147 
 148 fn edit-environment _self: (addr environment), key: grapheme, data-disk: (addr disk) {
 149   var self/esi: (addr environment) <- copy _self
 150   var globals/edi: (addr global-table) <- get self, globals
 151   var sandbox/ecx: (addr sandbox) <- get self, sandbox
 152   # ctrl-r
 153   # Assumption: 'real-screen' and 'real-keyboard' are 0
 154   {
 155     compare key, 0x12/ctrl-r
 156     break-if-!=
 157     var tmp/eax: (addr handle cell) <- copy 0
 158     var nil: (handle cell)
 159     tmp <- address nil
 160     allocate-pair tmp
 161     # (main real-screen real-keyboard)
 162     var real-keyboard: (handle cell)
 163     tmp <- address real-keyboard
 164     allocate-keyboard tmp
 165     # args = cons(real-keyboard, nil)
 166     var args: (handle cell)
 167     tmp <- address args
 168     new-pair tmp, real-keyboard, nil
 169     #
 170     var real-screen: (handle cell)
 171     tmp <- address real-screen
 172     allocate-screen tmp
 173     #  args = cons(real-screen, args)
 174     tmp <- address args
 175     new-pair tmp, real-screen, *tmp
 176     #
 177     var main: (handle cell)
 178     tmp <- address main
 179     new-symbol tmp, "main"
 180     # args = cons(main, args)
 181     tmp <- address args
 182     new-pair tmp, main, *tmp
 183     # clear real screen
 184     clear-screen 0/screen
 185     set-cursor-position 0/screen, 0, 0
 186     # run
 187     var out: (handle cell)
 188     var out-ah/ecx: (addr handle cell) <- address out
 189     var trace-storage: trace
 190     var trace/ebx: (addr trace) <- address trace-storage
 191     initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
 192     evaluate tmp, out-ah, nil, globals, trace, 0/no-fake-screen, 0/no-fake-keyboard, 0/definitions-created, 0/call-number
 193     # wait for a keypress
 194     {
 195       var tmp/eax: byte <- read-key 0/keyboard
 196       compare tmp, 0
 197       loop-if-=
 198     }
 199     #
 200     return
 201   }
 202   # ctrl-s: send multiple places
 203   {
 204     compare key, 0x13/ctrl-s
 205     break-if-!=
 206     {
 207       # cursor in go modal? do nothing
 208       var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 209       compare *cursor-in-go-modal-a, 0/false
 210       break-if-!=
 211       {
 212         # cursor in globals? update current definition
 213         var cursor-in-globals-a/edx: (addr boolean) <- get self, cursor-in-globals?
 214         compare *cursor-in-globals-a, 0/false
 215         break-if-=
 216         edit-globals globals, key
 217       }
 218       # update sandbox whether the cursor is in globals or sandbox
 219       edit-sandbox sandbox, key, globals, data-disk
 220     }
 221     return
 222   }
 223   # dispatch to go modal if necessary
 224   {
 225     var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 226     compare *cursor-in-go-modal-a, 0/false
 227     break-if-=
 228     # nested events for modal dialog
 229     # ignore spaces
 230     {
 231       compare key, 0x20/space
 232       break-if-!=
 233       return
 234     }
 235     # esc = exit modal dialog
 236     {
 237       compare key, 0x1b/escape
 238       break-if-!=
 239       var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 240       copy-to *cursor-in-go-modal-a, 0/false
 241       var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 242       clear-object go-modal-error-ah
 243       return
 244     }
 245     # enter = switch to global name and exit modal dialog
 246     {
 247       compare key, 0xa/newline
 248       break-if-!=
 249       # if no global name typed in, switch to sandbox
 250       var partial-global-name-ah/eax: (addr handle gap-buffer) <- get self, partial-global-name
 251       var partial-global-name/eax: (addr gap-buffer) <- lookup *partial-global-name-ah
 252       {
 253         var empty?/eax: boolean <- gap-buffer-empty? partial-global-name
 254         compare empty?, 0/false
 255         break-if-=
 256         var cursor-in-globals-a/eax: (addr boolean) <- get self, cursor-in-globals?
 257         copy-to *cursor-in-globals-a, 0/false
 258         # reset error state
 259         var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 260         clear-object go-modal-error-ah
 261         # done with go modal
 262         var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 263         copy-to *cursor-in-go-modal-a, 0/false
 264         return
 265       }
 266       # turn global name into a stream
 267       var name-storage: (stream byte 0x40)
 268       var name/ecx: (addr stream byte) <- address name-storage
 269       emit-gap-buffer partial-global-name, name
 270       # compute global index
 271       var index/ecx: int <- find-symbol-in-globals globals, name
 272       # if global not found, set error and return
 273       {
 274         compare index, 0
 275         break-if->=
 276         var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 277         copy-array-object "no such global", go-modal-error-ah
 278         return
 279       }
 280       # otherwise clear modal state
 281       clear-gap-buffer partial-global-name
 282       var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 283       clear-object go-modal-error-ah
 284       var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 285       copy-to *cursor-in-go-modal-a, 0/false
 286       # switch focus to global at index
 287       var globals-cursor-index/eax: (addr int) <- get globals, cursor-index
 288       copy-to *globals-cursor-index, index
 289       var cursor-in-globals-a/ecx: (addr boolean) <- get self, cursor-in-globals?
 290       copy-to *cursor-in-globals-a, 1/true
 291       return
 292     }
 293     # ctrl-m = create given global name and exit modal dialog
 294     {
 295       compare key, 0xd/ctrl-m
 296       break-if-!=
 297       # if no global name typed in, set error and return
 298       var partial-global-name-ah/eax: (addr handle gap-buffer) <- get self, partial-global-name
 299       var partial-global-name/eax: (addr gap-buffer) <- lookup *partial-global-name-ah
 300       {
 301         var empty?/eax: boolean <- gap-buffer-empty? partial-global-name
 302         compare empty?, 0/false
 303         break-if-=
 304         var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 305         copy-array-object "create what?", go-modal-error-ah
 306         return
 307       }
 308       # turn global name into a stream
 309       var name-storage: (stream byte 0x40)
 310       var name/edx: (addr stream byte) <- address name-storage
 311       emit-gap-buffer partial-global-name, name
 312       # compute global index
 313       var index/ecx: int <- find-symbol-in-globals globals, name
 314       # if global found, set error and return
 315       {
 316         compare index, 0
 317         break-if-<
 318         var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 319         copy-array-object "already exists", go-modal-error-ah
 320         return
 321       }
 322       # otherwise clear modal state
 323       clear-gap-buffer partial-global-name
 324       var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 325       clear-object go-modal-error-ah
 326       var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 327       copy-to *cursor-in-go-modal-a, 0/false
 328       # create new global
 329       create-empty-global globals, name, 0x2000/default-gap-buffer-size=8KB
 330       var globals-final-index/eax: (addr int) <- get globals, final-index
 331       var new-index/ecx: int <- copy *globals-final-index
 332       var globals-cursor-index/eax: (addr int) <- get globals, cursor-index
 333       copy-to *globals-cursor-index, new-index
 334       var cursor-in-globals-a/ecx: (addr boolean) <- get self, cursor-in-globals?
 335       copy-to *cursor-in-globals-a, 1/true
 336       return
 337     }
 338     # otherwise process like a regular gap-buffer
 339     var partial-global-name-ah/eax: (addr handle gap-buffer) <- get self, partial-global-name
 340     var partial-global-name/eax: (addr gap-buffer) <- lookup *partial-global-name-ah
 341     edit-gap-buffer partial-global-name, key
 342     return
 343   }
 344   # ctrl-g: go to a global (or the repl)
 345   {
 346     compare key, 7/ctrl-g
 347     break-if-!=
 348     # look for a word to prepopulate the modal
 349     var current-word-storage: (stream byte 0x40)
 350     var current-word/edi: (addr stream byte) <- address current-word-storage
 351     word-at-cursor self, current-word
 352     var partial-global-name-ah/eax: (addr handle gap-buffer) <- get self, partial-global-name
 353     var partial-global-name/eax: (addr gap-buffer) <- lookup *partial-global-name-ah
 354     clear-gap-buffer partial-global-name
 355     load-gap-buffer-from-stream partial-global-name, current-word
 356     # enable the modal
 357     var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 358     copy-to *cursor-in-go-modal-a, 1/true
 359     return
 360   }
 361   # dispatch the key to either sandbox or globals
 362   {
 363     var cursor-in-globals-a/eax: (addr boolean) <- get self, cursor-in-globals?
 364     compare *cursor-in-globals-a, 0/false
 365     break-if-=
 366     edit-globals globals, key
 367     return
 368   }
 369   edit-sandbox sandbox, key, globals, data-disk
 370 }
 371 
 372 fn read-and-evaluate-and-save-gap-buffer-to-globals _in-ah: (addr handle gap-buffer), result-ah: (addr handle cell), globals: (addr global-table), definitions-created: (addr stream int), trace: (addr trace), inner-screen-var: (addr handle cell), inner-keyboard-var: (addr handle cell) {
 373   var in-ah/eax: (addr handle gap-buffer) <- copy _in-ah
 374   var in/eax: (addr gap-buffer) <- lookup *in-ah
 375   var read-result-h: (handle cell)
 376   var read-result-ah/esi: (addr handle cell) <- address read-result-h
 377   read-cell in, read-result-ah, trace
 378   var error?/eax: boolean <- has-errors? trace
 379   {
 380     compare error?, 0/false
 381     break-if-=
 382     return
 383   }
 384   macroexpand read-result-ah, globals, trace
 385   var error?/eax: boolean <- has-errors? trace
 386   {
 387     compare error?, 0/false
 388     break-if-=
 389     return
 390   }
 391   var nil-h: (handle cell)
 392   var nil-ah/eax: (addr handle cell) <- address nil-h
 393   allocate-pair nil-ah
 394 #?   set-cursor-position 0/screen, 0 0
 395 #?   turn-on-debug-print
 396   var call-number-storage: int
 397   var call-number/edi: (addr int) <- address call-number-storage
 398   debug-print "^", 4/fg, 0/bg
 399   evaluate read-result-ah, result-ah, *nil-ah, globals, trace, inner-screen-var, inner-keyboard-var, definitions-created, call-number
 400   debug-print "$", 4/fg, 0/bg
 401   var error?/eax: boolean <- has-errors? trace
 402   {
 403     compare error?, 0/false
 404     break-if-=
 405     return
 406   }
 407   # refresh various rendering caches
 408   mark-lines-dirty trace
 409   # If any definitions were created or modified in the process, link this gap
 410   # buffer to them.
 411   # TODO: detect and create UI for conflicts.
 412   stash-gap-buffer-to-globals globals, definitions-created, _in-ah
 413 }
 414 
 415 fn test-go-modal {
 416   var env-storage: environment
 417   var env/esi: (addr environment) <- address env-storage
 418   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 419   # setup: screen
 420   var screen-on-stack: screen
 421   var screen/edi: (addr screen) <- address screen-on-stack
 422   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 423   # hit ctrl-g
 424   edit-environment env, 7/ctrl-g, 0/no-disk
 425   render-environment screen, env
 426   #
 427   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-go-modal/0"
 428   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-go-modal/1"
 429   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-go-modal/2"
 430   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-go-modal/3"
 431   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-go-modal/4"
 432   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-go-modal/5"
 433   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-go-modal/6-text"
 434   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-go-modal/6"
 435   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-go-modal/7"
 436   # cursor is in the modal
 437   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                |                                                                                               ", "F - test-go-modal/8-cursor"
 438   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                 ...............................................................                                ", "F - test-go-modal/8"
 439   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-go-modal/9"
 440   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-go-modal/10"
 441   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-go-modal/11"
 442   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-go-modal/12"
 443   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-go-modal/13"
 444   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-go-modal/14"
 445   # menu at bottom is correct in context
 446   check-screen-row                     screen,               0xf/y, " ^r  run main   enter  go   ^m  create   esc  cancel   ^a  <<   ^b  <word   ^f  word>   ^e  >>                                  ", "F - test-go-modal/15-text"
 447   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-go-modal/15"
 448 }
 449 
 450 fn test-leave-go-modal {
 451   var env-storage: environment
 452   var env/esi: (addr environment) <- address env-storage
 453   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 454   # setup: screen
 455   var screen-on-stack: screen
 456   var screen/edi: (addr screen) <- address screen-on-stack
 457   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 458   # hit ctrl-g
 459   edit-environment env, 7/ctrl-g, 0/no-disk
 460   render-environment screen, env
 461   # cancel
 462   edit-environment env, 0x1b/escape, 0/no-disk
 463   render-environment screen, env
 464   # no modal
 465   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-leave-go-modal/0"
 466   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-leave-go-modal/1"
 467   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-leave-go-modal/2"
 468   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-leave-go-modal/3"
 469   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-leave-go-modal/4"
 470   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-leave-go-modal/5"
 471   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                                                                                                                ", "F - test-leave-go-modal/6"
 472   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                                                                                                                ", "F - test-leave-go-modal/7"
 473   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                                                                                                                ", "F - test-leave-go-modal/8"
 474   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-leave-go-modal/9"
 475   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-leave-go-modal/10"
 476   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-leave-go-modal/11"
 477   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-leave-go-modal/12"
 478   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-leave-go-modal/13"
 479   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-leave-go-modal/14"
 480   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-leave-go-modal/15"
 481 }
 482 
 483 fn test-jump-to-global {
 484   var env-storage: environment
 485   var env/esi: (addr environment) <- address env-storage
 486   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 487   # setup: screen
 488   var screen-on-stack: screen
 489   var screen/edi: (addr screen) <- address screen-on-stack
 490   initialize-screen screen, 0x80/width, 0x30/height, 0/no-pixel-graphics
 491   # define a global
 492   type-in env, screen, "(define f 42)"
 493   edit-environment env, 0x13/ctrl-s, 0/no-disk
 494   render-environment screen, env
 495   # hit ctrl-g
 496   edit-environment env, 7/ctrl-g, 0/no-disk
 497   render-environment screen, env
 498   # type global name
 499   type-in env, screen, "f"
 500   # submit
 501   edit-environment env, 0xa/newline, 0/no-disk
 502   render-environment screen, env
 503   #                                                                 | global definitions                                                                 | sandbox
 504   # cursor now in global definition
 505   check-screen-row                     screen,                 1/y, "                                           (define f 42)                              screen:                                   ", "F - test-jump-to-global/1"
 506   check-background-color-in-screen-row screen,   7/bg=cursor,  1/y, "                                                        |                                                                       ", "F - test-jump-to-global/1-cursor"
 507   # no modal
 508   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-jump-to-global/bg0"
 509   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-jump-to-global/bg1"
 510   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-jump-to-global/bg2"
 511   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-jump-to-global/bg3"
 512   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-jump-to-global/bg4"
 513   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-jump-to-global/bg5"
 514   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                                                                                                                ", "F - test-jump-to-global/bg6"
 515   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                                                                                                                ", "F - test-jump-to-global/bg7"
 516   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                                                                                                                ", "F - test-jump-to-global/bg8"
 517   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-jump-to-global/bg9"
 518   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-jump-to-global/bg10"
 519   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-jump-to-global/bg11"
 520   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-jump-to-global/bg12"
 521   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-jump-to-global/bg13"
 522   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-jump-to-global/bg14"
 523   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-jump-to-global/bg15"
 524 }
 525 
 526 fn test-go-modal-prepopulates-word-at-cursor {
 527   var env-storage: environment
 528   var env/esi: (addr environment) <- address env-storage
 529   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 530   # setup: screen
 531   var screen-on-stack: screen
 532   var screen/edi: (addr screen) <- address screen-on-stack
 533   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 534   # type a word at the cursor
 535   type-in env, screen, "fn1"
 536   # hit ctrl-g
 537   edit-environment env, 7/ctrl-g, 0/no-disk
 538   render-environment screen, env
 539   # modal prepopulates word at cursor
 540   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/0"
 541   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/1"
 542   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/2"
 543   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/3"
 544   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/4"
 545   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/5"
 546   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-go-modal-prepopulates-word-at-cursor/6-text"
 547   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/6"
 548   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/7"
 549   # word at cursor
 550   check-screen-row                     screen,                 8/y, "                                fn1                                                                                             ", "F - test-go-modal-prepopulates-word-at-cursor/8-text"
 551   # new cursor position
 552   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                   |                                                                                            ", "F - test-go-modal-prepopulates-word-at-cursor/8-cursor"
 553   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                ... ............................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/8"
 554   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/9"
 555   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/10"
 556   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/11"
 557   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/12"
 558   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/13"
 559   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/14"
 560   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/15"
 561   # cancel
 562   edit-environment env, 0x1b/escape, 0/no-disk
 563   render-environment screen, env
 564   # type one more space
 565   edit-environment env, 0x20/space, 0/no-disk
 566   render-environment screen, env
 567   # hit ctrl-g again
 568   edit-environment env, 7/ctrl-g, 0/no-disk
 569   render-environment screen, env
 570   # no word prepopulated since cursor is not on the word
 571   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-0"
 572   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-1"
 573   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-2"
 574   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-3"
 575   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-4"
 576   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-5"
 577   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-go-modal-prepopulates-word-at-cursor/test2-6-text"
 578   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-6"
 579   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-7"
 580   # no word at cursor
 581   check-screen-row                     screen,                 8/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-8-text"
 582   # new cursor position
 583   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                |                                                                                               ", "F - test-go-modal-prepopulates-word-at-cursor/test2-8-cursor"
 584   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                 ...............................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-8"
 585   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-9"
 586   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-10"
 587   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-11"
 588   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-12"
 589   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-13"
 590   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-14"
 591   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test2-15"
 592   # cancel
 593   edit-environment env, 0x1b/escape, 0/no-disk
 594   render-environment screen, env
 595   # move cursor to the left until it's on the word again
 596   edit-environment env, 0x80/left-arrow, 0/no-disk
 597   render-environment screen, env
 598   edit-environment env, 0x80/left-arrow, 0/no-disk
 599   render-environment screen, env
 600   # hit ctrl-g again
 601   edit-environment env, 7/ctrl-g, 0/no-disk
 602   render-environment screen, env
 603   # word prepopulated like before
 604   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-0"
 605   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-1"
 606   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-2"
 607   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-3"
 608   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-4"
 609   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-5"
 610   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-go-modal-prepopulates-word-at-cursor/test3-6-text"
 611   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-6"
 612   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-7"
 613   # word at cursor
 614   check-screen-row                     screen,                 8/y, "                                fn1                                                                                             ", "F - test-go-modal-prepopulates-word-at-cursor/test3-8-text"
 615   # new cursor position
 616   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                   |                                                                                            ", "F - test-go-modal-prepopulates-word-at-cursor/test3-8-cursor"
 617   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                ... ............................................................                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-8"
 618   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-9"
 619   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-10"
 620   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-11"
 621   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-12"
 622   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-13"
 623   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-14"
 624   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-go-modal-prepopulates-word-at-cursor/test3-15"
 625 }
 626 
 627 fn test-jump-to-nonexistent-global {
 628   var env-storage: environment
 629   var env/esi: (addr environment) <- address env-storage
 630   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 631   # setup: screen
 632   var screen-on-stack: screen
 633   var screen/edi: (addr screen) <- address screen-on-stack
 634   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 635   # type in any (nonexistent) global name
 636   type-in env, screen, "f"
 637   # hit ctrl-g
 638   edit-environment env, 7/ctrl-g, 0/no-disk
 639   render-environment screen, env
 640   # submit
 641   edit-environment env, 0xa/newline, 0/no-disk
 642   render-environment screen, env
 643   # modal now shows an error
 644   #                                                                 | global definitions                                                                 | sandbox
 645   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/0"
 646   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/1"
 647   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/2"
 648   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/3"
 649   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/4"
 650   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/5"
 651   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-jump-to-nonexistent-global/6-text"
 652   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-jump-to-nonexistent-global/6"
 653   check-screen-row-in-color            screen, 4/fg=error,     7/y, "                                no such global                                                                                  ", "F - test-jump-to-nonexistent-global/7-text"
 654   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-jump-to-nonexistent-global/7"
 655   check-screen-row                     screen,                 8/y, "                                f                                                                                               ", "F - test-jump-to-nonexistent-global/8-text"
 656   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                 |                                                                                              ", "F - test-jump-to-nonexistent-global/8-cursor"
 657   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                . ..............................................................                                ", "F - test-jump-to-nonexistent-global/8"
 658   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/9"
 659   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/10"
 660   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/11"
 661   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/12"
 662   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/13"
 663   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/14"
 664   # menu at bottom is correct in context
 665   check-screen-row                     screen,               0xf/y, " ^r  run main   enter  go   ^m  create   esc  cancel   ^a  <<   ^b  <word   ^f  word>   ^e  >>                                  ", "F - test-jump-to-nonexistent-global/15-text"
 666   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/15"
 667   # cancel
 668   edit-environment env, 0x1b/escape, 0/no-disk
 669   render-environment screen, env
 670   # hit ctrl-g again
 671   edit-environment env, 7/ctrl-g, 0/no-disk
 672   render-environment screen, env
 673   # word prepopulated like before, but no error
 674   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-0"
 675   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-1"
 676   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-2"
 677   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-3"
 678   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-4"
 679   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-5"
 680   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-jump-to-nonexistent-global/test2-6-text"
 681   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-jump-to-nonexistent-global/test2-6"
 682   check-screen-row-in-color            screen, 4/fg=error,     7/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-7-text"
 683   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-jump-to-nonexistent-global/test2-7"
 684   # same word at cursor
 685   check-screen-row                     screen,                 8/y, "                                f                                                                                               ", "F - test-jump-to-nonexistent-global/test2-8-text"
 686   # new cursor position
 687   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                 |                                                                                              ", "F - test-jump-to-nonexistent-global/test2-8-cursor"
 688   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                . ..............................................................                                ", "F - test-jump-to-nonexistent-global/test2-8"
 689   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-9"
 690   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-10"
 691   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-11"
 692   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-12"
 693   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-13"
 694   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-14"
 695   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-jump-to-nonexistent-global/test2-15"
 696 }
 697 
 698 fn test-create-global {
 699   var env-storage: environment
 700   var env/esi: (addr environment) <- address env-storage
 701   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 702   # setup: screen
 703   var screen-on-stack: screen
 704   var screen/edi: (addr screen) <- address screen-on-stack
 705   initialize-screen screen, 0x80/width, 0x30/height, 0/no-pixel-graphics
 706   # hit ctrl-g
 707   edit-environment env, 7/ctrl-g, 0/no-disk
 708   render-environment screen, env
 709   # type global name
 710   type-in env, screen, "fn1"
 711   # create
 712   edit-environment env, 0xd/ctrl-m, 0/no-disk
 713   render-environment screen, env
 714   #                                                                 | global definitions                                                                 | sandbox
 715   # cursor now on global side
 716   check-background-color-in-screen-row screen,   7/bg=cursor,  1/y, "                                           |                                                                                    ", "F - test-create-global/1-cursor"
 717   # no modal
 718   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-create-global/bg0"
 719   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-create-global/bg1"
 720   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-create-global/bg2"
 721   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-create-global/bg3"
 722   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-create-global/bg4"
 723   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-create-global/bg5"
 724   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                                                                                                                ", "F - test-create-global/bg6"
 725   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                                                                                                                ", "F - test-create-global/bg7"
 726   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                                                                                                                ", "F - test-create-global/bg8"
 727   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-create-global/bg9"
 728   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-create-global/bg10"
 729   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-create-global/bg11"
 730   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-create-global/bg12"
 731   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-create-global/bg13"
 732   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-create-global/bg14"
 733   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-create-global/bg15"
 734 }
 735 
 736 fn test-create-nonexistent-global {
 737   var env-storage: environment
 738   var env/esi: (addr environment) <- address env-storage
 739   initialize-environment env, 8/fake-screen-width, 3/fake-screen-height
 740   # setup: screen
 741   var screen-on-stack: screen
 742   var screen/edi: (addr screen) <- address screen-on-stack
 743   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 744   # define a global
 745   type-in env, screen, "(define f 42)"
 746   edit-environment env, 0x13/ctrl-s, 0/no-disk
 747   render-environment screen, env
 748   # type in its name
 749   type-in env, screen, "f"
 750   # hit ctrl-g
 751   edit-environment env, 7/ctrl-g, 0/no-disk
 752   render-environment screen, env
 753   # submit
 754   edit-environment env, 0xd/ctrl-m, 0/no-disk
 755   render-environment screen, env
 756   # modal now shows an error
 757   #                                                                 | global definitions                                                                 | sandbox
 758   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-create-nonexistent-global/0"
 759   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-create-nonexistent-global/1"
 760   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-create-nonexistent-global/2"
 761   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-create-nonexistent-global/3"
 762   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-create-nonexistent-global/4"
 763   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-create-nonexistent-global/5"
 764   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-create-nonexistent-global/6-text"
 765   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-create-nonexistent-global/6"
 766   check-screen-row-in-color            screen, 4/fg=error,     7/y, "                                already exists                                                                                  ", "F - test-create-nonexistent-global/7-text"
 767   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-create-nonexistent-global/7"
 768   check-screen-row-in-color            screen, 0/fg,           8/y, "                                f                                                                                               ", "F - test-create-nonexistent-global/8-text"
 769   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                 |                                                                                              ", "F - test-create-nonexistent-global/8-cursor"
 770   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                . ..............................................................                                ", "F - test-create-nonexistent-global/8"
 771   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-create-nonexistent-global/9"
 772   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-create-nonexistent-global/10"
 773   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-create-nonexistent-global/11"
 774   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-create-nonexistent-global/12"
 775   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-create-nonexistent-global/13"
 776   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-create-nonexistent-global/14"
 777   # menu at bottom is correct in context
 778   check-screen-row                     screen,               0xf/y, " ^r  run main   enter  go   ^m  create   esc  cancel   ^a  <<   ^b  <word   ^f  word>   ^e  >>                                  ", "F - test-create-nonexistent-global/15-text"
 779   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-create-nonexistent-global/15"
 780   # cancel
 781   edit-environment env, 0x1b/escape, 0/no-disk
 782   render-environment screen, env
 783   # hit ctrl-g again
 784   edit-environment env, 7/ctrl-g, 0/no-disk
 785   render-environment screen, env
 786   # word prepopulated like before, but no error
 787   check-background-color-in-screen-row screen, 0xf/bg=modal,   0/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-0"
 788   check-background-color-in-screen-row screen, 0xf/bg=modal,   1/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-1"
 789   check-background-color-in-screen-row screen, 0xf/bg=modal,   2/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-2"
 790   check-background-color-in-screen-row screen, 0xf/bg=modal,   3/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-3"
 791   check-background-color-in-screen-row screen, 0xf/bg=modal,   4/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-4"
 792   check-background-color-in-screen-row screen, 0xf/bg=modal,   5/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-5"
 793   check-screen-row                     screen,                 6/y, "                                    go to global (or leave blank to go to REPL)                                                 ", "F - test-create-nonexistent-global/test2-6-text"
 794   check-background-color-in-screen-row screen, 0xf/bg=modal,   6/y, "                                ................................................................                                ", "F - test-create-nonexistent-global/test2-6"
 795   check-screen-row-in-color            screen, 4/fg=error,     7/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-7-text"
 796   check-background-color-in-screen-row screen, 0xf/bg=modal,   7/y, "                                ................................................................                                ", "F - test-create-nonexistent-global/test2-7"
 797   # same word at cursor
 798   check-screen-row-in-color            screen, 0/fg,           8/y, "                                f                                                                                               ", "F - test-create-nonexistent-global/test2-8-text"
 799   # new cursor position
 800   check-background-color-in-screen-row screen,   0/bg=cursor,  8/y, "                                 |                                                                                              ", "F - test-create-nonexistent-global/test2-8-cursor"
 801   check-background-color-in-screen-row screen, 0xf/bg=modal,   8/y, "                                . ..............................................................                                ", "F - test-create-nonexistent-global/test2-8"
 802   check-background-color-in-screen-row screen, 0xf/bg=modal,   9/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-9"
 803   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xa/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-10"
 804   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xb/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-11"
 805   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xc/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-12"
 806   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xd/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-13"
 807   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xe/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-14"
 808   check-background-color-in-screen-row screen, 0xf/bg=modal, 0xf/y, "                                                                                                                                ", "F - test-create-nonexistent-global/test2-15"
 809 }
 810 
 811 fn render-go-modal screen: (addr screen), _self: (addr environment) {
 812   var self/esi: (addr environment) <- copy _self
 813   var width/eax: int <- copy 0
 814   var height/ecx: int <- copy 0
 815   width, height <- screen-size screen
 816   # xmin = max(0, width/2 - 0x20)
 817   var xmin: int
 818   var tmp/edx: int <- copy width
 819   tmp <- shift-right 1
 820   tmp <- subtract 0x20/half-global-name-capacity
 821   {
 822     compare tmp, 0
 823     break-if->=
 824     tmp <- copy 0
 825   }
 826   copy-to xmin, tmp
 827   # xmax = min(width, width/2 + 0x20)
 828   var xmax: int
 829   tmp <- copy width
 830   tmp <- shift-right 1
 831   tmp <- add 0x20/half-global-name-capacity
 832   {
 833     compare tmp, width
 834     break-if-<=
 835     tmp <- copy width
 836   }
 837   copy-to xmax, tmp
 838   # ymin = height/2 - 2
 839   var ymin: int
 840   tmp <- copy height
 841   tmp <- shift-right 1
 842   tmp <- subtract 2
 843   copy-to ymin, tmp
 844   # ymax = height/2 + 1
 845   var ymax: int
 846   tmp <- add 3
 847   copy-to ymax, tmp
 848   #
 849   clear-rect screen, xmin, ymin, xmax, ymax, 0xf/bg=modal
 850   add-to xmin, 4
 851   set-cursor-position screen, xmin, ymin
 852   draw-text-rightward-from-cursor screen, "go to global (or leave blank to go to REPL)", xmax, 8/fg=dark-grey, 0xf/bg=modal
 853   var partial-global-name-ah/eax: (addr handle gap-buffer) <- get self, partial-global-name
 854   var _partial-global-name/eax: (addr gap-buffer) <- lookup *partial-global-name-ah
 855   var partial-global-name/edx: (addr gap-buffer) <- copy _partial-global-name
 856   subtract-from xmin, 4
 857   increment ymin
 858   {
 859     var go-modal-error-ah/eax: (addr handle array byte) <- get self, go-modal-error
 860     var go-modal-error/eax: (addr array byte) <- lookup *go-modal-error-ah
 861     compare go-modal-error, 0
 862     break-if-=
 863     var dummy/eax: int <- draw-text-rightward screen, go-modal-error, xmin, xmax, ymin, 4/fg=error, 0xf/bg=modal
 864   }
 865   increment ymin
 866   var dummy/eax: int <- copy 0
 867   var dummy2/ecx: int <- copy 0
 868   dummy, dummy2 <- render-gap-buffer-wrapping-right-then-down screen, partial-global-name, xmin, ymin, xmax, ymax, 1/always-render-cursor, 0/fg=black, 0xf/bg=modal
 869 }
 870 
 871 fn render-go-modal-menu screen: (addr screen), _self: (addr environment) {
 872   var self/esi: (addr environment) <- copy _self
 873   var _width/eax: int <- copy 0
 874   var height/ecx: int <- copy 0
 875   _width, height <- screen-size screen
 876   var width/edx: int <- copy _width
 877   var y/ecx: int <- copy height
 878   y <- decrement
 879   var height/ebx: int <- copy y
 880   height <- increment
 881   clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
 882   set-cursor-position screen, 0/x, y
 883   draw-text-rightward-from-cursor screen, " ^r ", width, 0/fg, 0x5c/bg=menu-highlight
 884   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0xc5/bg=blue-bg
 885   draw-text-rightward-from-cursor screen, " enter ", width, 0/fg, 0xc/bg=menu-really-highlight
 886   draw-text-rightward-from-cursor screen, " go  ", width, 7/fg, 0xc5/bg=blue-bg
 887   draw-text-rightward-from-cursor screen, " ^m ", width, 0/fg, 0xc/bg=menu-really-highlight
 888   draw-text-rightward-from-cursor screen, " create  ", width, 7/fg, 0xc5/bg=blue-bg
 889   draw-text-rightward-from-cursor screen, " esc ", width, 0/fg, 0x5c/bg=menu-highlight
 890   draw-text-rightward-from-cursor screen, " cancel  ", width, 7/fg, 0xc5/bg=blue-bg
 891   draw-text-rightward-from-cursor screen, " ^a ", width, 0/fg, 0x5c/bg=menu-highlight
 892   draw-text-rightward-from-cursor screen, " <<  ", width, 7/fg, 0xc5/bg=blue-bg
 893   draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg, 0x5c/bg=menu-highlight
 894   draw-text-rightward-from-cursor screen, " <word  ", width, 7/fg, 0xc5/bg=blue-bg
 895   draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg, 0x5c/bg=menu-highlight
 896   draw-text-rightward-from-cursor screen, " word>  ", width, 7/fg, 0xc5/bg=blue-bg
 897   draw-text-rightward-from-cursor screen, " ^e ", width, 0/fg, 0x5c/bg=menu-highlight
 898   draw-text-rightward-from-cursor screen, " >>  ", width, 7/fg, 0xc5/bg=blue-bg
 899 }
 900 
 901 fn word-at-cursor _self: (addr environment), out: (addr stream byte) {
 902   var self/esi: (addr environment) <- copy _self
 903   var cursor-in-go-modal-a/eax: (addr boolean) <- get self, cursor-in-go-modal?
 904   compare *cursor-in-go-modal-a, 0/false
 905   {
 906     break-if-=
 907     # cursor in go modal
 908     return
 909   }
 910   var cursor-in-globals-a/edx: (addr boolean) <- get self, cursor-in-globals?
 911   compare *cursor-in-globals-a, 0/false
 912   {
 913     break-if-=
 914     # cursor in some global editor
 915     var globals/eax: (addr global-table) <- get self, globals
 916     var cursor-index-addr/ecx: (addr int) <- get globals, cursor-index
 917     var cursor-index/ecx: int <- copy *cursor-index-addr
 918     var globals-data-ah/eax: (addr handle array global) <- get globals, data
 919     var globals-data/eax: (addr array global) <- lookup *globals-data-ah
 920     var cursor-offset/ecx: (offset global) <- compute-offset globals-data, cursor-index
 921     var curr-global/eax: (addr global) <- index globals-data, cursor-offset
 922     var curr-global-data-ah/eax: (addr handle gap-buffer) <- get curr-global, input
 923     var curr-global-data/eax: (addr gap-buffer) <- lookup *curr-global-data-ah
 924     word-at-gap curr-global-data, out
 925     return
 926   }
 927   # cursor in sandbox
 928   var sandbox/ecx: (addr sandbox) <- get self, sandbox
 929   var sandbox-data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
 930   var sandbox-data/eax: (addr gap-buffer) <- lookup *sandbox-data-ah
 931   word-at-gap sandbox-data, out
 932 }
 933 
 934 # Gotcha: some saved state may not load.
 935 fn load-state _self: (addr environment), data-disk: (addr disk) {
 936   var self/esi: (addr environment) <- copy _self
 937   # data-disk -> stream
 938   var s-storage: (stream byte 0x2000)  # space for 16/sectors
 939   var s/ebx: (addr stream byte) <- address s-storage
 940   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sectors from data disk", 3/fg, 0/bg
 941   move-cursor-to-left-margin-of-next-line 0/screen
 942   load-sectors data-disk, 0/lba, 0x10/sectors, s
 943 #?   draw-stream-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, s, 7/fg, 0xc5/bg=blue-bg
 944   # stream -> gap-buffer (HACK: we temporarily cannibalize the sandbox's gap-buffer)
 945   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "parsing", 3/fg, 0/bg
 946   move-cursor-to-left-margin-of-next-line 0/screen
 947   var sandbox/eax: (addr sandbox) <- get self, sandbox
 948   var data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
 949   var data/eax: (addr gap-buffer) <- lookup *data-ah
 950   load-gap-buffer-from-stream data, s
 951   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "  into gap buffer", 3/fg, 0/bg
 952   move-cursor-to-left-margin-of-next-line 0/screen
 953   clear-stream s
 954   # read: gap-buffer -> cell
 955   var initial-root-storage: (handle cell)
 956   var initial-root/ecx: (addr handle cell) <- address initial-root-storage
 957   var trace-storage: trace
 958   var trace/edi: (addr trace) <- address trace-storage
 959   initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
 960   read-cell data, initial-root, trace
 961   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "  into s-expressions", 3/fg, 0/bg
 962   move-cursor-to-left-margin-of-next-line 0/screen
 963   clear-gap-buffer data
 964   #
 965   {
 966     var initial-root-addr/eax: (addr cell) <- lookup *initial-root
 967     compare initial-root-addr, 0
 968     break-if-!=
 969     return
 970   }
 971   # load globals from assoc(initial-root, 'globals)
 972   var globals-literal-storage: (handle cell)
 973   var globals-literal-ah/eax: (addr handle cell) <- address globals-literal-storage
 974   new-symbol globals-literal-ah, "globals"
 975   var globals-literal/eax: (addr cell) <- lookup *globals-literal-ah
 976   var globals-cell-storage: (handle cell)
 977   var globals-cell-ah/edx: (addr handle cell) <- address globals-cell-storage
 978   clear-trace trace
 979   lookup-symbol globals-literal, globals-cell-ah, *initial-root, 0/no-globals, trace, 0/no-screen, 0/no-keyboard
 980   var globals-cell/eax: (addr cell) <- lookup *globals-cell-ah
 981   {
 982     compare globals-cell, 0
 983     break-if-=
 984     var globals/eax: (addr global-table) <- get self, globals
 985     load-globals globals-cell-ah, globals
 986   }
 987   # sandbox = assoc(initial-root, 'sandbox)
 988   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sandbox", 3/fg, 0/bg
 989   var sandbox-literal-storage: (handle cell)
 990   var sandbox-literal-ah/eax: (addr handle cell) <- address sandbox-literal-storage
 991   new-symbol sandbox-literal-ah, "sandbox"
 992   var sandbox-literal/eax: (addr cell) <- lookup *sandbox-literal-ah
 993   var sandbox-cell-storage: (handle cell)
 994   var sandbox-cell-ah/edx: (addr handle cell) <- address sandbox-cell-storage
 995   clear-trace trace
 996   lookup-symbol sandbox-literal, sandbox-cell-ah, *initial-root, 0/no-globals, trace, 0/no-screen, 0/no-keyboard
 997   var sandbox-cell/eax: (addr cell) <- lookup *sandbox-cell-ah
 998   {
 999     compare sandbox-cell, 0
1000     break-if-=
1001     var sandbox-data-ah/eax: (addr handle stream byte) <- get sandbox-cell, text-data
1002     var _sandbox-data/eax: (addr stream byte) <- lookup *sandbox-data-ah
1003     var sandbox-data/ecx: (addr stream byte) <- copy _sandbox-data
1004     # stream -> gap-buffer
1005     var sandbox/eax: (addr sandbox) <- get self, sandbox
1006     var data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
1007     var data/eax: (addr gap-buffer) <- lookup *data-ah
1008     load-gap-buffer-from-stream data, sandbox-data
1009   }
1010 }
1011 
1012 # Save state as an alist of alists:
1013 #   ((globals . ((a . (fn ...))
1014 #                ...))
1015 #    (sandbox . ...))
1016 fn store-state data-disk: (addr disk), sandbox: (addr sandbox), globals: (addr global-table) {
1017   compare data-disk, 0/no-disk
1018   {
1019     break-if-!=
1020     return
1021   }
1022   var stream-storage: (stream byte 0x2000)  # space enough for 16/sectors
1023   var stream/edi: (addr stream byte) <- address stream-storage
1024   write stream, "(\n"
1025   write-globals stream, globals
1026   write-sandbox stream, sandbox
1027   write stream, ")\n"
1028   store-sectors data-disk, 0/lba, 0x10/sectors, stream
1029 }