https://github.com/akkartik/mu/blob/master/apps/tile/grapheme-stack.mu
  1 type grapheme-stack {
  2   data: (handle array grapheme)
  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 grapheme) <- 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 grapheme-stack-empty? _self: (addr grapheme-stack) -> result/eax: boolean {
 15 $grapheme-stack-empty?:body: {
 16   var self/esi: (addr grapheme-stack) <- copy _self
 17   var top/eax: (addr int) <- get self, top
 18   compare *top, 0
 19   {
 20     break-if-=
 21     result <- copy 1  # false
 22     break $grapheme-stack-empty?:body
 23   }
 24   result <- copy 0  # false
 25 }
 26 }
 27 
 28 fn push-grapheme-stack _self: (addr grapheme-stack), _val: grapheme {
 29   var self/esi: (addr grapheme-stack) <- copy _self
 30   var top-addr/ecx: (addr int) <- get self, top
 31   var data-ah/edx: (addr handle array grapheme) <- get self, data
 32   var data/eax: (addr array grapheme) <- lookup *data-ah
 33   var top/edx: int <- copy *top-addr
 34   var dest-addr/edx: (addr grapheme) <- index data, top
 35   var val/eax: grapheme <- copy _val
 36   copy-to *dest-addr, val
 37   add-to *top-addr, 1
 38 }
 39 
 40 fn pop-grapheme-stack _self: (addr grapheme-stack) -> val/eax: grapheme {
 41 $pop-grapheme-stack:body: {
 42   var self/esi: (addr grapheme-stack) <- copy _self
 43   var top-addr/ecx: (addr int) <- get self, top
 44   {
 45     compare *top-addr, 0
 46     break-if->
 47     val <- copy -1
 48     break $pop-grapheme-stack:body
 49   }
 50   subtract-from *top-addr, 1
 51   var data-ah/edx: (addr handle array grapheme) <- get self, data
 52   var data/eax: (addr array grapheme) <- lookup *data-ah
 53   var top/edx: int <- copy *top-addr
 54   var result-addr/eax: (addr grapheme) <- index data, top
 55   val <- copy *result-addr
 56 }
 57 }
 58 
 59 # dump stack to screen from bottom to top
 60 # don't move the cursor or anything
 61 fn render-stack-from-bottom _self: (addr grapheme-stack), screen: (addr screen) {
 62   var self/esi: (addr grapheme-stack) <- copy _self
 63   var data-ah/edi: (addr handle array grapheme) <- get self, data
 64   var _data/eax: (addr array grapheme) <- lookup *data-ah
 65   var data/edi: (addr array grapheme) <- copy _data
 66   var top-addr/ecx: (addr int) <- get self, top
 67   var i/eax: int <- copy 0
 68   {
 69     compare i, *top-addr
 70     break-if->=
 71     var g/edx: (addr grapheme) <- index data, i
 72     print-grapheme screen, *g
 73     i <- increment
 74     loop
 75   }
 76 }
 77 
 78 # dump stack to screen from top to bottom
 79 # don't move the cursor or anything
 80 fn render-stack-from-top _self: (addr grapheme-stack), screen: (addr screen) {
 81   var self/esi: (addr grapheme-stack) <- copy _self
 82   var data-ah/edi: (addr handle array grapheme) <- get self, data
 83   var _data/eax: (addr array grapheme) <- lookup *data-ah
 84   var data/edi: (addr array grapheme) <- copy _data
 85   var top-addr/ecx: (addr int) <- get self, top
 86   var i/eax: int <- copy *top-addr
 87   i <- decrement
 88   {
 89     compare i, 0
 90     break-if-<
 91     var g/edx: (addr grapheme) <- index data, i
 92     print-grapheme screen, *g
 93     i <- decrement
 94     loop
 95   }
 96 }
 97 
 98 # compare from bottom
 99 # beware: modifies 'stream', which must be disposed of after a false result
100 fn prefix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> result/eax: boolean {
101 $prefix-match?:body: {
102   var self/esi: (addr grapheme-stack) <- copy _self
103   var data-ah/edi: (addr handle array grapheme) <- get self, data
104   var _data/eax: (addr array grapheme) <- lookup *data-ah
105   var data/edi: (addr array grapheme) <- copy _data
106   var top-addr/ecx: (addr int) <- get self, top
107   var i/ebx: int <- copy 0
108   {
109     compare i, *top-addr
110     break-if->=
111     # if curr != expected, return false
112     {
113       var curr-a/edx: (addr grapheme) <- index data, i
114       var expected/eax: grapheme <- read-grapheme s
115       {
116         compare expected, *curr-a
117         break-if-=
118         result <- copy 0  # false
119         break $prefix-match?:body
120       }
121     }
122     i <- increment
123     loop
124   }
125   result <- copy 1   # true
126 }
127 }
128 
129 # compare from bottom
130 # beware: modifies 'stream', which must be disposed of after a false result
131 fn suffix-match? _self: (addr grapheme-stack), s: (addr stream byte) -> result/eax: boolean {
132 $suffix-match?:body: {
133   var self/esi: (addr grapheme-stack) <- copy _self
134   var data-ah/edi: (addr handle array grapheme) <- get self, data
135   var _data/eax: (addr array grapheme) <- lookup *data-ah
136   var data/edi: (addr array grapheme) <- copy _data
137   var top-addr/eax: (addr int) <- get self, top
138   var i/ebx: int <- copy *top-addr
139   i <- decrement
140   {
141     compare i, 0
142     break-if-<
143     {
144       var curr-a/edx: (addr grapheme) <- index data, i
145       var expected/eax: grapheme <- read-grapheme s
146       # if curr != expected, return false
147       {
148         compare expected, *curr-a
149         break-if-=
150         result <- copy 0  # false
151         break $suffix-match?:body
152       }
153     }
154     i <- decrement
155     loop
156   }
157   result <- copy 1   # true
158 }
159 }