https://github.com/akkartik/mu/blob/master/apps/tile/gap-buffer.mu
1 type gap-buffer {
2 left: grapheme-stack
3 right: grapheme-stack
4 }
5
6 fn initialize-gap-buffer _self: (addr gap-buffer) {
7 var self/esi: (addr gap-buffer) <- copy _self
8 var left/eax: (addr grapheme-stack) <- get self, left
9 initialize-grapheme-stack left, 0x10
10 var right/eax: (addr grapheme-stack) <- get self, right
11 initialize-grapheme-stack right, 0x10
12 }
13
14
15 fn initialize-gap-buffer-with self: (addr gap-buffer), s: (addr array byte) {
16 initialize-gap-buffer self
17 var stream-storage: (stream byte 0x10)
18 var stream/ecx: (addr stream byte) <- address stream-storage
19 write stream, s
20 {
21 var done?/eax: boolean <- stream-empty? stream
22 compare done?, 0
23 break-if-!=
24 var g/eax: grapheme <- read-grapheme stream
25 add-grapheme-at-gap self, g
26 loop
27 }
28 }
29
30 fn gap-buffer-to-string self: (addr gap-buffer), out: (addr handle array byte) {
31 var s-storage: (stream byte 0x100)
32 var s/ecx: (addr stream byte) <- address s-storage
33 emit-gap-buffer self, s
34 stream-to-string s, out
35 }
36
37 fn emit-gap-buffer _self: (addr gap-buffer), out: (addr stream byte) {
38 var self/esi: (addr gap-buffer) <- copy _self
39 clear-stream out
40 var left/eax: (addr grapheme-stack) <- get self, left
41 emit-stack-from-bottom left, out
42 var right/eax: (addr grapheme-stack) <- get self, right
43 emit-stack-from-top right, out
44 }
45
46
47 fn emit-stack-from-bottom _self: (addr grapheme-stack), out: (addr stream byte) {
48 var self/esi: (addr grapheme-stack) <- copy _self
49 var data-ah/edi: (addr handle array grapheme) <- get self, data
50 var _data/eax: (addr array grapheme) <- lookup *data-ah
51 var data/edi: (addr array grapheme) <- copy _data
52 var top-addr/ecx: (addr int) <- get self, top
53 var i/eax: int <- copy 0
54 {
55 compare i, *top-addr
56 break-if->=
57 var g/edx: (addr grapheme) <- index data, i
58 write-grapheme out, *g
59 i <- increment
60 loop
61 }
62 }
63
64
65 fn emit-stack-from-top _self: (addr grapheme-stack), out: (addr stream byte) {
66 var self/esi: (addr grapheme-stack) <- copy _self
67 var data-ah/edi: (addr handle array grapheme) <- get self, data
68 var _data/eax: (addr array grapheme) <- lookup *data-ah
69 var data/edi: (addr array grapheme) <- copy _data
70 var top-addr/ecx: (addr int) <- get self, top
71 var i/eax: int <- copy *top-addr
72 i <- decrement
73 {
74 compare i, 0
75 break-if-<
76 var g/edx: (addr grapheme) <- index data, i
77 write-grapheme out, *g
78 i <- decrement
79 loop
80 }
81 }
82
83 fn render-gap-buffer screen: (addr screen), _gap: (addr gap-buffer) {
84 var gap/esi: (addr gap-buffer) <- copy _gap
85 var left/eax: (addr grapheme-stack) <- get gap, left
86 render-stack-from-bottom left, screen
87 var right/eax: (addr grapheme-stack) <- get gap, right
88 render-stack-from-top right, screen
89 }
90
91 fn gap-buffer-length _gap: (addr gap-buffer) -> result/eax: int {
92 var gap/esi: (addr gap-buffer) <- copy _gap
93 var left/eax: (addr grapheme-stack) <- get gap, left
94 var tmp/eax: (addr int) <- get left, top
95 var left-length/ecx: int <- copy *tmp
96 var right/esi: (addr grapheme-stack) <- get gap, right
97 tmp <- get right, top
98 result <- copy *tmp
99 result <- add left-length
100 }
101
102 fn add-grapheme-at-gap _self: (addr gap-buffer), g: grapheme {
103 var self/esi: (addr gap-buffer) <- copy _self
104 var left/eax: (addr grapheme-stack) <- get self, left
105 push-grapheme-stack left, g
106 }
107
108 fn gap-to-start self: (addr gap-buffer) {
109 {
110 var curr/eax: grapheme <- gap-left self
111 compare curr, -1
112 loop-if-!=
113 }
114 }
115
116 fn gap-to-end self: (addr gap-buffer) {
117 {
118 var curr/eax: grapheme <- gap-right self
119 compare curr, -1
120 loop-if-!=
121 }
122 }
123
124 fn gap-at-start? _self: (addr gap-buffer) -> result/eax: boolean {
125 var self/esi: (addr gap-buffer) <- copy _self
126 var left/eax: (addr grapheme-stack) <- get self, left
127 result <- grapheme-stack-empty? left
128 }
129
130 fn gap-at-end? _self: (addr gap-buffer) -> result/eax: boolean {
131 var self/esi: (addr gap-buffer) <- copy _self
132 var right/eax: (addr grapheme-stack) <- get self, right
133 result <- grapheme-stack-empty? right
134 }
135
136 fn gap-right _self: (addr gap-buffer) -> result/eax: grapheme {
137 $gap-right:body: {
138 var self/esi: (addr gap-buffer) <- copy _self
139 var g/edx: grapheme <- copy 0
140 {
141 var right/ecx: (addr grapheme-stack) <- get self, right
142 result <- pop-grapheme-stack right
143 compare result, -1
144 break-if-= $gap-right:body
145 g <- copy result
146 }
147 {
148 var left/ecx: (addr grapheme-stack) <- get self, left
149 push-grapheme-stack left, g
150 }
151 }
152 }
153
154 fn gap-left _self: (addr gap-buffer) -> result/eax: grapheme {
155 $gap-left:body: {
156 var self/esi: (addr gap-buffer) <- copy _self
157 var g/edx: grapheme <- copy 0
158 {
159 var left/ecx: (addr grapheme-stack) <- get self, left
160 result <- pop-grapheme-stack left
161 compare result, -1
162 break-if-= $gap-left:body
163 g <- copy result
164 }
165 {
166 var right/ecx: (addr grapheme-stack) <- get self, right
167 push-grapheme-stack right, g
168 }
169 }
170 }
171
172 fn gap-index _self: (addr gap-buffer) -> result/eax: int {
173 var self/eax: (addr gap-buffer) <- copy _self
174 var left/eax: (addr grapheme-stack) <- get self, left
175 var top-addr/eax: (addr int) <- get left, top
176 result <- copy *top-addr
177 }
178
179 fn first-grapheme-in-gap-buffer _self: (addr gap-buffer) -> result/eax: grapheme {
180 $first-grapheme-in-gap-buffer:body: {
181 var self/esi: (addr gap-buffer) <- copy _self
182
183 var left/eax: (addr grapheme-stack) <- get self, left
184 var top-addr/ecx: (addr int) <- get left, top
185 compare *top-addr, 0
186 {
187 break-if-<=
188 var data-ah/eax: (addr handle array grapheme) <- get left, data
189 var data/eax: (addr array grapheme) <- lookup *data-ah
190 var result-addr/eax: (addr grapheme) <- index data, 0
191 result <- copy *result-addr
192 break $first-grapheme-in-gap-buffer:body
193 }
194
195 var right/eax: (addr grapheme-stack) <- get self, right
196 top-addr <- get right, top
197 compare *top-addr, 0
198 {
199 break-if-<=
200 var data-ah/eax: (addr handle array grapheme) <- get right, data
201 var data/eax: (addr array grapheme) <- lookup *data-ah
202 var top/ecx: int <- copy *top-addr
203 top <- decrement
204 var result-addr/eax: (addr grapheme) <- index data, top
205 result <- copy *result-addr
206 break $first-grapheme-in-gap-buffer:body
207 }
208
209 result <- copy -1
210 }
211 }
212
213 fn delete-before-gap _self: (addr gap-buffer) {
214 var self/eax: (addr gap-buffer) <- copy _self
215 var left/eax: (addr grapheme-stack) <- get self, left
216 var dummy/eax: grapheme <- pop-grapheme-stack left
217 }
218
219 fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> result/eax: boolean {
220 $gap-buffer-equal?:body: {
221 var self/esi: (addr gap-buffer) <- copy _self
222
223
224
225 var stream-storage: (stream byte 0x10)
226 var expected-stream/ecx: (addr stream byte) <- address stream-storage
227 write expected-stream, s
228
229 var left/edx: (addr grapheme-stack) <- get self, left
230 result <- prefix-match? left, expected-stream
231 compare result, 0
232 break-if-= $gap-buffer-equal?:body
233
234 var right/edx: (addr grapheme-stack) <- get self, right
235 result <- suffix-match? right, expected-stream
236 compare result, 0
237 break-if-= $gap-buffer-equal?:body
238
239 result <- stream-empty? expected-stream
240 }
241 }
242
243 fn test-gap-buffer-equal-from-end? {
244 var _g: gap-buffer
245 var g/esi: (addr gap-buffer) <- address _g
246 initialize-gap-buffer g
247
248 var c/eax: grapheme <- copy 0x61
249 add-grapheme-at-gap g, c
250 add-grapheme-at-gap g, c
251 add-grapheme-at-gap g, c
252
253 var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
254 var result/eax: int <- copy _result
255 check-ints-equal result, 1, "F - test-gap-buffer-equal-from-end?"
256 }
257
258 fn test-gap-buffer-equal-from-middle? {
259 var _g: gap-buffer
260 var g/esi: (addr gap-buffer) <- address _g
261 initialize-gap-buffer g
262
263 var c/eax: grapheme <- copy 0x61
264 add-grapheme-at-gap g, c
265 add-grapheme-at-gap g, c
266 add-grapheme-at-gap g, c
267 var dummy/eax: grapheme <- gap-left g
268
269 var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
270 var result/eax: int <- copy _result
271 check-ints-equal result, 1, "F - test-gap-buffer-equal-from-middle?"
272 }
273
274 fn test-gap-buffer-equal-from-start? {
275 var _g: gap-buffer
276 var g/esi: (addr gap-buffer) <- address _g
277 initialize-gap-buffer g
278
279 var c/eax: grapheme <- copy 0x61
280 add-grapheme-at-gap g, c
281 add-grapheme-at-gap g, c
282 add-grapheme-at-gap g, c
283 var dummy/eax: grapheme <- gap-left g
284 dummy <- gap-left g
285 dummy <- gap-left g
286
287 var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
288 var result/eax: int <- copy _result
289 check-ints-equal result, 1, "F - test-gap-buffer-equal-from-start?"
290 }