https://github.com/akkartik/mu/blob/main/linux/tile/grapheme-stack.mu
  1 type grapheme-stack {
  2   data: (handle array code-point-utf8)
  3   top: int
  4 }
  5 
  6 fn initialize-grapheme-stack _self: (addr grapheme-stack), n: int {
  7   var self/esi: (addr grapheme-stack) <- copy _self
  8   var d/edi: (addr handle array code-point-utf8) <- get self, data
  9   populate d, n
 10   var top/eax: (addr int) <- get self, top
 11   copy-to *top, 0
 12 }
 13 
 14 fn clear-grapheme-stack _self: (addr grapheme-stack) {
 15   var self/esi: (addr grapheme-stack) <- copy _self
 16   var top/eax: (addr int) <- get self, top
 17   copy-to *top, 0
 18 }
 19 
 20 fn grapheme-stack-empty? _self: (addr grapheme-stack) -> _/eax: boolean {
 21   var self/esi: (addr grapheme-stack) <- copy _self
 22   var top/eax: (addr int) <- get self, top
 23   compare *top, 0
 24   {
 25     break-if-!=
 26     return 1/true
 27   }
 28   return 0/false
 29 }
 30 
 31 fn push-grapheme-stack _self: (addr grapheme-stack), _val: code-point-utf8 {
 32   var self/esi: (addr grapheme-stack) <- copy _self
 33   var top-addr/ecx: (addr int) <- get self, top
 34   var data-ah/edx: (addr handle array code-point-utf8) <- get self, data
 35   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
 36   var top/edx: int <- copy *top-addr
 37   var dest-addr/edx: (addr code-point-utf8) <- index data, top
 38   var val/eax: code-point-utf8 <- copy _val
 39   copy-to *dest-addr, val
 40   add-to *top-addr, 1
 41 }
 42 
 43 fn pop-grapheme-stack _self: (addr grapheme-stack) -> _/eax: code-point-utf8 {
 44   var self/esi: (addr grapheme-stack) <- copy _self
 45   var top-addr/ecx: (addr int) <- get self, top
 46   {
 47     compare *top-addr, 0
 48     break-if->
 49     return -1
 50   }
 51   subtract-from *top-addr, 1
 52   var data-ah/edx: (addr handle array code-point-utf8) <- get self, data
 53   var data/eax: (addr array code-point-utf8) <- lookup *data-ah
 54   var top/edx: int <- copy *top-addr
 55   var result-addr/eax: (addr code-point-utf8) <- index data, top
 56   return *result-addr
 57 }
 58 
 59 fn copy-grapheme-stack _src: (addr grapheme-stack), dest: (addr grapheme-stack) {
 60   var src/esi: (addr grapheme-stack) <- copy _src
 61   var data-ah/edi: (addr handle array code-point-utf8) <- get src, data
 62   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
 63   var data/edi: (addr array code-point-utf8) <- copy _data
 64   var top-addr/ecx: (addr int) <- get src, top
 65   var i/eax: int <- copy 0
 66   {
 67     compare i, *top-addr
 68     break-if->=
 69     var g/edx: (addr code-point-utf8) <- index data, i
 70     push-grapheme-stack dest, *g
 71     i <- increment
 72     loop
 73   }
 74 }
 75 
 76 # dump stack to screen from bottom to top
 77 # don't move the cursor or anything
 78 fn render-stack-from-bottom _self: (addr grapheme-stack), screen: (addr screen) {
 79   var self/esi: (addr grapheme-stack) <- copy _self
 80   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
 81   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
 82   var data/edi: (addr array code-point-utf8) <- copy _data
 83   var top-addr/ecx: (addr int) <- get self, top
 84   var i/eax: int <- copy 0
 85   {
 86     compare i, *top-addr
 87     break-if->=
 88     var g/edx: (addr code-point-utf8) <- index data, i
 89     print-code-point-utf8 screen, *g
 90     i <- increment
 91     loop
 92   }
 93 }
 94 
 95 # dump stack to screen from top to bottom
 96 # don't move the cursor or anything
 97 fn render-stack-from-top _self: (addr grapheme-stack), screen: (addr screen) {
 98   var self/esi: (addr grapheme-stack) <- copy _self
 99   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
100   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
101   var data/edi: (addr array code-point-utf8) <- copy _data
102   var top-addr/ecx: (addr int) <- get self, top
103   var i/eax: int <- copy *top-addr
104   i <- decrement
105   {
106     compare i, 0
107     break-if-<
108     var g/edx: (addr code-point-utf8) <- index data, i
109     print-code-point-utf8 screen, *g
110     i <- decrement
111     loop
112   }
113 }
114 
115 # compare from bottom
116 # beware: modifies 'stream', which must be disposed of after a false result
117 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
118   var self/esi: (addr grapheme-stack) <- copy _self
119   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
120   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
121   var data/edi: (addr array code-point-utf8) <- copy _data
122   var top-addr/ecx: (addr int) <- get self, top
123   var i/ebx: int <- copy 0
124   {
125     compare i, *top-addr
126     break-if->=
127     # if curr != expected, return false
128     {
129       var curr-a/edx: (addr code-point-utf8) <- index data, i
130       var expected/eax: code-point-utf8 <- read-code-point-utf8 s
131       {
132         compare expected, *curr-a
133         break-if-=
134         return 0/false
135       }
136     }
137     i <- increment
138     loop
139   }
140   return 1   # true
141 }
142 
143 # compare from bottom
144 # beware: modifies 'stream', which must be disposed of after a false result
145 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> _/eax: boolean {
146   var self/esi: (addr grapheme-stack) <- copy _self
147   var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
148   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
149   var data/edi: (addr array code-point-utf8) <- copy _data
150   var top-addr/eax: (addr int) <- get self, top
151   var i/ebx: int <- copy *top-addr
152   i <- decrement
153   {
154     compare i, 0
155     break-if-<
156     {
157       var curr-a/edx: (addr code-point-utf8) <- index data, i
158       var expected/eax: code-point-utf8 <- read-code-point-utf8 s
159       # if curr != expected, return false
160       {
161         compare expected, *curr-a
162         break-if-=
163         return 0/false
164       }
165     }
166     i <- decrement
167     loop
168   }
169   return 1   # true
170 }
171 
172 fn grapheme-stack-is-decimal-integer? _self: (addr grapheme-stack) -> _/eax: boolean {
173   var self/esi: (addr grapheme-stack) <- copy _self
174   var data-ah/eax: (addr handle array code-point-utf8) <- get self, data
175   var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
176   var data/edx: (addr array code-point-utf8) <- copy _data
177   var top-addr/ecx: (addr int) <- get self, top
178   var i/ebx: int <- copy 0
179   var result/eax: boolean <- copy 1/true
180   $grapheme-stack-is-integer?:loop: {
181     compare i, *top-addr
182     break-if->=
183     var g/edx: (addr code-point-utf8) <- index data, i
184     result <- decimal-digit? *g
185     compare result, 0/false
186     break-if-=
187     i <- increment
188     loop
189   }
190   return result
191 }