https://github.com/akkartik/mu/blob/main/shell/environment.mu
1 type environment {
2 globals: global-table
3 sandbox: sandbox
4 partial-function-name: (handle gap-buffer)
5 cursor-in-globals?: boolean
6 cursor-in-function-modal?: boolean
7 }
8
9 fn initialize-environment _self: (addr environment) {
10 var self/esi: (addr environment) <- copy _self
11 var globals/eax: (addr global-table) <- get self, globals
12 initialize-globals globals
13 var sandbox/eax: (addr sandbox) <- get self, sandbox
14 initialize-sandbox sandbox, 1/with-screen
15 var partial-function-name-ah/eax: (addr handle gap-buffer) <- get self, partial-function-name
16 allocate partial-function-name-ah
17 var partial-function-name/eax: (addr gap-buffer) <- lookup *partial-function-name-ah
18 initialize-gap-buffer partial-function-name, 0x40/function-name-capacity
19 }
20
21 fn render-environment screen: (addr screen), _self: (addr environment) {
22
23
24
25 var self/esi: (addr environment) <- copy _self
26 var cursor-in-globals-a/eax: (addr boolean) <- get self, cursor-in-globals?
27 var cursor-in-globals?/eax: boolean <- copy *cursor-in-globals-a
28 var globals/ecx: (addr global-table) <- get self, globals
29 render-globals screen, globals, cursor-in-globals?
30 var sandbox/edx: (addr sandbox) <- get self, sandbox
31 var cursor-in-sandbox?/ebx: boolean <- copy 1/true
32 cursor-in-sandbox? <- subtract cursor-in-globals?
33 render-sandbox screen, sandbox, 0x55/sandbox-left-margin, 0/sandbox-top-margin, 0x80/screen-width, 0x2f/screen-height-without-menu, cursor-in-sandbox?
34
35 {
36 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
37 compare *cursor-in-function-modal-a, 0/false
38 break-if-=
39 render-function-modal screen, self
40 render-function-modal-menu screen, self
41 return
42 }
43
44 {
45 var cursor-in-globals?/eax: (addr boolean) <- get self, cursor-in-globals?
46 compare *cursor-in-globals?, 0/false
47 break-if-=
48 render-globals-menu screen, globals
49 return
50 }
51 render-sandbox-menu screen, sandbox
52 }
53
54 fn edit-environment _self: (addr environment), key: grapheme, data-disk: (addr disk) {
55 var self/esi: (addr environment) <- copy _self
56 var globals/edi: (addr global-table) <- get self, globals
57 var sandbox/ecx: (addr sandbox) <- get self, sandbox
58
59
60 {
61 compare key, 0x12/ctrl-r
62 break-if-!=
63 var tmp/eax: (addr handle cell) <- copy 0
64 var nil: (handle cell)
65 tmp <- address nil
66 allocate-pair tmp
67
68 var real-keyboard: (handle cell)
69 tmp <- address real-keyboard
70 allocate-keyboard tmp
71
72 var args: (handle cell)
73 tmp <- address args
74 new-pair tmp, real-keyboard, nil
75
76 var real-screen: (handle cell)
77 tmp <- address real-screen
78 allocate-screen tmp
79
80 tmp <- address args
81 new-pair tmp, real-screen, *tmp
82
83 var main: (handle cell)
84 tmp <- address main
85 new-symbol tmp, "main"
86
87 tmp <- address args
88 new-pair tmp, main, *tmp
89
90 clear-screen 0/screen
91 set-cursor-position 0/screen, 0, 0
92
93 var out: (handle cell)
94 var out-ah/ecx: (addr handle cell) <- address out
95 var trace-storage: trace
96 var trace/ebx: (addr trace) <- address trace-storage
97 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
98 evaluate tmp, out-ah, nil, globals, trace, 0/no-fake-screen, 0/no-fake-keyboard, 0/call-number
99
100 {
101 var tmp/eax: byte <- read-key 0/keyboard
102 compare tmp, 0
103 loop-if-=
104 }
105
106 return
107 }
108
109 {
110 compare key, 0x13/ctrl-s
111 break-if-!=
112 {
113
114 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
115 compare *cursor-in-function-modal-a, 0/false
116 break-if-!=
117 {
118
119 var cursor-in-globals-a/edx: (addr boolean) <- get self, cursor-in-globals?
120 compare *cursor-in-globals-a, 0/false
121 break-if-=
122 edit-globals globals, key
123 }
124
125 edit-sandbox sandbox, key, globals, data-disk, 1/tweak-real-screen
126 }
127 return
128 }
129
130 {
131 compare key, 7/ctrl-g
132 break-if-!=
133 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
134 compare *cursor-in-function-modal-a, 0/false
135 break-if-!=
136
137 var current-word-storage: (stream byte 0x40)
138 var current-word/edi: (addr stream byte) <- address current-word-storage
139 word-at-cursor self, current-word
140 var partial-function-name-ah/eax: (addr handle gap-buffer) <- get self, partial-function-name
141 var partial-function-name/eax: (addr gap-buffer) <- lookup *partial-function-name-ah
142 clear-gap-buffer partial-function-name
143 load-gap-buffer-from-stream partial-function-name, current-word
144
145 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
146 copy-to *cursor-in-function-modal-a, 1/true
147 return
148 }
149
150 {
151 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
152 compare *cursor-in-function-modal-a, 0/false
153 break-if-=
154
155
156 {
157 compare key, 0x20/space
158 break-if-!=
159 return
160 }
161
162 {
163 compare key, 0x1b/escape
164 break-if-!=
165 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
166 copy-to *cursor-in-function-modal-a, 0/false
167 return
168 }
169
170 {
171 compare key, 0xa/newline
172 break-if-!=
173 var cursor-in-globals-a/edx: (addr boolean) <- get self, cursor-in-globals?
174 copy-to *cursor-in-globals-a, 1/true
175 var partial-function-name-ah/eax: (addr handle gap-buffer) <- get self, partial-function-name
176 var partial-function-name/eax: (addr gap-buffer) <- lookup *partial-function-name-ah
177 {
178 {
179 var empty?/eax: boolean <- gap-buffer-empty? partial-function-name
180 compare empty?, 0/false
181 }
182 break-if-!=
183 set-global-cursor-index globals, partial-function-name
184 }
185 var cursor-in-globals-a/ecx: (addr boolean) <- get self, cursor-in-globals?
186 copy-to *cursor-in-globals-a, 1/true
187 {
188 var empty?/eax: boolean <- gap-buffer-empty? partial-function-name
189 compare empty?, 0/false
190 break-if-=
191 copy-to *cursor-in-globals-a, 0/false
192 }
193 clear-gap-buffer partial-function-name
194 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
195 copy-to *cursor-in-function-modal-a, 0/false
196 return
197 }
198
199 var partial-function-name-ah/eax: (addr handle gap-buffer) <- get self, partial-function-name
200 var partial-function-name/eax: (addr gap-buffer) <- lookup *partial-function-name-ah
201 edit-gap-buffer partial-function-name, key
202 return
203 }
204
205 {
206 var cursor-in-globals-a/eax: (addr boolean) <- get self, cursor-in-globals?
207 compare *cursor-in-globals-a, 0/false
208 break-if-=
209 edit-globals globals, key
210 return
211 }
212 edit-sandbox sandbox, key, globals, data-disk, 1/tweak-real-screen
213 }
214
215 fn word-at-cursor _self: (addr environment), out: (addr stream byte) {
216 var self/esi: (addr environment) <- copy _self
217 var cursor-in-function-modal-a/eax: (addr boolean) <- get self, cursor-in-function-modal?
218 compare *cursor-in-function-modal-a, 0/false
219 {
220 break-if-=
221
222 return
223 }
224 var cursor-in-globals-a/edx: (addr boolean) <- get self, cursor-in-globals?
225 compare *cursor-in-globals-a, 0/false
226 {
227 break-if-=
228
229 var globals/eax: (addr global-table) <- get self, globals
230 var cursor-index-addr/ecx: (addr int) <- get globals, cursor-index
231 var cursor-index/ecx: int <- copy *cursor-index-addr
232 var globals-data-ah/eax: (addr handle array global) <- get globals, data
233 var globals-data/eax: (addr array global) <- lookup *globals-data-ah
234 var cursor-offset/ecx: (offset global) <- compute-offset globals-data, cursor-index
235 var curr-global/eax: (addr global) <- index globals-data, cursor-offset
236 var curr-global-data-ah/eax: (addr handle gap-buffer) <- get curr-global, input
237 var curr-global-data/eax: (addr gap-buffer) <- lookup *curr-global-data-ah
238 word-at-gap curr-global-data, out
239 return
240 }
241
242 var sandbox/ecx: (addr sandbox) <- get self, sandbox
243 var sandbox-data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
244 var sandbox-data/eax: (addr gap-buffer) <- lookup *sandbox-data-ah
245 word-at-gap sandbox-data, out
246 }
247
248 fn render-function-modal screen: (addr screen), _self: (addr environment) {
249 var self/esi: (addr environment) <- copy _self
250 var width/eax: int <- copy 0
251 var height/ecx: int <- copy 0
252 width, height <- screen-size screen
253
254 var xmin: int
255 var tmp/edx: int <- copy width
256 tmp <- shift-right 1
257 tmp <- subtract 0x20/half-function-name-capacity
258 {
259 compare tmp, 0
260 break-if->=
261 tmp <- copy 0
262 }
263 copy-to xmin, tmp
264
265 var xmax: int
266 tmp <- copy width
267 tmp <- shift-right 1
268 tmp <- add 0x20/half-function-name-capacity
269 {
270 compare tmp, width
271 break-if-<=
272 tmp <- copy width
273 }
274 copy-to xmax, tmp
275
276 var ymin: int
277 tmp <- copy height
278 tmp <- shift-right 1
279 tmp <- subtract 2
280 copy-to ymin, tmp
281
282 var ymax: int
283 tmp <- add 3
284 copy-to ymax, tmp
285
286 clear-rect screen, xmin, ymin, xmax, ymax, 0xf/bg=modal
287 add-to xmin, 4
288 set-cursor-position screen, xmin, ymin
289 draw-text-rightward-from-cursor screen, "go to function (or leave blank to go to REPL)", xmax, 8/fg=dark-grey, 0xf/bg=modal
290 var partial-function-name-ah/eax: (addr handle gap-buffer) <- get self, partial-function-name
291 var _partial-function-name/eax: (addr gap-buffer) <- lookup *partial-function-name-ah
292 var partial-function-name/edx: (addr gap-buffer) <- copy _partial-function-name
293 subtract-from xmin, 4
294 add-to ymin 2
295 var dummy/eax: int <- copy 0
296 var dummy2/ecx: int <- copy 0
297 dummy, dummy2 <- render-gap-buffer-wrapping-right-then-down screen, partial-function-name, xmin, ymin, xmax, ymax, 1/always-render-cursor, 0/fg=black, 0xf/bg=modal
298 }
299
300 fn render-function-modal-menu screen: (addr screen), _self: (addr environment) {
301 var self/esi: (addr environment) <- copy _self
302 var _width/eax: int <- copy 0
303 var height/ecx: int <- copy 0
304 _width, height <- screen-size screen
305 var width/edx: int <- copy _width
306 var y/ecx: int <- copy height
307 y <- decrement
308 var height/ebx: int <- copy y
309 height <- increment
310 clear-rect screen, 0/x, y, width, height, 0xc5/bg=blue-bg
311 set-cursor-position screen, 0/x, y
312 draw-text-rightward-from-cursor screen, " ^r ", width, 0/fg, 0x5c/bg=menu-highlight
313 draw-text-rightward-from-cursor screen, " run main ", width, 7/fg, 0xc5/bg=blue-bg
314 draw-text-rightward-from-cursor screen, " enter ", width, 0/fg, 0x5c/bg=menu-highlight
315 draw-text-rightward-from-cursor screen, " submit ", width, 7/fg, 0xc5/bg=blue-bg
316 draw-text-rightward-from-cursor screen, " esc ", width, 0/fg, 0x5c/bg=menu-highlight
317 draw-text-rightward-from-cursor screen, " cancel ", width, 7/fg, 0xc5/bg=blue-bg
318 draw-text-rightward-from-cursor screen, " ^a ", width, 0/fg, 0x5c/bg=menu-highlight
319 draw-text-rightward-from-cursor screen, " << ", width, 7/fg, 0xc5/bg=blue-bg
320 draw-text-rightward-from-cursor screen, " ^b ", width, 0/fg, 0x5c/bg=menu-highlight
321 draw-text-rightward-from-cursor screen, " <word ", width, 7/fg, 0xc5/bg=blue-bg
322 draw-text-rightward-from-cursor screen, " ^f ", width, 0/fg, 0x5c/bg=menu-highlight
323 draw-text-rightward-from-cursor screen, " word> ", width, 7/fg, 0xc5/bg=blue-bg
324 draw-text-rightward-from-cursor screen, " ^e ", width, 0/fg, 0x5c/bg=menu-highlight
325 draw-text-rightward-from-cursor screen, " >> ", width, 7/fg, 0xc5/bg=blue-bg
326 }
327
328
329 fn load-state _self: (addr environment), data-disk: (addr disk) {
330 var self/esi: (addr environment) <- copy _self
331
332 var s-storage: (stream byte 0x1000)
333 var s/ebx: (addr stream byte) <- address s-storage
334 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sectors from data disk", 3/fg, 0/bg
335 move-cursor-to-left-margin-of-next-line 0/screen
336 load-sectors data-disk, 0/lba, 8/sectors, s
337
338
339 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "parsing", 3/fg, 0/bg
340 move-cursor-to-left-margin-of-next-line 0/screen
341 var sandbox/eax: (addr sandbox) <- get self, sandbox
342 var data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
343 var data/eax: (addr gap-buffer) <- lookup *data-ah
344 load-gap-buffer-from-stream data, s
345 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " into gap buffer", 3/fg, 0/bg
346 move-cursor-to-left-margin-of-next-line 0/screen
347 clear-stream s
348
349 var initial-root-storage: (handle cell)
350 var initial-root/ecx: (addr handle cell) <- address initial-root-storage
351 var trace-storage: trace
352 var trace/edi: (addr trace) <- address trace-storage
353 initialize-trace trace, 1/only-errors, 0x10/capacity, 0/visible
354 read-cell data, initial-root, trace
355 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " into s-expressions", 3/fg, 0/bg
356 move-cursor-to-left-margin-of-next-line 0/screen
357 clear-gap-buffer data
358
359 {
360 var initial-root-addr/eax: (addr cell) <- lookup *initial-root
361 compare initial-root-addr, 0
362 break-if-!=
363 return
364 }
365
366 var globals-literal-storage: (handle cell)
367 var globals-literal-ah/eax: (addr handle cell) <- address globals-literal-storage
368 new-symbol globals-literal-ah, "globals"
369 var globals-literal/eax: (addr cell) <- lookup *globals-literal-ah
370 var globals-cell-storage: (handle cell)
371 var globals-cell-ah/edx: (addr handle cell) <- address globals-cell-storage
372 clear-trace trace
373 lookup-symbol globals-literal, globals-cell-ah, *initial-root, 0/no-globals, trace, 0/no-screen, 0/no-keyboard
374 var globals-cell/eax: (addr cell) <- lookup *globals-cell-ah
375 {
376 compare globals-cell, 0
377 break-if-=
378 var globals/eax: (addr global-table) <- get self, globals
379 load-globals globals-cell-ah, globals
380 }
381
382 draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "loading sandbox", 3/fg, 0/bg
383 var sandbox-literal-storage: (handle cell)
384 var sandbox-literal-ah/eax: (addr handle cell) <- address sandbox-literal-storage
385 new-symbol sandbox-literal-ah, "sandbox"
386 var sandbox-literal/eax: (addr cell) <- lookup *sandbox-literal-ah
387 var sandbox-cell-storage: (handle cell)
388 var sandbox-cell-ah/edx: (addr handle cell) <- address sandbox-cell-storage
389 clear-trace trace
390 lookup-symbol sandbox-literal, sandbox-cell-ah, *initial-root, 0/no-globals, trace, 0/no-screen, 0/no-keyboard
391 var sandbox-cell/eax: (addr cell) <- lookup *sandbox-cell-ah
392 {
393 compare sandbox-cell, 0
394 break-if-=
395
396 clear-trace trace
397 print-cell sandbox-cell-ah, s, trace
398
399 var sandbox/eax: (addr sandbox) <- get self, sandbox
400 var data-ah/eax: (addr handle gap-buffer) <- get sandbox, data
401 var data/eax: (addr gap-buffer) <- lookup *data-ah
402 load-gap-buffer-from-stream data, s
403 }
404 }
405
406
407
408
409
410 fn store-state data-disk: (addr disk), sandbox: (addr sandbox), globals: (addr global-table) {
411 compare data-disk, 0/no-disk
412 {
413 break-if-!=
414 return
415 }
416 var stream-storage: (stream byte 0x1000)
417 var stream/edi: (addr stream byte) <- address stream-storage
418 write stream, "(\n"
419 write-globals stream, globals
420 write-sandbox stream, sandbox
421 write stream, ")\n"
422 store-sectors data-disk, 0/lba, 8/sectors, stream
423 }