https://github.com/akkartik/mu/blob/main/shell/print.mu
  1 fn print-cell _in: (addr handle cell), out: (addr stream byte), trace: (addr trace) {
  2   trace-text trace, "print", "print"
  3   trace-lower trace
  4   var in/eax: (addr handle cell) <- copy _in
  5   var in-addr/eax: (addr cell) <- lookup *in
  6   {
  7     var nil?/eax: boolean <- nil? in-addr
  8     compare nil?, 0/false
  9     break-if-=
 10     write out, "()"
 11     trace-higher trace
 12     return
 13   }
 14   var in-type/ecx: (addr int) <- get in-addr, type
 15   compare *in-type, 0/pair
 16   {
 17     break-if-!=
 18     print-list in-addr, out, trace
 19     trace-higher trace
 20     return
 21   }
 22   compare *in-type, 1/number
 23   {
 24     break-if-!=
 25     print-number in-addr, out, trace
 26     trace-higher trace
 27     return
 28   }
 29   compare *in-type, 2/symbol
 30   {
 31     break-if-!=
 32     print-symbol in-addr, out, trace
 33     trace-higher trace
 34     return
 35   }
 36 }
 37 
 38 # debug helper
 39 fn dump-cell in-ah: (addr handle cell) {
 40   var stream-storage: (stream byte 0x40)
 41   var stream/edx: (addr stream byte) <- address stream-storage
 42   print-cell in-ah, stream, 0/no-trace
 43   var d1/eax: int <- copy 0
 44   var d2/ecx: int <- copy 0
 45   d1, d2 <- draw-stream-wrapping-right-then-down 0/screen, stream, 0/xmin, 0/ymin, 0x80/xmax, 0x30/ymax, 0/x, 0/y, 7/fg, 0/bg
 46 }
 47 
 48 fn print-symbol _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
 49   trace-text trace, "print", "symbol"
 50   var in/esi: (addr cell) <- copy _in
 51   var data-ah/eax: (addr handle stream byte) <- get in, text-data
 52   var _data/eax: (addr stream byte) <- lookup *data-ah
 53   var data/esi: (addr stream byte) <- copy _data
 54   rewind-stream data
 55   write-stream out, data
 56   # trace
 57   rewind-stream data
 58   var stream-storage: (stream byte 0x40)
 59   var stream/ecx: (addr stream byte) <- address stream-storage
 60   write stream, "=> symbol "
 61   write-stream stream, data
 62   trace trace, "print", stream
 63 }
 64 
 65 fn print-number _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
 66   var in/esi: (addr cell) <- copy _in
 67   var val/eax: (addr float) <- get in, number-data
 68   write-float-decimal-approximate out, *val, 3/precision
 69   # trace
 70   var stream-storage: (stream byte 0x40)
 71   var stream/ecx: (addr stream byte) <- address stream-storage
 72   write stream, "=> number "
 73   write-float-decimal-approximate stream, *val, 3/precision
 74   trace trace, "print", stream
 75 }
 76 
 77 fn print-list _in: (addr cell), out: (addr stream byte), trace: (addr trace) {
 78   var curr/esi: (addr cell) <- copy _in
 79   write out, "("
 80   $print-list:loop: {
 81     var left/ecx: (addr handle cell) <- get curr, left
 82     print-cell left, out, trace
 83     var right/ecx: (addr handle cell) <- get curr, right
 84     var right-addr/eax: (addr cell) <- lookup *right
 85     {
 86       compare right-addr, 0
 87       break-if-!=
 88       abort "null encountered"
 89     }
 90     {
 91       var right-nil?/eax: boolean <- nil? right-addr
 92       compare right-nil?, 0/false
 93       {
 94         break-if-=
 95         trace-text trace, "print", "right is null"
 96         break $print-list:loop
 97       }
 98     }
 99     write out, " "
100     var right-type-addr/edx: (addr int) <- get right-addr, type
101     {
102       compare *right-type-addr, 0/pair
103       break-if-=
104       write out, ". "
105       print-cell right, out, trace
106       break $print-list:loop
107     }
108     curr <- copy right-addr
109     loop
110   }
111   write out, ")"
112 }
113 
114 # Most lisps intern nil, but we don't really have globals yet, so we'll be
115 # less efficient for now.
116 fn nil? _in: (addr cell) -> _/eax: boolean {
117   var in/esi: (addr cell) <- copy _in
118   # if type != pair, return false
119   var type/eax: (addr int) <- get in, type
120   compare *type, 0/pair
121   {
122     break-if-=
123     return 0/false
124   }
125   # if left != null, return false
126   var left-ah/eax: (addr handle cell) <- get in, left
127   var left/eax: (addr cell) <- lookup *left-ah
128   compare left, 0
129   {
130     break-if-=
131     return 0/false
132   }
133   # if right != null, return false
134   var right-ah/eax: (addr handle cell) <- get in, right
135   var right/eax: (addr cell) <- lookup *right-ah
136   compare right, 0
137   {
138     break-if-=
139     return 0/false
140   }
141   return 1/true
142 }
143 
144 fn test-print-cell-zero {
145   var num-storage: (handle cell)
146   var num/esi: (addr handle cell) <- address num-storage
147   new-integer num, 0
148   var out-storage: (stream byte 0x40)
149   var out/edi: (addr stream byte) <- address out-storage
150   print-cell num, out, 0/no-trace
151   check-stream-equal out, "0", "F - test-print-cell-zero"
152 }
153 
154 fn test-print-cell-integer {
155   var num-storage: (handle cell)
156   var num/esi: (addr handle cell) <- address num-storage
157   new-integer num, 1
158   var out-storage: (stream byte 0x40)
159   var out/edi: (addr stream byte) <- address out-storage
160   print-cell num, out, 0/no-trace
161   check-stream-equal out, "1", "F - test-print-cell-integer"
162 }
163 
164 fn test-print-cell-integer-2 {
165   var num-storage: (handle cell)
166   var num/esi: (addr handle cell) <- address num-storage
167   new-integer num, 0x30
168   var out-storage: (stream byte 0x40)
169   var out/edi: (addr stream byte) <- address out-storage
170   print-cell num, out, 0/no-trace
171   check-stream-equal out, "48", "F - test-print-cell-integer-2"
172 }
173 
174 fn test-print-cell-fraction {
175   var num-storage: (handle cell)
176   var num/esi: (addr handle cell) <- address num-storage
177   var val/xmm0: float <- rational 1, 2
178   new-float num, val
179   var out-storage: (stream byte 0x40)
180   var out/edi: (addr stream byte) <- address out-storage
181   print-cell num, out, 0/no-trace
182   check-stream-equal out, "0.5", "F - test-print-cell-fraction"
183 }
184 
185 fn test-print-cell-symbol {
186   var sym-storage: (handle cell)
187   var sym/esi: (addr handle cell) <- address sym-storage
188   new-symbol sym, "abc"
189   var out-storage: (stream byte 0x40)
190   var out/edi: (addr stream byte) <- address out-storage
191   print-cell sym, out, 0/no-trace
192   check-stream-equal out, "abc", "F - test-print-cell-symbol"
193 }
194 
195 fn test-print-cell-nil-list {
196   var nil-storage: (handle cell)
197   var nil/esi: (addr handle cell) <- address nil-storage
198   allocate-pair nil
199   var out-storage: (stream byte 0x40)
200   var out/edi: (addr stream byte) <- address out-storage
201   print-cell nil, out, 0/no-trace
202   check-stream-equal out, "()", "F - test-print-cell-nil-list"
203 }
204 
205 fn test-print-cell-singleton-list {
206   # list
207   var left-storage: (handle cell)
208   var left/ecx: (addr handle cell) <- address left-storage
209   new-symbol left, "abc"
210   var nil-storage: (handle cell)
211   var nil/edx: (addr handle cell) <- address nil-storage
212   allocate-pair nil
213   var list-storage: (handle cell)
214   var list/esi: (addr handle cell) <- address list-storage
215   new-pair list, *left, *nil
216   #
217   var out-storage: (stream byte 0x40)
218   var out/edi: (addr stream byte) <- address out-storage
219   print-cell list, out, 0/no-trace
220   check-stream-equal out, "(abc)", "F - test-print-cell-singleton-list"
221 }
222 
223 fn test-print-cell-list {
224   # list = cons "abc", nil
225   var left-storage: (handle cell)
226   var left/ecx: (addr handle cell) <- address left-storage
227   new-symbol left, "abc"
228   var nil-storage: (handle cell)
229   var nil/edx: (addr handle cell) <- address nil-storage
230   allocate-pair nil
231   var list-storage: (handle cell)
232   var list/esi: (addr handle cell) <- address list-storage
233   new-pair list, *left, *nil
234   # list = cons 64, list
235   new-integer left, 0x40
236   new-pair list, *left, *list
237   #
238   var out-storage: (stream byte 0x40)
239   var out/edi: (addr stream byte) <- address out-storage
240   print-cell list, out, 0/no-trace
241   check-stream-equal out, "(64 abc)", "F - test-print-cell-list"
242 }
243 
244 fn test-print-cell-list-of-nil {
245   # list = cons "abc", nil
246   var left-storage: (handle cell)
247   var left/ecx: (addr handle cell) <- address left-storage
248   allocate-pair left
249   var nil-storage: (handle cell)
250   var nil/edx: (addr handle cell) <- address nil-storage
251   allocate-pair nil
252   var list-storage: (handle cell)
253   var list/esi: (addr handle cell) <- address list-storage
254   new-pair list, *left, *nil
255   # list = cons 64, list
256   new-integer left, 0x40
257   new-pair list, *left, *list
258   #
259   var out-storage: (stream byte 0x40)
260   var out/edi: (addr stream byte) <- address out-storage
261   print-cell list, out, 0/no-trace
262   check-stream-equal out, "(64 ())", "F - test-print-cell-list-nil"
263 }
264 
265 fn test-print-dotted-list {
266   # list = cons 64, "abc"
267   var left-storage: (handle cell)
268   var left/ecx: (addr handle cell) <- address left-storage
269   new-symbol left, "abc"
270   var right-storage: (handle cell)
271   var right/edx: (addr handle cell) <- address right-storage
272   new-integer right, 0x40
273   var list-storage: (handle cell)
274   var list/esi: (addr handle cell) <- address list-storage
275   new-pair list, *left, *right
276   #
277   var out-storage: (stream byte 0x40)
278   var out/edi: (addr stream byte) <- address out-storage
279   print-cell list, out, 0/no-trace
280   check-stream-equal out, "(abc . 64)", "F - test-print-dotted-list"
281 }