https://github.com/akkartik/mu/blob/master/apps/tile/value.mu
  1 fn render-value-at screen: (addr screen), row: int, col: int, _val: (addr value), max-width: int {
  2   move-cursor screen, row, col
  3   var val/esi: (addr value) <- copy _val
  4   var val-type/ecx: (addr int) <- get val, type
  5   # per-type rendering logic goes here
  6   compare *val-type, 1  # string
  7   {
  8     break-if-!=
  9     var val-ah/eax: (addr handle array byte) <- get val, text-data
 10     var val-string/eax: (addr array byte) <- lookup *val-ah
 11     compare val-string, 0
 12     break-if-=
 13     var orig-len/ecx: int <- length val-string
 14     var truncated: (handle array byte)
 15     var truncated-ah/esi: (addr handle array byte) <- address truncated
 16     substring val-string, 0, 0xc, truncated-ah
 17     var truncated-string/eax: (addr array byte) <- lookup *truncated-ah
 18     var len/edx: int <- length truncated-string
 19     start-color screen, 0xf2, 7
 20     print-code-point screen, 0x275d  # open-quote
 21     print-string screen, truncated-string
 22     compare len, orig-len
 23     {
 24       break-if-=
 25       print-code-point screen, 0x2026  # ellipses
 26     }
 27     print-code-point screen, 0x275e  # close-quote
 28     reset-formatting screen
 29     return
 30   }
 31   compare *val-type, 2  # array
 32   {
 33     break-if-!=
 34     var val-ah/eax: (addr handle array value) <- get val, array-data
 35     var val-array/eax: (addr array value) <- lookup *val-ah
 36     render-array-at screen, row, col, val-array
 37     return
 38   }
 39   compare *val-type, 3  # file
 40   {
 41     break-if-!=
 42     var val-ah/eax: (addr handle buffered-file) <- get val, file-data
 43     var val-file/eax: (addr buffered-file) <- lookup *val-ah
 44     start-color screen, 0, 7
 45     # TODO
 46     print-string screen, " FILE "
 47     return
 48   }
 49   compare *val-type, 4  # screen
 50   {
 51     break-if-!=
 52 #?     print-string 0, "render-screen"
 53     var val-ah/eax: (addr handle screen) <- get val, screen-data
 54     var val-screen/eax: (addr screen) <- lookup *val-ah
 55     render-screen screen, row, col, val-screen
 56 #?     print-string 0, "}\n"
 57     return
 58   }
 59   # render ints by default for now
 60   var val-int/eax: (addr int) <- get val, int-data
 61   render-integer screen, *val-int, max-width
 62 }
 63 
 64 # synaesthesia
 65 fn render-integer screen: (addr screen), val: int, max-width: int {
 66 $render-integer:body: {
 67   # if max-width is 0, we're inside an array. No coloring.
 68   compare max-width, 0
 69   {
 70     break-if-!=
 71     print-int32-decimal screen, val
 72     break $render-integer:body
 73   }
 74   var bg/eax: int <- hash-color val
 75   var fg/ecx: int <- copy 7
 76   {
 77     compare bg, 2
 78     break-if-!=
 79     fg <- copy 0
 80   }
 81   {
 82     compare bg, 3
 83     break-if-!=
 84     fg <- copy 0
 85   }
 86   {
 87     compare bg, 6
 88     break-if-!=
 89     fg <- copy 0
 90   }
 91   start-color screen, fg, bg
 92   print-grapheme screen, 0x20  # space
 93   print-int32-decimal-right-justified screen, val, max-width
 94   print-grapheme screen, 0x20  # space
 95 }
 96 }
 97 
 98 fn render-array-at screen: (addr screen), row: int, col: int, _a: (addr array value) {
 99   start-color screen, 0xf2, 7
100   # don't surround in spaces
101   print-grapheme screen, 0x5b  # '['
102   increment col
103   var a/esi: (addr array value) <- copy _a
104   var max/ecx: int <- length a
105   var i/eax: int <- copy 0
106   {
107     compare i, max
108     break-if->=
109     {
110       compare i, 0
111       break-if-=
112       print-string screen, " "
113     }
114     var off/ecx: (offset value) <- compute-offset a, i
115     var x/ecx: (addr value) <- index a, off
116     render-value-at screen, row, col, x, 0
117     {
118       var w/eax: int <- value-width x, 0
119       add-to col, w
120       increment col
121     }
122     i <- increment
123     loop
124   }
125   print-grapheme screen, 0x5d  # ']'
126 }
127 
128 fn render-screen screen: (addr screen), row: int, col: int, _target-screen: (addr screen) {
129   reset-formatting screen
130   move-cursor screen, row, col
131   var target-screen/esi: (addr screen) <- copy _target-screen
132   var ncols-a/ecx: (addr int) <- get target-screen, num-cols
133   print-upper-border screen, *ncols-a
134   var r/edx: int <- copy 1
135   var nrows-a/ebx: (addr int) <- get target-screen, num-rows
136   {
137     compare r, *nrows-a
138     break-if->
139     increment row  # mutate arg
140     move-cursor screen, row, col
141     print-string screen, " "
142     var c/edi: int <- copy 1
143     {
144       compare c, *ncols-a
145       break-if->
146       print-screen-cell-of-fake-screen screen, target-screen, r, c
147       c <- increment
148       loop
149     }
150     print-string screen, " "
151     r <- increment
152     loop
153   }
154   increment row  # mutate arg
155   move-cursor screen, row, col
156   print-lower-border screen, *ncols-a
157 }
158 
159 fn hash-color val: int -> _/eax: int {
160   var result/eax: int <- try-modulo val, 7  # assumes that 7 is always the background color
161   return result
162 }
163 
164 fn print-screen-cell-of-fake-screen screen: (addr screen), _target: (addr screen), _row: int, _col: int {
165   start-color screen, 0, 0xf6
166   var target/esi: (addr screen) <- copy _target
167   var row/ecx: int <- copy _row
168   var col/edx: int <- copy _col
169   # if cursor is at screen-cell, add some fancy
170   {
171     var cursor-row/eax: (addr int) <- get target, cursor-row
172     compare *cursor-row, row
173     break-if-!=
174     var cursor-col/eax: (addr int) <- get target, cursor-col
175     compare *cursor-col, col
176     break-if-!=
177     start-blinking screen
178     start-color screen, 0, 1
179   }
180   var g/eax: grapheme <- screen-grapheme-at target, row, col
181   {
182     compare g, 0
183     break-if-!=
184     g <- copy 0x20  # space
185   }
186   print-grapheme screen, g
187   reset-formatting screen
188 }
189 
190 fn print-upper-border screen: (addr screen), width: int {
191   print-code-point screen, 0x250c  # top-left corner
192   var i/eax: int <- copy 0
193   {
194     compare i, width
195     break-if->=
196     print-code-point screen, 0x2500  # horizontal line
197     i <- increment
198     loop
199   }
200   print-code-point screen, 0x2510  # top-right corner
201 }
202 
203 fn print-lower-border screen: (addr screen), width: int {
204   print-code-point screen, 0x2514  # bottom-left corner
205   var i/eax: int <- copy 0
206   {
207     compare i, width
208     break-if->=
209     print-code-point screen, 0x2500  # horizontal line
210     i <- increment
211     loop
212   }
213   print-code-point screen, 0x2518  # bottom-right corner
214 }
215 
216 fn value-width _v: (addr value), top-level: boolean -> _/eax: int {
217   var v/esi: (addr value) <- copy _v
218   var type/eax: (addr int) <- get v, type
219   {
220     compare *type, 0  # int
221     break-if-!=
222     var v-int/edx: (addr int) <- get v, int-data
223     var result/eax: int <- decimal-size *v-int
224     return result
225   }
226   {
227     compare *type, 1  # string
228     break-if-!=
229     var s-ah/eax: (addr handle array byte) <- get v, text-data
230     var s/eax: (addr array byte) <- lookup *s-ah
231     compare s, 0
232     break-if-=
233     var result/eax: int <- length s
234     compare result, 0xd  # max string size
235     {
236       break-if-<=
237       result <- copy 0xd
238     }
239     # if it's a nested string, include space for quotes
240     # we don't do this for the top-level, where the quotes will overflow
241     # into surrounding padding.
242     compare top-level, 0  # false
243     {
244       break-if-!=
245       result <- add 2
246     }
247     return result
248   }
249   {
250     compare *type, 2  # array
251     break-if-!=
252     var a-ah/eax: (addr handle array value) <- get v, array-data
253     var a/eax: (addr array value) <- lookup *a-ah
254     compare a, 0
255     break-if-=
256     var result/eax: int <- array-width a
257     return result
258   }
259   {
260     compare *type, 3  # file handle
261     break-if-!=
262     var f-ah/eax: (addr handle buffered-file) <- get v, file-data
263     var f/eax: (addr buffered-file) <- lookup *f-ah
264     compare f, 0
265     break-if-=
266     # TODO: visualizing file handles
267     return 4
268   }
269   {
270     compare *type, 4  # screen
271     break-if-!=
272     var screen-ah/eax: (addr handle screen) <- get v, screen-data
273     var screen/eax: (addr screen) <- lookup *screen-ah
274     compare screen, 0
275     break-if-=
276     var ncols/ecx: (addr int) <- get screen, num-cols
277     var result/eax: int <- copy *ncols
278     result <- add 2  # left/right margins
279     return *ncols
280   }
281   return 0
282 }
283 
284 # keep sync'd with render-array-at
285 fn array-width _a: (addr array value) -> _/eax: int {
286   var a/esi: (addr array value) <- copy _a
287   var max/ecx: int <- length a
288   var i/eax: int <- copy 0
289   var result/edi: int <- copy 0
290   {
291     compare i, max
292     break-if->=
293     {
294       compare i, 0
295       break-if-=
296       result <- increment  # for space
297     }
298     var off/ecx: (offset value) <- compute-offset a, i
299     var x/ecx: (addr value) <- index a, off
300     {
301       var w/eax: int <- value-width x, 0
302       result <- add w
303     }
304     i <- increment
305     loop
306   }
307   # we won't add 2 for surrounding brackets since we don't surround arrays in
308   # spaces like other value types
309   return result
310 }
311 
312 fn value-height _v: (addr value) -> _/eax: int {
313   var v/esi: (addr value) <- copy _v
314   var type/eax: (addr int) <- get v, type
315   {
316     compare *type, 3  # file handle
317     break-if-!=
318     # TODO: visualizing file handles
319     return 1
320   }
321   {
322     compare *type, 4  # screen
323     break-if-!=
324     var screen-ah/eax: (addr handle screen) <- get v, screen-data
325     var screen/eax: (addr screen) <- lookup *screen-ah
326     compare screen, 0
327     break-if-=
328     var nrows/ecx: (addr int) <- get screen, num-rows
329     var result/eax: int <- copy *nrows
330     result <- add 2  # top and bottom border
331     return result
332   }
333   return 1
334 }
335 
336 fn deep-copy-value _src: (addr value), _dest: (addr value) {
337 #?   print-string 0, "deep-copy-value\n"
338   var src/esi: (addr value) <- copy _src
339   var dest/edi: (addr value) <- copy _dest
340   var type/ebx: (addr int) <- get src, type
341   var y/ecx: (addr int) <- get dest, type
342   copy-object type, y
343   compare *type, 0   # int
344   {
345     break-if-!=
346 #?     print-string 0, "int value\n"
347     var x/eax: (addr int) <- get src, int-data
348     y <- get dest, int-data
349     copy-object x, y
350     return
351   }
352   compare *type, 1  # string
353   {
354     break-if-!=
355 #?     print-string 0, "string value\n"
356     var src-ah/eax: (addr handle array byte) <- get src, text-data
357     var src/eax: (addr array byte) <- lookup *src-ah
358     var dest-ah/edx: (addr handle array byte) <- get dest, text-data
359     copy-array-object src, dest-ah
360     return
361   }
362   compare *type, 2  # array
363   {
364     break-if-!=
365 #?     print-string 0, "array value\n"
366     var src-ah/eax: (addr handle array value) <- get src, array-data
367     var _src/eax: (addr array value) <- lookup *src-ah
368     var src/esi: (addr array value) <- copy _src
369     var n/ecx: int <- length src
370     var dest-ah/edx: (addr handle array value) <- get dest, array-data
371     populate dest-ah, n
372     var _dest/eax: (addr array value) <- lookup *dest-ah
373     var dest/edi: (addr array value) <- copy _dest
374     var i/eax: int <- copy 0
375     {
376       compare i, n
377       break-if->=
378       {
379         var offset/edx: (offset value) <- compute-offset src, i
380         var src-element/eax: (addr value) <- index src, offset
381         var dest-element/ecx: (addr value) <- index dest, offset
382         deep-copy-value src-element, dest-element
383       }
384       i <- increment
385       loop
386     }
387     copy-array-object src, dest-ah
388     return
389   }
390   compare *type, 3  # file
391   {
392     break-if-!=
393 #?     print-string 0, "file value\n"
394     var src-filename-ah/eax: (addr handle array byte) <- get src, filename
395     var _src-filename/eax: (addr array byte) <- lookup *src-filename-ah
396     var src-filename/ecx: (addr array byte) <- copy _src-filename
397     var dest-filename-ah/ebx: (addr handle array byte) <- get dest, filename
398     copy-array-object src-filename, dest-filename-ah
399     var src-file-ah/eax: (addr handle buffered-file) <- get src, file-data
400     var src-file/eax: (addr buffered-file) <- lookup *src-file-ah
401     var dest-file-ah/edx: (addr handle buffered-file) <- get dest, file-data
402     copy-file src-file, dest-file-ah, src-filename
403     return
404   }
405   compare *type, 4  # screen
406   {
407     break-if-!=
408 #?     print-string 0, "screen value\n"
409     var src-screen-ah/eax: (addr handle screen) <- get src, screen-data
410     var _src-screen/eax: (addr screen) <- lookup *src-screen-ah
411     var src-screen/ecx: (addr screen) <- copy _src-screen
412     var dest-screen-ah/eax: (addr handle screen) <- get dest, screen-data
413     allocate dest-screen-ah
414     var dest-screen/eax: (addr screen) <- lookup *dest-screen-ah
415     copy-object src-screen, dest-screen
416     var dest-screen-data-ah/ebx: (addr handle array screen-cell) <- get dest-screen, data
417     var src-screen-data-ah/eax: (addr handle array screen-cell) <- get src-screen, data
418     var src-screen-data/eax: (addr array screen-cell) <- lookup *src-screen-data-ah
419     copy-array-object src-screen-data, dest-screen-data-ah
420     return
421   }
422 }