https://github.com/akkartik/mu/blob/main/linux/tile/gap-buffer.mu
1 type gap-buffer {
2 left: code-point-utf8-stack
3 right: code-point-utf8-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 code-point-utf8-stack) <- get self, left
9 initialize-code-point-utf8-stack left, 0x10/max-word-size
10 var right/eax: (addr code-point-utf8-stack) <- get self, right
11 initialize-code-point-utf8-stack right, 0x10/max-word-size
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/max-word-size)
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/false
23 break-if-!=
24 var g/eax: code-point-utf8 <- read-code-point-utf8 stream
25 add-code-point-utf8-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-array 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 code-point-utf8-stack) <- get self, left
41 emit-stack-from-bottom left, out
42 var right/eax: (addr code-point-utf8-stack) <- get self, right
43 emit-stack-from-top right, out
44 }
45
46
47 fn emit-stack-from-bottom _self: (addr code-point-utf8-stack), out: (addr stream byte) {
48 var self/esi: (addr code-point-utf8-stack) <- copy _self
49 var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
50 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
51 var data/edi: (addr array code-point-utf8) <- 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 code-point-utf8) <- index data, i
58 write-code-point-utf8 out, *g
59 i <- increment
60 loop
61 }
62 }
63
64
65 fn emit-stack-from-top _self: (addr code-point-utf8-stack), out: (addr stream byte) {
66 var self/esi: (addr code-point-utf8-stack) <- copy _self
67 var data-ah/edi: (addr handle array code-point-utf8) <- get self, data
68 var _data/eax: (addr array code-point-utf8) <- lookup *data-ah
69 var data/edi: (addr array code-point-utf8) <- 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 code-point-utf8) <- index data, i
77 write-code-point-utf8 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 code-point-utf8-stack) <- get gap, left
86 render-stack-from-bottom left, screen
87 var right/eax: (addr code-point-utf8-stack) <- get gap, right
88 render-stack-from-top right, screen
89 }
90
91 fn gap-buffer-length _gap: (addr gap-buffer) -> _/eax: int {
92 var gap/esi: (addr gap-buffer) <- copy _gap
93 var left/eax: (addr code-point-utf8-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 code-point-utf8-stack) <- get gap, right
97 tmp <- get right, top
98 var result/eax: int <- copy *tmp
99 result <- add left-length
100 return result
101 }
102
103 fn add-code-point-utf8-at-gap _self: (addr gap-buffer), g: code-point-utf8 {
104 var self/esi: (addr gap-buffer) <- copy _self
105 var left/eax: (addr code-point-utf8-stack) <- get self, left
106 push-code-point-utf8-stack left, g
107 }
108
109 fn gap-to-start self: (addr gap-buffer) {
110 {
111 var curr/eax: code-point-utf8 <- gap-left self
112 compare curr, -1
113 loop-if-!=
114 }
115 }
116
117 fn gap-to-end self: (addr gap-buffer) {
118 {
119 var curr/eax: code-point-utf8 <- gap-right self
120 compare curr, -1
121 loop-if-!=
122 }
123 }
124
125 fn gap-at-start? _self: (addr gap-buffer) -> _/eax: boolean {
126 var self/esi: (addr gap-buffer) <- copy _self
127 var left/eax: (addr code-point-utf8-stack) <- get self, left
128 var result/eax: boolean <- code-point-utf8-stack-empty? left
129 return result
130 }
131
132 fn gap-at-end? _self: (addr gap-buffer) -> _/eax: boolean {
133 var self/esi: (addr gap-buffer) <- copy _self
134 var right/eax: (addr code-point-utf8-stack) <- get self, right
135 var result/eax: boolean <- code-point-utf8-stack-empty? right
136 return result
137 }
138
139 fn gap-right _self: (addr gap-buffer) -> _/eax: code-point-utf8 {
140 var self/esi: (addr gap-buffer) <- copy _self
141 var g/eax: code-point-utf8 <- copy 0
142 var right/ecx: (addr code-point-utf8-stack) <- get self, right
143 g <- pop-code-point-utf8-stack right
144 compare g, -1
145 {
146 break-if-=
147 var left/ecx: (addr code-point-utf8-stack) <- get self, left
148 push-code-point-utf8-stack left, g
149 }
150 return g
151 }
152
153 fn gap-left _self: (addr gap-buffer) -> _/eax: code-point-utf8 {
154 var self/esi: (addr gap-buffer) <- copy _self
155 var g/eax: code-point-utf8 <- copy 0
156 {
157 var left/ecx: (addr code-point-utf8-stack) <- get self, left
158 g <- pop-code-point-utf8-stack left
159 }
160 compare g, -1
161 {
162 break-if-=
163 var right/ecx: (addr code-point-utf8-stack) <- get self, right
164 push-code-point-utf8-stack right, g
165 }
166 return g
167 }
168
169 fn gap-index _self: (addr gap-buffer) -> _/eax: int {
170 var self/eax: (addr gap-buffer) <- copy _self
171 var left/eax: (addr code-point-utf8-stack) <- get self, left
172 var top-addr/eax: (addr int) <- get left, top
173 var result/eax: int <- copy *top-addr
174 return result
175 }
176
177 fn first-code-point-utf8-in-gap-buffer _self: (addr gap-buffer) -> _/eax: code-point-utf8 {
178 var self/esi: (addr gap-buffer) <- copy _self
179
180 var left/eax: (addr code-point-utf8-stack) <- get self, left
181 var top-addr/ecx: (addr int) <- get left, top
182 compare *top-addr, 0
183 {
184 break-if-<=
185 var data-ah/eax: (addr handle array code-point-utf8) <- get left, data
186 var data/eax: (addr array code-point-utf8) <- lookup *data-ah
187 var result-addr/eax: (addr code-point-utf8) <- index data, 0
188 return *result-addr
189 }
190
191 var right/eax: (addr code-point-utf8-stack) <- get self, right
192 top-addr <- get right, top
193 compare *top-addr, 0
194 {
195 break-if-<=
196 var data-ah/eax: (addr handle array code-point-utf8) <- get right, data
197 var data/eax: (addr array code-point-utf8) <- lookup *data-ah
198 var top/ecx: int <- copy *top-addr
199 top <- decrement
200 var result-addr/eax: (addr code-point-utf8) <- index data, top
201 return *result-addr
202 }
203
204 return -1
205 }
206
207 fn code-point-utf8-before-cursor-in-gap-buffer _self: (addr gap-buffer) -> _/eax: code-point-utf8 {
208 var self/esi: (addr gap-buffer) <- copy _self
209
210 var left/ecx: (addr code-point-utf8-stack) <- get self, left
211 var top-addr/edx: (addr int) <- get left, top
212 compare *top-addr, 0
213 {
214 break-if-<=
215 var result/eax: code-point-utf8 <- pop-code-point-utf8-stack left
216 push-code-point-utf8-stack left, result
217 return result
218 }
219
220 return -1
221 }
222
223 fn delete-before-gap _self: (addr gap-buffer) {
224 var self/eax: (addr gap-buffer) <- copy _self
225 var left/eax: (addr code-point-utf8-stack) <- get self, left
226 var dummy/eax: code-point-utf8 <- pop-code-point-utf8-stack left
227 }
228
229 fn pop-after-gap _self: (addr gap-buffer) -> _/eax: code-point-utf8 {
230 var self/eax: (addr gap-buffer) <- copy _self
231 var right/eax: (addr code-point-utf8-stack) <- get self, right
232 var result/eax: code-point-utf8 <- pop-code-point-utf8-stack right
233 return result
234 }
235
236 fn gap-buffer-equal? _self: (addr gap-buffer), s: (addr array byte) -> _/eax: boolean {
237 var self/esi: (addr gap-buffer) <- copy _self
238
239
240
241 var stream-storage: (stream byte 0x10/max-word-size)
242 var expected-stream/ecx: (addr stream byte) <- address stream-storage
243 write expected-stream, s
244
245 var left/edx: (addr code-point-utf8-stack) <- get self, left
246 var result/eax: boolean <- prefix-match? left, expected-stream
247 compare result, 0/false
248 {
249 break-if-!=
250 return result
251 }
252
253 var right/edx: (addr code-point-utf8-stack) <- get self, right
254 result <- suffix-match? right, expected-stream
255 compare result, 0/false
256 {
257 break-if-!=
258 return result
259 }
260
261 result <- stream-empty? expected-stream
262 return result
263 }
264
265 fn test-gap-buffer-equal-from-end? {
266 var _g: gap-buffer
267 var g/esi: (addr gap-buffer) <- address _g
268 initialize-gap-buffer g
269
270 var c/eax: code-point-utf8 <- copy 0x61/a
271 add-code-point-utf8-at-gap g, c
272 add-code-point-utf8-at-gap g, c
273 add-code-point-utf8-at-gap g, c
274
275 var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
276 var result/eax: int <- copy _result
277 check-ints-equal result, 1, "F - test-gap-buffer-equal-from-end?"
278 }
279
280 fn test-gap-buffer-equal-from-middle? {
281 var _g: gap-buffer
282 var g/esi: (addr gap-buffer) <- address _g
283 initialize-gap-buffer g
284
285 var c/eax: code-point-utf8 <- copy 0x61/a
286 add-code-point-utf8-at-gap g, c
287 add-code-point-utf8-at-gap g, c
288 add-code-point-utf8-at-gap g, c
289 var dummy/eax: code-point-utf8 <- gap-left g
290
291 var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
292 var result/eax: int <- copy _result
293 check-ints-equal result, 1, "F - test-gap-buffer-equal-from-middle?"
294 }
295
296 fn test-gap-buffer-equal-from-start? {
297 var _g: gap-buffer
298 var g/esi: (addr gap-buffer) <- address _g
299 initialize-gap-buffer g
300
301 var c/eax: code-point-utf8 <- copy 0x61/a
302 add-code-point-utf8-at-gap g, c
303 add-code-point-utf8-at-gap g, c
304 add-code-point-utf8-at-gap g, c
305 var dummy/eax: code-point-utf8 <- gap-left g
306 dummy <- gap-left g
307 dummy <- gap-left g
308
309 var _result/eax: boolean <- gap-buffer-equal? g, "aaa"
310 var result/eax: int <- copy _result
311 check-ints-equal result, 1, "F - test-gap-buffer-equal-from-start?"
312 }
313
314 fn copy-gap-buffer _src-ah: (addr handle gap-buffer), _dest-ah: (addr handle gap-buffer) {
315
316 var src-ah/eax: (addr handle gap-buffer) <- copy _src-ah
317 var _src-a/eax: (addr gap-buffer) <- lookup *src-ah
318 var src-a/esi: (addr gap-buffer) <- copy _src-a
319 var dest-ah/eax: (addr handle gap-buffer) <- copy _dest-ah
320 var _dest-a/eax: (addr gap-buffer) <- lookup *dest-ah
321 var dest-a/edi: (addr gap-buffer) <- copy _dest-a
322
323 var src/ecx: (addr code-point-utf8-stack) <- get src-a, left
324 var dest/edx: (addr code-point-utf8-stack) <- get dest-a, left
325 copy-code-point-utf8-stack src, dest
326
327 src <- get src-a, right
328 dest <- get dest-a, right
329 copy-code-point-utf8-stack src, dest
330 }
331
332 fn gap-buffer-is-decimal-integer? _self: (addr gap-buffer) -> _/eax: boolean {
333 var self/esi: (addr gap-buffer) <- copy _self
334 var curr/ecx: (addr code-point-utf8-stack) <- get self, left
335 var result/eax: boolean <- code-point-utf8-stack-is-decimal-integer? curr
336 {
337 compare result, 0/false
338 break-if-=
339 curr <- get self, right
340 result <- code-point-utf8-stack-is-decimal-integer? curr
341 }
342 return result
343 }