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