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 }