https://github.com/akkartik/mu/blob/main/shell/sandbox.mu
   1 type sandbox {
   2   data: (handle gap-buffer)
   3   value: (handle stream byte)
   4   screen-var: (handle cell)
   5   keyboard-var: (handle cell)
   6   trace: (handle trace)
   7   cursor-in-data?: boolean
   8   cursor-in-keyboard?: boolean
   9   cursor-in-trace?: boolean
  10 }
  11 
  12 fn initialize-sandbox _self: (addr sandbox), fake-screen-and-keyboard?: boolean {
  13   var self/esi: (addr sandbox) <- copy _self
  14   var data-ah/eax: (addr handle gap-buffer) <- get self, data
  15   allocate data-ah
  16   var data/eax: (addr gap-buffer) <- lookup *data-ah
  17   initialize-gap-buffer data, 0x1000/4KB
  18   #
  19   var value-ah/eax: (addr handle stream byte) <- get self, value
  20   populate-stream value-ah, 0x1000/4KB
  21   #
  22   {
  23     compare fake-screen-and-keyboard?, 0/false
  24     break-if-=
  25     var screen-ah/eax: (addr handle cell) <- get self, screen-var
  26     new-fake-screen screen-ah, 8/width, 3/height, 1/enable-pixel-graphics
  27     var keyboard-ah/eax: (addr handle cell) <- get self, keyboard-var
  28     new-fake-keyboard keyboard-ah, 0x10/keyboard-capacity
  29   }
  30   #
  31   var trace-ah/eax: (addr handle trace) <- get self, trace
  32   allocate trace-ah
  33   var trace/eax: (addr trace) <- lookup *trace-ah
  34   initialize-trace trace, 4/max-depth, 0x8000/lines, 0x80/visible
  35   var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
  36   copy-to *cursor-in-data?, 1/true
  37 }
  38 
  39 ## some helpers for tests
  40 
  41 fn initialize-sandbox-with _self: (addr sandbox), s: (addr array byte) {
  42   var self/esi: (addr sandbox) <- copy _self
  43   var data-ah/eax: (addr handle gap-buffer) <- get self, data
  44   allocate data-ah
  45   var data/eax: (addr gap-buffer) <- lookup *data-ah
  46   initialize-gap-buffer-with data, s
  47   var value-ah/eax: (addr handle stream byte) <- get self, value
  48   populate-stream value-ah, 0x1000/4KB
  49   var trace-ah/eax: (addr handle trace) <- get self, trace
  50   allocate trace-ah
  51   var trace/eax: (addr trace) <- lookup *trace-ah
  52   initialize-trace trace, 3/max-depth, 0x8000/lines, 0x80/visible
  53   var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
  54   copy-to *cursor-in-data?, 1/true
  55 }
  56 
  57 fn allocate-sandbox-with _out: (addr handle sandbox), s: (addr array byte) {
  58   var out/eax: (addr handle sandbox) <- copy _out
  59   allocate out
  60   var out-addr/eax: (addr sandbox) <- lookup *out
  61   initialize-sandbox-with out-addr, s
  62 }
  63 
  64 fn write-sandbox out: (addr stream byte), _self: (addr sandbox) {
  65   var self/eax: (addr sandbox) <- copy _self
  66   var data-ah/eax: (addr handle gap-buffer) <- get self, data
  67   var data/eax: (addr gap-buffer) <- lookup *data-ah
  68   {
  69     var len/eax: int <- gap-buffer-length data
  70     compare len, 0
  71     break-if-!=
  72     return
  73   }
  74   write out, "  (sandbox . "
  75   append-gap-buffer data, out
  76   write out, ")\n"
  77 }
  78 
  79 ##
  80 
  81 fn render-sandbox screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int, xmax: int, ymax: int {
  82   clear-rect screen, xmin, ymin, xmax, ymax, 0xc5/bg=blue-bg
  83   add-to xmin, 1/padding-left
  84   add-to ymin, 1/padding-top
  85   subtract-from xmax, 1/padding-right
  86   var self/esi: (addr sandbox) <- copy _self
  87   # data
  88   var data-ah/eax: (addr handle gap-buffer) <- get self, data
  89   var _data/eax: (addr gap-buffer) <- lookup *data-ah
  90   var data/edx: (addr gap-buffer) <- copy _data
  91   var x/eax: int <- copy xmin
  92   var y/ecx: int <- copy ymin
  93   y <- maybe-render-empty-screen screen, self, xmin, y
  94   y <- maybe-render-keyboard screen, self, xmin, y
  95   var cursor-in-sandbox?/ebx: (addr boolean) <- get self, cursor-in-data?
  96   x, y <- render-gap-buffer-wrapping-right-then-down screen, data, x, y, xmax, ymax, *cursor-in-sandbox?, 7/fg, 0xc5/bg=blue-bg
  97   y <- increment
  98   # trace
  99   var trace-ah/eax: (addr handle trace) <- get self, trace
 100   var _trace/eax: (addr trace) <- lookup *trace-ah
 101   var trace/edx: (addr trace) <- copy _trace
 102   var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
 103   y <- render-trace screen, trace, xmin, y, xmax, ymax, *cursor-in-trace?
 104   # value
 105   $render-sandbox:value: {
 106     compare y, ymax
 107     break-if->=
 108     var value-ah/eax: (addr handle stream byte) <- get self, value
 109     var _value/eax: (addr stream byte) <- lookup *value-ah
 110     var value/esi: (addr stream byte) <- copy _value
 111     rewind-stream value
 112     var done?/eax: boolean <- stream-empty? value
 113     compare done?, 0/false
 114     break-if-!=
 115     var x/eax: int <- copy 0
 116     x, y <- draw-text-wrapping-right-then-down screen, "=> ", xmin, y, xmax, ymax, xmin, y, 7/fg, 0xc5/bg=blue-bg
 117     var x2/edx: int <- copy x
 118     var dummy/eax: int <- draw-stream-rightward screen, value, x2, xmax, y, 7/fg=grey, 0xc5/bg=blue-bg
 119   }
 120   y <- add 2  # padding
 121   y <- maybe-render-screen screen, self, xmin, y
 122   # render menu
 123   var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
 124   compare *cursor-in-data?, 0/false
 125   {
 126     break-if-=
 127     render-sandbox-menu screen, self
 128     return
 129   }
 130   var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
 131   compare *cursor-in-trace?, 0/false
 132   {
 133     break-if-=
 134     render-trace-menu screen
 135     return
 136   }
 137   var cursor-in-keyboard?/eax: (addr boolean) <- get self, cursor-in-keyboard?
 138   compare *cursor-in-keyboard?, 0/false
 139   {
 140     break-if-=
 141     render-keyboard-menu screen
 142     return
 143   }
 144 }
 145 
 146 fn clear-sandbox-output screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int, xmax: int, ymax: int {
 147   # render just enough of the sandbox to figure out what to erase
 148   var self/esi: (addr sandbox) <- copy _self
 149   var data-ah/eax: (addr handle gap-buffer) <- get self, data
 150   var _data/eax: (addr gap-buffer) <- lookup *data-ah
 151   var data/edx: (addr gap-buffer) <- copy _data
 152   var x/eax: int <- copy xmin
 153   var y/ecx: int <- copy ymin
 154   y <- maybe-render-empty-screen screen, self, xmin, y
 155   y <- maybe-render-keyboard screen, self, xmin, y
 156   var cursor-in-sandbox?/ebx: (addr boolean) <- get self, cursor-in-data?
 157   x, y <- render-gap-buffer-wrapping-right-then-down screen, data, x, y, xmax, ymax, *cursor-in-sandbox?, 3/fg, 0xc5/bg=blue-bg
 158   y <- increment
 159   clear-rect screen, xmin, y, xmax, ymax, 0xc5/bg=blue-bg
 160 }
 161 
 162 fn maybe-render-empty-screen screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int -> _/ecx: int {
 163   var self/esi: (addr sandbox) <- copy _self
 164   var screen-obj-cell-ah/eax: (addr handle cell) <- get self, screen-var
 165   var screen-obj-cell/eax: (addr cell) <- lookup *screen-obj-cell-ah
 166   compare screen-obj-cell, 0
 167   {
 168     break-if-!=
 169     return ymin
 170   }
 171   var screen-obj-cell-type/ecx: (addr int) <- get screen-obj-cell, type
 172   compare *screen-obj-cell-type, 5/screen
 173   {
 174     break-if-=
 175     return ymin  # silently give up on rendering the screen
 176   }
 177   var y/ecx: int <- copy ymin
 178   var screen-obj-ah/eax: (addr handle screen) <- get screen-obj-cell, screen-data
 179   var _screen-obj/eax: (addr screen) <- lookup *screen-obj-ah
 180   var screen-obj/edx: (addr screen) <- copy _screen-obj
 181   var x/eax: int <- draw-text-rightward screen, "screen:   ", xmin, 0x99/xmax, y, 0x17/fg, 0xc5/bg=blue-bg
 182   y <- render-empty-screen screen, screen-obj, x, y
 183   return y
 184 }
 185 
 186 fn maybe-render-screen screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int -> _/ecx: int {
 187   var self/esi: (addr sandbox) <- copy _self
 188   var screen-obj-cell-ah/eax: (addr handle cell) <- get self, screen-var
 189   var screen-obj-cell/eax: (addr cell) <- lookup *screen-obj-cell-ah
 190   compare screen-obj-cell, 0
 191   {
 192     break-if-!=
 193     return ymin
 194   }
 195   var screen-obj-cell-type/ecx: (addr int) <- get screen-obj-cell, type
 196   compare *screen-obj-cell-type, 5/screen
 197   {
 198     break-if-=
 199     return ymin  # silently give up on rendering the screen
 200   }
 201   var screen-obj-ah/eax: (addr handle screen) <- get screen-obj-cell, screen-data
 202   var _screen-obj/eax: (addr screen) <- lookup *screen-obj-ah
 203   var screen-obj/edx: (addr screen) <- copy _screen-obj
 204   {
 205     var screen-empty?/eax: boolean <- fake-screen-empty? screen-obj
 206     compare screen-empty?, 0/false
 207     break-if-=
 208     return ymin
 209   }
 210   var x/eax: int <- draw-text-rightward screen, "screen:   ", xmin, 0x99/xmax, ymin, 0x17/fg, 0xc5/bg=blue-bg
 211   var y/ecx: int <- copy ymin
 212   y <- render-screen screen, screen-obj, x, y
 213   return y
 214 }
 215 
 216 fn render-empty-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int -> _/ecx: int {
 217   var target-screen/esi: (addr screen) <- copy _target-screen
 218   var screen-y/edi: int <- copy ymin
 219   # screen
 220   var height/edx: (addr int) <- get target-screen, height
 221   var y/ecx: int <- copy 0
 222   {
 223     compare y, *height
 224     break-if->=
 225     set-cursor-position screen, xmin, screen-y
 226     var width/edx: (addr int) <- get target-screen, width
 227     var x/ebx: int <- copy 0
 228     {
 229       compare x, *width
 230       break-if->=
 231       draw-code-point-at-cursor screen, 0x20/space, 0x18/fg, 0/bg
 232       move-cursor-right screen
 233       x <- increment
 234       loop
 235     }
 236     y <- increment
 237     screen-y <- increment
 238     loop
 239   }
 240   return screen-y
 241 }
 242 
 243 fn render-screen screen: (addr screen), _target-screen: (addr screen), xmin: int, ymin: int -> _/ecx: int {
 244   var target-screen/esi: (addr screen) <- copy _target-screen
 245   var screen-y/edi: int <- copy ymin
 246   # text data
 247   {
 248     var height/edx: (addr int) <- get target-screen, height
 249     var y/ecx: int <- copy 0
 250     {
 251       compare y, *height
 252       break-if->=
 253       set-cursor-position screen, xmin, screen-y
 254       var width/edx: (addr int) <- get target-screen, width
 255       var x/ebx: int <- copy 0
 256       {
 257         compare x, *width
 258         break-if->=
 259         print-screen-cell-of-fake-screen screen, target-screen, x, y
 260         move-cursor-right screen
 261         x <- increment
 262         loop
 263       }
 264       y <- increment
 265       screen-y <- increment
 266       loop
 267     }
 268   }
 269   # pixel data
 270   {
 271     # screen top left pixels x y width height
 272     var tmp/eax: int <- copy xmin
 273     tmp <- shift-left 3/log2-font-width
 274     var left: int
 275     copy-to left, tmp
 276     tmp <- copy ymin
 277     tmp <- shift-left 4/log2-font-height
 278     var top: int
 279     copy-to top, tmp
 280     var pixels-ah/eax: (addr handle array byte) <- get target-screen, pixels
 281     var _pixels/eax: (addr array byte) <- lookup *pixels-ah
 282     var pixels/edi: (addr array byte) <- copy _pixels
 283     compare pixels, 0
 284     break-if-=
 285     var y/ebx: int <- copy 0
 286     var height-addr/edx: (addr int) <- get target-screen, height
 287     var height/edx: int <- copy *height-addr
 288     height <- shift-left 4/log2-font-height
 289     {
 290       compare y, height
 291       break-if->=
 292       var width-addr/edx: (addr int) <- get target-screen, width
 293       var width/edx: int <- copy *width-addr
 294       width <- shift-left 3/log2-font-width
 295       var x/eax: int <- copy 0
 296       {
 297         compare x, width
 298         break-if->=
 299         {
 300           var idx/ecx: int <- pixel-index target-screen, x, y
 301           var color-addr/ecx: (addr byte) <- index pixels, idx
 302           var color/ecx: byte <- copy-byte *color-addr
 303           var color2/ecx: int <- copy color
 304           compare color2, 0
 305           break-if-=
 306           var x2/eax: int <- copy x
 307           x2 <- add left
 308           var y2/ebx: int <- copy y
 309           y2 <- add top
 310           pixel screen, x2, y2, color2
 311         }
 312         x <- increment
 313         loop
 314       }
 315       y <- increment
 316       loop
 317     }
 318   }
 319   return screen-y
 320 }
 321 
 322 fn has-keyboard? _self: (addr sandbox) -> _/eax: boolean {
 323   var self/esi: (addr sandbox) <- copy _self
 324   var keyboard-obj-cell-ah/eax: (addr handle cell) <- get self, keyboard-var
 325   var keyboard-obj-cell/eax: (addr cell) <- lookup *keyboard-obj-cell-ah
 326   compare keyboard-obj-cell, 0
 327   {
 328     break-if-!=
 329     return 0/false
 330   }
 331   var keyboard-obj-cell-type/ecx: (addr int) <- get keyboard-obj-cell, type
 332   compare *keyboard-obj-cell-type, 6/keyboard
 333   {
 334     break-if-=
 335     return 0/false
 336   }
 337   var keyboard-obj-ah/eax: (addr handle gap-buffer) <- get keyboard-obj-cell, keyboard-data
 338   var _keyboard-obj/eax: (addr gap-buffer) <- lookup *keyboard-obj-ah
 339   var keyboard-obj/edx: (addr gap-buffer) <- copy _keyboard-obj
 340   compare keyboard-obj, 0
 341   {
 342     break-if-!=
 343     return 0/false
 344   }
 345   return 1/true
 346 }
 347 
 348 fn maybe-render-keyboard screen: (addr screen), _self: (addr sandbox), xmin: int, ymin: int -> _/ecx: int {
 349   var self/esi: (addr sandbox) <- copy _self
 350   var keyboard-obj-cell-ah/eax: (addr handle cell) <- get self, keyboard-var
 351   var keyboard-obj-cell/eax: (addr cell) <- lookup *keyboard-obj-cell-ah
 352   compare keyboard-obj-cell, 0
 353   {
 354     break-if-!=
 355     return ymin
 356   }
 357   var keyboard-obj-cell-type/ecx: (addr int) <- get keyboard-obj-cell, type
 358   compare *keyboard-obj-cell-type, 6/keyboard
 359   {
 360     break-if-=
 361     return ymin  # silently give up on rendering the keyboard
 362   }
 363   var keyboard-obj-ah/eax: (addr handle gap-buffer) <- get keyboard-obj-cell, keyboard-data
 364   var _keyboard-obj/eax: (addr gap-buffer) <- lookup *keyboard-obj-ah
 365   var keyboard-obj/edx: (addr gap-buffer) <- copy _keyboard-obj
 366   var y/ecx: int <- copy ymin
 367   y <- increment  # padding
 368   var x/eax: int <- draw-text-rightward screen, "keyboard: ", xmin, 0x99/xmax, y, 0x17/fg, 0xc5/bg=blue-bg
 369   var cursor-in-keyboard?/esi: (addr boolean) <- get self, cursor-in-keyboard?
 370   y <- render-keyboard screen, keyboard-obj, x, y, *cursor-in-keyboard?
 371   y <- increment  # padding
 372   return y
 373 }
 374 
 375 fn render-keyboard screen: (addr screen), _keyboard: (addr gap-buffer), xmin: int, ymin: int, render-cursor?: boolean -> _/ecx: int {
 376   var keyboard/esi: (addr gap-buffer) <- copy _keyboard
 377   var width/edx: int <- copy 0x10/keyboard-capacity
 378   var y/edi: int <- copy ymin
 379   # keyboard
 380   var x/eax: int <- copy xmin
 381   var xmax/ecx: int <- copy x
 382   xmax <- add 0x10
 383   var ymax/edx: int <- copy ymin
 384   ymax <- add 1
 385   clear-rect screen, x, y, xmax, ymax, 0/bg
 386   x <- render-gap-buffer screen, keyboard, x, y, render-cursor?, 3/fg, 0/bg
 387   y <- increment
 388   return y
 389 }
 390 
 391 fn print-screen-cell-of-fake-screen screen: (addr screen), _target: (addr screen), x: int, y: int {
 392   var target/ecx: (addr screen) <- copy _target
 393   var data-ah/eax: (addr handle array screen-cell) <- get target, data
 394   var data/eax: (addr array screen-cell) <- lookup *data-ah
 395   var index/ecx: int <- screen-cell-index target, x, y
 396   var offset/ecx: (offset screen-cell) <- compute-offset data, index
 397   var src-cell/esi: (addr screen-cell) <- index data, offset
 398   var src-grapheme/eax: (addr grapheme) <- get src-cell, data
 399   var src-color/ecx: (addr int) <- get src-cell, color
 400   var src-background-color/edx: (addr int) <- get src-cell, background-color
 401   draw-grapheme-at-cursor screen, *src-grapheme, *src-color, *src-background-color
 402 }
 403 
 404 fn render-sandbox-menu screen: (addr screen), _self: (addr sandbox) {
 405   var _width/eax: int <- copy 0
 406   var height/ecx: int <- copy 0
 407   _width, height <- screen-size screen
 408   var width/edx: int <- copy _width
 409   var y/ecx: int <- copy height
 410   y <- decrement
 411   var height/ebx: int <- copy y
 412   height <- increment
 413   clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
 414   set-cursor-position screen, 0/x, y
 415   draw-text-rightward-from-cursor screen, " ctrl+... ", width, 0xf/fg, 0xc5/bg=blue-bg
 416   draw-text-rightward-from-cursor screen, " r ", width, 0/fg, 0x5c/bg=black
 417   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0xc5/bg=blue-bg
 418   $render-sandbox-menu:render-ctrl-m: {
 419     var self/eax: (addr sandbox) <- copy _self
 420     var has-trace?/eax: boolean <- has-trace? self
 421     compare has-trace?, 0/false
 422     {
 423       break-if-=
 424       draw-text-rightward-from-cursor screen, " m ", width, 0/fg, 0x38/bg=trace
 425       draw-text-rightward-from-cursor screen, " to trace  ", width, 7/fg, 0xc5/bg=blue-bg
 426       break $render-sandbox-menu:render-ctrl-m
 427     }
 428     draw-text-rightward-from-cursor screen, " m ", width, 0/fg, 3/bg=keyboard
 429     draw-text-rightward-from-cursor screen, " to keyboard  ", width, 7/fg, 0xc5/bg=blue-bg
 430   }
 431   draw-text-rightward-from-cursor screen, " s ", width, 0/fg, 0x5c/bg=black
 432   draw-text-rightward-from-cursor screen, " run sandbox  ", width, 7/fg, 0xc5/bg=blue-bg
 433   draw-text-rightward-from-cursor screen, " a ", width, 0/fg, 0x5c/bg=black
 434   draw-text-rightward-from-cursor screen, " <<  ", width, 7/fg, 0xc5/bg=blue-bg
 435   draw-text-rightward-from-cursor screen, " b ", width, 0/fg, 0x5c/bg=black
 436   draw-text-rightward-from-cursor screen, " <word  ", width, 7/fg, 0xc5/bg=blue-bg
 437   draw-text-rightward-from-cursor screen, " f ", width, 0/fg, 0x5c/bg=black
 438   draw-text-rightward-from-cursor screen, " word>  ", width, 7/fg, 0xc5/bg=blue-bg
 439   draw-text-rightward-from-cursor screen, " e ", width, 0/fg, 0x5c/bg=black
 440   draw-text-rightward-from-cursor screen, " >>  ", width, 7/fg, 0xc5/bg=blue-bg
 441 }
 442 
 443 fn render-keyboard-menu screen: (addr screen) {
 444   var width/eax: int <- copy 0
 445   var height/ecx: int <- copy 0
 446   width, height <- screen-size screen
 447   var y/ecx: int <- copy height
 448   y <- decrement
 449   var height/edx: int <- copy y
 450   height <- increment
 451   clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
 452   set-cursor-position screen, 0/x, y
 453   draw-text-rightward-from-cursor screen, " ctrl+... ", width, 0xf/fg, 0xc5/bg=blue-bg
 454   draw-text-rightward-from-cursor screen, " r ", width, 0/fg, 0x5c/bg=black
 455   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0xc5/bg=blue-bg
 456   draw-text-rightward-from-cursor screen, " s ", width, 0/fg, 0x5c/bg=black
 457   draw-text-rightward-from-cursor screen, " run sandbox  ", width, 7/fg, 0xc5/bg=blue-bg
 458   draw-text-rightward-from-cursor screen, " m ", width, 0/fg, 7/bg
 459   draw-text-rightward-from-cursor screen, " to sandbox  ", width, 7/fg, 0xc5/bg=blue-bg
 460 }
 461 
 462 fn edit-sandbox _self: (addr sandbox), key: byte, globals: (addr global-table), data-disk: (addr disk), real-screen: (addr screen), tweak-real-screen?: boolean {
 463   var self/esi: (addr sandbox) <- copy _self
 464   var g/edx: grapheme <- copy key
 465   # ctrl-s
 466   {
 467     compare g, 0x13/ctrl-s
 468     break-if-!=
 469     # if cursor is in trace, skip
 470     var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
 471     compare *cursor-in-trace?, 0/false
 472     break-if-!=
 473     # minor gotcha here: any bindings created later in this iteration won't be
 474     # persisted until the next call to ctrl-s.
 475     store-state data-disk, self, globals
 476     #
 477     run-sandbox self, globals, real-screen, tweak-real-screen?
 478     return
 479   }
 480   # ctrl-m
 481   {
 482     compare g, 0xd/ctrl-m
 483     break-if-!=
 484     # if cursor in data, switch to trace or fall through to keyboard
 485     {
 486       var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
 487       compare *cursor-in-data?, 0/false
 488       break-if-=
 489       var has-trace?/eax: boolean <- has-trace? self
 490       compare has-trace?, 0/false
 491       {
 492         break-if-=
 493         var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
 494         copy-to *cursor-in-data?, 0/false
 495         var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
 496         copy-to *cursor-in-trace?, 1/false
 497         return
 498       }
 499       var has-keyboard?/eax: boolean <- has-keyboard? self
 500       compare has-keyboard?, 0/false
 501       {
 502         break-if-=
 503         var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
 504         copy-to *cursor-in-data?, 0/false
 505         var cursor-in-keyboard?/eax: (addr boolean) <- get self, cursor-in-keyboard?
 506         copy-to *cursor-in-keyboard?, 1/false
 507         return
 508       }
 509       return
 510     }
 511     # if cursor in trace, switch to keyboard or fall through to data
 512     {
 513       var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
 514       compare *cursor-in-trace?, 0/false
 515       break-if-=
 516       copy-to *cursor-in-trace?, 0/false
 517       var cursor-target/ecx: (addr boolean) <- get self, cursor-in-keyboard?
 518       var has-keyboard?/eax: boolean <- has-keyboard? self
 519       compare has-keyboard?, 0/false
 520       {
 521         break-if-!=
 522         cursor-target <- get self, cursor-in-data?
 523       }
 524       copy-to *cursor-target, 1/true
 525       return
 526     }
 527     # otherwise if cursor in keyboard, switch to data
 528     {
 529       var cursor-in-keyboard?/eax: (addr boolean) <- get self, cursor-in-keyboard?
 530       compare *cursor-in-keyboard?, 0/false
 531       break-if-=
 532       copy-to *cursor-in-keyboard?, 0/false
 533       var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
 534       copy-to *cursor-in-data?, 1/true
 535       return
 536     }
 537     return
 538   }
 539   # if cursor in data, send key to data
 540   {
 541     var cursor-in-data?/eax: (addr boolean) <- get self, cursor-in-data?
 542     compare *cursor-in-data?, 0/false
 543     break-if-=
 544     var data-ah/eax: (addr handle gap-buffer) <- get self, data
 545     var data/eax: (addr gap-buffer) <- lookup *data-ah
 546     edit-gap-buffer data, g
 547     return
 548   }
 549   # if cursor in keyboard, send key to keyboard
 550   {
 551     var cursor-in-keyboard?/eax: (addr boolean) <- get self, cursor-in-keyboard?
 552     compare *cursor-in-keyboard?, 0/false
 553     break-if-=
 554     var keyboard-cell-ah/eax: (addr handle cell) <- get self, keyboard-var
 555     var keyboard-cell/eax: (addr cell) <- lookup *keyboard-cell-ah
 556     compare keyboard-cell, 0
 557     {
 558       break-if-!=
 559       return
 560     }
 561     var keyboard-cell-type/ecx: (addr int) <- get keyboard-cell, type
 562     compare *keyboard-cell-type, 6/keyboard
 563     {
 564       break-if-=
 565       return
 566     }
 567     var keyboard-ah/eax: (addr handle gap-buffer) <- get keyboard-cell, keyboard-data
 568     var keyboard/eax: (addr gap-buffer) <- lookup *keyboard-ah
 569     edit-gap-buffer keyboard, g
 570     return
 571   }
 572   # if cursor in trace, send key to trace
 573   {
 574     var cursor-in-trace?/eax: (addr boolean) <- get self, cursor-in-trace?
 575     compare *cursor-in-trace?, 0/false
 576     break-if-=
 577     var trace-ah/eax: (addr handle trace) <- get self, trace
 578     var trace/eax: (addr trace) <- lookup *trace-ah
 579     # if expanding the trace, first check if we need to run the sandbox again with a deeper trace
 580     {
 581       compare g, 0xa/newline
 582       break-if-!=
 583       {
 584         var need-rerun?/eax: boolean <- cursor-too-deep? trace
 585         compare need-rerun?, 0/false
 586       }
 587       break-if-=
 588       var max-depth-addr/eax: (addr int) <- get trace, max-depth
 589       increment *max-depth-addr
 590       run-sandbox self, globals, real-screen, tweak-real-screen?
 591     }
 592     edit-trace trace, g
 593     return
 594   }
 595 }
 596 
 597 # hack: tweak-real-screen guards things there are no tests for
 598 fn run-sandbox _self: (addr sandbox), globals: (addr global-table), real-screen: (addr screen), tweak-real-screen?: boolean {
 599   var self/esi: (addr sandbox) <- copy _self
 600   var data-ah/ecx: (addr handle gap-buffer) <- get self, data
 601   var value-ah/eax: (addr handle stream byte) <- get self, value
 602   var _value/eax: (addr stream byte) <- lookup *value-ah
 603   var value/edx: (addr stream byte) <- copy _value
 604   var trace-ah/eax: (addr handle trace) <- get self, trace
 605   var _trace/eax: (addr trace) <- lookup *trace-ah
 606   var trace/ebx: (addr trace) <- copy _trace
 607   clear-trace trace
 608   {
 609     compare tweak-real-screen?, 0/false
 610     break-if-=
 611     clear-sandbox-output real-screen, self, 0x56/sandbox-left-margin, 1/y, 0x80/screen-width, 0x2f/screen-height-without-menu
 612   }
 613   var screen-cell/eax: (addr handle cell) <- get self, screen-var
 614   clear-screen-cell screen-cell
 615   var keyboard-cell/esi: (addr handle cell) <- get self, keyboard-var
 616   rewind-keyboard-cell keyboard-cell  # don't clear keys from before
 617   {
 618     compare tweak-real-screen?, 0/false
 619     break-if-=
 620     set-cursor-position real-screen, 0/x, 0/y  # for any debug prints during evaluation
 621   }
 622   run data-ah, value, globals, trace, screen-cell, keyboard-cell
 623 }
 624 
 625 fn run _in-ah: (addr handle gap-buffer), out: (addr stream byte), globals: (addr global-table), trace: (addr trace), screen-cell: (addr handle cell), keyboard-cell: (addr handle cell) {
 626   var in-ah/eax: (addr handle gap-buffer) <- copy _in-ah
 627   var in/eax: (addr gap-buffer) <- lookup *in-ah
 628   var read-result-h: (handle cell)
 629   var read-result-ah/esi: (addr handle cell) <- address read-result-h
 630   read-cell in, read-result-ah, trace
 631   var error?/eax: boolean <- has-errors? trace
 632   {
 633     compare error?, 0/false
 634     break-if-=
 635     return
 636   }
 637   macroexpand read-result-ah, globals, trace
 638   var error?/eax: boolean <- has-errors? trace
 639   {
 640     compare error?, 0/false
 641     break-if-=
 642     return
 643   }
 644   var nil-h: (handle cell)
 645   var nil-ah/eax: (addr handle cell) <- address nil-h
 646   allocate-pair nil-ah
 647   var eval-result-h: (handle cell)
 648   var eval-result-ah/edi: (addr handle cell) <- address eval-result-h
 649 #?   set-cursor-position 0/screen, 0 0
 650 #?   turn-on-debug-print
 651   debug-print "^", 4/fg, 0/bg
 652   evaluate read-result-ah, eval-result-ah, *nil-ah, globals, trace, screen-cell, keyboard-cell, 1/call-number
 653   debug-print "$", 4/fg, 0/bg
 654   var error?/eax: boolean <- has-errors? trace
 655   {
 656     compare error?, 0/false
 657     break-if-=
 658     return
 659   }
 660   # if there was no error and the read-result starts with "set" or "def", save
 661   # the gap buffer in the modified global, then create a new one for the next
 662   # command.
 663   maybe-stash-gap-buffer-to-global globals, read-result-ah, _in-ah
 664   clear-stream out
 665   print-cell eval-result-ah, out, trace
 666   mark-lines-dirty trace
 667 }
 668 
 669 fn read-evaluate-and-move-to-globals _in-ah: (addr handle gap-buffer), globals: (addr global-table), definition-name: (addr stream byte) {
 670   var in-ah/eax: (addr handle gap-buffer) <- copy _in-ah
 671   var in/eax: (addr gap-buffer) <- lookup *in-ah
 672   var read-result-h: (handle cell)
 673   var read-result-ah/esi: (addr handle cell) <- address read-result-h
 674   var trace-storage: trace
 675   var trace/edx: (addr trace) <- address trace-storage
 676   initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
 677   read-cell in, read-result-ah, trace
 678   macroexpand read-result-ah, globals, trace
 679   var nil-storage: (handle cell)
 680   var nil-ah/eax: (addr handle cell) <- address nil-storage
 681   allocate-pair nil-ah
 682   var eval-result-storage: (handle cell)
 683   var eval-result/edi: (addr handle cell) <- address eval-result-storage
 684   debug-print "^", 4/fg, 0/bg
 685   evaluate read-result-ah, eval-result, *nil-ah, globals, trace, 0/no-screen-cell, 0/no-keyboard-cell, 1/call-number
 686   {
 687     var error?/eax: boolean <- has-errors? trace
 688     compare error?, 0/false
 689     break-if-=
 690     set-cursor-position 0/screen, 0x40/x, 0x18/y
 691     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "error when loading definition for ", 4/fg 0/bg
 692     rewind-stream definition-name
 693     draw-stream-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, definition-name, 3/fg 0/bg
 694     set-cursor-position 0/screen, 0x40/x, 0x19/y
 695     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "see trace in grey at top-left", 7/fg 0/bg
 696     dump-trace trace  # will print from 0, 0
 697     {
 698       loop
 699     }
 700   }
 701   debug-print "$", 4/fg, 0/bg
 702   move-gap-buffer-to-global globals, read-result-ah, _in-ah
 703 }
 704 
 705 fn test-run-integer {
 706   var sandbox-storage: sandbox
 707   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 708   initialize-sandbox-with sandbox, "1"
 709   # eval
 710   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 711   # setup: screen
 712   var screen-on-stack: screen
 713   var screen/edi: (addr screen) <- address screen-on-stack
 714   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 715   #
 716   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 717   # skip one line of padding
 718   check-screen-row screen, 1/y, " 1    ", "F - test-run-integer/0"
 719   check-screen-row screen, 2/y, " ...  ", "F - test-run-integer/1"
 720   check-screen-row screen, 3/y, " => 1 ", "F - test-run-integer/2"
 721 }
 722 
 723 fn test-run-error-invalid-integer {
 724   var sandbox-storage: sandbox
 725   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 726   initialize-sandbox-with sandbox, "1a"
 727   # eval
 728   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 729   # setup: screen
 730   var screen-on-stack: screen
 731   var screen/edi: (addr screen) <- address screen-on-stack
 732   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 733   #
 734   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 735   # skip one line of padding
 736   check-screen-row            screen,               1/y, " 1a             ", "F - test-run-error-invalid-integer/0"
 737   check-screen-row            screen,               2/y, " ...            ", "F - test-run-error-invalid-integer/1"
 738   check-screen-row-in-color   screen, 0xc/fg=error, 3/y, " invalid number ", "F - test-run-error-invalid-integer/2"
 739 }
 740 
 741 fn test-run-error-unknown-symbol {
 742   var sandbox-storage: sandbox
 743   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 744   initialize-sandbox-with sandbox, "a"
 745   # eval
 746   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 747   # setup: screen
 748   var screen-on-stack: screen
 749   var screen/edi: (addr screen) <- address screen-on-stack
 750   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 751   #
 752   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 753   # skip one line of padding
 754   check-screen-row            screen,               1/y, " a                  ", "F - test-run-error-unknown-symbol/0"
 755   check-screen-row            screen,               2/y, " ...                ", "F - test-run-error-unknown-symbol/1"
 756   check-screen-row-in-color   screen, 0xc/fg=error, 3/y, " unbound symbol: a  ", "F - test-run-error-unknown-symbol/2"
 757 }
 758 
 759 fn test-run-with-spaces {
 760   var sandbox-storage: sandbox
 761   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 762   initialize-sandbox-with sandbox, " 1 \n"
 763   # eval
 764   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 765   # setup: screen
 766   var screen-on-stack: screen
 767   var screen/edi: (addr screen) <- address screen-on-stack
 768   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 769   #
 770   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 771   # skip one line of padding
 772   check-screen-row screen, 1/y, "  1   ", "F - test-run-with-spaces/0"
 773   check-screen-row screen, 2/y, "      ", "F - test-run-with-spaces/1"
 774   check-screen-row screen, 3/y, " ...  ", "F - test-run-with-spaces/2"
 775   check-screen-row screen, 4/y, " => 1 ", "F - test-run-with-spaces/3"
 776 }
 777 
 778 fn test-run-quote {
 779   var sandbox-storage: sandbox
 780   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 781   initialize-sandbox-with sandbox, "'a"
 782   # eval
 783   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 784   # setup: screen
 785   var screen-on-stack: screen
 786   var screen/edi: (addr screen) <- address screen-on-stack
 787   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 788   #
 789   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 790   # skip one line of padding
 791   check-screen-row screen, 1/y, " 'a   ", "F - test-run-quote/0"
 792   check-screen-row screen, 2/y, " ...  ", "F - test-run-quote/1"
 793   check-screen-row screen, 3/y, " => a ", "F - test-run-quote/2"
 794 }
 795 
 796 fn test-run-dotted-list {
 797   var sandbox-storage: sandbox
 798   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 799   initialize-sandbox-with sandbox, "'(a . b)"
 800   # eval
 801   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 802   # setup: screen
 803   var screen-on-stack: screen
 804   var screen/edi: (addr screen) <- address screen-on-stack
 805   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 806   #
 807   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 808   # skip one line of padding
 809   check-screen-row screen, 1/y, " '(a . b)   ", "F - test-run-dotted-list/0"
 810   check-screen-row screen, 2/y, " ...        ", "F - test-run-dotted-list/1"
 811   check-screen-row screen, 3/y, " => (a . b) ", "F - test-run-dotted-list/2"
 812 }
 813 
 814 fn test-run-dot-and-list {
 815   var sandbox-storage: sandbox
 816   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 817   initialize-sandbox-with sandbox, "'(a . (b))"
 818   # eval
 819   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 820   # setup: screen
 821   var screen-on-stack: screen
 822   var screen/edi: (addr screen) <- address screen-on-stack
 823   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 824   #
 825   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 826   # skip one line of padding
 827   check-screen-row screen, 1/y, " '(a . (b)) ", "F - test-run-dot-and-list/0"
 828   check-screen-row screen, 2/y, " ...        ", "F - test-run-dot-and-list/1"
 829   check-screen-row screen, 3/y, " => (a b)   ", "F - test-run-dot-and-list/2"
 830 }
 831 
 832 fn test-run-final-dot {
 833   var sandbox-storage: sandbox
 834   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 835   initialize-sandbox-with sandbox, "'(a .)"
 836   # eval
 837   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 838   # setup: screen
 839   var screen-on-stack: screen
 840   var screen/edi: (addr screen) <- address screen-on-stack
 841   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 842   #
 843   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 844   # skip one line of padding
 845   check-screen-row screen, 1/y, " '(a .)               ", "F - test-run-final-dot/0"
 846   check-screen-row screen, 2/y, " ...                  ", "F - test-run-final-dot/1"
 847   check-screen-row screen, 3/y, " '. )' makes no sense ", "F - test-run-final-dot/2"
 848   # further errors may occur
 849 }
 850 
 851 fn test-run-double-dot {
 852   var sandbox-storage: sandbox
 853   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 854   initialize-sandbox-with sandbox, "'(a . .)"
 855   # eval
 856   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 857   # setup: screen
 858   var screen-on-stack: screen
 859   var screen/edi: (addr screen) <- address screen-on-stack
 860   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 861   #
 862   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 863   # skip one line of padding
 864   check-screen-row screen, 1/y, " '(a . .)             ", "F - test-run-double-dot/0"
 865   check-screen-row screen, 2/y, " ...                  ", "F - test-run-double-dot/1"
 866   check-screen-row screen, 3/y, " '. .' makes no sense ", "F - test-run-double-dot/2"
 867   # further errors may occur
 868 }
 869 
 870 fn test-run-multiple-expressions-after-dot {
 871   var sandbox-storage: sandbox
 872   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 873   initialize-sandbox-with sandbox, "'(a . b c)"
 874   # eval
 875   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 876   # setup: screen
 877   var screen-on-stack: screen
 878   var screen/edi: (addr screen) <- address screen-on-stack
 879   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 880   #
 881   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 882   # skip one line of padding
 883   check-screen-row screen, 1/y, " '(a . b c)                                           ", "F - test-run-multiple-expressions-after-dot/0"
 884   check-screen-row screen, 2/y, " ...                                                  ", "F - test-run-multiple-expressions-after-dot/1"
 885   check-screen-row screen, 3/y, " cannot have multiple expressions between '.' and ')' ", "F - test-run-multiple-expressions-after-dot/2"
 886   # further errors may occur
 887 }
 888 
 889 fn test-run-stream {
 890   var sandbox-storage: sandbox
 891   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 892   initialize-sandbox-with sandbox, "[a b]"
 893   # eval
 894   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 895   # setup: screen
 896   var screen-on-stack: screen
 897   var screen/edi: (addr screen) <- address screen-on-stack
 898   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 899   #
 900   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 901   # skip one line of padding
 902   check-screen-row screen, 1/y, " [a b]    ", "F - test-run-stream/0"
 903   check-screen-row screen, 2/y, " ...      ", "F - test-run-stream/1"
 904   check-screen-row screen, 3/y, " => [a b] ", "F - test-run-stream/2"
 905 }
 906 
 907 fn test-run-move-cursor-into-trace {
 908   var sandbox-storage: sandbox
 909   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 910   initialize-sandbox-with sandbox, "12"
 911   # eval
 912   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 913   # setup: screen
 914   var screen-on-stack: screen
 915   var screen/edi: (addr screen) <- address screen-on-stack
 916   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 917   #
 918   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 919   # skip one line of padding
 920   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-move-cursor-into-trace/pre-0"
 921   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "   |   ", "F - test-run-move-cursor-into-trace/pre-0/cursor"
 922   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-move-cursor-into-trace/pre-1"
 923   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "       ", "F - test-run-move-cursor-into-trace/pre-1/cursor"
 924   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-move-cursor-into-trace/pre-2"
 925   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-move-cursor-into-trace/pre-2/cursor"
 926   # move cursor into trace
 927   edit-sandbox sandbox, 0xd/ctrl-m, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 928   #
 929   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 930   # skip one line of padding
 931   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-move-cursor-into-trace/trace-0"
 932   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "       ", "F - test-run-move-cursor-into-trace/trace-0/cursor"
 933   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-move-cursor-into-trace/trace-1"
 934   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " |||   ", "F - test-run-move-cursor-into-trace/trace-1/cursor"
 935   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-move-cursor-into-trace/trace-2"
 936   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-move-cursor-into-trace/trace-2/cursor"
 937   # move cursor into input
 938   edit-sandbox sandbox, 0xd/ctrl-m, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 939   #
 940   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 941   # skip one line of padding
 942   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-move-cursor-into-trace/input-0"
 943   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "   |   ", "F - test-run-move-cursor-into-trace/input-0/cursor"
 944   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-move-cursor-into-trace/input-1"
 945   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "       ", "F - test-run-move-cursor-into-trace/input-1/cursor"
 946   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-move-cursor-into-trace/input-2"
 947   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-move-cursor-into-trace/input-2/cursor"
 948 }
 949 
 950 fn has-trace? _self: (addr sandbox) -> _/eax: boolean {
 951   var self/esi: (addr sandbox) <- copy _self
 952   var trace-ah/eax: (addr handle trace) <- get self, trace
 953   var _trace/eax: (addr trace) <- lookup *trace-ah
 954   var trace/edx: (addr trace) <- copy _trace
 955   compare trace, 0
 956   {
 957     break-if-!=
 958     abort "null trace"
 959   }
 960   var first-free/ebx: (addr int) <- get trace, first-free
 961   compare *first-free, 0
 962   {
 963     break-if->
 964     return 0/false
 965   }
 966   return 1/true
 967 }
 968 
 969 fn test-run-expand-trace {
 970   var sandbox-storage: sandbox
 971   var sandbox/esi: (addr sandbox) <- address sandbox-storage
 972   initialize-sandbox-with sandbox, "12"
 973   # eval
 974   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 975   # setup: screen
 976   var screen-on-stack: screen
 977   var screen/edi: (addr screen) <- address screen-on-stack
 978   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
 979   #
 980   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 981   # skip one line of padding
 982   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-expand-trace/pre0-0"
 983   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "   |   ", "F - test-run-expand-trace/pre0-0/cursor"
 984   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-expand-trace/pre0-1"
 985   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "       ", "F - test-run-expand-trace/pre0-1/cursor"
 986   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-expand-trace/pre0-2"
 987   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-expand-trace/pre0-2/cursor"
 988   # move cursor into trace
 989   edit-sandbox sandbox, 0xd/ctrl-m, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
 990   #
 991   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
 992   # skip one line of padding
 993   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-expand-trace/pre1-0"
 994   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "       ", "F - test-run-expand-trace/pre1-0/cursor"
 995   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-expand-trace/pre1-1"
 996   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " |||   ", "F - test-run-expand-trace/pre1-1/cursor"
 997   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-expand-trace/pre1-2"
 998   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-expand-trace/pre1-2/cursor"
 999   # expand
1000   edit-sandbox sandbox, 0xa/newline, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
1001   #
1002   clear-screen screen
1003   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
1004   # skip one line of padding
1005   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-expand-trace/expand-0"
1006   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "       ", "F - test-run-expand-trace/expand-0/cursor"
1007   check-screen-row screen,                                  2/y, " 1 toke", "F - test-run-expand-trace/expand-1"
1008   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ||||||", "F - test-run-expand-trace/expand-1/cursor"
1009   check-screen-row screen,                                  3/y, " ...   ", "F - test-run-expand-trace/expand-2"
1010   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-expand-trace/expand-2/cursor"
1011   check-screen-row screen,                                  4/y, " 1 pars", "F - test-run-expand-trace/expand-2"
1012   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "       ", "F - test-run-expand-trace/expand-2/cursor"
1013 }
1014 
1015 fn test-run-can-rerun-when-expanding-trace {
1016   var sandbox-storage: sandbox
1017   var sandbox/esi: (addr sandbox) <- address sandbox-storage
1018   # initialize sandbox with a max-depth of 3
1019   initialize-sandbox-with sandbox, "12"
1020   # eval
1021   edit-sandbox sandbox, 0x13/ctrl-s, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
1022   # setup: screen
1023   var screen-on-stack: screen
1024   var screen/edi: (addr screen) <- address screen-on-stack
1025   initialize-screen screen, 0x80/width, 0x10/height, 0/no-pixel-graphics
1026   #
1027   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
1028   # skip one line of padding
1029   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-can-rerun-when-expanding-trace/pre0-0"
1030   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "   |   ", "F - test-run-can-rerun-when-expanding-trace/pre0-0/cursor"
1031   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-can-rerun-when-expanding-trace/pre0-1"
1032   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre0-1/cursor"
1033   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-can-rerun-when-expanding-trace/pre0-2"
1034   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre0-2/cursor"
1035   # move cursor into trace
1036   edit-sandbox sandbox, 0xd/ctrl-m, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
1037   #
1038   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
1039   # skip one line of padding
1040   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-can-rerun-when-expanding-trace/pre1-0"
1041   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre1-0/cursor"
1042   check-screen-row screen,                                  2/y, " ...   ", "F - test-run-can-rerun-when-expanding-trace/pre1-1"
1043   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " |||   ", "F - test-run-can-rerun-when-expanding-trace/pre1-1/cursor"
1044   check-screen-row screen,                                  3/y, " => 12 ", "F - test-run-can-rerun-when-expanding-trace/pre1-2"
1045   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre1-2/cursor"
1046   # expand
1047   edit-sandbox sandbox, 0xa/newline, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
1048   #
1049   clear-screen screen
1050   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
1051   # skip one line of padding
1052   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-can-rerun-when-expanding-trace/pre2-0"
1053   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre2-0/cursor"
1054   check-screen-row screen,                                  2/y, " 1 toke", "F - test-run-can-rerun-when-expanding-trace/pre2-1"
1055   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, " ||||||", "F - test-run-can-rerun-when-expanding-trace/pre2-1/cursor"
1056   check-screen-row screen,                                  3/y, " ...   ", "F - test-run-can-rerun-when-expanding-trace/pre2-2"
1057   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre2-2/cursor"
1058   check-screen-row screen,                                  4/y, " 1 pars", "F - test-run-can-rerun-when-expanding-trace/pre2-2"
1059   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "       ", "F - test-run-can-rerun-when-expanding-trace/pre2-2/cursor"
1060   # move cursor down and expand
1061   edit-sandbox sandbox, 0x6a/j, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
1062   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
1063   edit-sandbox sandbox, 0xa/newline, 0/no-globals, 0/no-disk, 0/no-screen, 0/no-tweak-screen
1064   #
1065   clear-screen screen
1066   render-sandbox screen, sandbox, 0/x, 0/y, 0x80/width, 0x10/height
1067   # screen looks same as if trace max-depth was really high
1068   check-screen-row screen,                                  1/y, " 12    ", "F - test-run-can-rerun-when-expanding-trace/expand-0"
1069   check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, "       ", "F - test-run-can-rerun-when-expanding-trace/expand-0/cursor"
1070   check-screen-row screen,                                  2/y, " 1 toke", "F - test-run-can-rerun-when-expanding-trace/expand-1"
1071   check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "       ", "F - test-run-can-rerun-when-expanding-trace/expand-1/cursor"
1072   check-screen-row screen,                                  3/y, " 2 next", "F - test-run-can-rerun-when-expanding-trace/expand-2"
1073   check-background-color-in-screen-row screen, 7/bg=cursor, 3/y, " ||||||", "F - test-run-can-rerun-when-expanding-trace/expand-2/cursor"
1074   check-screen-row screen,                                  4/y, " ...   ", "F - test-run-can-rerun-when-expanding-trace/expand-3"
1075   check-background-color-in-screen-row screen, 7/bg=cursor, 4/y, "       ", "F - test-run-can-rerun-when-expanding-trace/expand-3/cursor"
1076   check-screen-row screen,                                  5/y, " 2 => 1", "F - test-run-can-rerun-when-expanding-trace/expand-4"
1077   check-background-color-in-screen-row screen, 7/bg=cursor, 5/y, "       ", "F - test-run-can-rerun-when-expanding-trace/expand-4/cursor"
1078 }