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 }