https://github.com/akkartik/mu/blob/main/shell/global.mu
1 type global {
2 name: (handle array byte)
3 value: (handle cell)
4 }
5
6 type global-table {
7 data: (handle array global)
8 final-index: int
9 }
10
11 fn initialize-globals _self: (addr global-table) {
12 var self/esi: (addr global-table) <- copy _self
13 var data-ah/eax: (addr handle array global) <- get self, data
14 populate data-ah, 0x10
15
16 append-primitive self, "="
17
18 append-primitive self, "+"
19 append-primitive self, "-"
20 append-primitive self, "*"
21 append-primitive self, "/"
22 append-primitive self, "sqrt"
23
24 append-primitive self, "car"
25 append-primitive self, "cdr"
26 append-primitive self, "cons"
27
28 append-primitive self, "print"
29
30 append-primitive self, "key"
31
32 append-primitive self, "stream"
33 append-primitive self, "write"
34 }
35
36 fn render-globals screen: (addr screen), _self: (addr global-table), xmin: int, ymin: int, xmax: int, ymax: int {
37 clear-rect screen, xmin, ymin, xmax, ymax, 0x12/bg=almost-black
38 var self/esi: (addr global-table) <- copy _self
39
40 var bottom-line/ecx: int <- copy ymax
41 bottom-line <- decrement
42 var data-ah/eax: (addr handle array global) <- get self, data
43 var data/eax: (addr array global) <- lookup *data-ah
44 var curr-index/edx: int <- copy 1
45 var x/edi: int <- copy xmin
46 {
47 var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
48 var curr/ebx: (addr global) <- index data, curr-offset
49 var continue?/eax: boolean <- primitive-global? curr
50 compare continue?, 0/false
51 break-if-=
52 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
53 var _curr-name/eax: (addr array byte) <- lookup *curr-name-ah
54 var curr-name/ebx: (addr array byte) <- copy _curr-name
55 var tmpx/eax: int <- copy x
56 tmpx <- draw-text-rightward screen, curr-name, tmpx, xmax, bottom-line, 0x2a/fg=orange, 0x12/bg=almost-black
57 tmpx <- draw-text-rightward screen, " ", tmpx, xmax, bottom-line, 7/fg=grey, 0x12/bg=almost-black
58 x <- copy tmpx
59 curr-index <- increment
60 loop
61 }
62 var lowest-index/edi: int <- copy curr-index
63 var y/ecx: int <- copy ymin
64 var data-ah/eax: (addr handle array global) <- get self, data
65 var data/eax: (addr array global) <- lookup *data-ah
66 var final-index/edx: (addr int) <- get self, final-index
67 var curr-index/edx: int <- copy *final-index
68 {
69 compare curr-index, lowest-index
70 break-if-<
71 compare y, ymax
72 break-if->=
73 {
74 var curr-offset/ebx: (offset global) <- compute-offset data, curr-index
75 var curr/ebx: (addr global) <- index data, curr-offset
76 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
77 var _curr-name/eax: (addr array byte) <- lookup *curr-name-ah
78 var curr-name/edx: (addr array byte) <- copy _curr-name
79 var x/eax: int <- copy xmin
80 x, y <- draw-text-wrapping-right-then-down screen, curr-name, xmin, ymin, xmax, ymax, x, y, 0x2a/fg=orange, 0x12/bg=almost-black
81 x, y <- draw-text-wrapping-right-then-down screen, " <- ", xmin, ymin, xmax, ymax, x, y, 7/fg=grey, 0x12/bg=almost-black
82 var curr-value/edx: (addr handle cell) <- get curr, value
83 var s-storage: (stream byte 0x100)
84 var s/ebx: (addr stream byte) <- address s-storage
85 print-cell curr-value, s, 0/no-trace
86 x, y <- draw-stream-wrapping-right-then-down screen, s, xmin, ymin, xmax, ymax, x, y, 0x3/fg=cyan, 0x12/bg=almost-black
87 }
88 curr-index <- decrement
89 y <- increment
90 loop
91 }
92 }
93
94 fn primitive-global? _x: (addr global) -> _/eax: boolean {
95 var x/eax: (addr global) <- copy _x
96 var value-ah/eax: (addr handle cell) <- get x, value
97 var value/eax: (addr cell) <- lookup *value-ah
98 compare value, 0/null
99 {
100 break-if-!=
101 return 0/false
102 }
103 var value-type/eax: (addr int) <- get value, type
104 compare *value-type, 4/primitive
105 {
106 break-if-=
107 return 0/false
108 }
109 return 1/true
110 }
111
112 fn append-primitive _self: (addr global-table), name: (addr array byte) {
113 var self/esi: (addr global-table) <- copy _self
114 var final-index-addr/ecx: (addr int) <- get self, final-index
115 increment *final-index-addr
116 var curr-index/ecx: int <- copy *final-index-addr
117 var data-ah/eax: (addr handle array global) <- get self, data
118 var data/eax: (addr array global) <- lookup *data-ah
119 var curr-offset/esi: (offset global) <- compute-offset data, curr-index
120 var curr/esi: (addr global) <- index data, curr-offset
121 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
122 copy-array-object name, curr-name-ah
123 var curr-value-ah/eax: (addr handle cell) <- get curr, value
124 new-primitive-function curr-value-ah, curr-index
125 }
126
127 fn append-global _self: (addr global-table), name: (addr array byte), value: (handle cell) {
128 var self/esi: (addr global-table) <- copy _self
129 var final-index-addr/ecx: (addr int) <- get self, final-index
130 increment *final-index-addr
131 var curr-index/ecx: int <- copy *final-index-addr
132 var data-ah/eax: (addr handle array global) <- get self, data
133 var data/eax: (addr array global) <- lookup *data-ah
134 var curr-offset/esi: (offset global) <- compute-offset data, curr-index
135 var curr/esi: (addr global) <- index data, curr-offset
136 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
137 copy-array-object name, curr-name-ah
138 var curr-value-ah/eax: (addr handle cell) <- get curr, value
139 copy-handle value, curr-value-ah
140 }
141
142 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) {
143 var sym/eax: (addr cell) <- copy _sym
144 var sym-name-ah/eax: (addr handle stream byte) <- get sym, text-data
145 var _sym-name/eax: (addr stream byte) <- lookup *sym-name-ah
146 var sym-name/edx: (addr stream byte) <- copy _sym-name
147 var globals/esi: (addr global-table) <- copy _globals
148 {
149 compare globals, 0
150 break-if-=
151 var curr-index/ecx: int <- find-symbol-in-globals globals, sym-name
152 compare curr-index, -1/not-found
153 break-if-=
154 var global-data-ah/eax: (addr handle array global) <- get globals, data
155 var global-data/eax: (addr array global) <- lookup *global-data-ah
156 var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
157 var curr/ebx: (addr global) <- index global-data, curr-offset
158 var curr-value/eax: (addr handle cell) <- get curr, value
159 copy-object curr-value, out
160 return
161 }
162
163 {
164 var sym-is-screen?/eax: boolean <- stream-data-equal? sym-name, "screen"
165 compare sym-is-screen?, 0/false
166 break-if-=
167 compare screen-cell, 0
168 break-if-=
169 copy-object screen-cell, out
170 return
171 }
172
173 {
174 var sym-is-keyboard?/eax: boolean <- stream-data-equal? sym-name, "keyboard"
175 compare sym-is-keyboard?, 0/false
176 break-if-=
177 compare keyboard-cell, 0
178 break-if-=
179 copy-object keyboard-cell, out
180 return
181 }
182
183 var stream-storage: (stream byte 0x40)
184 var stream/ecx: (addr stream byte) <- address stream-storage
185 write stream, "unbound symbol: "
186 rewind-stream sym-name
187 write-stream stream, sym-name
188 trace trace, "error", stream
189 }
190
191
192
193 fn find-symbol-in-globals _globals: (addr global-table), sym-name: (addr stream byte) -> _/ecx: int {
194 var globals/esi: (addr global-table) <- copy _globals
195 compare globals, 0
196 {
197 break-if-!=
198 return -1/not-found
199 }
200 var global-data-ah/eax: (addr handle array global) <- get globals, data
201 var global-data/eax: (addr array global) <- lookup *global-data-ah
202 var final-index/ecx: (addr int) <- get globals, final-index
203 var curr-index/ecx: int <- copy *final-index
204 {
205 compare curr-index, 0
206 break-if-<
207 var curr-offset/ebx: (offset global) <- compute-offset global-data, curr-index
208 var curr/ebx: (addr global) <- index global-data, curr-offset
209 var curr-name-ah/eax: (addr handle array byte) <- get curr, name
210 var curr-name/eax: (addr array byte) <- lookup *curr-name-ah
211 var found?/eax: boolean <- stream-data-equal? sym-name, curr-name
212 compare found?, 0/false
213 {
214 break-if-=
215 return curr-index
216 }
217 curr-index <- decrement
218 loop
219 }
220 return -1/not-found
221 }
222
223
224 fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr handle cell), _globals: (addr global-table), trace: (addr trace) {
225 var f/esi: (addr cell) <- copy _f
226 var f-index-a/ecx: (addr int) <- get f, index-data
227 var f-index/ecx: int <- copy *f-index-a
228 var globals/eax: (addr global-table) <- copy _globals
229 var global-data-ah/eax: (addr handle array global) <- get globals, data
230 var global-data/eax: (addr array global) <- lookup *global-data-ah
231 var f-offset/ecx: (offset global) <- compute-offset global-data, f-index
232 var f-value/ecx: (addr global) <- index global-data, f-offset
233 var f-name-ah/ecx: (addr handle array byte) <- get f-value, name
234 var f-name/eax: (addr array byte) <- lookup *f-name-ah
235 {
236 var is-add?/eax: boolean <- string-equal? f-name, "+"
237 compare is-add?, 0/false
238 break-if-=
239 apply-add args-ah, out, trace
240 return
241 }
242 {
243 var is-subtract?/eax: boolean <- string-equal? f-name, "-"
244 compare is-subtract?, 0/false
245 break-if-=
246 apply-subtract args-ah, out, trace
247 return
248 }
249 {
250 var is-multiply?/eax: boolean <- string-equal? f-name, "*"
251 compare is-multiply?, 0/false
252 break-if-=
253 apply-multiply args-ah, out, trace
254 return
255 }
256 {
257 var is-divide?/eax: boolean <- string-equal? f-name, "/"
258 compare is-divide?, 0/false
259 break-if-=
260 apply-divide args-ah, out, trace
261 return
262 }
263 {
264 var is-square-root?/eax: boolean <- string-equal? f-name, "sqrt"
265 compare is-square-root?, 0/false
266 break-if-=
267 apply-square-root args-ah, out, trace
268 return
269 }
270 {
271 var is-car?/eax: boolean <- string-equal? f-name, "car"
272 compare is-car?, 0/false
273 break-if-=
274 apply-car args-ah, out, trace
275 return
276 }
277 {
278 var is-cdr?/eax: boolean <- string-equal? f-name, "cdr"
279 compare is-cdr?, 0/false
280 break-if-=
281 apply-cdr args-ah, out, trace
282 return
283 }
284 {
285 var is-cons?/eax: boolean <- string-equal? f-name, "cons"
286 compare is-cons?, 0/false
287 break-if-=
288 apply-cons args-ah, out, trace
289 return
290 }
291 {
292 var is-compare?/eax: boolean <- string-equal? f-name, "="
293 compare is-compare?, 0/false
294 break-if-=
295 apply-compare args-ah, out, trace
296 return
297 }
298 {
299 var is-print?/eax: boolean <- string-equal? f-name, "print"
300 compare is-print?, 0/false
301 break-if-=
302 apply-print args-ah, out, trace
303 return
304 }
305 {
306 var wait-for-key?/eax: boolean <- string-equal? f-name, "key"
307 compare wait-for-key?, 0/false
308 break-if-=
309 apply-wait-for-key args-ah, out, trace
310 return
311 }
312 {
313 var is-stream?/eax: boolean <- string-equal? f-name, "stream"
314 compare is-stream?, 0/false
315 break-if-=
316 apply-stream args-ah, out, trace
317 return
318 }
319 {
320 var write?/eax: boolean <- string-equal? f-name, "write"
321 compare write?, 0/false
322 break-if-=
323 apply-write args-ah, out, trace
324 return
325 }
326 abort "unknown primitive function"
327 }
328
329 fn apply-add _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
330 trace-text trace, "eval", "apply +"
331 var args-ah/eax: (addr handle cell) <- copy _args-ah
332 var _args/eax: (addr cell) <- lookup *args-ah
333 var args/esi: (addr cell) <- copy _args
334
335 var empty-args?/eax: boolean <- nil? args
336 compare empty-args?, 0/false
337 {
338 break-if-=
339 error trace, "+ needs 2 args but got 0"
340 return
341 }
342
343 var first-ah/eax: (addr handle cell) <- get args, left
344 var first/eax: (addr cell) <- lookup *first-ah
345 var first-type/ecx: (addr int) <- get first, type
346 compare *first-type, 1/number
347 {
348 break-if-=
349 error trace, "first arg for + is not a number"
350 return
351 }
352 var first-value/ecx: (addr float) <- get first, number-data
353
354 var right-ah/eax: (addr handle cell) <- get args, right
355
356
357 var right/eax: (addr cell) <- lookup *right-ah
358
359 var second-ah/eax: (addr handle cell) <- get right, left
360 var second/eax: (addr cell) <- lookup *second-ah
361 var second-type/edx: (addr int) <- get second, type
362 compare *second-type, 1/number
363 {
364 break-if-=
365 error trace, "second arg for + is not a number"
366 return
367 }
368 var second-value/edx: (addr float) <- get second, number-data
369
370 var result/xmm0: float <- copy *first-value
371 result <- add *second-value
372 new-float out, result
373 }
374
375 fn apply-subtract _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
376 trace-text trace, "eval", "apply -"
377 var args-ah/eax: (addr handle cell) <- copy _args-ah
378 var _args/eax: (addr cell) <- lookup *args-ah
379 var args/esi: (addr cell) <- copy _args
380
381 var empty-args?/eax: boolean <- nil? args
382 compare empty-args?, 0/false
383 {
384 break-if-=
385 error trace, "- needs 2 args but got 0"
386 return
387 }
388
389 var first-ah/eax: (addr handle cell) <- get args, left
390 var first/eax: (addr cell) <- lookup *first-ah
391 var first-type/ecx: (addr int) <- get first, type
392 compare *first-type, 1/number
393 {
394 break-if-=
395 error trace, "first arg for - is not a number"
396 return
397 }
398 var first-value/ecx: (addr float) <- get first, number-data
399
400 var right-ah/eax: (addr handle cell) <- get args, right
401 var right/eax: (addr cell) <- lookup *right-ah
402
403 var second-ah/eax: (addr handle cell) <- get right, left
404 var second/eax: (addr cell) <- lookup *second-ah
405 var second-type/edx: (addr int) <- get second, type
406 compare *second-type, 1/number
407 {
408 break-if-=
409 error trace, "second arg for - is not a number"
410 return
411 }
412 var second-value/edx: (addr float) <- get second, number-data
413
414 var result/xmm0: float <- copy *first-value
415 result <- subtract *second-value
416 new-float out, result
417 }
418
419 fn apply-multiply _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
420 trace-text trace, "eval", "apply *"
421 var args-ah/eax: (addr handle cell) <- copy _args-ah
422 var _args/eax: (addr cell) <- lookup *args-ah
423 var args/esi: (addr cell) <- copy _args
424
425 var empty-args?/eax: boolean <- nil? args
426 compare empty-args?, 0/false
427 {
428 break-if-=
429 error trace, "* needs 2 args but got 0"
430 return
431 }
432
433 var first-ah/eax: (addr handle cell) <- get args, left
434 var first/eax: (addr cell) <- lookup *first-ah
435 var first-type/ecx: (addr int) <- get first, type
436 compare *first-type, 1/number
437 {
438 break-if-=
439 error trace, "first arg for * is not a number"
440 return
441 }
442 var first-value/ecx: (addr float) <- get first, number-data
443
444 var right-ah/eax: (addr handle cell) <- get args, right
445 var right/eax: (addr cell) <- lookup *right-ah
446
447 var second-ah/eax: (addr handle cell) <- get right, left
448 var second/eax: (addr cell) <- lookup *second-ah
449 var second-type/edx: (addr int) <- get second, type
450 compare *second-type, 1/number
451 {
452 break-if-=
453 error trace, "second arg for * is not a number"
454 return
455 }
456 var second-value/edx: (addr float) <- get second, number-data
457
458 var result/xmm0: float <- copy *first-value
459 result <- multiply *second-value
460 new-float out, result
461 }
462
463 fn apply-divide _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
464 trace-text trace, "eval", "apply /"
465 var args-ah/eax: (addr handle cell) <- copy _args-ah
466 var _args/eax: (addr cell) <- lookup *args-ah
467 var args/esi: (addr cell) <- copy _args
468
469 var empty-args?/eax: boolean <- nil? args
470 compare empty-args?, 0/false
471 {
472 break-if-=
473 error trace, "/ needs 2 args but got 0"
474 return
475 }
476
477 var first-ah/eax: (addr handle cell) <- get args, left
478 var first/eax: (addr cell) <- lookup *first-ah
479 var first-type/ecx: (addr int) <- get first, type
480 compare *first-type, 1/number
481 {
482 break-if-=
483 error trace, "first arg for / is not a number"
484 return
485 }
486 var first-value/ecx: (addr float) <- get first, number-data
487
488 var right-ah/eax: (addr handle cell) <- get args, right
489 var right/eax: (addr cell) <- lookup *right-ah
490
491 var second-ah/eax: (addr handle cell) <- get right, left
492 var second/eax: (addr cell) <- lookup *second-ah
493 var second-type/edx: (addr int) <- get second, type
494 compare *second-type, 1/number
495 {
496 break-if-=
497 error trace, "second arg for / is not a number"
498 return
499 }
500 var second-value/edx: (addr float) <- get second, number-data
501
502 var result/xmm0: float <- copy *first-value
503 result <- divide *second-value
504 new-float out, result
505 }
506
507 fn apply-square-root _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
508 trace-text trace, "eval", "apply sqrt"
509 var args-ah/eax: (addr handle cell) <- copy _args-ah
510 var _args/eax: (addr cell) <- lookup *args-ah
511 var args/esi: (addr cell) <- copy _args
512
513 var empty-args?/eax: boolean <- nil? args
514 compare empty-args?, 0/false
515 {
516 break-if-=
517 error trace, "sqrt needs 1 args but got 0"
518 return
519 }
520
521 var first-ah/eax: (addr handle cell) <- get args, left
522 var first/eax: (addr cell) <- lookup *first-ah
523 var first-type/ecx: (addr int) <- get first, type
524 compare *first-type, 1/number
525 {
526 break-if-=
527 error trace, "arg for sqrt is not a number"
528 return
529 }
530 var first-value/ecx: (addr float) <- get first, number-data
531
532 var result/xmm0: float <- square-root *first-value
533 new-float out, result
534 }
535
536 fn apply-car _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
537 trace-text trace, "eval", "apply car"
538 var args-ah/eax: (addr handle cell) <- copy _args-ah
539 var _args/eax: (addr cell) <- lookup *args-ah
540 var args/esi: (addr cell) <- copy _args
541
542 var empty-args?/eax: boolean <- nil? args
543 compare empty-args?, 0/false
544 {
545 break-if-=
546 error trace, "car needs 1 args but got 0"
547 return
548 }
549
550 var first-ah/eax: (addr handle cell) <- get args, left
551 var first/eax: (addr cell) <- lookup *first-ah
552 var first-type/ecx: (addr int) <- get first, type
553 compare *first-type, 0/pair
554 {
555 break-if-=
556 error trace, "arg for car is not a pair"
557 return
558 }
559
560 var result/eax: (addr handle cell) <- get first, left
561 copy-object result, out
562 }
563
564 fn apply-cdr _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
565 trace-text trace, "eval", "apply cdr"
566 var args-ah/eax: (addr handle cell) <- copy _args-ah
567 var _args/eax: (addr cell) <- lookup *args-ah
568 var args/esi: (addr cell) <- copy _args
569
570 var empty-args?/eax: boolean <- nil? args
571 compare empty-args?, 0/false
572 {
573 break-if-=
574 error trace, "cdr needs 1 args but got 0"
575 return
576 }
577
578 var first-ah/eax: (addr handle cell) <- get args, left
579 var first/eax: (addr cell) <- lookup *first-ah
580 var first-type/ecx: (addr int) <- get first, type
581 compare *first-type, 0/pair
582 {
583 break-if-=
584 error trace, "arg for cdr is not a pair"
585 return
586 }
587
588 var result/eax: (addr handle cell) <- get first, right
589 copy-object result, out
590 }
591
592 fn apply-cons _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
593 trace-text trace, "eval", "apply cons"
594 var args-ah/eax: (addr handle cell) <- copy _args-ah
595 var _args/eax: (addr cell) <- lookup *args-ah
596 var args/esi: (addr cell) <- copy _args
597
598 var empty-args?/eax: boolean <- nil? args
599 compare empty-args?, 0/false
600 {
601 break-if-=
602 error trace, "cons needs 2 args but got 0"
603 return
604 }
605
606 var first-ah/ecx: (addr handle cell) <- get args, left
607
608 var right-ah/eax: (addr handle cell) <- get args, right
609 var right/eax: (addr cell) <- lookup *right-ah
610
611 var second-ah/eax: (addr handle cell) <- get right, left
612
613 new-pair out, *first-ah, *second-ah
614 }
615
616 fn apply-compare _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
617 trace-text trace, "eval", "apply ="
618 var args-ah/eax: (addr handle cell) <- copy _args-ah
619 var _args/eax: (addr cell) <- lookup *args-ah
620 var args/esi: (addr cell) <- copy _args
621
622 var empty-args?/eax: boolean <- nil? args
623 compare empty-args?, 0/false
624 {
625 break-if-=
626 error trace, "cons needs 2 args but got 0"
627 return
628 }
629
630 var first-ah/ecx: (addr handle cell) <- get args, left
631
632 var right-ah/eax: (addr handle cell) <- get args, right
633 var right/eax: (addr cell) <- lookup *right-ah
634
635 var second-ah/edx: (addr handle cell) <- get right, left
636
637 var _first/eax: (addr cell) <- lookup *first-ah
638 var first/ecx: (addr cell) <- copy _first
639 var second/eax: (addr cell) <- lookup *second-ah
640 var match?/eax: boolean <- cell-isomorphic? first, second, trace
641 compare match?, 0/false
642 {
643 break-if-!=
644 nil out
645 return
646 }
647 new-integer out, 1/true
648 }
649
650 fn apply-print _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
651 trace-text trace, "eval", "apply print"
652 var args-ah/eax: (addr handle cell) <- copy _args-ah
653 var _args/eax: (addr cell) <- lookup *args-ah
654 var args/esi: (addr cell) <- copy _args
655
656 var empty-args?/eax: boolean <- nil? args
657 compare empty-args?, 0/false
658 {
659 break-if-=
660 error trace, "print needs 2 args but got 0"
661 return
662 }
663
664 var first-ah/eax: (addr handle cell) <- get args, left
665 var first/eax: (addr cell) <- lookup *first-ah
666 var first-type/ecx: (addr int) <- get first, type
667 compare *first-type, 5/screen
668 {
669 break-if-=
670 error trace, "first arg for 'print' is not a screen"
671 return
672 }
673 var screen-ah/eax: (addr handle screen) <- get first, screen-data
674 var _screen/eax: (addr screen) <- lookup *screen-ah
675 var screen/ecx: (addr screen) <- copy _screen
676
677 var right-ah/eax: (addr handle cell) <- get args, right
678 var right/eax: (addr cell) <- lookup *right-ah
679
680 var second-ah/eax: (addr handle cell) <- get right, left
681 var stream-storage: (stream byte 0x100)
682 var stream/edi: (addr stream byte) <- address stream-storage
683 print-cell second-ah, stream, trace
684 draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen, stream, 7/fg, 0/bg
685
686 copy-object second-ah, out
687 }
688
689 fn apply-wait-for-key _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
690 trace-text trace, "eval", "apply key"
691 var args-ah/eax: (addr handle cell) <- copy _args-ah
692 var _args/eax: (addr cell) <- lookup *args-ah
693 var args/esi: (addr cell) <- copy _args
694
695 var empty-args?/eax: boolean <- nil? args
696 compare empty-args?, 0/false
697 {
698 break-if-=
699 error trace, "key needs 1 arg but got 0"
700 return
701 }
702
703 var first-ah/eax: (addr handle cell) <- get args, left
704 var first/eax: (addr cell) <- lookup *first-ah
705 var first-type/ecx: (addr int) <- get first, type
706 compare *first-type, 6/keyboard
707 {
708 break-if-=
709 error trace, "first arg for 'key' is not a keyboard"
710 return
711 }
712 var keyboard-ah/eax: (addr handle gap-buffer) <- get first, keyboard-data
713 var _keyboard/eax: (addr gap-buffer) <- lookup *keyboard-ah
714 var keyboard/ecx: (addr gap-buffer) <- copy _keyboard
715 var result/eax: int <- wait-for-key keyboard
716
717 new-integer out, result
718 }
719
720 fn wait-for-key keyboard: (addr gap-buffer) -> _/eax: int {
721
722 {
723 compare keyboard, 0/real-keyboard
724 break-if-!=
725 var key/eax: byte <- read-key 0/real-keyboard
726 var result/eax: int <- copy key
727 return result
728 }
729
730 var g/eax: grapheme <- read-from-gap-buffer keyboard
731 var result/eax: int <- copy g
732 return result
733 }
734
735 fn apply-stream _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
736 trace-text trace, "eval", "apply stream"
737 allocate-stream out
738 }
739
740 fn apply-write _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
741 trace-text trace, "eval", "apply write"
742 var args-ah/eax: (addr handle cell) <- copy _args-ah
743 var _args/eax: (addr cell) <- lookup *args-ah
744 var args/esi: (addr cell) <- copy _args
745
746 var empty-args?/eax: boolean <- nil? args
747 compare empty-args?, 0/false
748 {
749 break-if-=
750 error trace, "write needs 2 args but got 0"
751 return
752 }
753
754 var first-ah/edx: (addr handle cell) <- get args, left
755 var first/eax: (addr cell) <- lookup *first-ah
756 var first-type/ecx: (addr int) <- get first, type
757 compare *first-type, 3/stream
758 {
759 break-if-=
760 error trace, "first arg for 'write' is not a stream"
761 return
762 }
763 var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
764 var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
765 var stream-data/ebx: (addr stream byte) <- copy _stream-data
766
767 var right-ah/eax: (addr handle cell) <- get args, right
768 var right/eax: (addr cell) <- lookup *right-ah
769
770 var second-ah/eax: (addr handle cell) <- get right, left
771 var second/eax: (addr cell) <- lookup *second-ah
772 var second-type/ecx: (addr int) <- get second, type
773 compare *second-type, 1/number
774 {
775 break-if-=
776 error trace, "second arg for stream is not a number/grapheme"
777 return
778 }
779 var second-value/eax: (addr float) <- get second, number-data
780 var x-float/xmm0: float <- copy *second-value
781 var x/eax: int <- convert x-float
782 var x-grapheme/eax: grapheme <- copy x
783 write-grapheme stream-data, x-grapheme
784
785 copy-object first-ah, out
786 }