https://github.com/akkartik/mu/blob/main/shell/grapheme-stack.mu
1
2
3 type grapheme-stack {
4 data: (handle array grapheme)
5 top: int
6 }
7
8 fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int {
9 var self/esi: (addr grapheme-stack) <- copy _self
10 var d/edi: (addr handle array grapheme) <- get self, data
11 populate d, n
12 var top/eax: (addr int) <- get self, top
13 copy-to *top, 0
14 }
15
16 fn clear-grapheme-stack _self: (addr grapheme-stack) {
17 var self/esi: (addr grapheme-stack) <- copy _self
18 var top/eax: (addr int) <- get self, top
19 copy-to *top, 0
20 }
21
22 fn grapheme-stack-empty? _self: (addr grapheme-stack) -> _/eax: boolean {
23 var self/esi: (addr grapheme-stack) <- copy _self
24 var top/eax: (addr int) <- get self, top
25 compare *top, 0
26 {
27 break-if-!=
28 return 1/true
29 }
30 return 0/false
31 }
32
33 fn grapheme-stack-length _self: (addr grapheme-stack) -> _/eax: int {
34 var self/esi: (addr grapheme-stack) <- copy _self
35 var top/eax: (addr int) <- get self, top
36 return *top
37 }
38
39 fn push-grapheme-stack _self: (addr grapheme-stack), _val: grapheme {
40 var self/esi: (addr grapheme-stack) <- copy _self
41 var top-addr/ecx: (addr int) <- get self, top
42 var data-ah/edx: (addr handle array grapheme) <- get self, data
43 var data/eax: (addr array grapheme) <- lookup *data-ah
44 var top/edx: int <- copy *top-addr
45 var dest-addr/edx: (addr grapheme) <- index data, top
46 var val/eax: grapheme <- copy _val
47 copy-to *dest-addr, val
48 add-to *top-addr, 1
49 }
50
51 fn pop-grapheme-stack _self: (addr grapheme-stack) -> _/eax: grapheme {
52 var self/esi: (addr grapheme-stack) <- copy _self
53 var top-addr/ecx: (addr int) <- get self, top
54 {
55 compare *top-addr, 0
56 break-if->
57 return -1
58 }
59 subtract-from *top-addr, 1
60 var data-ah/edx: (addr handle array grapheme) <- get self, data
61 var data/eax: (addr array grapheme) <- lookup *data-ah
62 var top/edx: int <- copy *top-addr
63 var result-addr/eax: (addr grapheme) <- index data, top
64 return *result-addr
65 }
66
67 fn copy-grapheme-stack _src: (addr grapheme-stack), dest: (addr grapheme-stack) {
68 var src/esi: (addr grapheme-stack) <- copy _src
69 var data-ah/edi: (addr handle array grapheme) <- get src, data
70 var _data/eax: (addr array grapheme) <- lookup *data-ah
71 var data/edi: (addr array grapheme) <- copy _data
72 var top-addr/ecx: (addr int) <- get src, top
73 var i/eax: int <- copy 0
74 {
75 compare i, *top-addr
76 break-if->=
77 var g/edx: (addr grapheme) <- index data, i
78 push-grapheme-stack dest, *g
79 i <- increment
80 loop
81 }
82 }
83
84
85
86
87 fn render-stack-from-bottom-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int, color: int, background-color: int -> _/eax: int, _/ecx: int {
88 var self/esi: (addr grapheme-stack) <- copy _self
89 var matching-open-paren-index/edx: int <- get-matching-open-paren-index self, highlight-matching-open-paren?, open-paren-depth
90 var data-ah/edi: (addr handle array grapheme) <- get self, data
91 var _data/eax: (addr array grapheme) <- lookup *data-ah
92 var data/edi: (addr array grapheme) <- copy _data
93 var x/eax: int <- copy _x
94 var y/ecx: int <- copy _y
95 var top-addr/esi: (addr int) <- get self, top
96 var i/ebx: int <- copy 0
97 {
98 compare i, *top-addr
99 break-if->=
100 {
101 var g/esi: (addr grapheme) <- index data, i
102 var fg: int
103 {
104 var tmp/eax: int <- copy color
105 copy-to fg, tmp
106 }
107 {
108 compare i, matching-open-paren-index
109 break-if-!=
110 copy-to fg, 0xf/highlight
111 }
112 x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, fg, background-color
113 }
114 i <- increment
115 loop
116 }
117 return x, y
118 }
119
120
121 fn render-stack-from-bottom screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, highlight-matching-open-paren?: boolean, open-paren-depth: int -> _/eax: int {
122 var _width/eax: int <- copy 0
123 var _height/ecx: int <- copy 0
124 _width, _height <- screen-size screen
125 var width/edx: int <- copy _width
126 var height/ebx: int <- copy _height
127 var x2/eax: int <- copy 0
128 var y2/ecx: int <- copy 0
129 x2, y2 <- render-stack-from-bottom-wrapping-right-then-down screen, self, x, y, width, height, x, y, highlight-matching-open-paren?, open-paren-depth, 3/fg=cyan, 0xc5/bg=blue-bg
130 return x2
131 }
132
133
134
135
136
137
138 fn render-stack-from-top-wrapping-right-then-down screen: (addr screen), _self: (addr grapheme-stack), xmin: int, ymin: int, xmax: int, ymax: int, _x: int, _y: int, render-cursor?: boolean, color: int, background-color: int -> _/eax: int, _/ecx: int {
139 var self/esi: (addr grapheme-stack) <- copy _self
140 var matching-close-paren-index/edx: int <- get-matching-close-paren-index self, render-cursor?
141 var data-ah/eax: (addr handle array grapheme) <- get self, data
142 var _data/eax: (addr array grapheme) <- lookup *data-ah
143 var data/edi: (addr array grapheme) <- copy _data
144 var x/eax: int <- copy _x
145 var y/ecx: int <- copy _y
146 var top-addr/ebx: (addr int) <- get self, top
147 var i/ebx: int <- copy *top-addr
148 i <- decrement
149
150 {
151 compare render-cursor?, 0/false
152 break-if-=
153 compare i, 0
154 break-if-<
155 var g/esi: (addr grapheme) <- index data, i
156 x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, color, 7/bg=cursor
157 i <- decrement
158 }
159
160 {
161 compare i, 0
162 break-if-<
163
164 var fg: int
165 {
166 var tmp/eax: int <- copy color
167 copy-to fg, tmp
168 }
169 compare i, matching-close-paren-index
170 {
171 break-if-!=
172 copy-to fg, 0xf/highlight
173 }
174
175 var g/esi: (addr grapheme) <- index data, i
176 x, y <- render-grapheme screen, *g, xmin, ymin, xmax, ymax, x, y, fg, background-color
177 i <- decrement
178 loop
179 }
180 return x, y
181 }
182
183
184 fn render-stack-from-top screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, render-cursor?: boolean -> _/eax: int {
185 var _width/eax: int <- copy 0
186 var _height/ecx: int <- copy 0
187 _width, _height <- screen-size screen
188 var width/edx: int <- copy _width
189 var height/ebx: int <- copy _height
190 var x2/eax: int <- copy 0
191 var y2/ecx: int <- copy 0
192 x2, y2 <- render-stack-from-top-wrapping-right-then-down screen, self, x, y, width, height, x, y, render-cursor?, 3/fg=cyan, 0xc5/bg=blue-bg
193 return x2
194 }
195
196 fn test-render-grapheme-stack {
197
198 var gs-storage: grapheme-stack
199 var gs/edi: (addr grapheme-stack) <- address gs-storage
200 initialize-grapheme-stack gs, 5
201 var g/eax: grapheme <- copy 0x61/a
202 push-grapheme-stack gs, g
203 g <- copy 0x62/b
204 push-grapheme-stack gs, g
205 g <- copy 0x63/c
206 push-grapheme-stack gs, g
207
208 var screen-on-stack: screen
209 var screen/esi: (addr screen) <- address screen-on-stack
210 initialize-screen screen, 5, 4, 0/no-pixel-graphics
211
212 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 0/y, 0/no-highlight-matching-open-paren, 0/open-paren-depth
213 check-screen-row screen, 0/y, "abc ", "F - test-render-grapheme-stack from bottom"
214 check-ints-equal x, 3, "F - test-render-grapheme-stack from bottom: result"
215 check-background-color-in-screen-row screen, 7/bg=cursor, 0/y, " ", "F - test-render-grapheme-stack from bottom: bg"
216
217 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 1/y, 0/cursor=false
218 check-screen-row screen, 1/y, "cba ", "F - test-render-grapheme-stack from top without cursor"
219 check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result"
220 check-background-color-in-screen-row screen, 7/bg=cursor, 1/y, " ", "F - test-render-grapheme-stack from top without cursor: bg"
221
222 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
223 check-screen-row screen, 2/y, "cba ", "F - test-render-grapheme-stack from top with cursor"
224 check-ints-equal x, 3, "F - test-render-grapheme-stack from top with cursor: result"
225 check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "| ", "F - test-render-grapheme-stack from top with cursor: bg"
226 }
227
228 fn test-render-grapheme-stack-while-highlighting-matching-close-paren {
229
230 var gs-storage: grapheme-stack
231 var gs/edi: (addr grapheme-stack) <- address gs-storage
232 initialize-grapheme-stack gs, 5
233 var g/eax: grapheme <- copy 0x29/close-paren
234 push-grapheme-stack gs, g
235 g <- copy 0x62/b
236 push-grapheme-stack gs, g
237 g <- copy 0x28/open-paren
238 push-grapheme-stack gs, g
239
240 var screen-on-stack: screen
241 var screen/esi: (addr screen) <- address screen-on-stack
242 initialize-screen screen, 5, 4, 0/no-pixel-graphics
243
244 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
245 check-screen-row screen, 2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren"
246 check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "| ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: cursor"
247 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: matching paren"
248 }
249
250 fn test-render-grapheme-stack-while-highlighting-matching-close-paren-2 {
251
252 var gs-storage: grapheme-stack
253 var gs/edi: (addr grapheme-stack) <- address gs-storage
254 initialize-grapheme-stack gs, 0x10
255 var g/eax: grapheme <- copy 0x63/c
256 push-grapheme-stack gs, g
257 g <- copy 0x20/space
258 push-grapheme-stack gs, g
259 g <- copy 0x29/close-paren
260 push-grapheme-stack gs, g
261 g <- copy 0x29/close-paren
262 push-grapheme-stack gs, g
263 g <- copy 0x62/b
264 push-grapheme-stack gs, g
265 g <- copy 0x28/open-paren
266 push-grapheme-stack gs, g
267 g <- copy 0x20/space
268 push-grapheme-stack gs, g
269 g <- copy 0x61/a
270 push-grapheme-stack gs, g
271 g <- copy 0x28/open-paren
272 push-grapheme-stack gs, g
273
274 var screen-on-stack: screen
275 var screen/esi: (addr screen) <- address screen-on-stack
276 initialize-screen screen, 5, 4, 0/no-pixel-graphics
277
278 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true
279 check-screen-row screen, 2/y, "(a (b)) c ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2"
280 check-background-color-in-screen-row screen, 7/bg=cursor, 2/y, "| ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: cursor"
281 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: matching paren"
282 }
283
284 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end {
285
286 var gs-storage: grapheme-stack
287 var gs/edi: (addr grapheme-stack) <- address gs-storage
288 initialize-grapheme-stack gs, 5
289 var g/eax: grapheme <- copy 0x28/open-paren
290 push-grapheme-stack gs, g
291 g <- copy 0x62/b
292 push-grapheme-stack gs, g
293 g <- copy 0x29/close-paren
294 push-grapheme-stack gs, g
295
296 var screen-on-stack: screen
297 var screen/esi: (addr screen) <- address screen-on-stack
298 initialize-screen screen, 5, 4, 0/no-pixel-graphics
299
300 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
301 check-screen-row screen, 2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end"
302 check-screen-row-in-color screen, 0xf/fg=white, 2/y, "( ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end: matching paren"
303 }
304
305 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2 {
306
307 var gs-storage: grapheme-stack
308 var gs/edi: (addr grapheme-stack) <- address gs-storage
309 initialize-grapheme-stack gs, 0x10
310 var g/eax: grapheme <- copy 0x61/a
311 push-grapheme-stack gs, g
312 g <- copy 0x28/open-paren
313 push-grapheme-stack gs, g
314 g <- copy 0x28/open-paren
315 push-grapheme-stack gs, g
316 g <- copy 0x62/b
317 push-grapheme-stack gs, g
318 g <- copy 0x29/close-paren
319 push-grapheme-stack gs, g
320 g <- copy 0x29/close-paren
321 push-grapheme-stack gs, g
322
323 var screen-on-stack: screen
324 var screen/esi: (addr screen) <- address screen-on-stack
325 initialize-screen screen, 5, 4, 0/no-pixel-graphics
326
327 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth
328 check-screen-row screen, 2/y, "a((b)) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2"
329 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ( ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2: matching paren"
330 }
331
332 fn test-render-grapheme-stack-while-highlighting-matching-open-paren {
333
334 var gs-storage: grapheme-stack
335 var gs/edi: (addr grapheme-stack) <- address gs-storage
336 initialize-grapheme-stack gs, 5
337 var g/eax: grapheme <- copy 0x28/open-paren
338 push-grapheme-stack gs, g
339 g <- copy 0x62/b
340 push-grapheme-stack gs, g
341
342 var screen-on-stack: screen
343 var screen/esi: (addr screen) <- address screen-on-stack
344 initialize-screen screen, 5, 4, 0/no-pixel-graphics
345
346 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
347 check-screen-row screen, 2/y, "(b ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren"
348 check-screen-row-in-color screen, 0xf/fg=white, 2/y, "( ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren: matching paren"
349 }
350
351 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-2 {
352
353 var gs-storage: grapheme-stack
354 var gs/edi: (addr grapheme-stack) <- address gs-storage
355 initialize-grapheme-stack gs, 0x10
356 var g/eax: grapheme <- copy 0x61/a
357 push-grapheme-stack gs, g
358 g <- copy 0x28/open-paren
359 push-grapheme-stack gs, g
360 g <- copy 0x28/open-paren
361 push-grapheme-stack gs, g
362 g <- copy 0x62/b
363 push-grapheme-stack gs, g
364 g <- copy 0x29/close-paren
365 push-grapheme-stack gs, g
366
367 var screen-on-stack: screen
368 var screen/esi: (addr screen) <- address screen-on-stack
369 initialize-screen screen, 5, 4, 0/no-pixel-graphics
370
371 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth
372 check-screen-row screen, 2/y, "a((b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2"
373 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ( ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2: matching paren"
374 }
375
376
377
378 fn get-matching-close-paren-index _self: (addr grapheme-stack), render-cursor?: boolean -> _/edx: int {
379 var self/esi: (addr grapheme-stack) <- copy _self
380 var top-addr/edx: (addr int) <- get self, top
381
382 compare render-cursor?, 0/false
383 {
384 break-if-!=
385 return *top-addr
386 }
387 var data-ah/eax: (addr handle array grapheme) <- get self, data
388 var data/eax: (addr array grapheme) <- lookup *data-ah
389 var i/ecx: int <- copy *top-addr
390
391 compare i, 0
392 {
393 break-if->
394 return *top-addr
395 }
396
397 i <- decrement
398 var g/esi: (addr grapheme) <- index data, i
399 compare *g, 0x28/open-paren
400 {
401 break-if-=
402 return *top-addr
403 }
404
405 var paren-count/ebx: int <- copy 1
406 i <- decrement
407 {
408 compare i, 0
409 break-if-<
410 var g/esi: (addr grapheme) <- index data, i
411 compare *g, 0x28/open-paren
412 {
413 break-if-!=
414 paren-count <- increment
415 }
416 compare *g, 0x29/close-paren
417 {
418 break-if-!=
419 compare paren-count, 1
420 {
421 break-if-!=
422 return i
423 }
424 paren-count <- decrement
425 }
426 i <- decrement
427 loop
428 }
429 return *top-addr
430 }
431
432
433
434 fn get-matching-open-paren-index _self: (addr grapheme-stack), control: boolean, depth: int -> _/edx: int {
435 var self/esi: (addr grapheme-stack) <- copy _self
436 var top-addr/edx: (addr int) <- get self, top
437
438 compare control, 0/false
439 {
440 break-if-!=
441 return *top-addr
442 }
443 var data-ah/eax: (addr handle array grapheme) <- get self, data
444 var data/eax: (addr array grapheme) <- lookup *data-ah
445 var i/ecx: int <- copy *top-addr
446
447 compare i, 0
448 {
449 break-if->
450 return *top-addr
451 }
452
453 var paren-count/ebx: int <- copy 0
454 i <- decrement
455 {
456 compare i, 0
457 break-if-<
458 var g/esi: (addr grapheme) <- index data, i
459 compare *g, 0x29/close-paren
460 {
461 break-if-!=
462 paren-count <- increment
463 }
464 compare *g, 0x28/open-paren
465 {
466 break-if-!=
467 compare paren-count, depth
468 {
469 break-if-!=
470 return i
471 }
472 paren-count <- decrement
473 }
474 i <- decrement
475 loop
476 }
477 return *top-addr
478 }
479
480
481
482 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
483 var self/esi: (addr grapheme-stack) <- copy _self
484 var data-ah/edi: (addr handle array grapheme) <- get self, data
485 var _data/eax: (addr array grapheme) <- lookup *data-ah
486 var data/edi: (addr array grapheme) <- copy _data
487 var top-addr/ecx: (addr int) <- get self, top
488 var i/ebx: int <- copy 0
489 {
490 compare i, *top-addr
491 break-if->=
492
493 {
494 var curr-a/edx: (addr grapheme) <- index data, i
495 var expected/eax: grapheme <- read-grapheme s
496 {
497 compare expected, *curr-a
498 break-if-=
499 return 0/false
500 }
501 }
502 i <- increment
503 loop
504 }
505 return 1
506 }
507
508
509
510 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
511 var self/esi: (addr grapheme-stack) <- copy _self
512 var data-ah/edi: (addr handle array grapheme) <- get self, data
513 var _data/eax: (addr array grapheme) <- lookup *data-ah
514 var data/edi: (addr array grapheme) <- copy _data
515 var top-addr/eax: (addr int) <- get self, top
516 var i/ebx: int <- copy *top-addr
517 i <- decrement
518 {
519 compare i, 0
520 break-if-<
521 {
522 var curr-a/edx: (addr grapheme) <- index data, i
523 var expected/eax: grapheme <- read-grapheme s
524
525 {
526 compare expected, *curr-a
527 break-if-=
528 return 0/false
529 }
530 }
531 i <- decrement
532 loop
533 }
534 return 1
535 }
536
537 fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean {
538 var self/esi: (addr grapheme-stack) <- copy _self
539 var data-ah/eax: (addr handle array grapheme) <- get self, data
540 var _data/eax: (addr array grapheme) <- lookup *data-ah
541 var data/edx: (addr array grapheme) <- copy _data
542 var top-addr/ecx: (addr int) <- get self, top
543 var i/ebx: int <- copy 0
544 var result/eax: boolean <- copy 1/true
545 $grapheme-stack-is-integer?:loop: {
546 compare i, *top-addr
547 break-if->=
548 var g/edx: (addr grapheme) <- index data, i
549 result <- decimal-digit? *g
550 compare result, 0/false
551 break-if-=
552 i <- increment
553 loop
554 }
555 return result
556 }