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