# Mu - shell/global.mu

https://github.com/akkartik/mu/blob/main/shell/global.mu

      1 type global-table {
      2   data: (handle array global)
      3   final-index: int
      4   cursor-index: int
      5 }
      6
      7 type global {
      8   name: (handle array byte)
      9   input: (handle gap-buffer)
     10   value: (handle cell)
     11 }
     12
     13 fn initialize-globals _self: (addr global-table) {
     14   var self/esi: (addr global-table) <- copy _self
     15   compare self, 0
     16   {
     17     break-if-!=
     18     abort "initialize globals"
     19     return
     20   }
     21   var data-ah/eax: (addr handle array global) <- get self, data
     22   populate data-ah, 0x40
     23   initialize-primitives self
     24 }
     25
     26 fn load-globals in: (addr handle cell), self: (addr global-table) {
     27   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading globals:", 3/fg, 0/bg
     28   var remaining-ah/esi: (addr handle cell) <- copy in
     29   {
     30     var _remaining/eax: (addr cell) <- lookup *remaining-ah
     31     var remaining/ebx: (addr cell) <- copy _remaining
     32     var done?/eax: boolean <- nil? remaining
     33     compare done?, 0/false
     34     break-if-!=
     35 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "b", 2/fg 0/bg
     36     var curr-ah/eax: (addr handle cell) <- get remaining, left
     37     var _curr/eax: (addr cell) <- lookup *curr-ah
     38     var curr/ecx: (addr cell) <- copy _curr
     39     remaining-ah <- get remaining, right
     40     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " ", 2/fg 0/bg
     41     var name-ah/eax: (addr handle cell) <- get curr, left
     42     var name/eax: (addr cell) <- lookup *name-ah
     43     var name-data-ah/eax: (addr handle stream byte) <- get name, text-data
     44     var _name-data/eax: (addr stream byte) <- lookup *name-data-ah
     45     var name-data/edx: (addr stream byte) <- copy _name-data
     46     rewind-stream name-data
     47     draw-stream-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, name-data, 3/fg, 0/bg
     48     var value-ah/eax: (addr handle cell) <- get curr, right
     49     var value/eax: (addr cell) <- lookup *value-ah
     50     var value-data-ah/eax: (addr handle stream byte) <- get value, text-data
     51     var _value-data/eax: (addr stream byte) <- lookup *value-data-ah
     52     var value-data/ecx: (addr stream byte) <- copy _value-data
     53     var value-gap-buffer-storage: (handle gap-buffer)
     54     var value-gap-buffer-ah/edi: (addr handle gap-buffer) <- address value-gap-buffer-storage
     55     allocate value-gap-buffer-ah
     56     var value-gap-buffer/eax: (addr gap-buffer) <- lookup *value-gap-buffer-ah
     57     initialize-gap-buffer value-gap-buffer, 0x1000/4KB
     58 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "w", 2/fg 0/bg
     59     load-gap-buffer-from-stream value-gap-buffer, value-data
     60 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "x", 2/fg 0/bg
     61     read-evaluate-and-move-to-globals value-gap-buffer-ah, self, name-data
     62 #?     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "y", 2/fg 0/bg
     63     loop
     64   }
     65   move-cursor-to-left-margin-of-next-line 0/screen
     66 #?   abort "zz"
     67 }
     68
     69 fn write-globals out: (addr stream byte), _self: (addr global-table) {
     70   var self/esi: (addr global-table) <- copy _self
     71   compare self, 0
     72   {
     73     break-if-!=
     74     abort "write globals"
     75     return
     76   }
     77   write out, "  (globals . (\n"
     78   var data-ah/eax: (addr handle array global) <- get self, data
     79   var data/eax: (addr array global) <- lookup *data-ah
     80   var final-index/edx: (addr int) <- get self, final-index
     81   var curr-index/ecx: int <- copy 1/skip-0
     82   {
     83     compare curr-index, *final-index
     84     break-if->
     85     var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
     86     var curr/ebx: (addr global) <- index data, curr-offset
     87     var curr-value-ah/edx: (addr handle cell) <- get curr, value
     88     var curr-value/eax: (addr cell) <- lookup *curr-value-ah
     89     var curr-type/eax: (addr int) <- get curr-value, type
     90     {
     91       compare *curr-type, 4/primitive-function
     92       break-if-=
     93       compare *curr-type, 5/screen
     94       break-if-=
     95       compare *curr-type, 6/keyboard
     96       break-if-=
     97       compare *curr-type, 3/stream  # not implemented yet
     98       break-if-=
     99       write out, "    ("
    100       var curr-name-ah/eax: (addr handle array byte) <- get curr, name
    101       var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
    102       write out, curr-name
    103       write out, " . ["
    104       var curr-input-ah/eax: (addr handle gap-buffer) <- get curr, input
    105       var curr-input/eax: (addr gap-buffer) <- lookup *curr-input-ah
    106       append-gap-buffer curr-input, out
    107       write out, "])\n"
    108     }
    109     curr-index <- increment
    110     loop
    111   }
    112   write out, "  ))\n"
    113 }
    114
    115 # globals layout: 1 char padding, 41 code, 1 padding, 41 code, 1 padding =  85 chars
    116 fn render-globals screen: (addr screen), _self: (addr global-table), show-cursor?: boolean {
    117   clear-rect screen, 0/xmin, 0/ymin, 0x55/xmax, 0x2f/ymax=screen-height-without-menu, 0xdc/bg=green-bg
    118   var self/esi: (addr global-table) <- copy _self
    119   compare self, 0
    120   {
    121     break-if-!=
    122     abort "render globals"
    123     return
    124   }
    125   var data-ah/eax: (addr handle array global) <- get self, data
    126   var data/eax: (addr array global) <- lookup *data-ah
    127   var curr-index/edx: int <- copy 1
    128   {
    129     var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
    130     var curr/ebx: (addr global) <- index data, curr-offset
    131     var continue?/eax: boolean <- primitive-global? curr
    132     compare continue?, 0/false
    133     break-if-=
    134     curr-index <- increment
    135     loop
    136   }
    137   var lowest-index/edi: int <- copy curr-index
    138   var cursor-index/edx: (addr int) <- get self, cursor-index
    139   var curr-index/edx: int <- copy *cursor-index
    140   var y1: int
    141   copy-to y1, 1/padding-top
    142   var y2: int
    143   copy-to y2, 1/padding-top
    144   $render-globals:loop: {
    145     compare curr-index, lowest-index
    146     break-if-<
    147     {
    148       compare y1, 0x2f/ymax
    149       break-if-<
    150       compare y2, 0x2f/ymax
    151       break-if-<
    152       break $render-globals:loop
    153     }
    154     {
    155       var show-cursor?/edi: boolean <- copy show-cursor?
    156       {
    157         compare show-cursor?, 0/false
    158         break-if-=
    159         var cursor-index/eax: (addr int) <- get self, cursor-index
    160         compare *cursor-index, curr-index
    161         break-if-=
    162         show-cursor? <- copy 0/false
    163       }
    164       var curr-offset/edx: (offset global) <- compute-offset data, curr-index
    165       var curr/edx: (addr global) <- index data, curr-offset
    166       var curr-input-ah/edx: (addr handle gap-buffer) <- get curr, input
    167       var _curr-input/eax: (addr gap-buffer) <- lookup *curr-input-ah
    168       var curr-input/ebx: (addr gap-buffer) <- copy _curr-input
    169       compare curr-input, 0
    170       break-if-=
    171       $render-globals:render-global: {
    172         var x/eax: int <- copy 0
    173         var y/ecx: int <- copy y1
    174         compare y, y2
    175         {
    176           break-if->=
    177           x, y <- render-gap-buffer-wrapping-right-then-down screen, curr-input, 1/padding-left, y1, 0x2a/xmax, 0x2f/ymax, show-cursor?, 7/fg=definition, 0xc5/bg=blue-bg
    178           y <- add 2
    179           copy-to y1, y
    180           break $render-globals:render-global
    181         }
    182         x, y <- render-gap-buffer-wrapping-right-then-down screen, curr-input, 0x2b/xmin, y2, 0x54/xmax, 0x2f/ymax, show-cursor?, 7/fg=definition, 0xc5/bg=blue-bg
    183         y <- add 2
    184         copy-to y2, y
    185       }
    186     }
    187     curr-index <- decrement
    188     loop
    189   }
    190   # render primitives on top
    191   render-primitives screen, 1/xmin=padding-left, 0x55/xmax, 0x2f/ymax
    192 }
    193
    194 fn render-globals-menu screen: (addr screen), _self: (addr global-table) {
    195   var _width/eax: int <- copy 0
    196   var height/ecx: int <- copy 0
    197   _width, height <- screen-size screen
    198   var width/edx: int <- copy _width
    199   var y/ecx: int <- copy height
    200   y <- decrement
    201   var height/ebx: int <- copy y
    202   height <- increment
    203   clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
    204   set-cursor-position screen, 0/x, y
    205   draw-text-rightward-from-cursor screen, " ^r ", width, 0/fg, 0x5c/bg=menu-highlight
    206   draw-text-rightward-from-cursor screen, " run main  ", width, 7/fg, 0xc5/bg=blue-bg
    207   draw-text-rightward-from-cursor screen, " ^s ", width, 0/fg, 0x5c/bg=menu-highlight
    208   draw-text-rightward-from-cursor screen, " run sandbox  ", width, 7/fg, 0xc5/bg=blue-bg
    209   draw-text-rightward-from-cursor screen, " ^g ", width, 0/fg, 0x5c/bg=menu-highlight
    210   draw-text-rightward-from-cursor screen, " go to  ", width, 7/fg, 0xc5/bg=blue-bg
    211   draw-text-rightward-from-cursor screen, " ^a ", width, 0/fg, 0x5c/bg=menu-highlight
    212   draw-text-rightward-from-cursor screen, " <<  ", width, 7/fg, 0xc5/bg=blue-bg
    213   draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg, 0x5c/bg=menu-highlight
    214   draw-text-rightward-from-cursor screen, " <word  ", width, 7/fg, 0xc5/bg=blue-bg
    215   draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg, 0x5c/bg=menu-highlight
    216   draw-text-rightward-from-cursor screen, " word>  ", width, 7/fg, 0xc5/bg=blue-bg
    217   draw-text-rightward-from-cursor screen, " ^e ", width, 0/fg, 0x5c/bg=menu-highlight
    218   draw-text-rightward-from-cursor screen, " >>  ", width, 7/fg, 0xc5/bg=blue-bg
    219 }
    220
    221 fn edit-globals _self: (addr global-table), key: grapheme {
    222   var self/esi: (addr global-table) <- copy _self
    223   # ctrl-s
    224   {
    225     compare key, 0x13/ctrl-s
    226     break-if-!=
    227     #
    228     refresh-cursor-definition self
    229     return
    230   }
    231   var cursor-index-addr/ecx: (addr int) <- get self, cursor-index
    232   var cursor-index/ecx: int <- copy *cursor-index-addr
    233   var data-ah/eax: (addr handle array global) <- get self, data
    234   var data/eax: (addr array global) <- lookup *data-ah
    235   var cursor-offset/ecx: (offset global) <- compute-offset data, cursor-index
    236   var curr-global/eax: (addr global) <- index data, cursor-offset
    237   var curr-editor-ah/eax: (addr handle gap-buffer) <- get curr-global, input
    238   var curr-editor/eax: (addr gap-buffer) <- lookup *curr-editor-ah
    239   edit-gap-buffer curr-editor, key
    240 }
    241
    242 fn refresh-cursor-definition _self: (addr global-table) {
    243   var self/esi: (addr global-table) <- copy _self
    244   var cursor-index/edx: (addr int) <- get self, cursor-index
    245   refresh-definition self, *cursor-index
    246 }
    247
    248 fn refresh-definition _self: (addr global-table), _index: int {
    249   var self/esi: (addr global-table) <- copy _self
    250   var data-ah/eax: (addr handle array global) <- get self, data
    251   var data/eax: (addr array global) <- lookup *data-ah
    252   var index/ecx: int <- copy _index
    253   var offset/ecx: (offset global) <- compute-offset data, index
    254   var curr-global/ecx: (addr global) <- index data, offset
    255   var curr-input-ah/eax: (addr handle gap-buffer) <- get curr-global, input
    256   var curr-input/eax: (addr gap-buffer) <- lookup *curr-input-ah
    257   var read-result-h: (handle cell)
    258   var read-result-ah/edx: (addr handle cell) <- address read-result-h
    259   var trace-storage: trace
    260   var trace/ebx: (addr trace) <- address trace-storage
    261   initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
    262   read-cell curr-input, read-result-ah, trace
    263   macroexpand read-result-ah, self, trace
    264   var nil-h: (handle cell)
    265   {
    266     var nil-ah/eax: (addr handle cell) <- address nil-h
    267     allocate-pair nil-ah
    268   }
    269   var curr-value-ah/eax: (addr handle cell) <- get curr-global, value
    270   debug-print "GL", 4/fg, 0/bg
    271   evaluate read-result-ah, curr-value-ah, nil-h, self, trace, 0/no-screen-cell, 0/no-keyboard-cell, 1/call-number
    272   debug-print "GZ", 4/fg, 0/bg
    273 }
    274
    275 fn assign-or-create-global _self: (addr global-table), name: (addr array byte), value: (handle cell), trace: (addr trace) {
    276   var self/esi: (addr global-table) <- copy _self
    277   compare self, 0
    278   {
    279     break-if-!=
    280     abort "assign global"
    281     return
    282   }
    283   var curr-index/ecx: int <- find-symbol-name-in-globals self, name
    284   {
    285     compare curr-index, -1/not-found
    286     break-if-!=
    287     var final-index-addr/eax: (addr int) <- get self, final-index
    288     increment *final-index-addr
    289     curr-index <- copy *final-index-addr
    290     var cursor-index-addr/eax: (addr int) <- get self, cursor-index
    291     copy-to *cursor-index-addr, curr-index
    292   }
    293   var data-ah/eax: (addr handle array global) <- get self, data
    294   var data/eax: (addr array global) <- lookup *data-ah
    295   var curr-offset/esi: (offset global) <- compute-offset data, curr-index
    296   var curr/esi: (addr global) <- index data, curr-offset
    297   var curr-name-ah/eax: (addr handle array byte) <- get curr, name
    298   copy-array-object name, curr-name-ah
    299   var curr-value-ah/eax: (addr handle cell) <- get curr, value
    300   copy-handle value, curr-value-ah
    301 }
    302
    303 fn lookup-symbol-in-globals _sym: (addr cell), out: (addr handle cell), _globals: (addr global-table), trace: (addr trace), screen-cell: (addr handle cell), keyboard-cell: (addr handle cell) {
    304   var sym/eax: (addr cell) <- copy _sym
    305   var sym-name-ah/eax: (addr handle stream byte) <- get sym, text-data
    306   var _sym-name/eax: (addr stream byte) <- lookup *sym-name-ah
    307   var sym-name/edx: (addr stream byte) <- copy _sym-name
    308   var globals/esi: (addr global-table) <- copy _globals
    309   {
    310     compare globals, 0
    311     break-if-=
    312     var curr-index/ecx: int <- find-symbol-in-globals globals, sym-name
    313     compare curr-index, -1/not-found
    314     break-if-=
    315     var global-data-ah/eax: (addr handle array global) <- get globals, data
    316     var global-data/eax: (addr array global) <- lookup *global-data-ah
    317     var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
    318     var curr/ebx: (addr global) <- index global-data, curr-offset
    319     var curr-value/eax: (addr handle cell) <- get curr, value
    320     copy-object curr-value, out
    321     return
    322   }
    323   # if sym is "screen" and screen-cell exists, return it
    324   {
    325     var sym-is-screen?/eax: boolean <- stream-data-equal? sym-name, "screen"
    326     compare sym-is-screen?, 0/false
    327     break-if-=
    328     compare screen-cell, 0
    329     break-if-=
    330     copy-object screen-cell, out
    331     return
    332   }
    333   # if sym is "keyboard" and keyboard-cell exists, return it
    334   {
    335     var sym-is-keyboard?/eax: boolean <- stream-data-equal? sym-name, "keyboard"
    336     compare sym-is-keyboard?, 0/false
    337     break-if-=
    338     compare keyboard-cell, 0
    339     break-if-=
    340     copy-object keyboard-cell, out
    341     return
    342   }
    343   # otherwise error "unbound symbol: ", sym
    344   var stream-storage: (stream byte 0x40)
    345   var stream/ecx: (addr stream byte) <- address stream-storage
    346   write stream, "unbound symbol: "
    347   rewind-stream sym-name
    348   write-stream stream, sym-name
    349   error-stream trace, stream
    350 }
    351
    352 fn maybe-lookup-symbol-in-globals _sym: (addr cell), out: (addr handle cell), _globals: (addr global-table), trace: (addr trace) {
    353   var sym/eax: (addr cell) <- copy _sym
    354   var sym-name-ah/eax: (addr handle stream byte) <- get sym, text-data
    355   var _sym-name/eax: (addr stream byte) <- lookup *sym-name-ah
    356   var sym-name/edx: (addr stream byte) <- copy _sym-name
    357   var globals/esi: (addr global-table) <- copy _globals
    358   {
    359     compare globals, 0
    360     break-if-=
    361     var curr-index/ecx: int <- find-symbol-in-globals globals, sym-name
    362     compare curr-index, -1/not-found
    363     break-if-=
    364     var global-data-ah/eax: (addr handle array global) <- get globals, data
    365     var global-data/eax: (addr array global) <- lookup *global-data-ah
    366     var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
    367     var curr/ebx: (addr global) <- index global-data, curr-offset
    368     var curr-value/eax: (addr handle cell) <- get curr, value
    369     copy-object curr-value, out
    370     return
    371   }
    372 }
    373
    374 # return the index in globals containing 'sym'
    375 # or -1 if not found
    376 fn find-symbol-in-globals _globals: (addr global-table), sym-name: (addr stream byte) -> _/ecx: int {
    377   var globals/esi: (addr global-table) <- copy _globals
    378   compare globals, 0
    379   {
    380     break-if-!=
    381     return -1/not-found
    382   }
    383   var global-data-ah/eax: (addr handle array global) <- get globals, data
    384   var global-data/eax: (addr array global) <- lookup *global-data-ah
    385   var final-index/ecx: (addr int) <- get globals, final-index
    386   var curr-index/ecx: int <- copy *final-index
    387   {
    388     compare curr-index, 0
    389     break-if-<
    390     var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
    391     var curr/ebx: (addr global) <- index global-data, curr-offset
    392     var curr-name-ah/eax: (addr handle array byte) <- get curr, name
    393     var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
    394     var found?/eax: boolean <- stream-data-equal? sym-name, curr-name
    395     compare found?, 0/false
    396     {
    397       break-if-=
    398       return curr-index
    399     }
    400     curr-index <- decrement
    401     loop
    402   }
    403   return -1/not-found
    404 }
    405
    406 # return the index in globals containing 'sym'
    407 # or -1 if not found
    408 fn find-symbol-name-in-globals _globals: (addr global-table), sym-name: (addr array byte) -> _/ecx: int {
    409   var globals/esi: (addr global-table) <- copy _globals
    410   compare globals, 0
    411   {
    412     break-if-!=
    413     return -1/not-found
    414   }
    415   var global-data-ah/eax: (addr handle array global) <- get globals, data
    416   var global-data/eax: (addr array global) <- lookup *global-data-ah
    417   var final-index/ecx: (addr int) <- get globals, final-index
    418   var curr-index/ecx: int <- copy *final-index
    419   {
    420     compare curr-index, 0
    421     break-if-<
    422     var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
    423     var curr/ebx: (addr global) <- index global-data, curr-offset
    424     var curr-name-ah/eax: (addr handle array byte) <- get curr, name
    425     var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
    426     var found?/eax: boolean <- string-equal? sym-name, curr-name
    427     compare found?, 0/false
    428     {
    429       break-if-=
    430       return curr-index
    431     }
    432     curr-index <- decrement
    433     loop
    434   }
    435   return -1/not-found
    436 }
    437
    438 fn mutate-binding-in-globals name: (addr stream byte), val: (addr handle cell), _globals: (addr global-table), trace: (addr trace) {
    439   var globals/esi: (addr global-table) <- copy _globals
    440   {
    441     compare globals, 0
    442     break-if-=
    443     var curr-index/ecx: int <- find-symbol-in-globals globals, name
    444     compare curr-index, -1/not-found
    445     break-if-=
    446     var global-data-ah/eax: (addr handle array global) <- get globals, data
    447     var global-data/eax: (addr array global) <- lookup *global-data-ah
    448     var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
    449     var curr/ebx: (addr global) <- index global-data, curr-offset
    450     var dest/eax: (addr handle cell) <- get curr, value
    451     copy-object val, dest
    452     return
    453   }
    454   # otherwise error "unbound symbol: ", sym
    455   var stream-storage: (stream byte 0x40)
    456   var stream/ecx: (addr stream byte) <- address stream-storage
    457   write stream, "unbound symbol: "
    458   rewind-stream name
    459   write-stream stream, name
    460   error-stream trace, stream
    461 }
    462
    463 # Accepts an input s-expression, naively checks if it is a definition, and if
    464 # so saves the gap-buffer to the appropriate global, spinning up a new empty
    465 # one to replace it with.
    466 fn maybe-stash-gap-buffer-to-global _globals: (addr global-table), _definition-ah: (addr handle cell), gap: (addr handle gap-buffer) {
    467   # if 'definition' is not a pair, return
    468   var definition-ah/eax: (addr handle cell) <- copy _definition-ah
    469   var _definition/eax: (addr cell) <- lookup *definition-ah
    470   var definition/esi: (addr cell) <- copy _definition
    471   var definition-type/eax: (addr int) <- get definition, type
    472   compare *definition-type, 0/pair
    473   {
    474     break-if-=
    475     return
    476   }
    477   # if definition->left is neither "define" nor "set", return
    478   var left-ah/eax: (addr handle cell) <- get definition, left
    479   var _left/eax: (addr cell) <- lookup *left-ah
    480   var left/ecx: (addr cell) <- copy _left
    481   {
    482     var def?/eax: boolean <- symbol-equal? left, "define"
    483     compare def?, 0/false
    484     break-if-!=
    485     var set?/eax: boolean <- symbol-equal? left, "set"
    486     compare set?, 0/false
    487     break-if-!=
    488     return
    489   }
    490   # locate the global for definition->right->left
    491   var right-ah/eax: (addr handle cell) <- get definition, right
    492   var right/eax: (addr cell) <- lookup *right-ah
    493   var defined-symbol-ah/eax: (addr handle cell) <- get right, left
    494   var defined-symbol/eax: (addr cell) <- lookup *defined-symbol-ah
    495   var defined-symbol-name-ah/eax: (addr handle stream byte) <- get defined-symbol, text-data
    496   var defined-symbol-name/eax: (addr stream byte) <- lookup *defined-symbol-name-ah
    497   var index/ecx: int <- find-symbol-in-globals _globals, defined-symbol-name
    498   {
    499     compare index, -1/not-found
    500     break-if-!=
    501     return
    502   }
    503   # stash 'gap' to it
    504   var globals/eax: (addr global-table) <- copy _globals
    505   compare globals, 0
    506   {
    507     break-if-!=
    508     abort "stash to globals"
    509     return
    510   }
    511   var global-data-ah/eax: (addr handle array global) <- get globals, data
    512   var global-data/eax: (addr array global) <- lookup *global-data-ah
    513   var offset/ebx: (offset global) <- compute-offset global-data, index
    514   var dest-global/eax: (addr global) <- index global-data, offset
    515   var dest-ah/eax: (addr handle gap-buffer) <- get dest-global, input
    516   copy-object gap, dest-ah
    517   # initialize a new gap-buffer in 'gap'
    518   var dest/eax: (addr gap-buffer) <- lookup *dest-ah
    519   var capacity/ecx: int <- gap-buffer-capacity dest
    520   var gap2/eax: (addr handle gap-buffer) <- copy gap
    521   allocate gap2
    522   var gap-addr/eax: (addr gap-buffer) <- lookup *gap2
    523   initialize-gap-buffer gap-addr, capacity
    524 }
    525
    526 # Accepts an input s-expression, naively checks if it is a definition, and if
    527 # so saves the gap-buffer to the appropriate global.
    528 fn move-gap-buffer-to-global _globals: (addr global-table), _definition-ah: (addr handle cell), gap: (addr handle gap-buffer) {
    529   # if 'definition' is not a pair, return
    530   var definition-ah/eax: (addr handle cell) <- copy _definition-ah
    531   var _definition/eax: (addr cell) <- lookup *definition-ah
    532   var definition/esi: (addr cell) <- copy _definition
    533   var definition-type/eax: (addr int) <- get definition, type
    534   compare *definition-type, 0/pair
    535   {
    536     break-if-=
    537     return
    538   }
    539   # if definition->left is neither "define" nor "set", return
    540   var left-ah/eax: (addr handle cell) <- get definition, left
    541   var _left/eax: (addr cell) <- lookup *left-ah
    542   var left/ecx: (addr cell) <- copy _left
    543   {
    544     var def?/eax: boolean <- symbol-equal? left, "define"
    545     compare def?, 0/false
    546     break-if-!=
    547     var set?/eax: boolean <- symbol-equal? left, "set"
    548     compare set?, 0/false
    549     break-if-!=
    550     return
    551   }
    552   # locate the global for definition->right->left
    553   var right-ah/eax: (addr handle cell) <- get definition, right
    554   var right/eax: (addr cell) <- lookup *right-ah
    555   var defined-symbol-ah/eax: (addr handle cell) <- get right, left
    556   var defined-symbol/eax: (addr cell) <- lookup *defined-symbol-ah
    557   var defined-symbol-name-ah/eax: (addr handle stream byte) <- get defined-symbol, text-data
    558   var defined-symbol-name/eax: (addr stream byte) <- lookup *defined-symbol-name-ah
    559   var index/ecx: int <- find-symbol-in-globals _globals, defined-symbol-name
    560   {
    561     compare index, -1/not-found
    562     break-if-!=
    563     return
    564   }
    565   # move 'gap' to it
    566   var globals/eax: (addr global-table) <- copy _globals
    567   compare globals, 0
    568   {
    569     break-if-!=
    570     abort "move to globals"
    571     return
    572   }
    573   var global-data-ah/eax: (addr handle array global) <- get globals, data
    574   var global-data/eax: (addr array global) <- lookup *global-data-ah
    575   var offset/ebx: (offset global) <- compute-offset global-data, index
    576   var dest-global/eax: (addr global) <- index global-data, offset
    577   var dest-ah/eax: (addr handle gap-buffer) <- get dest-global, input
    578   copy-object gap, dest-ah
    579 }
    580
    581 fn set-global-cursor-index _globals: (addr global-table), name-gap: (addr gap-buffer) {
    582   var globals/esi: (addr global-table) <- copy _globals
    583   var name-storage: (stream byte 0x40)
    584   var name/ecx: (addr stream byte) <- address name-storage
    585   emit-gap-buffer name-gap, name
    586   var index/ecx: int <- find-symbol-in-globals globals, name
    587   var dest/edi: (addr int) <- get globals, cursor-index
    588   copy-to *dest, index
    589 }