diff --git a/513grapheme-stack.mu b/513grapheme-stack.mu index 5792e08c..0ce05fb6 100644 --- a/513grapheme-stack.mu +++ b/513grapheme-stack.mu @@ -1,4 +1,6 @@ -# code-point-utf8 stacks are the smallest unit of editable text +# Grapheme stacks are the smallest unit of editable text. +# +# (Currently they just support single-code-point graphemes.) type grapheme-stack { data: (handle array code-point-utf8) diff --git a/html/513grapheme-stack.mu.html b/html/513grapheme-stack.mu.html index 8476f08d..ccd0accd 100644 --- a/html/513grapheme-stack.mu.html +++ b/html/513grapheme-stack.mu.html @@ -62,577 +62,579 @@ if ('onhashchange' in window) {
https://github.com/akkartik/mu/blob/main/513grapheme-stack.mu- 1 # code-point-utf8 stacks are the smallest unit of editable text - 2 - 3 type grapheme-stack { - 4 data: (handle array code-point-utf8) - 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 code-point-utf8) <- 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: code-point-utf8 { - 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 code-point-utf8) <- get self, data - 43 var data/eax: (addr array code-point-utf8) <- lookup *data-ah - 44 var top/edx: int <- copy *top-addr - 45 var dest-addr/edx: (addr code-point-utf8) <- index data, top - 46 var val/eax: code-point-utf8 <- 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: code-point-utf8 { - 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 code-point-utf8) <- get self, data - 61 var data/eax: (addr array code-point-utf8) <- lookup *data-ah - 62 var top/edx: int <- copy *top-addr - 63 var result-addr/eax: (addr code-point-utf8) <- 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 code-point-utf8) <- get src, data - 70 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah - 71 var data/edi: (addr array code-point-utf8) <- 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 code-point-utf8) <- index data, i - 78 push-grapheme-stack dest, *g - 79 i <- increment - 80 loop - 81 } - 82 } - 83 - 84 # dump stack to screen from bottom to top - 85 # hardcoded colors: - 86 # matching paren - 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 code-point-utf8) <- get self, data - 91 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah - 92 var data/edi: (addr array code-point-utf8) <- 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 c: code-point -102 { -103 var g/eax: (addr code-point-utf8) <- index data, i -104 var tmp/eax: code-point <- to-code-point *g -105 copy-to c, tmp -106 } -107 var fg: int -108 { -109 var tmp/eax: int <- copy color -110 copy-to fg, tmp -111 } -112 { -113 compare i, matching-open-paren-index -114 break-if-!= -115 copy-to fg, 0xf/highlight -116 } -117 x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color # TODO: handle combining characters -118 } -119 i <- increment -120 loop -121 } -122 return x, y -123 } -124 -125 # helper for small words -126 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 { -127 var _width/eax: int <- copy 0 -128 var _height/ecx: int <- copy 0 -129 _width, _height <- screen-size screen -130 var width/edx: int <- copy _width -131 var height/ebx: int <- copy _height -132 var x2/eax: int <- copy 0 -133 var y2/ecx: int <- copy 0 -134 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 -135 return x2 # y2? yolo -136 } -137 -138 # dump stack to screen from top to bottom -139 # optionally render a 'cursor' with the top code-point-utf8 -140 # hard-coded colors: -141 # matching paren -142 # cursor -143 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 { -144 var self/esi: (addr grapheme-stack) <- copy _self -145 var matching-close-paren-index/edx: int <- get-matching-close-paren-index self, render-cursor? -146 var data-ah/eax: (addr handle array code-point-utf8) <- get self, data -147 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah -148 var data/edi: (addr array code-point-utf8) <- copy _data -149 var x/eax: int <- copy _x -150 var y/ecx: int <- copy _y -151 var top-addr/ebx: (addr int) <- get self, top -152 var i/ebx: int <- copy *top-addr -153 i <- decrement -154 # if render-cursor?, peel off first iteration -155 { -156 compare render-cursor?, 0/false -157 break-if-= -158 compare i, 0 -159 break-if-< -160 var c: code-point -161 { -162 var g/eax: (addr code-point-utf8) <- index data, i -163 var tmp/eax: code-point <- to-code-point *g -164 copy-to c, tmp -165 } -166 x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, background-color, color -167 i <- decrement -168 } -169 # remaining iterations -170 { -171 compare i, 0 -172 break-if-< -173 # highlight matching paren if needed -174 var fg: int -175 { -176 var tmp/eax: int <- copy color -177 copy-to fg, tmp -178 } -179 compare i, matching-close-paren-index -180 { -181 break-if-!= -182 copy-to fg, 0xf/highlight -183 } -184 # -185 var c: code-point -186 { -187 var g/eax: (addr code-point-utf8) <- index data, i -188 var tmp/eax: code-point <- to-code-point *g -189 copy-to c, tmp -190 } -191 x, y <- render-code-point screen, c, xmin, ymin, xmax, ymax, x, y, fg, background-color -192 i <- decrement -193 loop -194 } -195 return x, y -196 } -197 -198 # helper for small words -199 fn render-stack-from-top screen: (addr screen), self: (addr grapheme-stack), x: int, y: int, render-cursor?: boolean -> _/eax: int { -200 var _width/eax: int <- copy 0 -201 var _height/ecx: int <- copy 0 -202 _width, _height <- screen-size screen -203 var width/edx: int <- copy _width -204 var height/ebx: int <- copy _height -205 var x2/eax: int <- copy 0 -206 var y2/ecx: int <- copy 0 -207 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 -208 return x2 # y2? yolo -209 } -210 -211 fn test-render-grapheme-stack { -212 # setup: gs = "abc" -213 var gs-storage: grapheme-stack -214 var gs/edi: (addr grapheme-stack) <- address gs-storage -215 initialize-grapheme-stack gs, 5 -216 var g/eax: code-point-utf8 <- copy 0x61/a -217 push-grapheme-stack gs, g -218 g <- copy 0x62/b -219 push-grapheme-stack gs, g -220 g <- copy 0x63/c -221 push-grapheme-stack gs, g -222 # setup: screen -223 var screen-storage: screen -224 var screen/esi: (addr screen) <- address screen-storage -225 initialize-screen screen, 5, 4, 0/no-pixel-graphics -226 # -227 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 0/y, 0/no-highlight-matching-open-paren, 0/open-paren-depth -228 check-screen-row screen, 0/y, "abc ", "F - test-render-grapheme-stack from bottom" -229 check-ints-equal x, 3, "F - test-render-grapheme-stack from bottom: result" -230 check-background-color-in-screen-row screen, 3/bg=reverse, 0/y, " ", "F - test-render-grapheme-stack from bottom: bg" -231 # -232 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 1/y, 0/cursor=false -233 check-screen-row screen, 1/y, "cba ", "F - test-render-grapheme-stack from top without cursor" -234 check-ints-equal x, 3, "F - test-render-grapheme-stack from top without cursor: result" -235 check-background-color-in-screen-row screen, 3/bg=reverse, 1/y, " ", "F - test-render-grapheme-stack from top without cursor: bg" -236 # -237 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true -238 check-screen-row screen, 2/y, "cba ", "F - test-render-grapheme-stack from top with cursor" -239 check-ints-equal x, 3, "F - test-render-grapheme-stack from top with cursor: result" -240 check-background-color-in-screen-row screen, 3/bg=reverse, 2/y, "| ", "F - test-render-grapheme-stack from top with cursor: bg" -241 } -242 -243 fn test-render-grapheme-stack-while-highlighting-matching-close-paren { -244 # setup: gs = "(b)" -245 var gs-storage: grapheme-stack -246 var gs/edi: (addr grapheme-stack) <- address gs-storage -247 initialize-grapheme-stack gs, 5 -248 var g/eax: code-point-utf8 <- copy 0x29/close-paren -249 push-grapheme-stack gs, g -250 g <- copy 0x62/b -251 push-grapheme-stack gs, g -252 g <- copy 0x28/open-paren -253 push-grapheme-stack gs, g -254 # setup: screen -255 var screen-storage: screen -256 var screen/esi: (addr screen) <- address screen-storage -257 initialize-screen screen, 5, 4, 0/no-pixel-graphics -258 # -259 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true -260 check-screen-row screen, 2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren" -261 check-background-color-in-screen-row screen, 3/bg=reverse, 2/y, "| ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: cursor" -262 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren: matching paren" -263 } -264 -265 fn test-render-grapheme-stack-while-highlighting-matching-close-paren-2 { -266 # setup: gs = "(a (b)) c" -267 var gs-storage: grapheme-stack -268 var gs/edi: (addr grapheme-stack) <- address gs-storage -269 initialize-grapheme-stack gs, 0x10 -270 var g/eax: code-point-utf8 <- copy 0x63/c -271 push-grapheme-stack gs, g -272 g <- copy 0x20/space -273 push-grapheme-stack gs, g -274 g <- copy 0x29/close-paren -275 push-grapheme-stack gs, g + 1 # Grapheme stacks are the smallest unit of editable text. + 2 # + 3 # (Currently they just support single-code-point graphemes.) + 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 # dump stack to screen from bottom to top + 87 # hardcoded colors: + 88 # matching paren + 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 # TODO: handle combining characters +120 } +121 i <- increment +122 loop +123 } +124 return x, y +125 } +126 +127 # helper for small words +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 # y2? yolo +138 } +139 +140 # dump stack to screen from top to bottom +141 # optionally render a 'cursor' with the top code-point-utf8 +142 # hard-coded colors: +143 # matching paren +144 # cursor +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 # if render-cursor?, peel off first iteration +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 # remaining iterations +172 { +173 compare i, 0 +174 break-if-< +175 # highlight matching paren if needed +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 # helper for small words +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 # y2? yolo +211 } +212 +213 fn test-render-grapheme-stack { +214 # setup: gs = "abc" +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 # setup: screen +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 # setup: gs = "(b)" +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 # setup: screen +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 # setup: gs = "(a (b)) c" +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 0x62/b -279 push-grapheme-stack gs, g -280 g <- copy 0x28/open-paren -281 push-grapheme-stack gs, g -282 g <- copy 0x20/space -283 push-grapheme-stack gs, g -284 g <- copy 0x61/a -285 push-grapheme-stack gs, g -286 g <- copy 0x28/open-paren -287 push-grapheme-stack gs, g -288 # setup: screen -289 var screen-storage: screen -290 var screen/esi: (addr screen) <- address screen-storage -291 initialize-screen screen, 5, 4, 0/no-pixel-graphics -292 # -293 var x/eax: int <- render-stack-from-top screen, gs, 0/x, 2/y, 1/cursor=true -294 check-screen-row screen, 2/y, "(a (b)) c ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2" -295 check-background-color-in-screen-row screen, 3/bg=reverse, 2/y, "| ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: cursor" -296 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ) ", "F - test-render-grapheme-stack-while-highlighting-matching-close-paren-2: matching paren" -297 } -298 -299 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end { -300 # setup: gs = "(b)" -301 var gs-storage: grapheme-stack -302 var gs/edi: (addr grapheme-stack) <- address gs-storage -303 initialize-grapheme-stack gs, 5 -304 var g/eax: code-point-utf8 <- copy 0x28/open-paren -305 push-grapheme-stack gs, g -306 g <- copy 0x62/b -307 push-grapheme-stack gs, g -308 g <- copy 0x29/close-paren -309 push-grapheme-stack gs, g -310 # setup: screen -311 var screen-storage: screen -312 var screen/esi: (addr screen) <- address screen-storage -313 initialize-screen screen, 5, 4, 0/no-pixel-graphics -314 # -315 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth -316 check-screen-row screen, 2/y, "(b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end" -317 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" -318 } -319 -320 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2 { -321 # setup: gs = "a((b))" -322 var gs-storage: grapheme-stack -323 var gs/edi: (addr grapheme-stack) <- address gs-storage -324 initialize-grapheme-stack gs, 0x10 -325 var g/eax: code-point-utf8 <- copy 0x61/a -326 push-grapheme-stack gs, g -327 g <- copy 0x28/open-paren -328 push-grapheme-stack gs, g +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 # setup: screen +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 # setup: gs = "(b)" +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 # setup: screen +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 # setup: gs = "a((b))" +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 0x62/b -332 push-grapheme-stack gs, g -333 g <- copy 0x29/close-paren -334 push-grapheme-stack gs, g +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 # setup: screen -338 var screen-storage: screen -339 var screen/esi: (addr screen) <- address screen-storage -340 initialize-screen screen, 5, 4, 0/no-pixel-graphics -341 # -342 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 1/open-paren-depth -343 check-screen-row screen, 2/y, "a((b)) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-with-close-paren-at-end-2" -344 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" -345 } -346 -347 fn test-render-grapheme-stack-while-highlighting-matching-open-paren { -348 # setup: gs = "(b" -349 var gs-storage: grapheme-stack -350 var gs/edi: (addr grapheme-stack) <- address gs-storage -351 initialize-grapheme-stack gs, 5 -352 var g/eax: code-point-utf8 <- copy 0x28/open-paren -353 push-grapheme-stack gs, g -354 g <- copy 0x62/b -355 push-grapheme-stack gs, g -356 # setup: screen -357 var screen-storage: screen -358 var screen/esi: (addr screen) <- address screen-storage -359 initialize-screen screen, 5, 4, 0/no-pixel-graphics -360 # -361 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth -362 check-screen-row screen, 2/y, "(b ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren" -363 check-screen-row-in-color screen, 0xf/fg=white, 2/y, "( ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren: matching paren" -364 } -365 -366 fn test-render-grapheme-stack-while-highlighting-matching-open-paren-2 { -367 # setup: gs = "a((b)" -368 var gs-storage: grapheme-stack -369 var gs/edi: (addr grapheme-stack) <- address gs-storage -370 initialize-grapheme-stack gs, 0x10 -371 var g/eax: code-point-utf8 <- copy 0x61/a -372 push-grapheme-stack gs, g -373 g <- copy 0x28/open-paren -374 push-grapheme-stack gs, g +336 push-grapheme-stack gs, g +337 g <- copy 0x29/close-paren +338 push-grapheme-stack gs, g +339 # setup: screen +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 # setup: gs = "(b" +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 # setup: screen +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 # setup: gs = "a((b)" +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 0x62/b -378 push-grapheme-stack gs, g -379 g <- copy 0x29/close-paren -380 push-grapheme-stack gs, g -381 # setup: screen -382 var screen-storage: screen -383 var screen/esi: (addr screen) <- address screen-storage -384 initialize-screen screen, 5, 4, 0/no-pixel-graphics -385 # -386 var x/eax: int <- render-stack-from-bottom screen, gs, 0/x, 2/y, 1/highlight-matching-open-paren, 0/open-paren-depth -387 check-screen-row screen, 2/y, "a((b) ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2" -388 check-screen-row-in-color screen, 0xf/fg=white, 2/y, " ( ", "F - test-render-grapheme-stack-while-highlighting-matching-open-paren-2: matching paren" -389 } -390 -391 # return the index of the matching close-paren of the code-point-utf8 at cursor (top of stack) -392 # or top index if there's no matching close-paren -393 fn get-matching-close-paren-index _self: (addr grapheme-stack), render-cursor?: boolean -> _/edx: int { -394 var self/esi: (addr grapheme-stack) <- copy _self -395 var top-addr/edx: (addr int) <- get self, top -396 # if not rendering cursor, return -397 compare render-cursor?, 0/false -398 { -399 break-if-!= -400 return *top-addr -401 } -402 var data-ah/eax: (addr handle array code-point-utf8) <- get self, data -403 var data/eax: (addr array code-point-utf8) <- lookup *data-ah -404 var i/ecx: int <- copy *top-addr -405 # if stack is empty, return -406 compare i, 0 -407 { -408 break-if-> -409 return *top-addr -410 } -411 # if cursor is not '(' return -412 i <- decrement -413 var g/esi: (addr code-point-utf8) <- index data, i -414 compare *g, 0x28/open-paren -415 { -416 break-if-= -417 return *top-addr -418 } -419 # otherwise scan to matching paren -420 var paren-count/ebx: int <- copy 1 -421 i <- decrement -422 { -423 compare i, 0 -424 break-if-< -425 var g/esi: (addr code-point-utf8) <- index data, i -426 compare *g, 0x28/open-paren -427 { -428 break-if-!= -429 paren-count <- increment -430 } -431 compare *g, 0x29/close-paren -432 { -433 break-if-!= -434 compare paren-count, 1 -435 { -436 break-if-!= -437 return i -438 } -439 paren-count <- decrement -440 } -441 i <- decrement -442 loop -443 } -444 return *top-addr -445 } -446 -447 # return the index of the first open-paren at the given depth -448 # or top index if there's no matching close-paren -449 fn get-matching-open-paren-index _self: (addr grapheme-stack), control: boolean, depth: int -> _/edx: int { -450 var self/esi: (addr grapheme-stack) <- copy _self -451 var top-addr/edx: (addr int) <- get self, top -452 # if not rendering cursor, return -453 compare control, 0/false -454 { -455 break-if-!= -456 return *top-addr -457 } -458 var data-ah/eax: (addr handle array code-point-utf8) <- get self, data -459 var data/eax: (addr array code-point-utf8) <- lookup *data-ah -460 var i/ecx: int <- copy *top-addr -461 # if stack is empty, return -462 compare i, 0 -463 { -464 break-if-> -465 return *top-addr -466 } -467 # scan to matching open paren -468 var paren-count/ebx: int <- copy 0 -469 i <- decrement -470 { -471 compare i, 0 -472 break-if-< -473 var g/esi: (addr code-point-utf8) <- index data, i -474 compare *g, 0x29/close-paren -475 { -476 break-if-!= -477 paren-count <- increment -478 } -479 compare *g, 0x28/open-paren -480 { -481 break-if-!= -482 compare paren-count, depth -483 { -484 break-if-!= -485 return i -486 } -487 paren-count <- decrement -488 } -489 i <- decrement -490 loop -491 } -492 return *top-addr -493 } -494 -495 # compare from bottom -496 # beware: modifies 'stream', which must be disposed of after a false result -497 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean { -498 var self/esi: (addr grapheme-stack) <- copy _self -499 var data-ah/edi: (addr handle array code-point-utf8) <- get self, data -500 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah -501 var data/edi: (addr array code-point-utf8) <- copy _data -502 var top-addr/ecx: (addr int) <- get self, top -503 var i/ebx: int <- copy 0 -504 { -505 compare i, *top-addr -506 break-if->= -507 # if curr != expected, return false -508 { -509 var curr-a/edx: (addr code-point-utf8) <- index data, i -510 var expected/eax: code-point-utf8 <- read-code-point-utf8 s -511 { -512 compare expected, *curr-a -513 break-if-= -514 return 0/false -515 } -516 } -517 i <- increment -518 loop -519 } -520 return 1 # true -521 } -522 -523 # compare from bottom -524 # beware: modifies 'stream', which must be disposed of after a false result -525 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean { -526 var self/esi: (addr grapheme-stack) <- copy _self -527 var data-ah/edi: (addr handle array code-point-utf8) <- get self, data -528 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah -529 var data/edi: (addr array code-point-utf8) <- copy _data -530 var top-addr/eax: (addr int) <- get self, top -531 var i/ebx: int <- copy *top-addr -532 i <- decrement -533 { -534 compare i, 0 -535 break-if-< -536 { -537 var curr-a/edx: (addr code-point-utf8) <- index data, i -538 var expected/eax: code-point-utf8 <- read-code-point-utf8 s -539 # if curr != expected, return false -540 { -541 compare expected, *curr-a -542 break-if-= -543 return 0/false -544 } -545 } -546 i <- decrement -547 loop -548 } -549 return 1 # true -550 } -551 -552 fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean { -553 var self/esi: (addr grapheme-stack) <- copy _self -554 var data-ah/eax: (addr handle array code-point-utf8) <- get self, data -555 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah -556 var data/edx: (addr array code-point-utf8) <- copy _data -557 var top-addr/ecx: (addr int) <- get self, top -558 var i/ebx: int <- copy 0 -559 var result/eax: boolean <- copy 1/true -560 $grapheme-stack-is-integer?:loop: { -561 compare i, *top-addr -562 break-if->= -563 var g/edx: (addr code-point-utf8) <- index data, i -564 result <- decimal-digit? *g -565 compare result, 0/false -566 break-if-= -567 i <- increment -568 loop -569 } -570 return result -571 } +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 # setup: screen +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 # return the index of the matching close-paren of the code-point-utf8 at cursor (top of stack) +394 # or top index if there's no matching close-paren +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 # if not rendering cursor, return +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 # if stack is empty, return +408 compare i, 0 +409 { +410 break-if-> +411 return *top-addr +412 } +413 # if cursor is not '(' return +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 # otherwise scan to matching paren +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 # return the index of the first open-paren at the given depth +450 # or top index if there's no matching close-paren +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 # if not rendering cursor, return +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 # if stack is empty, return +464 compare i, 0 +465 { +466 break-if-> +467 return *top-addr +468 } +469 # scan to matching open paren +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 # compare from bottom +498 # beware: modifies 'stream', which must be disposed of after a false result +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 # if curr != expected, return false +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 # true +523 } +524 +525 # compare from bottom +526 # beware: modifies 'stream', which must be disposed of after a false result +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 # if curr != expected, return false +542 { +543 compare expected, *curr-a +544 break-if-= +545 return 0/false +546 } +547 } +548 i <- decrement +549 loop +550 } +551 return 1 # true +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 }