fix other mandelbrot variants
[mu.git] / shell / primitives.mu
bloba87009d3b4869f6ea3cf83df8b10cfa51056ae0c
1 # Primitives are functions that are implemented directly in Mu.
2 # They always evaluate all their arguments.
4 fn initialize-primitives _self: (addr global-table) {
5   var self/esi: (addr global-table) <- copy _self
6   # for numbers
7   append-primitive self, "+"
8   append-primitive self, "-"
9   append-primitive self, "*"
10   append-primitive self, "/"
11   append-primitive self, "%"
12   append-primitive self, "sqrt"
13   append-primitive self, "abs"
14   append-primitive self, "sgn"
15   append-primitive self, "<"
16   append-primitive self, ">"
17   append-primitive self, "<="
18   append-primitive self, ">="
19   # generic
20   append-primitive self, "apply"
21   append-primitive self, "="
22   append-primitive self, "no"
23   append-primitive self, "not"
24   append-primitive self, "dbg"
25   append-primitive self, "len"
26   # for pairs
27   append-primitive self, "car"
28   append-primitive self, "cdr"
29   append-primitive self, "cons"
30   append-primitive self, "cons?"
31   # for screens
32   append-primitive self, "print"
33   append-primitive self, "clear"
34   append-primitive self, "lines"
35   append-primitive self, "columns"
36   append-primitive self, "up"
37   append-primitive self, "down"
38   append-primitive self, "left"
39   append-primitive self, "right"
40   append-primitive self, "cr"
41   append-primitive self, "pixel"
42   append-primitive self, "line"
43   append-primitive self, "hline"
44   append-primitive self, "vline"
45   append-primitive self, "circle"
46   append-primitive self, "bezier"
47   append-primitive self, "width"
48   append-primitive self, "height"
49   append-primitive self, "new_screen"
50   append-primitive self, "blit"
51   # for keyboards
52   append-primitive self, "key"
53   # for streams
54   append-primitive self, "stream"
55   append-primitive self, "write"
56   append-primitive self, "read"
57   append-primitive self, "rewind"
58   # for arrays
59   append-primitive self, "array"
60   append-primitive self, "populate"
61   append-primitive self, "index"
62   append-primitive self, "iset"
63   # for images
64   append-primitive self, "img"
65   # misc
66   append-primitive self, "abort"
67   # keep sync'd with render-primitives
70 # Slightly misnamed; renders primitives as well as special forms that don't
71 # evaluate all their arguments.
72 fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
73   var y/ecx: int <- copy ymax
74   y <- subtract 0x11/primitives-border
75   clear-rect screen, xmin, y, xmax, ymax, 0xdc/bg=green-bg
76   y <- increment
77   var right-min/edx: int <- copy xmax
78   right-min <- subtract 0x1e/primitives-divider
79   set-cursor-position screen, right-min, y
80   draw-text-wrapping-right-then-down-from-cursor screen, "primitives", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
81   y <- increment
82   set-cursor-position screen, right-min, y
83   draw-text-wrapping-right-then-down-from-cursor screen, "  fn apply set if while", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
84   y <- increment
85   set-cursor-position screen, right-min, y
86   draw-text-wrapping-right-then-down-from-cursor screen, "booleans", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
87   y <- increment
88   set-cursor-position screen, right-min, y
89   draw-text-wrapping-right-then-down-from-cursor screen, "  = and or not", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
90   y <- increment
91   set-cursor-position screen, right-min, y
92   draw-text-wrapping-right-then-down-from-cursor screen, "lists", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
93   y <- increment
94   set-cursor-position screen, right-min, y
95   draw-text-wrapping-right-then-down-from-cursor screen, "  cons car cdr no cons? len", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
96   y <- increment
97   set-cursor-position screen, right-min, y
98   draw-text-wrapping-right-then-down-from-cursor screen, "numbers", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
99   y <- increment
100   set-cursor-position screen, right-min, y
101   draw-text-wrapping-right-then-down-from-cursor screen, "  + - * / %", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
102   y <- increment
103   set-cursor-position screen, right-min, y
104   draw-text-wrapping-right-then-down-from-cursor screen, "  < > <= >=", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
105   y <- increment
106   set-cursor-position screen, right-min, y
107   draw-text-wrapping-right-then-down-from-cursor screen, "  sqrt abs sgn", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
108   y <- increment
109   set-cursor-position screen, right-min, y
110   draw-text-wrapping-right-then-down-from-cursor screen, "arrays", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
111   y <- increment
112   set-cursor-position screen, right-min, y
113   draw-text-wrapping-right-then-down-from-cursor screen, "  array index iset len", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
114   y <- increment
115   var tmpx/eax: int <- copy right-min
116   tmpx <- draw-text-rightward screen, "  populate", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
117   tmpx <- draw-text-rightward screen, ": int _ -> array", tmpx, xmax, y, 7/fg=grey, 0xdc/bg=green-bg
118   y <- increment
119   set-cursor-position screen, right-min, y
120   draw-text-wrapping-right-then-down-from-cursor screen, "images", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
121   y <- increment
122   var tmpx/eax: int <- copy right-min
123   tmpx <- draw-text-rightward screen, "  img", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
124   tmpx <- draw-text-rightward screen, ": screen stream x y w h", tmpx, xmax, y, 7/fg=grey, 0xdc/bg=green-bg
125 #?   {
126 #?     compare screen, 0
127 #?     break-if-!=
128 #?     var foo/eax: byte <- read-key 0/keyboard
129 #?     compare foo, 0
130 #?     loop-if-=
131 #?   }
132   y <- copy ymax
133   y <- subtract 0x10/primitives-border
134   var left-max/edx: int <- copy xmax
135   left-max <- subtract 0x20/primitives-divider
136   var tmpx/eax: int <- copy xmin
137   tmpx <- draw-text-rightward screen, "cursor graphics", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
138   y <- increment
139   var tmpx/eax: int <- copy xmin
140   tmpx <- draw-text-rightward screen, "  print", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
141   tmpx <- draw-text-rightward screen, ": screen _ -> _", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
142   y <- increment
143   var tmpx/eax: int <- copy xmin
144   tmpx <- draw-text-rightward screen, "  lines columns", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
145   tmpx <- draw-text-rightward screen, ": screen -> number", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
146   y <- increment
147   var tmpx/eax: int <- copy xmin
148   tmpx <- draw-text-rightward screen, "  up down left right", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
149   tmpx <- draw-text-rightward screen, ": screen", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
150   y <- increment
151   var tmpx/eax: int <- copy xmin
152   tmpx <- draw-text-rightward screen, "  cr", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
153   tmpx <- draw-text-rightward screen, ": screen   ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
154   tmpx <- draw-text-rightward screen, "# move cursor down and to left margin", tmpx, left-max, y, 0x38/fg=trace, 0xdc/bg=green-bg
155   y <- increment
156   var tmpx/eax: int <- copy xmin
157   tmpx <- draw-text-rightward screen, "pixel graphics", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
158   y <- increment
159   var tmpx/eax: int <- copy xmin
160   tmpx <- draw-text-rightward screen, "  circle bezier line hline vline pixel", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
161   y <- increment
162   var tmpx/eax: int <- copy xmin
163   tmpx <- draw-text-rightward screen, "  width height", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
164   tmpx <- draw-text-rightward screen, ": screen -> number", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
165   y <- increment
166   var tmpx/eax: int <- copy xmin
167   tmpx <- draw-text-rightward screen, "  clear", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
168   tmpx <- draw-text-rightward screen, ": screen", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
169   y <- increment
170   var tmpx/eax: int <- copy xmin
171   tmpx <- draw-text-rightward screen, "input", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
172   y <- increment
173   var tmpx/eax: int <- copy xmin
174   tmpx <- draw-text-rightward screen, "  key", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
175   tmpx <- draw-text-rightward screen, ": keyboard -> code-point-utf8?", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
176   y <- increment
177   var tmpx/eax: int <- copy xmin
178   tmpx <- draw-text-rightward screen, "streams", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
179   y <- increment
180   var tmpx/eax: int <- copy xmin
181   tmpx <- draw-text-rightward screen, "  stream", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
182   tmpx <- draw-text-rightward screen, ": -> stream ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
183   y <- increment
184   var tmpx/eax: int <- copy xmin
185   tmpx <- draw-text-rightward screen, "  write", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
186   tmpx <- draw-text-rightward screen, ": stream code-point-utf8 -> stream", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
187   y <- increment
188   var tmpx/eax: int <- copy xmin
189   tmpx <- draw-text-rightward screen, "  rewind clear", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
190   tmpx <- draw-text-rightward screen, ": stream", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
191   y <- increment
192   var tmpx/eax: int <- copy xmin
193   tmpx <- draw-text-rightward screen, "  read", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
194   tmpx <- draw-text-rightward screen, ": stream -> code-point-utf8", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
197 fn primitive-global? _x: (addr global) -> _/eax: boolean {
198   var x/eax: (addr global) <- copy _x
199   var value-ah/eax: (addr handle cell) <- get x, value
200   var value/eax: (addr cell) <- lookup *value-ah
201   compare value, 0/null
202   {
203     break-if-!=
204     return 0/false
205   }
206   var primitive?/eax: boolean <- primitive? value
207   return primitive?
210 fn append-primitive _self: (addr global-table), name: (addr array byte) {
211   var self/esi: (addr global-table) <- copy _self
212   compare self, 0
213   {
214     break-if-!=
215     abort "append primitive"
216     return
217   }
218   var final-index-addr/ecx: (addr int) <- get self, final-index
219   increment *final-index-addr
220   var curr-index/ecx: int <- copy *final-index-addr
221   var data-ah/eax: (addr handle array global) <- get self, data
222   var data/eax: (addr array global) <- lookup *data-ah
223   var curr-offset/esi: (offset global) <- compute-offset data, curr-index
224   var curr/esi: (addr global) <- index data, curr-offset
225   var curr-name-ah/eax: (addr handle array byte) <- get curr, name
226   copy-array-object name, curr-name-ah
227   var curr-value-ah/eax: (addr handle cell) <- get curr, value
228   new-primitive-function curr-value-ah, curr-index
231 # a little strange; goes from value to name and selects primitive based on name
232 fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr handle cell), _globals: (addr global-table), trace: (addr trace) {
233   var f/esi: (addr cell) <- copy _f
234   var f-index-a/ecx: (addr int) <- get f, index-data
235   var f-index/ecx: int <- copy *f-index-a
236   var globals/eax: (addr global-table) <- copy _globals
237   compare globals, 0
238   {
239     break-if-!=
240     abort "apply primitive"
241     return
242   }
243   var global-data-ah/eax: (addr handle array global) <- get globals, data
244   var global-data/eax: (addr array global) <- lookup *global-data-ah
245   var f-offset/ecx: (offset global) <- compute-offset global-data, f-index
246   var f-value/ecx: (addr global) <- index global-data, f-offset
247   var f-name-ah/ecx: (addr handle array byte) <- get f-value, name
248   var f-name/eax: (addr array byte) <- lookup *f-name-ah
249   {
250     var add?/eax: boolean <- string-equal? f-name, "+"
251     compare add?, 0/false
252     break-if-=
253     apply-add args-ah, out, trace
254     return
255   }
256   {
257     var subtract?/eax: boolean <- string-equal? f-name, "-"
258     compare subtract?, 0/false
259     break-if-=
260     apply-subtract args-ah, out, trace
261     return
262   }
263   {
264     var multiply?/eax: boolean <- string-equal? f-name, "*"
265     compare multiply?, 0/false
266     break-if-=
267     apply-multiply args-ah, out, trace
268     return
269   }
270   {
271     var divide?/eax: boolean <- string-equal? f-name, "/"
272     compare divide?, 0/false
273     break-if-=
274     apply-divide args-ah, out, trace
275     return
276   }
277   # '%' is the remainder operator, because modulo isn't really meaningful for
278   # non-integers
279   #
280   # I considered calling this operator 'rem', but I want to follow Arc in
281   # using 'rem' for filtering out elements from lists.
282   #   https://arclanguage.github.io/ref/list.html#rem
283   {
284     var remainder?/eax: boolean <- string-equal? f-name, "%"
285     compare remainder?, 0/false
286     break-if-=
287     apply-remainder args-ah, out, trace
288     return
289   }
290   {
291     var square-root?/eax: boolean <- string-equal? f-name, "sqrt"
292     compare square-root?, 0/false
293     break-if-=
294     apply-square-root args-ah, out, trace
295     return
296   }
297   {
298     var abs?/eax: boolean <- string-equal? f-name, "abs"
299     compare abs?, 0/false
300     break-if-=
301     apply-abs args-ah, out, trace
302     return
303   }
304   {
305     var sgn?/eax: boolean <- string-equal? f-name, "sgn"
306     compare sgn?, 0/false
307     break-if-=
308     apply-sgn args-ah, out, trace
309     return
310   }
311   {
312     var car?/eax: boolean <- string-equal? f-name, "car"
313     compare car?, 0/false
314     break-if-=
315     apply-car args-ah, out, trace
316     return
317   }
318   {
319     var cdr?/eax: boolean <- string-equal? f-name, "cdr"
320     compare cdr?, 0/false
321     break-if-=
322     apply-cdr args-ah, out, trace
323     return
324   }
325   {
326     var cons?/eax: boolean <- string-equal? f-name, "cons"
327     compare cons?, 0/false
328     break-if-=
329     apply-cons args-ah, out, trace
330     return
331   }
332   {
333     var cons-check?/eax: boolean <- string-equal? f-name, "cons?"
334     compare cons-check?, 0/false
335     break-if-=
336     apply-cons-check args-ah, out, trace
337     return
338   }
339   {
340     var len?/eax: boolean <- string-equal? f-name, "len"
341     compare len?, 0/false
342     break-if-=
343     apply-len args-ah, out, trace
344     return
345   }
346   {
347     var cell-isomorphic?/eax: boolean <- string-equal? f-name, "="
348     compare cell-isomorphic?, 0/false
349     break-if-=
350     apply-cell-isomorphic args-ah, out, trace
351     return
352   }
353   {
354     var not?/eax: boolean <- string-equal? f-name, "no"
355     compare not?, 0/false
356     break-if-=
357     apply-not args-ah, out, trace
358     return
359   }
360   {
361     var not?/eax: boolean <- string-equal? f-name, "not"
362     compare not?, 0/false
363     break-if-=
364     apply-not args-ah, out, trace
365     return
366   }
367   {
368     var debug?/eax: boolean <- string-equal? f-name, "dbg"
369     compare debug?, 0/false
370     break-if-=
371     apply-debug args-ah, out, trace
372     return
373   }
374   {
375     var lesser?/eax: boolean <- string-equal? f-name, "<"
376     compare lesser?, 0/false
377     break-if-=
378     apply-< args-ah, out, trace
379     return
380   }
381   {
382     var greater?/eax: boolean <- string-equal? f-name, ">"
383     compare greater?, 0/false
384     break-if-=
385     apply-> args-ah, out, trace
386     return
387   }
388   {
389     var lesser-or-equal?/eax: boolean <- string-equal? f-name, "<="
390     compare lesser-or-equal?, 0/false
391     break-if-=
392     apply-<= args-ah, out, trace
393     return
394   }
395   {
396     var greater-or-equal?/eax: boolean <- string-equal? f-name, ">="
397     compare greater-or-equal?, 0/false
398     break-if-=
399     apply->= args-ah, out, trace
400     return
401   }
402   {
403     var print?/eax: boolean <- string-equal? f-name, "print"
404     compare print?, 0/false
405     break-if-=
406     apply-print args-ah, out, trace
407     return
408   }
409   {
410     var clear?/eax: boolean <- string-equal? f-name, "clear"
411     compare clear?, 0/false
412     break-if-=
413     apply-clear args-ah, out, trace
414     return
415   }
416   {
417     var lines?/eax: boolean <- string-equal? f-name, "lines"
418     compare lines?, 0/false
419     break-if-=
420     apply-lines args-ah, out, trace
421     return
422   }
423   {
424     var columns?/eax: boolean <- string-equal? f-name, "columns"
425     compare columns?, 0/false
426     break-if-=
427     apply-columns args-ah, out, trace
428     return
429   }
430   {
431     var up?/eax: boolean <- string-equal? f-name, "up"
432     compare up?, 0/false
433     break-if-=
434     apply-up args-ah, out, trace
435     return
436   }
437   {
438     var down?/eax: boolean <- string-equal? f-name, "down"
439     compare down?, 0/false
440     break-if-=
441     apply-down args-ah, out, trace
442     return
443   }
444   {
445     var left?/eax: boolean <- string-equal? f-name, "left"
446     compare left?, 0/false
447     break-if-=
448     apply-left args-ah, out, trace
449     return
450   }
451   {
452     var right?/eax: boolean <- string-equal? f-name, "right"
453     compare right?, 0/false
454     break-if-=
455     apply-right args-ah, out, trace
456     return
457   }
458   {
459     var cr?/eax: boolean <- string-equal? f-name, "cr"
460     compare cr?, 0/false
461     break-if-=
462     apply-cr args-ah, out, trace
463     return
464   }
465   {
466     var pixel?/eax: boolean <- string-equal? f-name, "pixel"
467     compare pixel?, 0/false
468     break-if-=
469     apply-pixel args-ah, out, trace
470     return
471   }
472   {
473     var line?/eax: boolean <- string-equal? f-name, "line"
474     compare line?, 0/false
475     break-if-=
476     apply-line args-ah, out, trace
477     return
478   }
479   {
480     var hline?/eax: boolean <- string-equal? f-name, "hline"
481     compare hline?, 0/false
482     break-if-=
483     apply-hline args-ah, out, trace
484     return
485   }
486   {
487     var vline?/eax: boolean <- string-equal? f-name, "vline"
488     compare vline?, 0/false
489     break-if-=
490     apply-vline args-ah, out, trace
491     return
492   }
493   {
494     var circle?/eax: boolean <- string-equal? f-name, "circle"
495     compare circle?, 0/false
496     break-if-=
497     apply-circle args-ah, out, trace
498     return
499   }
500   {
501     var bezier?/eax: boolean <- string-equal? f-name, "bezier"
502     compare bezier?, 0/false
503     break-if-=
504     apply-bezier args-ah, out, trace
505     return
506   }
507   {
508     var width?/eax: boolean <- string-equal? f-name, "width"
509     compare width?, 0/false
510     break-if-=
511     apply-width args-ah, out, trace
512     return
513   }
514   {
515     var height?/eax: boolean <- string-equal? f-name, "height"
516     compare height?, 0/false
517     break-if-=
518     apply-height args-ah, out, trace
519     return
520   }
521   {
522     var screen?/eax: boolean <- string-equal? f-name, "new_screen"
523     compare screen?, 0/false
524     break-if-=
525     apply-new-screen args-ah, out, trace
526     return
527   }
528   {
529     var blit?/eax: boolean <- string-equal? f-name, "blit"
530     compare blit?, 0/false
531     break-if-=
532     apply-blit args-ah, out, trace
533     return
534   }
535   {
536     var wait-for-key?/eax: boolean <- string-equal? f-name, "key"
537     compare wait-for-key?, 0/false
538     break-if-=
539     apply-wait-for-key args-ah, out, trace
540     return
541   }
542   {
543     var stream?/eax: boolean <- string-equal? f-name, "stream"
544     compare stream?, 0/false
545     break-if-=
546     apply-stream args-ah, out, trace
547     return
548   }
549   {
550     var write?/eax: boolean <- string-equal? f-name, "write"
551     compare write?, 0/false
552     break-if-=
553     apply-write args-ah, out, trace
554     return
555   }
556   {
557     var rewind?/eax: boolean <- string-equal? f-name, "rewind"
558     compare rewind?, 0/false
559     break-if-=
560     apply-rewind args-ah, out, trace
561     return
562   }
563   {
564     var read?/eax: boolean <- string-equal? f-name, "read"
565     compare read?, 0/false
566     break-if-=
567     apply-read args-ah, out, trace
568     return
569   }
570   {
571     var array?/eax: boolean <- string-equal? f-name, "array"
572     compare array?, 0/false
573     break-if-=
574     apply-array args-ah, out, trace
575     return
576   }
577   {
578     var populate?/eax: boolean <- string-equal? f-name, "populate"
579     compare populate?, 0/false
580     break-if-=
581     apply-populate args-ah, out, trace
582     return
583   }
584   {
585     var index?/eax: boolean <- string-equal? f-name, "index"
586     compare index?, 0/false
587     break-if-=
588     apply-index args-ah, out, trace
589     return
590   }
591   {
592     var iset?/eax: boolean <- string-equal? f-name, "iset"
593     compare iset?, 0/false
594     break-if-=
595     apply-iset args-ah, out, trace
596     return
597   }
598   {
599     var render-image?/eax: boolean <- string-equal? f-name, "img"
600     compare render-image?, 0/false
601     break-if-=
602     apply-render-image args-ah, out, trace
603     return
604   }
605   {
606     var abort?/eax: boolean <- string-equal? f-name, "abort"
607     compare abort?, 0/false
608     break-if-=
609     apply-abort args-ah, out, trace
610     return
611   }
612   abort "unknown primitive function"
615 fn apply-add _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
616   trace-text trace, "eval", "apply +"
617   var args-ah/eax: (addr handle cell) <- copy _args-ah
618   var _args/eax: (addr cell) <- lookup *args-ah
619   var args/esi: (addr cell) <- copy _args
620   {
621     var args-type/eax: (addr int) <- get args, type
622     compare *args-type, 0/pair
623     break-if-=
624     error trace, "args to + are not a list"
625     return
626   }
627   var empty-args?/eax: boolean <- nil? args
628   compare empty-args?, 0/false
629   {
630     break-if-=
631     error trace, "+ needs 2 args but got 0"
632     return
633   }
634   # args->left->value
635   var first-ah/eax: (addr handle cell) <- get args, left
636   var first/eax: (addr cell) <- lookup *first-ah
637   {
638     var first-type/eax: (addr int) <- get first, type
639     compare *first-type, 1/number
640     break-if-=
641     error trace, "first arg for + is not a number"
642     return
643   }
644   var first-value/ecx: (addr float) <- get first, number-data
645   # args->right->left->value
646   var right-ah/eax: (addr handle cell) <- get args, right
647   var right/eax: (addr cell) <- lookup *right-ah
648   {
649     var right-type/eax: (addr int) <- get right, type
650     compare *right-type, 0/pair
651     break-if-=
652     error trace, "+ encountered non-pair"
653     return
654   }
655   {
656     var nil?/eax: boolean <- nil? right
657     compare nil?, 0/false
658     break-if-=
659     error trace, "+ needs 2 args but got 1"
660     return
661   }
662   var second-ah/eax: (addr handle cell) <- get right, left
663   var second/eax: (addr cell) <- lookup *second-ah
664   {
665     var second-type/eax: (addr int) <- get second, type
666     compare *second-type, 1/number
667     break-if-=
668     error trace, "second arg for + is not a number"
669     return
670   }
671   var second-value/edx: (addr float) <- get second, number-data
672   # add
673   var result/xmm0: float <- copy *first-value
674   result <- add *second-value
675   new-float out, result
678 fn test-evaluate-missing-arg-in-add {
679   var t-storage: trace
680   var t/edi: (addr trace) <- address t-storage
681   initialize-trace t, 0x100/max-depth, 0x100/capacity, 0/visible  # we don't use trace UI
682   #
683   var nil-storage: (handle cell)
684   var nil-ah/ecx: (addr handle cell) <- address nil-storage
685   allocate-pair nil-ah
686   var one-storage: (handle cell)
687   var one-ah/edx: (addr handle cell) <- address one-storage
688   new-integer one-ah, 1
689   var add-storage: (handle cell)
690   var add-ah/ebx: (addr handle cell) <- address add-storage
691   new-symbol add-ah, "+"
692   # input is (+ 1)
693   var tmp-storage: (handle cell)
694   var tmp-ah/esi: (addr handle cell) <- address tmp-storage
695   new-pair tmp-ah, *one-ah, *nil-ah
696   new-pair tmp-ah, *add-ah, *tmp-ah
697 #?   dump-cell tmp-ah
698   #
699   var globals-storage: global-table
700   var globals/edx: (addr global-table) <- address globals-storage
701   initialize-globals globals
702   #
703   evaluate tmp-ah, tmp-ah, *nil-ah, globals, t, 0/no-screen, 0/no-keyboard, 0/definitions-created, 0/call-number
704   # no crash
707 fn apply-subtract _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
708   trace-text trace, "eval", "apply -"
709   var args-ah/eax: (addr handle cell) <- copy _args-ah
710   var _args/eax: (addr cell) <- lookup *args-ah
711   var args/esi: (addr cell) <- copy _args
712   {
713     var args-type/eax: (addr int) <- get args, type
714     compare *args-type, 0/pair
715     break-if-=
716     error trace, "args to - are not a list"
717     return
718   }
719   var empty-args?/eax: boolean <- nil? args
720   compare empty-args?, 0/false
721   {
722     break-if-=
723     error trace, "- needs 2 args but got 0"
724     return
725   }
726   # args->left->value
727   var first-ah/eax: (addr handle cell) <- get args, left
728   var first/eax: (addr cell) <- lookup *first-ah
729   {
730     var first-type/eax: (addr int) <- get first, type
731     compare *first-type, 1/number
732     break-if-=
733     error trace, "first arg for - is not a number"
734     return
735   }
736   var first-value/ecx: (addr float) <- get first, number-data
737   # args->right->left->value
738   var right-ah/eax: (addr handle cell) <- get args, right
739   var right/eax: (addr cell) <- lookup *right-ah
740   {
741     var right-type/eax: (addr int) <- get right, type
742     compare *right-type, 0/pair
743     break-if-=
744     error trace, "- encountered non-pair"
745     return
746   }
747   {
748     var nil?/eax: boolean <- nil? right
749     compare nil?, 0/false
750     break-if-=
751     error trace, "- needs 2 args but got 1"
752     return
753   }
754   var second-ah/eax: (addr handle cell) <- get right, left
755   var second/eax: (addr cell) <- lookup *second-ah
756   {
757     var second-type/eax: (addr int) <- get second, type
758     compare *second-type, 1/number
759     break-if-=
760     error trace, "second arg for - is not a number"
761     return
762   }
763   var second-value/edx: (addr float) <- get second, number-data
764   # subtract
765   var result/xmm0: float <- copy *first-value
766   result <- subtract *second-value
767   new-float out, result
770 fn apply-multiply _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
771   trace-text trace, "eval", "apply *"
772   var args-ah/eax: (addr handle cell) <- copy _args-ah
773   var _args/eax: (addr cell) <- lookup *args-ah
774   var args/esi: (addr cell) <- copy _args
775   {
776     var args-type/eax: (addr int) <- get args, type
777     compare *args-type, 0/pair
778     break-if-=
779     error trace, "args to * are not a list"
780     return
781   }
782   var empty-args?/eax: boolean <- nil? args
783   compare empty-args?, 0/false
784   {
785     break-if-=
786     error trace, "* needs 2 args but got 0"
787     return
788   }
789   # args->left->value
790   var first-ah/eax: (addr handle cell) <- get args, left
791   var first/eax: (addr cell) <- lookup *first-ah
792   {
793     var first-type/eax: (addr int) <- get first, type
794     compare *first-type, 1/number
795     break-if-=
796     error trace, "first arg for * is not a number"
797     return
798   }
799   var first-value/ecx: (addr float) <- get first, number-data
800   # args->right->left->value
801   var right-ah/eax: (addr handle cell) <- get args, right
802   var right/eax: (addr cell) <- lookup *right-ah
803   {
804     var right-type/eax: (addr int) <- get right, type
805     compare *right-type, 0/pair
806     break-if-=
807     error trace, "* encountered non-pair"
808     return
809   }
810   {
811     var nil?/eax: boolean <- nil? right
812     compare nil?, 0/false
813     break-if-=
814     error trace, "* needs 2 args but got 1"
815     return
816   }
817   var second-ah/eax: (addr handle cell) <- get right, left
818   var second/eax: (addr cell) <- lookup *second-ah
819   {
820     var second-type/eax: (addr int) <- get second, type
821     compare *second-type, 1/number
822     break-if-=
823     error trace, "second arg for * is not a number"
824     return
825   }
826   var second-value/edx: (addr float) <- get second, number-data
827   # multiply
828   var result/xmm0: float <- copy *first-value
829   result <- multiply *second-value
830   new-float out, result
833 fn apply-divide _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
834   trace-text trace, "eval", "apply /"
835   var args-ah/eax: (addr handle cell) <- copy _args-ah
836   var _args/eax: (addr cell) <- lookup *args-ah
837   var args/esi: (addr cell) <- copy _args
838   {
839     var args-type/eax: (addr int) <- get args, type
840     compare *args-type, 0/pair
841     break-if-=
842     error trace, "args to / are not a list"
843     return
844   }
845   var empty-args?/eax: boolean <- nil? args
846   compare empty-args?, 0/false
847   {
848     break-if-=
849     error trace, "/ needs 2 args but got 0"
850     return
851   }
852   # args->left->value
853   var first-ah/eax: (addr handle cell) <- get args, left
854   var first/eax: (addr cell) <- lookup *first-ah
855   {
856     var first-type/eax: (addr int) <- get first, type
857     compare *first-type, 1/number
858     break-if-=
859     error trace, "first arg for / is not a number"
860     return
861   }
862   var first-value/ecx: (addr float) <- get first, number-data
863   # args->right->left->value
864   var right-ah/eax: (addr handle cell) <- get args, right
865   var right/eax: (addr cell) <- lookup *right-ah
866   {
867     var right-type/eax: (addr int) <- get right, type
868     compare *right-type, 0/pair
869     break-if-=
870     error trace, "/ encountered non-pair"
871     return
872   }
873   {
874     var nil?/eax: boolean <- nil? right
875     compare nil?, 0/false
876     break-if-=
877     error trace, "/ needs 2 args but got 1"
878     return
879   }
880   var second-ah/eax: (addr handle cell) <- get right, left
881   var second/eax: (addr cell) <- lookup *second-ah
882   {
883     var second-type/eax: (addr int) <- get second, type
884     compare *second-type, 1/number
885     break-if-=
886     error trace, "second arg for / is not a number"
887     return
888   }
889   var second-value/edx: (addr float) <- get second, number-data
890   # divide
891   var result/xmm0: float <- copy *first-value
892   result <- divide *second-value
893   new-float out, result
896 fn apply-remainder _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
897   trace-text trace, "eval", "apply %"
898   var args-ah/eax: (addr handle cell) <- copy _args-ah
899   var _args/eax: (addr cell) <- lookup *args-ah
900   var args/esi: (addr cell) <- copy _args
901   {
902     var args-type/eax: (addr int) <- get args, type
903     compare *args-type, 0/pair
904     break-if-=
905     error trace, "args to % are not a list"
906     return
907   }
908   var empty-args?/eax: boolean <- nil? args
909   compare empty-args?, 0/false
910   {
911     break-if-=
912     error trace, "% needs 2 args but got 0"
913     return
914   }
915   # args->left->value
916   var first-ah/eax: (addr handle cell) <- get args, left
917   var first/eax: (addr cell) <- lookup *first-ah
918   {
919     var first-type/eax: (addr int) <- get first, type
920     compare *first-type, 1/number
921     break-if-=
922     error trace, "first arg for % is not a number"
923     return
924   }
925   var first-value/ecx: (addr float) <- get first, number-data
926   # args->right->left->value
927   var right-ah/eax: (addr handle cell) <- get args, right
928   var right/eax: (addr cell) <- lookup *right-ah
929   {
930     var right-type/eax: (addr int) <- get right, type
931     compare *right-type, 0/pair
932     break-if-=
933     error trace, "% encountered non-pair"
934     return
935   }
936   {
937     var nil?/eax: boolean <- nil? right
938     compare nil?, 0/false
939     break-if-=
940     error trace, "% needs 2 args but got 1"
941     return
942   }
943   var second-ah/eax: (addr handle cell) <- get right, left
944   var second/eax: (addr cell) <- lookup *second-ah
945   {
946     var second-type/eax: (addr int) <- get second, type
947     compare *second-type, 1/number
948     break-if-=
949     error trace, "second arg for % is not a number"
950     return
951   }
952   var second-value/edx: (addr float) <- get second, number-data
953   # divide
954   var quotient/xmm0: float <- copy *first-value
955   quotient <- divide *second-value
956   var quotient-int/eax: int <- truncate quotient
957   quotient <- convert quotient-int
958   var sub-result/xmm1: float <- copy quotient
959   sub-result <- multiply *second-value
960   var result/xmm0: float <- copy *first-value
961   result <- subtract sub-result
962   new-float out, result
965 fn apply-square-root _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
966   trace-text trace, "eval", "apply sqrt"
967   var args-ah/eax: (addr handle cell) <- copy _args-ah
968   var _args/eax: (addr cell) <- lookup *args-ah
969   var args/esi: (addr cell) <- copy _args
970   {
971     var args-type/eax: (addr int) <- get args, type
972     compare *args-type, 0/pair
973     break-if-=
974     error trace, "args to sqrt are not a list"
975     return
976   }
977   var empty-args?/eax: boolean <- nil? args
978   compare empty-args?, 0/false
979   {
980     break-if-=
981     error trace, "sqrt needs 1 arg but got 0"
982     return
983   }
984   # args->left->value
985   var first-ah/eax: (addr handle cell) <- get args, left
986   var first/eax: (addr cell) <- lookup *first-ah
987   {
988     var first-type/eax: (addr int) <- get first, type
989     compare *first-type, 1/number
990     break-if-=
991     error trace, "arg for sqrt is not a number"
992     return
993   }
994   var first-value/eax: (addr float) <- get first, number-data
995   # square-root
996   var result/xmm0: float <- square-root *first-value
997   new-float out, result
1000 fn apply-abs _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1001   trace-text trace, "eval", "apply abs"
1002   var args-ah/eax: (addr handle cell) <- copy _args-ah
1003   var _args/eax: (addr cell) <- lookup *args-ah
1004   var args/esi: (addr cell) <- copy _args
1005   {
1006     var args-type/eax: (addr int) <- get args, type
1007     compare *args-type, 0/pair
1008     break-if-=
1009     error trace, "args to abs are not a list"
1010     return
1011   }
1012   var empty-args?/eax: boolean <- nil? args
1013   compare empty-args?, 0/false
1014   {
1015     break-if-=
1016     error trace, "abs needs 1 arg but got 0"
1017     return
1018   }
1019   # args->left->value
1020   var first-ah/eax: (addr handle cell) <- get args, left
1021   var first/eax: (addr cell) <- lookup *first-ah
1022   {
1023     var first-type/eax: (addr int) <- get first, type
1024     compare *first-type, 1/number
1025     break-if-=
1026     error trace, "arg for abs is not a number"
1027     return
1028   }
1029   var first-value/ecx: (addr float) <- get first, number-data
1030   #
1031   var result/xmm0: float <- copy *first-value
1032   var zero: float
1033   compare result, zero
1034   {
1035     break-if-float>=
1036     var neg1/eax: int <- copy -1
1037     var neg1-f/xmm1: float <- convert neg1
1038     result <- multiply neg1-f
1039   }
1040   new-float out, result
1043 fn apply-sgn _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1044   trace-text trace, "eval", "apply sgn"
1045   var args-ah/eax: (addr handle cell) <- copy _args-ah
1046   var _args/eax: (addr cell) <- lookup *args-ah
1047   var args/esi: (addr cell) <- copy _args
1048   {
1049     var args-type/eax: (addr int) <- get args, type
1050     compare *args-type, 0/pair
1051     break-if-=
1052     error trace, "args to sgn are not a list"
1053     return
1054   }
1055   var empty-args?/eax: boolean <- nil? args
1056   compare empty-args?, 0/false
1057   {
1058     break-if-=
1059     error trace, "sgn needs 1 arg but got 0"
1060     return
1061   }
1062   # args->left->value
1063   var first-ah/eax: (addr handle cell) <- get args, left
1064   var first/eax: (addr cell) <- lookup *first-ah
1065   {
1066     var first-type/eax: (addr int) <- get first, type
1067     compare *first-type, 1/number
1068     break-if-=
1069     error trace, "arg for sgn is not a number"
1070     return
1071   }
1072   var first-value/ecx: (addr float) <- get first, number-data
1073   #
1074   var result/xmm0: float <- copy *first-value
1075   var zero: float
1076   $apply-sgn:core: {
1077     compare result, zero
1078     break-if-=
1079     {
1080       break-if-float>
1081       var neg1/eax: int <- copy -1
1082       result <- convert neg1
1083       break $apply-sgn:core
1084     }
1085     {
1086       break-if-float<
1087       var one/eax: int <- copy 1
1088       result <- convert one
1089       break $apply-sgn:core
1090     }
1091   }
1092   new-float out, result
1095 fn apply-car _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1096   trace-text trace, "eval", "apply car"
1097   var args-ah/eax: (addr handle cell) <- copy _args-ah
1098   var _args/eax: (addr cell) <- lookup *args-ah
1099   var args/esi: (addr cell) <- copy _args
1100   {
1101     var args-type/eax: (addr int) <- get args, type
1102     compare *args-type, 0/pair
1103     break-if-=
1104     error trace, "args to car are not a list"
1105     return
1106   }
1107   var empty-args?/eax: boolean <- nil? args
1108   compare empty-args?, 0/false
1109   {
1110     break-if-=
1111     error trace, "car needs 1 arg but got 0"
1112     return
1113   }
1114   # args->left
1115   var first-ah/edx: (addr handle cell) <- get args, left
1116   var first/eax: (addr cell) <- lookup *first-ah
1117   {
1118     var first-type/eax: (addr int) <- get first, type
1119     compare *first-type, 0/pair
1120     break-if-=
1121     error trace, "arg for car is not a pair"
1122     return
1123   }
1124   # nil? return nil
1125   {
1126     var nil?/eax: boolean <- nil? first
1127     compare nil?, 0/false
1128     break-if-=
1129     copy-object first-ah, out
1130     return
1131   }
1132   # car
1133   var result/eax: (addr handle cell) <- get first, left
1134   copy-object result, out
1137 fn apply-cdr _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1138   trace-text trace, "eval", "apply cdr"
1139   var args-ah/eax: (addr handle cell) <- copy _args-ah
1140   var _args/eax: (addr cell) <- lookup *args-ah
1141   var args/esi: (addr cell) <- copy _args
1142   {
1143     var args-type/eax: (addr int) <- get args, type
1144     compare *args-type, 0/pair
1145     break-if-=
1146     error trace, "args to cdr are not a list"
1147     return
1148   }
1149   var empty-args?/eax: boolean <- nil? args
1150   compare empty-args?, 0/false
1151   {
1152     break-if-=
1153     error trace, "cdr needs 1 arg but got 0"
1154     return
1155   }
1156   # args->left
1157   var first-ah/edx: (addr handle cell) <- get args, left
1158   var first/eax: (addr cell) <- lookup *first-ah
1159   {
1160     var first-type/eax: (addr int) <- get first, type
1161     compare *first-type, 0/pair
1162     break-if-=
1163     error trace, "arg for cdr is not a pair"
1164     return
1165   }
1166   # nil? return nil
1167   {
1168     var nil?/eax: boolean <- nil? first
1169     compare nil?, 0/false
1170     break-if-=
1171     copy-object first-ah, out
1172     return
1173   }
1174   # cdr
1175   var result/eax: (addr handle cell) <- get first, right
1176   copy-object result, out
1179 fn apply-cons _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1180   trace-text trace, "eval", "apply cons"
1181   var args-ah/eax: (addr handle cell) <- copy _args-ah
1182   var _args/eax: (addr cell) <- lookup *args-ah
1183   var args/esi: (addr cell) <- copy _args
1184   {
1185     var args-type/eax: (addr int) <- get args, type
1186     compare *args-type, 0/pair
1187     break-if-=
1188     error trace, "args to 'cons' are not a list"
1189     return
1190   }
1191   var empty-args?/eax: boolean <- nil? args
1192   compare empty-args?, 0/false
1193   {
1194     break-if-=
1195     error trace, "cons needs 2 args but got 0"
1196     return
1197   }
1198   # args->left
1199   var first-ah/ecx: (addr handle cell) <- get args, left
1200   # args->right->left
1201   var right-ah/eax: (addr handle cell) <- get args, right
1202   var right/eax: (addr cell) <- lookup *right-ah
1203   {
1204     var right-type/eax: (addr int) <- get right, type
1205     compare *right-type, 0/pair
1206     break-if-=
1207     error trace, "'cons' encountered non-pair"
1208     return
1209   }
1210   {
1211     var nil?/eax: boolean <- nil? right
1212     compare nil?, 0/false
1213     break-if-=
1214     error trace, "'cons' needs 2 args but got 1"
1215     return
1216   }
1217   var second-ah/eax: (addr handle cell) <- get right, left
1218   # cons
1219   new-pair out, *first-ah, *second-ah
1222 fn apply-cons-check _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1223   trace-text trace, "eval", "apply cons?"
1224   var args-ah/eax: (addr handle cell) <- copy _args-ah
1225   var _args/eax: (addr cell) <- lookup *args-ah
1226   var args/esi: (addr cell) <- copy _args
1227   {
1228     var args-type/eax: (addr int) <- get args, type
1229     compare *args-type, 0/pair
1230     break-if-=
1231     error trace, "args to cons? are not a list"
1232     return
1233   }
1234   var empty-args?/eax: boolean <- nil? args
1235   compare empty-args?, 0/false
1236   {
1237     break-if-=
1238     error trace, "cons? needs 1 arg but got 0"
1239     return
1240   }
1241   # args->left
1242   var first-ah/edx: (addr handle cell) <- get args, left
1243   var first/eax: (addr cell) <- lookup *first-ah
1244   {
1245     var first-type/eax: (addr int) <- get first, type
1246     compare *first-type, 0/pair
1247     break-if-=
1248     nil out
1249     return
1250   }
1251   new-integer out, 1
1254 fn apply-len _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1255   trace-text trace, "eval", "apply len"
1256   var args-ah/eax: (addr handle cell) <- copy _args-ah
1257   var _args/eax: (addr cell) <- lookup *args-ah
1258   var args/esi: (addr cell) <- copy _args
1259   {
1260     var args-type/eax: (addr int) <- get args, type
1261     compare *args-type, 0/pair
1262     break-if-=
1263     error trace, "args to len are not a list"
1264     return
1265   }
1266   var empty-args?/eax: boolean <- nil? args
1267   compare empty-args?, 0/false
1268   {
1269     break-if-=
1270     error trace, "len needs 1 arg but got 0"
1271     return
1272   }
1273   # args->left
1274   var first-ah/edx: (addr handle cell) <- get args, left
1275   var first/eax: (addr cell) <- lookup *first-ah
1276   {
1277     {
1278       var first-pair?/eax: boolean <- pair? first
1279       compare first-pair?, 0/false
1280     }
1281     break-if-=
1282     var result/eax: int <- list-length first
1283     new-integer out, result
1284     return
1285   }
1286   {
1287     {
1288       var first-array?/eax: boolean <- array? first
1289       compare first-array?, 0/false
1290     }
1291     break-if-=
1292     var result/eax: int <- array-length first
1293     new-integer out, result
1294     return
1295   }
1296   nil out
1299 fn list-length in: (addr cell) -> _/eax: int {
1300   var curr/ecx: (addr cell) <- copy in
1301   var result/edi: int <- copy 0
1302   {
1303     var pair?/eax: boolean <- pair? curr
1304     {
1305       compare pair?, 0/false
1306       break-if-!=
1307       abort "len: ran into a non-cons"
1308     }
1309     var nil?/eax: boolean <- nil? curr
1310     compare nil?, 0/false
1311     break-if-!=
1312     result <- increment
1313     var next-ah/eax: (addr handle cell) <- get curr, right
1314     var next/eax: (addr cell) <- lookup *next-ah
1315     curr <- copy next
1316     loop
1317   }
1318   return result
1321 fn array-length _in: (addr cell) -> _/eax: int {
1322   var in/esi: (addr cell) <- copy _in
1323   var in-data-ah/eax: (addr handle array handle cell) <- get in, array-data
1324   var in-data/eax: (addr array handle cell) <- lookup *in-data-ah
1325   var result/eax: int <- length in-data
1326   return result
1329 fn apply-cell-isomorphic _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1330   trace-text trace, "eval", "apply '='"
1331   var args-ah/eax: (addr handle cell) <- copy _args-ah
1332   var _args/eax: (addr cell) <- lookup *args-ah
1333   var args/esi: (addr cell) <- copy _args
1334   {
1335     var args-type/eax: (addr int) <- get args, type
1336     compare *args-type, 0/pair
1337     break-if-=
1338     error trace, "args to '=' are not a list"
1339     return
1340   }
1341   var empty-args?/eax: boolean <- nil? args
1342   compare empty-args?, 0/false
1343   {
1344     break-if-=
1345     error trace, "'=' needs 2 args but got 0"
1346     return
1347   }
1348   # args->left
1349   var first-ah/ecx: (addr handle cell) <- get args, left
1350   # args->right->left
1351   var right-ah/eax: (addr handle cell) <- get args, right
1352   var right/eax: (addr cell) <- lookup *right-ah
1353   {
1354     var right-type/eax: (addr int) <- get right, type
1355     compare *right-type, 0/pair
1356     break-if-=
1357     error trace, "'=' encountered non-pair"
1358     return
1359   }
1360   {
1361     var nil?/eax: boolean <- nil? right
1362     compare nil?, 0/false
1363     break-if-=
1364     error trace, "'=' needs 2 args but got 1"
1365     return
1366   }
1367   var second-ah/edx: (addr handle cell) <- get right, left
1368   # compare
1369   var _first/eax: (addr cell) <- lookup *first-ah
1370   var first/ecx: (addr cell) <- copy _first
1371   var second/eax: (addr cell) <- lookup *second-ah
1372   var match?/eax: boolean <- cell-isomorphic? first, second, trace
1373   compare match?, 0/false
1374   {
1375     break-if-!=
1376     nil out
1377     return
1378   }
1379   new-integer out, 1/true
1382 fn apply-not _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1383   trace-text trace, "eval", "apply 'not'"
1384   var args-ah/eax: (addr handle cell) <- copy _args-ah
1385   var _args/eax: (addr cell) <- lookup *args-ah
1386   var args/esi: (addr cell) <- copy _args
1387   {
1388     var args-type/eax: (addr int) <- get args, type
1389     compare *args-type, 0/pair
1390     break-if-=
1391     error trace, "args to 'not' are not a list"
1392     return
1393   }
1394   var empty-args?/eax: boolean <- nil? args
1395   compare empty-args?, 0/false
1396   {
1397     break-if-=
1398     error trace, "'not' needs 1 arg but got 0"
1399     return
1400   }
1401   # args->left
1402   var first-ah/eax: (addr handle cell) <- get args, left
1403   var first/eax: (addr cell) <- lookup *first-ah
1404   # not
1405   var nil?/eax: boolean <- nil? first
1406   compare nil?, 0/false
1407   {
1408     break-if-!=
1409     nil out
1410     return
1411   }
1412   new-integer out, 1
1415 fn apply-debug _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1416   trace-text trace, "eval", "apply 'debug'"
1417   var args-ah/eax: (addr handle cell) <- copy _args-ah
1418   var _args/eax: (addr cell) <- lookup *args-ah
1419   var args/esi: (addr cell) <- copy _args
1420   {
1421     var args-type/eax: (addr int) <- get args, type
1422     compare *args-type, 0/pair
1423     break-if-=
1424     error trace, "args to 'debug' are not a list"
1425     return
1426   }
1427   var empty-args?/eax: boolean <- nil? args
1428   compare empty-args?, 0/false
1429   {
1430     break-if-=
1431     error trace, "'debug' needs 1 arg but got 0"
1432     return
1433   }
1434   # dump args->left uglily to screen and wait for a keypress
1435   var first-ah/eax: (addr handle cell) <- get args, left
1436   dump-cell-from-cursor-over-full-screen first-ah, 7/fg 0/bg
1437   {
1438     var foo/eax: byte <- read-key 0/keyboard
1439     compare foo, 0
1440     loop-if-=
1441   }
1442   # return nothing
1445 fn apply-< _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1446   trace-text trace, "eval", "apply '<'"
1447   var args-ah/eax: (addr handle cell) <- copy _args-ah
1448   var _args/eax: (addr cell) <- lookup *args-ah
1449   var args/esi: (addr cell) <- copy _args
1450   {
1451     var args-type/eax: (addr int) <- get args, type
1452     compare *args-type, 0/pair
1453     break-if-=
1454     error trace, "args to '<' are not a list"
1455     return
1456   }
1457   var empty-args?/eax: boolean <- nil? args
1458   compare empty-args?, 0/false
1459   {
1460     break-if-=
1461     error trace, "'<' needs 2 args but got 0"
1462     return
1463   }
1464   # args->left
1465   var first-ah/ecx: (addr handle cell) <- get args, left
1466   # args->right->left
1467   var right-ah/eax: (addr handle cell) <- get args, right
1468   var right/eax: (addr cell) <- lookup *right-ah
1469   {
1470     var right-type/eax: (addr int) <- get right, type
1471     compare *right-type, 0/pair
1472     break-if-=
1473     error trace, "'<' encountered non-pair"
1474     return
1475   }
1476   {
1477     var nil?/eax: boolean <- nil? right
1478     compare nil?, 0/false
1479     break-if-=
1480     error trace, "'<' needs 2 args but got 1"
1481     return
1482   }
1483   var second-ah/edx: (addr handle cell) <- get right, left
1484   # compare
1485   var _first/eax: (addr cell) <- lookup *first-ah
1486   var first/ecx: (addr cell) <- copy _first
1487   {
1488     var first-type/eax: (addr int) <- get first, type
1489     compare *first-type, 1/number
1490     break-if-=
1491     error trace, "first arg for '<' is not a number"
1492     return
1493   }
1494   var first-value/ecx: (addr float) <- get first, number-data
1495   var first-float/xmm0: float <- copy *first-value
1496   var second/eax: (addr cell) <- lookup *second-ah
1497   {
1498     var second-type/eax: (addr int) <- get second, type
1499     compare *second-type, 1/number
1500     break-if-=
1501     error trace, "second arg for '<' is not a number"
1502     return
1503   }
1504   var second-value/eax: (addr float) <- get second, number-data
1505   compare first-float, *second-value
1506   {
1507     break-if-float<
1508     nil out
1509     return
1510   }
1511   new-integer out, 1/true
1514 fn apply-> _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1515   trace-text trace, "eval", "apply '>'"
1516   var args-ah/eax: (addr handle cell) <- copy _args-ah
1517   var _args/eax: (addr cell) <- lookup *args-ah
1518   var args/esi: (addr cell) <- copy _args
1519   {
1520     var args-type/eax: (addr int) <- get args, type
1521     compare *args-type, 0/pair
1522     break-if-=
1523     error trace, "args to '>' are not a list"
1524     return
1525   }
1526   var empty-args?/eax: boolean <- nil? args
1527   compare empty-args?, 0/false
1528   {
1529     break-if-=
1530     error trace, "'>' needs 2 args but got 0"
1531     return
1532   }
1533   # args->left
1534   var first-ah/ecx: (addr handle cell) <- get args, left
1535   # args->right->left
1536   var right-ah/eax: (addr handle cell) <- get args, right
1537   var right/eax: (addr cell) <- lookup *right-ah
1538   {
1539     var right-type/eax: (addr int) <- get right, type
1540     compare *right-type, 0/pair
1541     break-if-=
1542     error trace, "'>' encountered non-pair"
1543     return
1544   }
1545   {
1546     var nil?/eax: boolean <- nil? right
1547     compare nil?, 0/false
1548     break-if-=
1549     error trace, "'>' needs 2 args but got 1"
1550     return
1551   }
1552   var second-ah/edx: (addr handle cell) <- get right, left
1553   # compare
1554   var _first/eax: (addr cell) <- lookup *first-ah
1555   var first/ecx: (addr cell) <- copy _first
1556   {
1557     var first-type/eax: (addr int) <- get first, type
1558     compare *first-type, 1/number
1559     break-if-=
1560     error trace, "first arg for '>' is not a number"
1561     return
1562   }
1563   var first-value/ecx: (addr float) <- get first, number-data
1564   var first-float/xmm0: float <- copy *first-value
1565   var second/eax: (addr cell) <- lookup *second-ah
1566   {
1567     var second-type/eax: (addr int) <- get second, type
1568     compare *second-type, 1/number
1569     break-if-=
1570     error trace, "second arg for '>' is not a number"
1571     return
1572   }
1573   var second-value/eax: (addr float) <- get second, number-data
1574   compare first-float, *second-value
1575   {
1576     break-if-float>
1577     nil out
1578     return
1579   }
1580   new-integer out, 1/true
1583 fn apply-<= _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1584   trace-text trace, "eval", "apply '<='"
1585   var args-ah/eax: (addr handle cell) <- copy _args-ah
1586   var _args/eax: (addr cell) <- lookup *args-ah
1587   var args/esi: (addr cell) <- copy _args
1588   {
1589     var args-type/eax: (addr int) <- get args, type
1590     compare *args-type, 0/pair
1591     break-if-=
1592     error trace, "args to '<=' are not a list"
1593     return
1594   }
1595   var empty-args?/eax: boolean <- nil? args
1596   compare empty-args?, 0/false
1597   {
1598     break-if-=
1599     error trace, "'<=' needs 2 args but got 0"
1600     return
1601   }
1602   # args->left
1603   var first-ah/ecx: (addr handle cell) <- get args, left
1604   # args->right->left
1605   var right-ah/eax: (addr handle cell) <- get args, right
1606   var right/eax: (addr cell) <- lookup *right-ah
1607   {
1608     var right-type/eax: (addr int) <- get right, type
1609     compare *right-type, 0/pair
1610     break-if-=
1611     error trace, "'<=' encountered non-pair"
1612     return
1613   }
1614   {
1615     var nil?/eax: boolean <- nil? right
1616     compare nil?, 0/false
1617     break-if-=
1618     error trace, "'<=' needs 2 args but got 1"
1619     return
1620   }
1621   var second-ah/edx: (addr handle cell) <- get right, left
1622   # compare
1623   var _first/eax: (addr cell) <- lookup *first-ah
1624   var first/ecx: (addr cell) <- copy _first
1625   {
1626     var first-type/eax: (addr int) <- get first, type
1627     compare *first-type, 1/number
1628     break-if-=
1629     error trace, "first arg for '<=' is not a number"
1630     return
1631   }
1632   var first-value/ecx: (addr float) <- get first, number-data
1633   var first-float/xmm0: float <- copy *first-value
1634   var second/eax: (addr cell) <- lookup *second-ah
1635   {
1636     var second-type/eax: (addr int) <- get second, type
1637     compare *second-type, 1/number
1638     break-if-=
1639     error trace, "second arg for '<=' is not a number"
1640     return
1641   }
1642   var second-value/eax: (addr float) <- get second, number-data
1643   compare first-float, *second-value
1644   {
1645     break-if-float<=
1646     nil out
1647     return
1648   }
1649   new-integer out, 1/true
1652 fn apply->= _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1653   trace-text trace, "eval", "apply '>='"
1654   var args-ah/eax: (addr handle cell) <- copy _args-ah
1655   var _args/eax: (addr cell) <- lookup *args-ah
1656   var args/esi: (addr cell) <- copy _args
1657   {
1658     var args-type/eax: (addr int) <- get args, type
1659     compare *args-type, 0/pair
1660     break-if-=
1661     error trace, "args to '>=' are not a list"
1662     return
1663   }
1664   var empty-args?/eax: boolean <- nil? args
1665   compare empty-args?, 0/false
1666   {
1667     break-if-=
1668     error trace, "'>=' needs 2 args but got 0"
1669     return
1670   }
1671   # args->left
1672   var first-ah/ecx: (addr handle cell) <- get args, left
1673   # args->right->left
1674   var right-ah/eax: (addr handle cell) <- get args, right
1675   var right/eax: (addr cell) <- lookup *right-ah
1676   {
1677     var right-type/eax: (addr int) <- get right, type
1678     compare *right-type, 0/pair
1679     break-if-=
1680     error trace, "'>=' encountered non-pair"
1681     return
1682   }
1683   {
1684     var nil?/eax: boolean <- nil? right
1685     compare nil?, 0/false
1686     break-if-=
1687     error trace, "'>=' needs 2 args but got 1"
1688     return
1689   }
1690   var second-ah/edx: (addr handle cell) <- get right, left
1691   # compare
1692   var _first/eax: (addr cell) <- lookup *first-ah
1693   var first/ecx: (addr cell) <- copy _first
1694   {
1695     var first-type/eax: (addr int) <- get first, type
1696     compare *first-type, 1/number
1697     break-if-=
1698     error trace, "first arg for '>=' is not a number"
1699     return
1700   }
1701   var first-value/ecx: (addr float) <- get first, number-data
1702   var first-float/xmm0: float <- copy *first-value
1703   var second/eax: (addr cell) <- lookup *second-ah
1704   {
1705     var second-type/eax: (addr int) <- get second, type
1706     compare *second-type, 1/number
1707     break-if-=
1708     error trace, "second arg for '>=' is not a number"
1709     return
1710   }
1711   var second-value/eax: (addr float) <- get second, number-data
1712   compare first-float, *second-value
1713   {
1714     break-if-float>=
1715     nil out
1716     return
1717   }
1718   new-integer out, 1/true
1721 fn apply-print _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1722   trace-text trace, "eval", "apply 'print'"
1723   var args-ah/eax: (addr handle cell) <- copy _args-ah
1724   var _args/eax: (addr cell) <- lookup *args-ah
1725   var args/esi: (addr cell) <- copy _args
1726   {
1727     var args-type/eax: (addr int) <- get args, type
1728     compare *args-type, 0/pair
1729     break-if-=
1730     error trace, "args to 'print' are not a list"
1731     return
1732   }
1733   var empty-args?/eax: boolean <- nil? args
1734   compare empty-args?, 0/false
1735   {
1736     break-if-=
1737     error trace, "'print' needs 2 args but got 0"
1738     return
1739   }
1740   # screen = args->left
1741   var first-ah/eax: (addr handle cell) <- get args, left
1742   var first/eax: (addr cell) <- lookup *first-ah
1743   {
1744     var first-type/eax: (addr int) <- get first, type
1745     compare *first-type, 5/screen
1746     break-if-=
1747     error trace, "first arg for 'print' is not a screen"
1748     return
1749   }
1750   var screen-ah/eax: (addr handle screen) <- get first, screen-data
1751   var _screen/eax: (addr screen) <- lookup *screen-ah
1752   var screen/ecx: (addr screen) <- copy _screen
1753   # args->right->left
1754   var right-ah/eax: (addr handle cell) <- get args, right
1755   var right/eax: (addr cell) <- lookup *right-ah
1756   {
1757     var right-type/eax: (addr int) <- get right, type
1758     compare *right-type, 0/pair
1759     break-if-=
1760     error trace, "'print' encountered non-pair"
1761     return
1762   }
1763   {
1764     var nil?/eax: boolean <- nil? right
1765     compare nil?, 0/false
1766     break-if-=
1767     error trace, "'print' needs 2 args but got 1"
1768     return
1769   }
1770   var second-ah/eax: (addr handle cell) <- get right, left
1771   var stream-storage: (stream byte 0x100)
1772   var stream/edi: (addr stream byte) <- address stream-storage
1773   print-cell second-ah, stream, trace
1774   draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen, stream, 7/fg, 0/bg
1775   # return what was printed
1776   copy-object second-ah, out
1779 fn apply-clear _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1780   trace-text trace, "eval", "apply 'clear'"
1781   var args-ah/eax: (addr handle cell) <- copy _args-ah
1782   var _args/eax: (addr cell) <- lookup *args-ah
1783   var args/esi: (addr cell) <- copy _args
1784   {
1785     var args-type/eax: (addr int) <- get args, type
1786     compare *args-type, 0/pair
1787     break-if-=
1788     error trace, "args to 'clear' are not a list"
1789     return
1790   }
1791   var empty-args?/eax: boolean <- nil? args
1792   compare empty-args?, 0/false
1793   {
1794     break-if-=
1795     error trace, "'clear' needs 1 arg but got 0"
1796     return
1797   }
1798   # screen = args->left
1799   var first-ah/eax: (addr handle cell) <- get args, left
1800   var first/eax: (addr cell) <- lookup *first-ah
1801   var first-type/ecx: (addr int) <- get first, type
1802   compare *first-type, 3/stream
1803   {
1804     break-if-!=
1805     var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
1806     var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
1807     var stream-data/ebx: (addr stream byte) <- copy _stream-data
1808     clear-stream stream-data
1809     return
1810   }
1811   compare *first-type, 5/screen
1812   {
1813     break-if-!=
1814     var screen-ah/eax: (addr handle screen) <- get first, screen-data
1815     var _screen/eax: (addr screen) <- lookup *screen-ah
1816     var screen/ecx: (addr screen) <- copy _screen
1817     clear-screen screen
1818     return
1819   }
1820   error trace, "first arg for 'clear' is not a screen or a stream"
1823 fn apply-up _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1824   trace-text trace, "eval", "apply 'up'"
1825   var args-ah/eax: (addr handle cell) <- copy _args-ah
1826   var _args/eax: (addr cell) <- lookup *args-ah
1827   var args/esi: (addr cell) <- copy _args
1828   {
1829     var args-type/eax: (addr int) <- get args, type
1830     compare *args-type, 0/pair
1831     break-if-=
1832     error trace, "args to 'up' are not a list"
1833     return
1834   }
1835   var empty-args?/eax: boolean <- nil? args
1836   compare empty-args?, 0/false
1837   {
1838     break-if-=
1839     error trace, "'up' needs 1 arg but got 0"
1840     return
1841   }
1842   # screen = args->left
1843   var first-ah/eax: (addr handle cell) <- get args, left
1844   var first/eax: (addr cell) <- lookup *first-ah
1845   {
1846     var first-type/eax: (addr int) <- get first, type
1847     compare *first-type, 5/screen
1848     break-if-=
1849     error trace, "first arg for 'up' is not a screen"
1850     return
1851   }
1852   var screen-ah/eax: (addr handle screen) <- get first, screen-data
1853   var _screen/eax: (addr screen) <- lookup *screen-ah
1854   var screen/ecx: (addr screen) <- copy _screen
1855   #
1856   move-cursor-up screen
1859 fn apply-down _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1860   trace-text trace, "eval", "apply 'down'"
1861   var args-ah/eax: (addr handle cell) <- copy _args-ah
1862   var _args/eax: (addr cell) <- lookup *args-ah
1863   var args/esi: (addr cell) <- copy _args
1864   {
1865     var args-type/eax: (addr int) <- get args, type
1866     compare *args-type, 0/pair
1867     break-if-=
1868     error trace, "args to 'down' are not a list"
1869     return
1870   }
1871   var empty-args?/eax: boolean <- nil? args
1872   compare empty-args?, 0/false
1873   {
1874     break-if-=
1875     error trace, "'down' needs 1 arg but got 0"
1876     return
1877   }
1878   # screen = args->left
1879   var first-ah/eax: (addr handle cell) <- get args, left
1880   var first/eax: (addr cell) <- lookup *first-ah
1881   {
1882     var first-type/eax: (addr int) <- get first, type
1883     compare *first-type, 5/screen
1884     break-if-=
1885     error trace, "first arg for 'down' is not a screen"
1886     return
1887   }
1888   var screen-ah/eax: (addr handle screen) <- get first, screen-data
1889   var _screen/eax: (addr screen) <- lookup *screen-ah
1890   var screen/ecx: (addr screen) <- copy _screen
1891   #
1892   move-cursor-down screen
1895 fn apply-left _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1896   trace-text trace, "eval", "apply 'left'"
1897   var args-ah/eax: (addr handle cell) <- copy _args-ah
1898   var _args/eax: (addr cell) <- lookup *args-ah
1899   var args/esi: (addr cell) <- copy _args
1900   {
1901     var args-type/eax: (addr int) <- get args, type
1902     compare *args-type, 0/pair
1903     break-if-=
1904     error trace, "args to 'left' are not a list"
1905     return
1906   }
1907   var empty-args?/eax: boolean <- nil? args
1908   compare empty-args?, 0/false
1909   {
1910     break-if-=
1911     error trace, "'left' needs 1 arg but got 0"
1912     return
1913   }
1914   # screen = args->left
1915   var first-ah/eax: (addr handle cell) <- get args, left
1916   var first/eax: (addr cell) <- lookup *first-ah
1917   {
1918     var first-type/eax: (addr int) <- get first, type
1919     compare *first-type, 5/screen
1920     break-if-=
1921     error trace, "first arg for 'left' is not a screen"
1922     return
1923   }
1924   var screen-ah/eax: (addr handle screen) <- get first, screen-data
1925   var _screen/eax: (addr screen) <- lookup *screen-ah
1926   var screen/ecx: (addr screen) <- copy _screen
1927   #
1928   move-cursor-left screen
1931 fn apply-right _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1932   trace-text trace, "eval", "apply 'right'"
1933   var args-ah/eax: (addr handle cell) <- copy _args-ah
1934   var _args/eax: (addr cell) <- lookup *args-ah
1935   var args/esi: (addr cell) <- copy _args
1936   {
1937     var args-type/eax: (addr int) <- get args, type
1938     compare *args-type, 0/pair
1939     break-if-=
1940     error trace, "args to 'right' are not a list"
1941     return
1942   }
1943   var empty-args?/eax: boolean <- nil? args
1944   compare empty-args?, 0/false
1945   {
1946     break-if-=
1947     error trace, "'right' needs 1 arg but got 0"
1948     return
1949   }
1950   # screen = args->left
1951   var first-ah/eax: (addr handle cell) <- get args, left
1952   var first/eax: (addr cell) <- lookup *first-ah
1953   {
1954     var first-type/eax: (addr int) <- get first, type
1955     compare *first-type, 5/screen
1956     break-if-=
1957     error trace, "first arg for 'right' is not a screen"
1958     return
1959   }
1960   var screen-ah/eax: (addr handle screen) <- get first, screen-data
1961   var _screen/eax: (addr screen) <- lookup *screen-ah
1962   var screen/ecx: (addr screen) <- copy _screen
1963   #
1964   move-cursor-right screen
1967 fn apply-cr _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
1968   trace-text trace, "eval", "apply 'cr'"
1969   var args-ah/eax: (addr handle cell) <- copy _args-ah
1970   var _args/eax: (addr cell) <- lookup *args-ah
1971   var args/esi: (addr cell) <- copy _args
1972   {
1973     var args-type/eax: (addr int) <- get args, type
1974     compare *args-type, 0/pair
1975     break-if-=
1976     error trace, "args to 'cr' are not a list"
1977     return
1978   }
1979   var empty-args?/eax: boolean <- nil? args
1980   compare empty-args?, 0/false
1981   {
1982     break-if-=
1983     error trace, "'cr' needs 1 arg but got 0"
1984     return
1985   }
1986   # screen = args->left
1987   var first-ah/eax: (addr handle cell) <- get args, left
1988   var first/eax: (addr cell) <- lookup *first-ah
1989   {
1990     var first-type/eax: (addr int) <- get first, type
1991     compare *first-type, 5/screen
1992     break-if-=
1993     error trace, "first arg for 'cr' is not a screen"
1994     return
1995   }
1996   var screen-ah/eax: (addr handle screen) <- get first, screen-data
1997   var _screen/eax: (addr screen) <- lookup *screen-ah
1998   var screen/ecx: (addr screen) <- copy _screen
1999   #
2000   move-cursor-to-left-margin-of-next-line screen
2003 fn apply-pixel _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
2004   trace-text trace, "eval", "apply 'pixel'"
2005   var args-ah/eax: (addr handle cell) <- copy _args-ah
2006   var _args/eax: (addr cell) <- lookup *args-ah
2007   var args/esi: (addr cell) <- copy _args
2008   {
2009     var args-type/eax: (addr int) <- get args, type
2010     compare *args-type, 0/pair
2011     break-if-=
2012     error trace, "args to 'pixel' are not a list"
2013     return
2014   }
2015   var empty-args?/eax: boolean <- nil? args
2016   compare empty-args?, 0/false
2017   {
2018     break-if-=
2019     error trace, "'pixel' needs 4 args but got 0"
2020     return
2021   }
2022   # screen = args->left
2023   var first-ah/eax: (addr handle cell) <- get args, left
2024   var first/eax: (addr cell) <- lookup *first-ah
2025   {
2026     var first-type/eax: (addr int) <- get first, type
2027     compare *first-type, 5/screen
2028     break-if-=
2029     error trace, "first arg for 'pixel' is not a screen"
2030     return
2031   }
2032   var screen-ah/eax: (addr handle screen) <- get first, screen-data
2033   var _screen/eax: (addr screen) <- lookup *screen-ah
2034   var screen/edi: (addr screen) <- copy _screen
2035   # x = args->right->left->value
2036   var rest-ah/eax: (addr handle cell) <- get args, right
2037   var _rest/eax: (addr cell) <- lookup *rest-ah
2038   var rest/esi: (addr cell) <- copy _rest
2039   {
2040     var rest-type/eax: (addr int) <- get rest, type
2041     compare *rest-type, 0/pair
2042     break-if-=
2043     error trace, "'pixel' encountered non-pair"
2044     return
2045   }
2046   {
2047     var rest-nil?/eax: boolean <- nil? rest
2048     compare rest-nil?, 0/false
2049     break-if-=
2050     error trace, "'pixel' needs 4 args but got 1"
2051     return
2052   }
2053   var second-ah/eax: (addr handle cell) <- get rest, left
2054   var second/eax: (addr cell) <- lookup *second-ah
2055   {
2056     var second-type/eax: (addr int) <- get second, type
2057     compare *second-type, 1/number
2058     break-if-=
2059     error trace, "second arg for 'pixel' is not an int (x coordinate)"
2060     return
2061   }
2062   var second-value/eax: (addr float) <- get second, number-data
2063   var x/edx: int <- convert *second-value
2064   # y = rest->right->left->value
2065   var rest-ah/eax: (addr handle cell) <- get rest, right
2066   var _rest/eax: (addr cell) <- lookup *rest-ah
2067   rest <- copy _rest
2068   {
2069     var rest-type/eax: (addr int) <- get rest, type
2070     compare *rest-type, 0/pair
2071     break-if-=
2072     error trace, "'pixel' encountered non-pair"
2073     return
2074   }
2075   {
2076     var rest-nil?/eax: boolean <- nil? rest
2077     compare rest-nil?, 0/false
2078     break-if-=
2079     error trace, "'pixel' needs 4 args but got 2"
2080     return
2081   }
2082   var third-ah/eax: (addr handle cell) <- get rest, left
2083   var third/eax: (addr cell) <- lookup *third-ah
2084   {
2085     var third-type/eax: (addr int) <- get third, type
2086     compare *third-type, 1/number
2087     break-if-=
2088     error trace, "third arg for 'pixel' is not an int (y coordinate)"
2089     return
2090   }
2091   var third-value/eax: (addr float) <- get third, number-data
2092   var y/ebx: int <- convert *third-value
2093   # color = rest->right->left->value
2094   var rest-ah/eax: (addr handle cell) <- get rest, right
2095   var _rest/eax: (addr cell) <- lookup *rest-ah
2096   rest <- copy _rest
2097   {
2098     var rest-type/eax: (addr int) <- get rest, type
2099     compare *rest-type, 0/pair
2100     break-if-=
2101     error trace, "'pixel' encountered non-pair"
2102     return
2103   }
2104   {
2105     var rest-nil?/eax: boolean <- nil? rest
2106     compare rest-nil?, 0/false
2107     break-if-=
2108     error trace, "'pixel' needs 4 args but got 3"
2109     return
2110   }
2111   var fourth-ah/eax: (addr handle cell) <- get rest, left
2112   var fourth/eax: (addr cell) <- lookup *fourth-ah
2113   {
2114     var fourth-type/eax: (addr int) <- get fourth, type
2115     compare *fourth-type, 1/number
2116     break-if-=
2117     error trace, "fourth arg for 'pixel' is not an int (color; 0..0xff)"
2118     return
2119   }
2120   var fourth-value/eax: (addr float) <- get fourth, number-data
2121   var color/eax: int <- convert *fourth-value
2122   pixel screen, x, y, color
2123   # return nothing
2126 fn apply-line _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
2127   trace-text trace, "eval", "apply 'line'"
2128   var args-ah/eax: (addr handle cell) <- copy _args-ah
2129   var _args/eax: (addr cell) <- lookup *args-ah
2130   var args/esi: (addr cell) <- copy _args
2131   {
2132     var args-type/eax: (addr int) <- get args, type
2133     compare *args-type, 0/pair
2134     break-if-=
2135     error trace, "args to 'line' are not a list"
2136     return
2137   }
2138   var empty-args?/eax: boolean <- nil? args
2139   compare empty-args?, 0/false
2140   {
2141     break-if-=
2142     error trace, "'line' needs 6 args but got 0"
2143     return
2144   }
2145   # screen = args->left
2146   var first-ah/eax: (addr handle cell) <- get args, left
2147   var first/eax: (addr cell) <- lookup *first-ah
2148   {
2149     var first-type/eax: (addr int) <- get first, type
2150     compare *first-type, 5/screen
2151     break-if-=
2152     error trace, "first arg for 'line' is not a screen"
2153     return
2154   }
2155   var screen-ah/eax: (addr handle screen) <- get first, screen-data
2156   var _screen/eax: (addr screen) <- lookup *screen-ah
2157   var screen/edi: (addr screen) <- copy _screen
2158   # x1 = args->right->left->value
2159   var rest-ah/eax: (addr handle cell) <- get args, right
2160   var _rest/eax: (addr cell) <- lookup *rest-ah
2161   var rest/esi: (addr cell) <- copy _rest
2162   {
2163     var rest-type/eax: (addr int) <- get rest, type
2164     compare *rest-type, 0/pair
2165     break-if-=
2166     error trace, "'line' encountered non-pair"
2167     return
2168   }
2169   {
2170     var rest-nil?/eax: boolean <- nil? rest
2171     compare rest-nil?, 0/false
2172     break-if-=
2173     error trace, "'line' needs 6 args but got 1"
2174     return
2175   }
2176   var second-ah/eax: (addr handle cell) <- get rest, left
2177   var second/eax: (addr cell) <- lookup *second-ah
2178   {
2179     var second-type/eax: (addr int) <- get second, type
2180     compare *second-type, 1/number
2181     break-if-=
2182     error trace, "second arg for 'line' is not a number (screen x coordinate of start point)"
2183     return
2184   }
2185   var second-value/eax: (addr float) <- get second, number-data
2186   var x1/edx: int <- convert *second-value
2187   # y1 = rest->right->left->value
2188   var rest-ah/eax: (addr handle cell) <- get rest, right
2189   var _rest/eax: (addr cell) <- lookup *rest-ah
2190   rest <- copy _rest
2191   {
2192     var rest-type/eax: (addr int) <- get rest, type
2193     compare *rest-type, 0/pair
2194     break-if-=
2195     error trace, "'line' encountered non-pair"
2196     return
2197   }
2198   {
2199     var rest-nil?/eax: boolean <- nil? rest
2200     compare rest-nil?, 0/false
2201     break-if-=
2202     error trace, "'line' needs 6 args but got 2"
2203     return
2204   }
2205   var third-ah/eax: (addr handle cell) <- get rest, left
2206   var third/eax: (addr cell) <- lookup *third-ah
2207   {
2208     var third-type/eax: (addr int) <- get third, type
2209     compare *third-type, 1/number
2210     break-if-=
2211     error trace, "third arg for 'line' is not a number (screen y coordinate of start point)"
2212     return
2213   }
2214   var third-value/eax: (addr float) <- get third, number-data
2215   var y1/ebx: int <- convert *third-value
2216   # x2 = rest->right->left->value
2217   var rest-ah/eax: (addr handle cell) <- get rest, right
2218   var _rest/eax: (addr cell) <- lookup *rest-ah
2219   var rest/esi: (addr cell) <- copy _rest
2220   {
2221     var rest-type/eax: (addr int) <- get rest, type
2222     compare *rest-type, 0/pair
2223     break-if-=
2224     error trace, "'line' encountered non-pair"
2225     return
2226   }
2227   {
2228     var rest-nil?/eax: boolean <- nil? rest
2229     compare rest-nil?, 0/false
2230     break-if-=
2231     error trace, "'line' needs 6 args but got 3"
2232     return
2233   }
2234   var fourth-ah/eax: (addr handle cell) <- get rest, left
2235   var fourth/eax: (addr cell) <- lookup *fourth-ah
2236   {
2237     var fourth-type/eax: (addr int) <- get fourth, type
2238     compare *fourth-type, 1/number
2239     break-if-=
2240     error trace, "fourth arg for 'line' is not a number (screen x coordinate of end point)"
2241     return
2242   }
2243   var fourth-value/eax: (addr float) <- get fourth, number-data
2244   var x2/ecx: int <- convert *fourth-value
2245   # y2 = rest->right->left->value
2246   var rest-ah/eax: (addr handle cell) <- get rest, right
2247   var _rest/eax: (addr cell) <- lookup *rest-ah
2248   rest <- copy _rest
2249   {
2250     var rest-type/eax: (addr int) <- get rest, type
2251     compare *rest-type, 0/pair
2252     break-if-=
2253     error trace, "'line' encountered non-pair"
2254     return
2255   }
2256   {
2257     var rest-nil?/eax: boolean <- nil? rest
2258     compare rest-nil?, 0/false
2259     break-if-=
2260     error trace, "'line' needs 6 args but got 4"
2261     return
2262   }
2263   var fifth-ah/eax: (addr handle cell) <- get rest, left
2264   var fifth/eax: (addr cell) <- lookup *fifth-ah
2265   {
2266     var fifth-type/eax: (addr int) <- get fifth, type
2267     compare *fifth-type, 1/number
2268     break-if-=
2269     error trace, "fifth arg for 'line' is not a number (screen y coordinate of end point)"
2270     return
2271   }
2272   var fifth-value/eax: (addr float) <- get fifth, number-data
2273   var tmp/eax: int <- convert *fifth-value
2274   var y2: int
2275   copy-to y2, tmp
2276   # color = rest->right->left->value
2277   var rest-ah/eax: (addr handle cell) <- get rest, right
2278   var _rest/eax: (addr cell) <- lookup *rest-ah
2279   rest <- copy _rest
2280   {
2281     var rest-type/eax: (addr int) <- get rest, type
2282     compare *rest-type, 0/pair
2283     break-if-=
2284     error trace, "'line' encountered non-pair"
2285     return
2286   }
2287   {
2288     var rest-nil?/eax: boolean <- nil? rest
2289     compare rest-nil?, 0/false
2290     break-if-=
2291     error trace, "'line' needs 6 args but got 5"
2292     return
2293   }
2294   var sixth-ah/eax: (addr handle cell) <- get rest, left
2295   var sixth/eax: (addr cell) <- lookup *sixth-ah
2296   {
2297     var sixth-type/eax: (addr int) <- get sixth, type
2298     compare *sixth-type, 1/number
2299     break-if-=
2300     error trace, "sixth arg for 'line' is not an int (color; 0..0xff)"
2301     return
2302   }
2303   var sixth-value/eax: (addr float) <- get sixth, number-data
2304   var color/eax: int <- convert *sixth-value
2305   draw-line screen, x1, y1, x2, y2, color
2306   # return nothing
2309 fn apply-hline _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
2310   trace-text trace, "eval", "apply 'hline'"
2311   var args-ah/eax: (addr handle cell) <- copy _args-ah
2312   var _args/eax: (addr cell) <- lookup *args-ah
2313   var args/esi: (addr cell) <- copy _args
2314   {
2315     var args-type/eax: (addr int) <- get args, type
2316     compare *args-type, 0/pair
2317     break-if-=
2318     error trace, "args to 'hline' are not a list"
2319     return
2320   }
2321   var empty-args?/eax: boolean <- nil? args
2322   compare empty-args?, 0/false
2323   {
2324     break-if-=
2325     error trace, "'hline' needs 5 args but got 0"
2326     return
2327   }
2328   # screen = args->left
2329   var first-ah/eax: (addr handle cell) <- get args, left
2330   var first/eax: (addr cell) <- lookup *first-ah
2331   {
2332     var first-type/eax: (addr int) <- get first, type
2333     compare *first-type, 5/screen
2334     break-if-=
2335     error trace, "first arg for 'hline' is not a screen"
2336     return
2337   }
2338   var screen-ah/eax: (addr handle screen) <- get first, screen-data
2339   var _screen/eax: (addr screen) <- lookup *screen-ah
2340   var screen/edi: (addr screen) <- copy _screen
2341   # y = args->right->left->value
2342   var rest-ah/eax: (addr handle cell) <- get args, right
2343   var _rest/eax: (addr cell) <- lookup *rest-ah
2344   var rest/esi: (addr cell) <- copy _rest
2345   {
2346     var rest-type/eax: (addr int) <- get rest, type
2347     compare *rest-type, 0/pair
2348     break-if-=
2349     error trace, "'hline' encountered non-pair"
2350     return
2351   }
2352   {
2353     var rest-nil?/eax: boolean <- nil? rest
2354     compare rest-nil?, 0/false
2355     break-if-=
2356     error trace, "'hline' needs 5 args but got 1"
2357     return
2358   }
2359   var second-ah/eax: (addr handle cell) <- get rest, left
2360   var second/eax: (addr cell) <- lookup *second-ah
2361   {
2362     var second-type/eax: (addr int) <- get second, type
2363     compare *second-type, 1/number
2364     break-if-=
2365     error trace, "second arg for 'hline' is not a number (screen y coordinate)"
2366     return
2367   }
2368   var second-value/eax: (addr float) <- get second, number-data
2369   var y/edx: int <- convert *second-value
2370   # x1 = rest->right->left->value
2371   var rest-ah/eax: (addr handle cell) <- get rest, right
2372   var _rest/eax: (addr cell) <- lookup *rest-ah
2373   rest <- copy _rest
2374   {
2375     var rest-type/eax: (addr int) <- get rest, type
2376     compare *rest-type, 0/pair
2377     break-if-=
2378     error trace, "'hline' encountered non-pair"
2379     return
2380   }
2381   {
2382     var rest-nil?/eax: boolean <- nil? rest
2383     compare rest-nil?, 0/false
2384     break-if-=
2385     error trace, "'hline' needs 5 args but got 2"
2386     return
2387   }
2388   var third-ah/eax: (addr handle cell) <- get rest, left
2389   var third/eax: (addr cell) <- lookup *third-ah
2390   {
2391     var third-type/eax: (addr int) <- get third, type
2392     compare *third-type, 1/number
2393     break-if-=
2394     error trace, "third arg for 'hline' is not a number (screen x coordinate of start point)"
2395     return
2396   }
2397   var third-value/eax: (addr float) <- get third, number-data
2398   var x1/ebx: int <- convert *third-value
2399   # x2 = rest->right->left->value
2400   var rest-ah/eax: (addr handle cell) <- get rest, right
2401   var _rest/eax: (addr cell) <- lookup *rest-ah
2402   var rest/esi: (addr cell) <- copy _rest
2403   {
2404     var rest-type/eax: (addr int) <- get rest, type
2405     compare *rest-type, 0/pair
2406     break-if-=
2407     error trace, "'hline' encountered non-pair"
2408     return
2409   }
2410   {
2411     var rest-nil?/eax: boolean <- nil? rest
2412     compare rest-nil?, 0/false
2413     break-if-=
2414     error trace, "'hline' needs 5 args but got 3"
2415     return
2416   }
2417   var fourth-ah/eax: (addr handle cell) <- get rest, left
2418   var fourth/eax: (addr cell) <- lookup *fourth-ah
2419   {
2420     var fourth-type/eax: (addr int) <- get fourth, type
2421     compare *fourth-type, 1/number
2422     break-if-=
2423     error trace, "fourth arg for 'hline' is not a number (screen x coordinate of end point)"
2424     return
2425   }
2426   var fourth-value/eax: (addr float) <- get fourth, number-data
2427   var x2/ecx: int <- convert *fourth-value
2428   # color = rest->right->left->value
2429   var rest-ah/eax: (addr handle cell) <- get rest, right
2430   var _rest/eax: (addr cell) <- lookup *rest-ah
2431   rest <- copy _rest
2432   {
2433     var rest-type/eax: (addr int) <- get rest, type
2434     compare *rest-type, 0/pair
2435     break-if-=
2436     error trace, "'hline' encountered non-pair"
2437     return
2438   }
2439   {
2440     var rest-nil?/eax: boolean <- nil? rest
2441     compare rest-nil?, 0/false
2442     break-if-=
2443     error trace, "'hline' needs 5 args but got 5"
2444     return
2445   }
2446   var fifth-ah/eax: (addr handle cell) <- get rest, left
2447   var fifth/eax: (addr cell) <- lookup *fifth-ah
2448   {
2449     var fifth-type/eax: (addr int) <- get fifth, type
2450     compare *fifth-type, 1/number
2451     break-if-=
2452     error trace, "fifth arg for 'hline' is not an int (color; 0..0xff)"
2453     return
2454   }
2455   var fifth-value/eax: (addr float) <- get fifth, number-data
2456   var color/eax: int <- convert *fifth-value
2457   draw-horizontal-line screen, y, x1, x2, color
2458   # return nothing
2461 fn apply-vline _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
2462   trace-text trace, "eval", "apply 'vline'"
2463   var args-ah/eax: (addr handle cell) <- copy _args-ah
2464   var _args/eax: (addr cell) <- lookup *args-ah
2465   var args/esi: (addr cell) <- copy _args
2466   {
2467     var args-type/eax: (addr int) <- get args, type
2468     compare *args-type, 0/pair
2469     break-if-=
2470     error trace, "args to 'vline' are not a list"
2471     return
2472   }
2473   var empty-args?/eax: boolean <- nil? args
2474   compare empty-args?, 0/false
2475   {
2476     break-if-=
2477     error trace, "'vline' needs 5 args but got 0"
2478     return
2479   }
2480   # screen = args->left
2481   var first-ah/eax: (addr handle cell) <- get args, left
2482   var first/eax: (addr cell) <- lookup *first-ah
2483   {
2484     var first-type/eax: (addr int) <- get first, type
2485     compare *first-type, 5/screen
2486     break-if-=
2487     error trace, "first arg for 'vline' is not a screen"
2488     return
2489   }
2490   var screen-ah/eax: (addr handle screen) <- get first, screen-data
2491   var _screen/eax: (addr screen) <- lookup *screen-ah
2492   var screen/edi: (addr screen) <- copy _screen
2493   # x = args->right->left->value
2494   var rest-ah/eax: (addr handle cell) <- get args, right
2495   var _rest/eax: (addr cell) <- lookup *rest-ah
2496   var rest/esi: (addr cell) <- copy _rest
2497   {
2498     var rest-type/eax: (addr int) <- get rest, type
2499     compare *rest-type, 0/pair
2500     break-if-=
2501     error trace, "'vline' encountered non-pair"
2502     return
2503   }
2504   {
2505     var rest-nil?/eax: boolean <- nil? rest
2506     compare rest-nil?, 0/false
2507     break-if-=
2508     error trace, "'vline' needs 5 args but got 1"
2509     return
2510   }
2511   var second-ah/eax: (addr handle cell) <- get rest, left
2512   var second/eax: (addr cell) <- lookup *second-ah
2513   {
2514     var second-type/eax: (addr int) <- get second, type
2515     compare *second-type, 1/number
2516     break-if-=
2517     error trace, "second arg for 'vline' is not a number (screen x coordinate)"
2518     return
2519   }
2520   var second-value/eax: (addr float) <- get second, number-data
2521   var x/edx: int <- convert *second-value
2522   # y1 = rest->right->left->value
2523   var rest-ah/eax: (addr handle cell) <- get rest, right
2524   var _rest/eax: (addr cell) <- lookup *rest-ah
2525   rest <- copy _rest
2526   {
2527     var rest-type/eax: (addr int) <- get rest, type
2528     compare *rest-type, 0/pair
2529     break-if-=
2530     error trace, "'vline' encountered non-pair"
2531     return
2532   }
2533   {
2534     var rest-nil?/eax: boolean <- nil? rest
2535     compare rest-nil?, 0/false
2536     break-if-=
2537     error trace, "'vline' needs 5 args but got 2"
2538     return
2539   }
2540   var third-ah/eax: (addr handle cell) <- get rest, left
2541   var third/eax: (addr cell) <- lookup *third-ah
2542   {
2543     var third-type/eax: (addr int) <- get third, type
2544     compare *third-type, 1/number
2545     break-if-=
2546     error trace, "third arg for 'vline' is not a number (screen y coordinate of start point)"
2547     return
2548   }
2549   var third-value/eax: (addr float) <- get third, number-data
2550   var y1/ebx: int <- convert *third-value
2551   # y2 = rest->right->left->value
2552   var rest-ah/eax: (addr handle cell) <- get rest, right
2553   var _rest/eax: (addr cell) <- lookup *rest-ah
2554   var rest/esi: (addr cell) <- copy _rest
2555   {
2556     var rest-type/eax: (addr int) <- get rest, type
2557     compare *rest-type, 0/pair
2558     break-if-=
2559     error trace, "'vline' encountered non-pair"
2560     return
2561   }
2562   {
2563     var rest-nil?/eax: boolean <- nil? rest
2564     compare rest-nil?, 0/false
2565     break-if-=
2566     error trace, "'vline' needs 5 args but got 3"
2567     return
2568   }
2569   var fourth-ah/eax: (addr handle cell) <- get rest, left
2570   var fourth/eax: (addr cell) <- lookup *fourth-ah
2571   {
2572     var fourth-type/eax: (addr int) <- get fourth, type
2573     compare *fourth-type, 1/number
2574     break-if-=
2575     error trace, "fourth arg for 'vline' is not a number (screen y coordinate of end point)"
2576     return
2577   }
2578   var fourth-value/eax: (addr float) <- get fourth, number-data
2579   var y2/ecx: int <- convert *fourth-value
2580   # color = rest->right->left->value
2581   var rest-ah/eax: (addr handle cell) <- get rest, right
2582   var _rest/eax: (addr cell) <- lookup *rest-ah
2583   rest <- copy _rest
2584   {
2585     var rest-type/eax: (addr int) <- get rest, type
2586     compare *rest-type, 0/pair
2587     break-if-=
2588     error trace, "'vline' encountered non-pair"
2589     return
2590   }
2591   {
2592     var rest-nil?/eax: boolean <- nil? rest
2593     compare rest-nil?, 0/false
2594     break-if-=
2595     error trace, "'vline' needs 5 args but got 5"
2596     return
2597   }
2598   var fifth-ah/eax: (addr handle cell) <- get rest, left
2599   var fifth/eax: (addr cell) <- lookup *fifth-ah
2600   {
2601     var fifth-type/eax: (addr int) <- get fifth, type
2602     compare *fifth-type, 1/number
2603     break-if-=
2604     error trace, "fifth arg for 'vline' is not an int (color; 0..0xff)"
2605     return
2606   }
2607   var fifth-value/eax: (addr float) <- get fifth, number-data
2608   var color/eax: int <- convert *fifth-value
2609   draw-vertical-line screen, x, y1, y2, color
2610   # return nothing
2613 fn apply-circle _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
2614   trace-text trace, "eval", "apply 'circle'"
2615   var args-ah/eax: (addr handle cell) <- copy _args-ah
2616   var _args/eax: (addr cell) <- lookup *args-ah
2617   var args/esi: (addr cell) <- copy _args
2618   {
2619     var args-type/eax: (addr int) <- get args, type
2620     compare *args-type, 0/pair
2621     break-if-=
2622     error trace, "args to 'circle' are not a list"
2623     return
2624   }
2625   var empty-args?/eax: boolean <- nil? args
2626   compare empty-args?, 0/false
2627   {
2628     break-if-=
2629     error trace, "'circle' needs 5 args but got 0"
2630     return
2631   }
2632   # screen = args->left
2633   var first-ah/eax: (addr handle cell) <- get args, left
2634   var first/eax: (addr cell) <- lookup *first-ah
2635   {
2636     var first-type/eax: (addr int) <- get first, type
2637     compare *first-type, 5/screen
2638     break-if-=
2639     error trace, "first arg for 'circle' is not a screen"
2640     return
2641   }
2642   var screen-ah/eax: (addr handle screen) <- get first, screen-data
2643   var _screen/eax: (addr screen) <- lookup *screen-ah
2644   var screen/edi: (addr screen) <- copy _screen
2645   # cx = args->right->left->value
2646   var rest-ah/eax: (addr handle cell) <- get args, right
2647   var _rest/eax: (addr cell) <- lookup *rest-ah
2648   var rest/esi: (addr cell) <- copy _rest
2649   {
2650     var rest-type/eax: (addr int) <- get rest, type
2651     compare *rest-type, 0/pair
2652     break-if-=
2653     error trace, "'circle' encountered non-pair"
2654     return
2655   }
2656   {
2657     var rest-nil?/eax: boolean <- nil? rest
2658     compare rest-nil?, 0/false
2659     break-if-=
2660     error trace, "'circle' needs 5 args but got 1"
2661     return
2662   }
2663   var second-ah/eax: (addr handle cell) <- get rest, left
2664   var second/eax: (addr cell) <- lookup *second-ah
2665   {
2666     var second-type/eax: (addr int) <- get second, type
2667     compare *second-type, 1/number
2668     break-if-=
2669     error trace, "second arg for 'circle' is not a number (screen x coordinate of center)"
2670     return
2671   }
2672   var second-value/eax: (addr float) <- get second, number-data
2673   var cx/edx: int <- convert *second-value
2674   # cy = rest->right->left->value
2675   var rest-ah/eax: (addr handle cell) <- get rest, right
2676   var _rest/eax: (addr cell) <- lookup *rest-ah
2677   rest <- copy _rest
2678   {
2679     var rest-type/eax: (addr int) <- get rest, type
2680     compare *rest-type, 0/pair
2681     break-if-=
2682     error trace, "'circle' encountered non-pair"
2683     return
2684   }
2685   {
2686     var rest-nil?/eax: boolean <- nil? rest
2687     compare rest-nil?, 0/false
2688     break-if-=
2689     error trace, "'circle' needs 5 args but got 2"
2690     return
2691   }
2692   var third-ah/eax: (addr handle cell) <- get rest, left
2693   var third/eax: (addr cell) <- lookup *third-ah
2694   {
2695     var third-type/eax: (addr int) <- get third, type
2696     compare *third-type, 1/number
2697     break-if-=
2698     error trace, "third arg for 'circle' is not a number (screen y coordinate of center)"
2699     return
2700   }
2701   var third-value/eax: (addr float) <- get third, number-data
2702   var cy/ebx: int <- convert *third-value
2703   # r = rest->right->left->value
2704   var rest-ah/eax: (addr handle cell) <- get rest, right
2705   var _rest/eax: (addr cell) <- lookup *rest-ah
2706   var rest/esi: (addr cell) <- copy _rest
2707   {
2708     var rest-type/eax: (addr int) <- get rest, type
2709     compare *rest-type, 0/pair
2710     break-if-=
2711     error trace, "'circle' encountered non-pair"
2712     return
2713   }
2714   {
2715     var rest-nil?/eax: boolean <- nil? rest
2716     compare rest-nil?, 0/false
2717     break-if-=
2718     error trace, "'circle' needs 5 args but got 3"
2719     return
2720   }
2721   var fourth-ah/eax: (addr handle cell) <- get rest, left
2722   var fourth/eax: (addr cell) <- lookup *fourth-ah
2723   {
2724     var fourth-type/eax: (addr int) <- get fourth, type
2725     compare *fourth-type, 1/number
2726     break-if-=
2727     error trace, "fourth arg for 'circle' is not a number (screen radius)"
2728     return
2729   }
2730   var fourth-value/eax: (addr float) <- get fourth, number-data
2731   var r/ecx: int <- convert *fourth-value
2732   # color = rest->right->left->value
2733   var rest-ah/eax: (addr handle cell) <- get rest, right
2734   var _rest/eax: (addr cell) <- lookup *rest-ah
2735   rest <- copy _rest
2736   {
2737     var rest-type/eax: (addr int) <- get rest, type
2738     compare *rest-type, 0/pair
2739     break-if-=
2740     error trace, "'circle' encountered non-pair"
2741     return
2742   }
2743   {
2744     var rest-nil?/eax: boolean <- nil? rest
2745     compare rest-nil?, 0/false
2746     break-if-=
2747     error trace, "'circle' needs 5 args but got 5"
2748     return
2749   }
2750   var fifth-ah/eax: (addr handle cell) <- get rest, left
2751   var fifth/eax: (addr cell) <- lookup *fifth-ah
2752   {
2753     var fifth-type/eax: (addr int) <- get fifth, type
2754     compare *fifth-type, 1/number
2755     break-if-=
2756     error trace, "fifth arg for 'circle' is not an int (color; 0..0xff)"
2757     return
2758   }
2759   var fifth-value/eax: (addr float) <- get fifth, number-data
2760   var color/eax: int <- convert *fifth-value
2761   draw-circle screen, cx, cy, r, color
2762   # return nothing
2765 fn apply-bezier _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
2766   trace-text trace, "eval", "apply 'bezier'"
2767   var args-ah/eax: (addr handle cell) <- copy _args-ah
2768   var _args/eax: (addr cell) <- lookup *args-ah
2769   var args/esi: (addr cell) <- copy _args
2770   {
2771     var args-type/eax: (addr int) <- get args, type
2772     compare *args-type, 0/pair
2773     break-if-=
2774     error trace, "args to 'bezier' are not a list"
2775     return
2776   }
2777   var empty-args?/eax: boolean <- nil? args
2778   compare empty-args?, 0/false
2779   {
2780     break-if-=
2781     error trace, "'bezier' needs 8 args but got 0"
2782     return
2783   }
2784   # screen = args->left
2785   var first-ah/eax: (addr handle cell) <- get args, left
2786   var first/eax: (addr cell) <- lookup *first-ah
2787   {
2788     var first-type/eax: (addr int) <- get first, type
2789     compare *first-type, 5/screen
2790     break-if-=
2791     error trace, "first arg for 'bezier' is not a screen"
2792     return
2793   }
2794   var screen-ah/eax: (addr handle screen) <- get first, screen-data
2795   var _screen/eax: (addr screen) <- lookup *screen-ah
2796   var screen/edi: (addr screen) <- copy _screen
2797   # x0 = args->right->left->value
2798   var rest-ah/eax: (addr handle cell) <- get args, right
2799   var _rest/eax: (addr cell) <- lookup *rest-ah
2800   var rest/esi: (addr cell) <- copy _rest
2801   {
2802     var rest-type/eax: (addr int) <- get rest, type
2803     compare *rest-type, 0/pair
2804     break-if-=
2805     error trace, "'bezier' encountered non-pair"
2806     return
2807   }
2808   {
2809     var rest-nil?/eax: boolean <- nil? rest
2810     compare rest-nil?, 0/false
2811     break-if-=
2812     error trace, "'bezier' needs 8 args but got 1"
2813     return
2814   }
2815   var second-ah/eax: (addr handle cell) <- get rest, left
2816   var second/eax: (addr cell) <- lookup *second-ah
2817   {
2818     var second-type/eax: (addr int) <- get second, type
2819     compare *second-type, 1/number
2820     break-if-=
2821     error trace, "second arg for 'bezier' is not a number (screen x coordinate of start point)"
2822     return
2823   }
2824   var second-value/eax: (addr float) <- get second, number-data
2825   var x0/edx: int <- convert *second-value
2826   # y0 = rest->right->left->value
2827   var rest-ah/eax: (addr handle cell) <- get rest, right
2828   var _rest/eax: (addr cell) <- lookup *rest-ah
2829   rest <- copy _rest
2830   {
2831     var rest-type/eax: (addr int) <- get rest, type
2832     compare *rest-type, 0/pair
2833     break-if-=
2834     error trace, "'bezier' encountered non-pair"
2835     return
2836   }
2837   {
2838     var rest-nil?/eax: boolean <- nil? rest
2839     compare rest-nil?, 0/false
2840     break-if-=
2841     error trace, "'bezier' needs 8 args but got 2"
2842     return
2843   }
2844   var third-ah/eax: (addr handle cell) <- get rest, left
2845   var third/eax: (addr cell) <- lookup *third-ah
2846   {
2847     var third-type/eax: (addr int) <- get third, type
2848     compare *third-type, 1/number
2849     break-if-=
2850     error trace, "third arg for 'bezier' is not a number (screen y coordinate of start point)"
2851     return
2852   }
2853   var third-value/eax: (addr float) <- get third, number-data
2854   var y0/ebx: int <- convert *third-value
2855   # x1 = rest->right->left->value
2856   var rest-ah/eax: (addr handle cell) <- get rest, right
2857   var _rest/eax: (addr cell) <- lookup *rest-ah
2858   var rest/esi: (addr cell) <- copy _rest
2859   {
2860     var rest-type/eax: (addr int) <- get rest, type
2861     compare *rest-type, 0/pair
2862     break-if-=
2863     error trace, "'bezier' encountered non-pair"
2864     return
2865   }
2866   {
2867     var rest-nil?/eax: boolean <- nil? rest
2868     compare rest-nil?, 0/false
2869     break-if-=
2870     error trace, "'bezier' needs 8 args but got 3"
2871     return
2872   }
2873   var fourth-ah/eax: (addr handle cell) <- get rest, left
2874   var fourth/eax: (addr cell) <- lookup *fourth-ah
2875   {
2876     var fourth-type/eax: (addr int) <- get fourth, type
2877     compare *fourth-type, 1/number
2878     break-if-=
2879     error trace, "fourth arg for 'bezier' is not a number (screen x coordinate of control point)"
2880     return
2881   }
2882   var fourth-value/eax: (addr float) <- get fourth, number-data
2883   var tmp/eax: int <- convert *fourth-value
2884   var x1: int
2885   copy-to x1, tmp
2886   # y1 = rest->right->left->value
2887   var rest-ah/eax: (addr handle cell) <- get rest, right
2888   var _rest/eax: (addr cell) <- lookup *rest-ah
2889   rest <- copy _rest
2890   {
2891     var rest-type/eax: (addr int) <- get rest, type
2892     compare *rest-type, 0/pair
2893     break-if-=
2894     error trace, "'bezier' encountered non-pair"
2895     return
2896   }
2897   {
2898     var rest-nil?/eax: boolean <- nil? rest
2899     compare rest-nil?, 0/false
2900     break-if-=
2901     error trace, "'bezier' needs 8 args but got 4"
2902     return
2903   }
2904   var fifth-ah/eax: (addr handle cell) <- get rest, left
2905   var fifth/eax: (addr cell) <- lookup *fifth-ah
2906   {
2907     var fifth-type/eax: (addr int) <- get fifth, type
2908     compare *fifth-type, 1/number
2909     break-if-=
2910     error trace, "fifth arg for 'bezier' is not a number (screen y coordinate of control point)"
2911     return
2912   }
2913   var fifth-value/eax: (addr float) <- get fifth, number-data
2914   var tmp/eax: int <- convert *fifth-value
2915   var y1: int
2916   copy-to y1, tmp
2917   # x2 = rest->right->left->value
2918   var rest-ah/eax: (addr handle cell) <- get rest, right
2919   var _rest/eax: (addr cell) <- lookup *rest-ah
2920   var rest/esi: (addr cell) <- copy _rest
2921   {
2922     var rest-type/eax: (addr int) <- get rest, type
2923     compare *rest-type, 0/pair
2924     break-if-=
2925     error trace, "'bezier' encountered non-pair"
2926     return
2927   }
2928   {
2929     var rest-nil?/eax: boolean <- nil? rest
2930     compare rest-nil?, 0/false
2931     break-if-=
2932     error trace, "'bezier' needs 8 args but got 3"
2933     return
2934   }
2935   var sixth-ah/eax: (addr handle cell) <- get rest, left
2936   var sixth/eax: (addr cell) <- lookup *sixth-ah
2937   {
2938     var sixth-type/eax: (addr int) <- get sixth, type
2939     compare *sixth-type, 1/number
2940     break-if-=
2941     error trace, "sixth arg for 'bezier' is not a number (screen x coordinate of end point)"
2942     return
2943   }
2944   var sixth-value/eax: (addr float) <- get sixth, number-data
2945   var tmp/eax: int <- convert *sixth-value
2946   var x2: int
2947   copy-to x2, tmp
2948   # y2 = rest->right->left->value
2949   var rest-ah/eax: (addr handle cell) <- get rest, right
2950   var _rest/eax: (addr cell) <- lookup *rest-ah
2951   rest <- copy _rest
2952   {
2953     var rest-type/eax: (addr int) <- get rest, type
2954     compare *rest-type, 0/pair
2955     break-if-=
2956     error trace, "'bezier' encountered non-pair"
2957     return
2958   }
2959   {
2960     var rest-nil?/eax: boolean <- nil? rest
2961     compare rest-nil?, 0/false
2962     break-if-=
2963     error trace, "'bezier' needs 8 args but got 4"
2964     return
2965   }
2966   var seventh-ah/eax: (addr handle cell) <- get rest, left
2967   var seventh/eax: (addr cell) <- lookup *seventh-ah
2968   {
2969     var seventh-type/eax: (addr int) <- get seventh, type
2970     compare *seventh-type, 1/number
2971     break-if-=
2972     error trace, "seventh arg for 'bezier' is not a number (screen y coordinate of end point)"
2973     return
2974   }
2975   var seventh-value/eax: (addr float) <- get seventh, number-data
2976   var tmp/eax: int <- convert *seventh-value
2977   var y2: int
2978   copy-to y2, tmp
2979   # color = rest->right->left->value
2980   var rest-ah/eax: (addr handle cell) <- get rest, right
2981   var _rest/eax: (addr cell) <- lookup *rest-ah
2982   rest <- copy _rest
2983   {
2984     var rest-type/eax: (addr int) <- get rest, type
2985     compare *rest-type, 0/pair
2986     break-if-=
2987     error trace, "'bezier' encountered non-pair"
2988     return
2989   }
2990   {
2991     var rest-nil?/eax: boolean <- nil? rest
2992     compare rest-nil?, 0/false
2993     break-if-=
2994     error trace, "'bezier' needs 8 args but got 5"
2995     return
2996   }
2997   var eighth-ah/eax: (addr handle cell) <- get rest, left
2998   var eighth/eax: (addr cell) <- lookup *eighth-ah
2999   {
3000     var eighth-type/eax: (addr int) <- get eighth, type
3001     compare *eighth-type, 1/number
3002     break-if-=
3003     error trace, "eighth arg for 'bezier' is not an int (color; 0..0xff)"
3004     return
3005   }
3006   var eighth-value/eax: (addr float) <- get eighth, number-data
3007   var color/eax: int <- convert *eighth-value
3008   draw-monotonic-bezier screen, x0, y0, x1, y1, x2, y2, color
3009   # return nothing
3012 fn apply-wait-for-key _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3013   trace-text trace, "eval", "apply 'key'"
3014   var args-ah/eax: (addr handle cell) <- copy _args-ah
3015   var _args/eax: (addr cell) <- lookup *args-ah
3016   var args/esi: (addr cell) <- copy _args
3017   {
3018     var args-type/eax: (addr int) <- get args, type
3019     compare *args-type, 0/pair
3020     break-if-=
3021     error trace, "args to 'key' are not a list"
3022     return
3023   }
3024   var empty-args?/eax: boolean <- nil? args
3025   compare empty-args?, 0/false
3026   {
3027     break-if-=
3028     error trace, "'key' needs 1 arg but got 0"
3029     return
3030   }
3031   # keyboard = args->left
3032   var first-ah/eax: (addr handle cell) <- get args, left
3033   var first/eax: (addr cell) <- lookup *first-ah
3034   {
3035     var first-type/eax: (addr int) <- get first, type
3036     compare *first-type, 6/keyboard
3037     break-if-=
3038     error trace, "first arg for 'key' is not a keyboard"
3039     return
3040   }
3041   var keyboard-ah/eax: (addr handle gap-buffer) <- get first, keyboard-data
3042   var _keyboard/eax: (addr gap-buffer) <- lookup *keyboard-ah
3043   var keyboard/ecx: (addr gap-buffer) <- copy _keyboard
3044   var result/eax: int <- wait-for-key keyboard
3045   # return key typed
3046   new-integer out, result
3049 fn wait-for-key keyboard: (addr gap-buffer) -> _/eax: int {
3050   # if keyboard is 0, use real keyboard
3051   {
3052     compare keyboard, 0/real-keyboard
3053     break-if-!=
3054     var key/eax: byte <- read-key 0/real-keyboard
3055     var result/eax: int <- copy key
3056     return result
3057   }
3058   # otherwise read from fake keyboard
3059   var g/eax: code-point-utf8 <- read-from-gap-buffer keyboard
3060   var result/eax: int <- copy g
3061   return result
3064 fn apply-stream _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3065   trace-text trace, "eval", "apply stream"
3066   allocate-stream out
3069 fn apply-write _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3070   trace-text trace, "eval", "apply 'write'"
3071   var args-ah/eax: (addr handle cell) <- copy _args-ah
3072   var _args/eax: (addr cell) <- lookup *args-ah
3073   var args/esi: (addr cell) <- copy _args
3074   {
3075     var args-type/eax: (addr int) <- get args, type
3076     compare *args-type, 0/pair
3077     break-if-=
3078     error trace, "args to 'write' are not a list"
3079     return
3080   }
3081   var empty-args?/eax: boolean <- nil? args
3082   compare empty-args?, 0/false
3083   {
3084     break-if-=
3085     error trace, "'write' needs 2 args but got 0"
3086     return
3087   }
3088   # stream = args->left
3089   var first-ah/edx: (addr handle cell) <- get args, left
3090   var first/eax: (addr cell) <- lookup *first-ah
3091   {
3092     var first-type/eax: (addr int) <- get first, type
3093     compare *first-type, 3/stream
3094     break-if-=
3095     error trace, "first arg for 'write' is not a stream"
3096     return
3097   }
3098   var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
3099   var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
3100   var stream-data/ebx: (addr stream byte) <- copy _stream-data
3101   # args->right->left
3102   var right-ah/eax: (addr handle cell) <- get args, right
3103   var right/eax: (addr cell) <- lookup *right-ah
3104   {
3105     var right-type/eax: (addr int) <- get right, type
3106     compare *right-type, 0/pair
3107     break-if-=
3108     error trace, "'write' encountered non-pair"
3109     return
3110   }
3111   {
3112     var nil?/eax: boolean <- nil? right
3113     compare nil?, 0/false
3114     break-if-=
3115     error trace, "'write' needs 2 args but got 1"
3116     return
3117   }
3118   var second-ah/eax: (addr handle cell) <- get right, left
3119   var second/eax: (addr cell) <- lookup *second-ah
3120   {
3121     var second-type/eax: (addr int) <- get second, type
3122     compare *second-type, 1/number
3123     break-if-=
3124     error trace, "second arg for 'write' is not a number/code-point-utf8"
3125     return
3126   }
3127   var second-value/eax: (addr float) <- get second, number-data
3128   var x-float/xmm0: float <- copy *second-value
3129   var x/eax: int <- convert x-float
3130   var x-code-point-utf8/eax: code-point-utf8 <- copy x
3131   write-code-point-utf8 stream-data, x-code-point-utf8
3132   # return the stream
3133   copy-object first-ah, out
3136 fn apply-rewind _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3137   trace-text trace, "eval", "apply 'rewind'"
3138   var args-ah/eax: (addr handle cell) <- copy _args-ah
3139   var _args/eax: (addr cell) <- lookup *args-ah
3140   var args/esi: (addr cell) <- copy _args
3141   {
3142     var args-type/eax: (addr int) <- get args, type
3143     compare *args-type, 0/pair
3144     break-if-=
3145     error trace, "args to 'rewind' are not a list"
3146     return
3147   }
3148   var empty-args?/eax: boolean <- nil? args
3149   compare empty-args?, 0/false
3150   {
3151     break-if-=
3152     error trace, "'rewind' needs 1 arg but got 0"
3153     return
3154   }
3155   # stream = args->left
3156   var first-ah/edx: (addr handle cell) <- get args, left
3157   var first/eax: (addr cell) <- lookup *first-ah
3158   {
3159     var first-type/eax: (addr int) <- get first, type
3160     compare *first-type, 3/stream
3161     break-if-=
3162     error trace, "first arg for 'rewind' is not a stream"
3163     return
3164   }
3165   var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
3166   var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
3167   var stream-data/ebx: (addr stream byte) <- copy _stream-data
3168   rewind-stream stream-data
3169   copy-object first-ah, out
3172 fn apply-read _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3173   trace-text trace, "eval", "apply 'read'"
3174   var args-ah/eax: (addr handle cell) <- copy _args-ah
3175   var _args/eax: (addr cell) <- lookup *args-ah
3176   var args/esi: (addr cell) <- copy _args
3177   {
3178     var args-type/eax: (addr int) <- get args, type
3179     compare *args-type, 0/pair
3180     break-if-=
3181     error trace, "args to 'read' are not a list"
3182     return
3183   }
3184   var empty-args?/eax: boolean <- nil? args
3185   compare empty-args?, 0/false
3186   {
3187     break-if-=
3188     error trace, "'read' needs 1 arg but got 0"
3189     return
3190   }
3191   # stream = args->left
3192   var first-ah/edx: (addr handle cell) <- get args, left
3193   var first/eax: (addr cell) <- lookup *first-ah
3194   {
3195     var first-type/eax: (addr int) <- get first, type
3196     compare *first-type, 3/stream
3197     break-if-=
3198     error trace, "first arg for 'read' is not a stream"
3199     return
3200   }
3201   var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
3202   var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
3203   var stream-data/ebx: (addr stream byte) <- copy _stream-data
3204 #?   rewind-stream stream-data
3205   var result-code-point-utf8/eax: code-point-utf8 <- read-code-point-utf8 stream-data
3206   var result/eax: int <- copy result-code-point-utf8
3207   new-integer out, result
3210 fn apply-lines _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3211   trace-text trace, "eval", "apply 'lines'"
3212   var args-ah/eax: (addr handle cell) <- copy _args-ah
3213   var _args/eax: (addr cell) <- lookup *args-ah
3214   var args/esi: (addr cell) <- copy _args
3215   {
3216     var args-type/eax: (addr int) <- get args, type
3217     compare *args-type, 0/pair
3218     break-if-=
3219     error trace, "args to 'lines' are not a list"
3220     return
3221   }
3222   var empty-args?/eax: boolean <- nil? args
3223   compare empty-args?, 0/false
3224   {
3225     break-if-=
3226     error trace, "'lines' needs 1 arg but got 0"
3227     return
3228   }
3229   # screen = args->left
3230   var first-ah/eax: (addr handle cell) <- get args, left
3231   var first/eax: (addr cell) <- lookup *first-ah
3232   {
3233     var first-type/eax: (addr int) <- get first, type
3234     compare *first-type, 5/screen
3235     break-if-=
3236     error trace, "first arg for 'lines' is not a screen"
3237     return
3238   }
3239   var screen-ah/eax: (addr handle screen) <- get first, screen-data
3240   var _screen/eax: (addr screen) <- lookup *screen-ah
3241   var screen/edx: (addr screen) <- copy _screen
3242   # compute dimensions
3243   var dummy/eax: int <- copy 0
3244   var height/ecx: int <- copy 0
3245   dummy, height <- screen-size screen
3246   var result/xmm0: float <- convert height
3247   new-float out, result
3250 fn apply-columns _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3251   trace-text trace, "eval", "apply 'columns'"
3252   var args-ah/eax: (addr handle cell) <- copy _args-ah
3253   var _args/eax: (addr cell) <- lookup *args-ah
3254   var args/esi: (addr cell) <- copy _args
3255   {
3256     var args-type/eax: (addr int) <- get args, type
3257     compare *args-type, 0/pair
3258     break-if-=
3259     error trace, "args to 'columns' are not a list"
3260     return
3261   }
3262   var empty-args?/eax: boolean <- nil? args
3263   compare empty-args?, 0/false
3264   {
3265     break-if-=
3266     error trace, "'columns' needs 1 arg but got 0"
3267     return
3268   }
3269   # screen = args->left
3270   var first-ah/eax: (addr handle cell) <- get args, left
3271   var first/eax: (addr cell) <- lookup *first-ah
3272   {
3273     var first-type/eax: (addr int) <- get first, type
3274     compare *first-type, 5/screen
3275     break-if-=
3276     error trace, "first arg for 'columns' is not a screen"
3277     return
3278   }
3279   var screen-ah/eax: (addr handle screen) <- get first, screen-data
3280   var _screen/eax: (addr screen) <- lookup *screen-ah
3281   var screen/edx: (addr screen) <- copy _screen
3282   # compute dimensions
3283   var width/eax: int <- copy 0
3284   var dummy/ecx: int <- copy 0
3285   width, dummy <- screen-size screen
3286   var result/xmm0: float <- convert width
3287   new-float out, result
3290 fn apply-width _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3291   trace-text trace, "eval", "apply 'width'"
3292   var args-ah/eax: (addr handle cell) <- copy _args-ah
3293   var _args/eax: (addr cell) <- lookup *args-ah
3294   var args/esi: (addr cell) <- copy _args
3295   {
3296     var args-type/eax: (addr int) <- get args, type
3297     compare *args-type, 0/pair
3298     break-if-=
3299     error trace, "args to 'width' are not a list"
3300     return
3301   }
3302   var empty-args?/eax: boolean <- nil? args
3303   compare empty-args?, 0/false
3304   {
3305     break-if-=
3306     error trace, "'width' needs 1 arg but got 0"
3307     return
3308   }
3309   # screen = args->left
3310   var first-ah/eax: (addr handle cell) <- get args, left
3311   var first/eax: (addr cell) <- lookup *first-ah
3312   {
3313     var first-type/eax: (addr int) <- get first, type
3314     compare *first-type, 5/screen
3315     break-if-=
3316     error trace, "first arg for 'width' is not a screen"
3317     return
3318   }
3319   var screen-ah/eax: (addr handle screen) <- get first, screen-data
3320   var _screen/eax: (addr screen) <- lookup *screen-ah
3321   var screen/edx: (addr screen) <- copy _screen
3322   # compute dimensions
3323   var width/eax: int <- copy 0
3324   var dummy/ecx: int <- copy 0
3325   width, dummy <- screen-size screen
3326   width <- shift-left 3/log2-font-width
3327   var result/xmm0: float <- convert width
3328   new-float out, result
3331 fn apply-height _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3332   trace-text trace, "eval", "apply 'height'"
3333   var args-ah/eax: (addr handle cell) <- copy _args-ah
3334   var _args/eax: (addr cell) <- lookup *args-ah
3335   var args/esi: (addr cell) <- copy _args
3336   {
3337     var args-type/eax: (addr int) <- get args, type
3338     compare *args-type, 0/pair
3339     break-if-=
3340     error trace, "args to 'height' are not a list"
3341     return
3342   }
3343   var empty-args?/eax: boolean <- nil? args
3344   compare empty-args?, 0/false
3345   {
3346     break-if-=
3347     error trace, "'height' needs 1 arg but got 0"
3348     return
3349   }
3350   # screen = args->left
3351   var first-ah/eax: (addr handle cell) <- get args, left
3352   var first/eax: (addr cell) <- lookup *first-ah
3353   {
3354     var first-type/eax: (addr int) <- get first, type
3355     compare *first-type, 5/screen
3356     break-if-=
3357     error trace, "first arg for 'height' is not a screen"
3358     return
3359   }
3360   var screen-ah/eax: (addr handle screen) <- get first, screen-data
3361   var _screen/eax: (addr screen) <- lookup *screen-ah
3362   var screen/edx: (addr screen) <- copy _screen
3363   # compute dimensions
3364   var dummy/eax: int <- copy 0
3365   var height/ecx: int <- copy 0
3366   dummy, height <- screen-size screen
3367   height <- shift-left 4/log2-font-height
3368   var result/xmm0: float <- convert height
3369   new-float out, result
3372 fn apply-new-screen _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3373   trace-text trace, "eval", "apply 'screen'"
3374   var args-ah/eax: (addr handle cell) <- copy _args-ah
3375   var _args/eax: (addr cell) <- lookup *args-ah
3376   var args/esi: (addr cell) <- copy _args
3377   {
3378     var args-type/eax: (addr int) <- get args, type
3379     compare *args-type, 0/pair
3380     break-if-=
3381     error trace, "args to 'screen' are not a list"
3382     return
3383   }
3384   var empty-args?/eax: boolean <- nil? args
3385   compare empty-args?, 0/false
3386   {
3387     break-if-=
3388     error trace, "'screen' needs 2 args but got 0"
3389     return
3390   }
3391   # args->left->value
3392   var first-ah/eax: (addr handle cell) <- get args, left
3393   var first/eax: (addr cell) <- lookup *first-ah
3394   {
3395     var first-type/eax: (addr int) <- get first, type
3396     compare *first-type, 1/number
3397     break-if-=
3398     error trace, "first arg for 'screen' is not a number (screen width in pixels)"
3399     return
3400   }
3401   var first-value-a/ecx: (addr float) <- get first, number-data
3402   var first-value/ecx: int <- convert *first-value-a
3403   # args->right->left->value
3404   var right-ah/eax: (addr handle cell) <- get args, right
3405   var right/eax: (addr cell) <- lookup *right-ah
3406   {
3407     var right-type/eax: (addr int) <- get right, type
3408     compare *right-type, 0/pair
3409     break-if-=
3410     error trace, "'screen' encountered non-pair"
3411     return
3412   }
3413   {
3414     var nil?/eax: boolean <- nil? right
3415     compare nil?, 0/false
3416     break-if-=
3417     error trace, "'screen' needs 2 args but got 1"
3418     return
3419   }
3420   var second-ah/eax: (addr handle cell) <- get right, left
3421   var second/eax: (addr cell) <- lookup *second-ah
3422   {
3423     var second-type/eax: (addr int) <- get second, type
3424     compare *second-type, 1/number
3425     break-if-=
3426     error trace, "second arg for 'screen' is not a number (screen height in pixels)"
3427     return
3428   }
3429   var second-value-a/edx: (addr float) <- get second, number-data
3430   var second-value/edx: int <- convert *second-value-a
3431   # create fake screen
3432   new-fake-screen out, first-value, second-value, 1/pixel-graphics
3435 fn apply-blit _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3436   trace-text trace, "eval", "apply 'blit'"
3437   var args-ah/eax: (addr handle cell) <- copy _args-ah
3438   var _args/eax: (addr cell) <- lookup *args-ah
3439   var args/esi: (addr cell) <- copy _args
3440   {
3441     var args-type/eax: (addr int) <- get args, type
3442     compare *args-type, 0/pair
3443     break-if-=
3444     error trace, "args to 'blit' are not a list"
3445     return
3446   }
3447   var empty-args?/eax: boolean <- nil? args
3448   compare empty-args?, 0/false
3449   {
3450     break-if-=
3451     error trace, "'blit' needs 2 args but got 0"
3452     return
3453   }
3454   # screen = args->left
3455   var first-ah/eax: (addr handle cell) <- get args, left
3456   var first/eax: (addr cell) <- lookup *first-ah
3457   {
3458     var first-type/eax: (addr int) <- get first, type
3459     compare *first-type, 5/screen
3460     break-if-=
3461     error trace, "first arg for 'blit' is not a screen"
3462     return
3463   }
3464   var src-ah/eax: (addr handle screen) <- get first, screen-data
3465   var _src/eax: (addr screen) <- lookup *src-ah
3466   var src/ecx: (addr screen) <- copy _src
3467   # args->right->left
3468   var right-ah/eax: (addr handle cell) <- get args, right
3469   var right/eax: (addr cell) <- lookup *right-ah
3470   {
3471     var right-type/eax: (addr int) <- get right, type
3472     compare *right-type, 0/pair
3473     break-if-=
3474     error trace, "'blit' encountered non-pair"
3475     return
3476   }
3477   {
3478     var nil?/eax: boolean <- nil? right
3479     compare nil?, 0/false
3480     break-if-=
3481     error trace, "'blit' needs 2 args but got 1"
3482     return
3483   }
3484   var second-ah/eax: (addr handle cell) <- get right, left
3485   var second/eax: (addr cell) <- lookup *second-ah
3486   {
3487     var second-type/eax: (addr int) <- get second, type
3488     compare *second-type, 5/screen
3489     break-if-=
3490     error trace, "second arg for 'blit' is not a screen"
3491     return
3492   }
3493   var dest-ah/eax: (addr handle screen) <- get second, screen-data
3494   var dest/eax: (addr screen) <- lookup *dest-ah
3495   #
3496   convert-screen-cells-to-pixels src
3497   copy-pixels src, dest
3500 fn apply-array _args-ah: (addr handle cell), _out-ah: (addr handle cell), trace: (addr trace) {
3501   trace-text trace, "eval", "apply 'array'"
3502   var args-ah/eax: (addr handle cell) <- copy _args-ah
3503   var _args/eax: (addr cell) <- lookup *args-ah
3504   var args/esi: (addr cell) <- copy _args
3505   {
3506     var args-type/eax: (addr int) <- get args, type
3507     compare *args-type, 0/pair
3508     break-if-=
3509     error trace, "args to 'array' are not a list"
3510     return
3511   }
3512   var capacity/eax: int <- list-length args
3513   var out-ah/edi: (addr handle cell) <- copy _out-ah
3514   new-array out-ah, capacity
3515   var out/eax: (addr cell) <- lookup *out-ah
3516   var out-data-ah/eax: (addr handle array handle cell) <- get out, array-data
3517   var _out-data/eax: (addr array handle cell) <- lookup *out-data-ah
3518   var out-data/edi: (addr array handle cell) <- copy _out-data
3519   var i/ecx: int <- copy 0
3520   {
3521     var done?/eax: boolean <- nil? args
3522     compare done?, 0/false
3523     break-if-!=
3524     var curr-ah/eax: (addr handle cell) <- get args, left
3525     var dest-ah/edx: (addr handle cell) <- index out-data, i
3526     copy-object curr-ah, dest-ah
3527     # update loop variables
3528     i <- increment
3529     var next-ah/eax: (addr handle cell) <- get args, right
3530     var next/eax: (addr cell) <- lookup *next-ah
3531     args <- copy next
3532     loop
3533   }
3536 fn apply-populate _args-ah: (addr handle cell), _out-ah: (addr handle cell), trace: (addr trace) {
3537   trace-text trace, "eval", "apply 'populate'"
3538   var args-ah/eax: (addr handle cell) <- copy _args-ah
3539   var _args/eax: (addr cell) <- lookup *args-ah
3540   var args/esi: (addr cell) <- copy _args
3541   {
3542     var args-type/eax: (addr int) <- get args, type
3543     compare *args-type, 0/pair
3544     break-if-=
3545     error trace, "args to 'populate' are not a list"
3546     return
3547   }
3548   var empty-args?/eax: boolean <- nil? args
3549   compare empty-args?, 0/false
3550   {
3551     break-if-=
3552     error trace, "'populate' needs 2 args but got 0"
3553     return
3554   }
3555   # args->left
3556   var first-ah/ecx: (addr handle cell) <- get args, left
3557   # args->right->left
3558   var right-ah/eax: (addr handle cell) <- get args, right
3559   var right/eax: (addr cell) <- lookup *right-ah
3560   {
3561     var right-type/eax: (addr int) <- get right, type
3562     compare *right-type, 0/pair
3563     break-if-=
3564     error trace, "'populate' encountered non-pair"
3565     return
3566   }
3567   {
3568     var nil?/eax: boolean <- nil? right
3569     compare nil?, 0/false
3570     break-if-=
3571     error trace, "'populate' needs 2 args but got 1"
3572     return
3573   }
3574   var second-ah/edx: (addr handle cell) <- get right, left
3575   #
3576   var first/eax: (addr cell) <- lookup *first-ah
3577   {
3578     var first-type/eax: (addr int) <- get first, type
3579     compare *first-type, 1/number
3580     break-if-=
3581     error trace, "first arg for 'populate' is not a number"
3582     return
3583   }
3584   var first-value/eax: (addr float) <- get first, number-data
3585   var capacity/ecx: int <- convert *first-value
3586   var out-ah/edi: (addr handle cell) <- copy _out-ah
3587   new-array out-ah, capacity
3588   var out/eax: (addr cell) <- lookup *out-ah
3589   var data-ah/eax: (addr handle array handle cell) <- get out, array-data
3590   var data/eax: (addr array handle cell) <- lookup *data-ah
3591   var i/ebx: int <- copy 0
3592   {
3593     compare i, capacity
3594     break-if->=
3595     var curr-ah/ecx: (addr handle cell) <- index data, i
3596     copy-object second-ah, curr-ah
3597     i <- increment
3598     loop
3599   }
3602 fn apply-index _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3603   trace-text trace, "eval", "apply 'index'"
3604   var args-ah/eax: (addr handle cell) <- copy _args-ah
3605   var _args/eax: (addr cell) <- lookup *args-ah
3606   var args/esi: (addr cell) <- copy _args
3607   {
3608     var args-type/eax: (addr int) <- get args, type
3609     compare *args-type, 0/pair
3610     break-if-=
3611     error trace, "args to 'index' are not a list"
3612     return
3613   }
3614   var empty-args?/eax: boolean <- nil? args
3615   compare empty-args?, 0/false
3616   {
3617     break-if-=
3618     error trace, "'index' needs 2 args but got 0"
3619     return
3620   }
3621   # args->left
3622   var first-ah/ecx: (addr handle cell) <- get args, left
3623   # args->right->left
3624   var right-ah/eax: (addr handle cell) <- get args, right
3625   var right/eax: (addr cell) <- lookup *right-ah
3626   {
3627     var right-type/eax: (addr int) <- get right, type
3628     compare *right-type, 0/pair
3629     break-if-=
3630     error trace, "'index' encountered non-pair"
3631     return
3632   }
3633   {
3634     var nil?/eax: boolean <- nil? right
3635     compare nil?, 0/false
3636     break-if-=
3637     error trace, "'index' needs 2 args but got 1"
3638     return
3639   }
3640   var second-ah/edx: (addr handle cell) <- get right, left
3641   # index
3642   var _first/eax: (addr cell) <- lookup *first-ah
3643   var first/ecx: (addr cell) <- copy _first
3644   {
3645     var first-type/eax: (addr int) <- get first, type
3646     compare *first-type, 7/array
3647     break-if-=
3648     error trace, "first arg for 'index' is not an array"
3649     return
3650   }
3651   var second/eax: (addr cell) <- lookup *second-ah
3652   {
3653     var second-type/eax: (addr int) <- get second, type
3654     compare *second-type, 1/number
3655     break-if-=
3656     error trace, "second arg for 'index' is not a number"
3657     return
3658   }
3659   var second-value/eax: (addr float) <- get second, number-data
3660   var index/edx: int <- truncate *second-value
3661   var data-ah/eax: (addr handle array handle cell) <- get first, array-data
3662   var data/eax: (addr array handle cell) <- lookup *data-ah
3663   {
3664     var len/eax: int <- length data
3665     compare index, len
3666     break-if-<
3667     error trace, "index: too few elements in array"
3668     compare index, len
3669     {
3670       break-if-<=
3671       error trace, "foo"
3672     }
3673     return
3674   }
3675   var offset/edx: (offset handle cell) <- compute-offset data, index
3676   var src/eax: (addr handle cell) <- index data, offset
3677   copy-object src, out
3680 fn apply-iset _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3681   trace-text trace, "eval", "apply 'iset'"
3682   var args-ah/eax: (addr handle cell) <- copy _args-ah
3683   var _args/eax: (addr cell) <- lookup *args-ah
3684   var args/esi: (addr cell) <- copy _args
3685   {
3686     var args-type/eax: (addr int) <- get args, type
3687     compare *args-type, 0/pair
3688     break-if-=
3689     error trace, "args to 'iset' are not a list"
3690     return
3691   }
3692   var empty-args?/eax: boolean <- nil? args
3693   compare empty-args?, 0/false
3694   {
3695     break-if-=
3696     error trace, "'iset' needs 3 args but got 0"
3697     return
3698   }
3699   # array = args->left
3700   var first-ah/eax: (addr handle cell) <- get args, left
3701   var first/eax: (addr cell) <- lookup *first-ah
3702   {
3703     var first-type/eax: (addr int) <- get first, type
3704     compare *first-type, 7/array
3705     break-if-=
3706     error trace, "first arg for 'iset' is not an array"
3707     return
3708   }
3709   var array-ah/eax: (addr handle array handle cell) <- get first, array-data
3710   var _array/eax: (addr array handle cell) <- lookup *array-ah
3711   var array/ecx: (addr array handle cell) <- copy _array
3712   # idx = args->right->left->value
3713   var rest-ah/eax: (addr handle cell) <- get args, right
3714   var _rest/eax: (addr cell) <- lookup *rest-ah
3715   var rest/esi: (addr cell) <- copy _rest
3716   {
3717     var rest-type/eax: (addr int) <- get rest, type
3718     compare *rest-type, 0/pair
3719     break-if-=
3720     error trace, "'iset' encountered non-pair"
3721     return
3722   }
3723   {
3724     var rest-nil?/eax: boolean <- nil? rest
3725     compare rest-nil?, 0/false
3726     break-if-=
3727     error trace, "'iset' needs 3 args but got 1"
3728     return
3729   }
3730   var second-ah/eax: (addr handle cell) <- get rest, left
3731   var second/eax: (addr cell) <- lookup *second-ah
3732   {
3733     var second-type/eax: (addr int) <- get second, type
3734     compare *second-type, 1/number
3735     break-if-=
3736     error trace, "second arg for 'iset' is not an int (index)"
3737     return
3738   }
3739   var second-value/eax: (addr float) <- get second, number-data
3740   var idx/eax: int <- truncate *second-value
3741   # offset based on idx after bounds check
3742   var max/edx: int <- length array
3743   compare idx, max
3744   {
3745     break-if-<
3746     error trace, "iset: too few elements in array"
3747     return
3748   }
3749   var offset/edx: (offset handle cell) <- compute-offset array, idx
3750   # val = rest->right->left
3751   var rest-ah/eax: (addr handle cell) <- get rest, right
3752   var _rest/eax: (addr cell) <- lookup *rest-ah
3753   rest <- copy _rest
3754   {
3755     var rest-type/eax: (addr int) <- get rest, type
3756     compare *rest-type, 0/pair
3757     break-if-=
3758     error trace, "'iset' encountered non-pair"
3759     return
3760   }
3761   {
3762     var rest-nil?/eax: boolean <- nil? rest
3763     compare rest-nil?, 0/false
3764     break-if-=
3765     error trace, "'iset' needs 3 args but got 2"
3766     return
3767   }
3768   var val-ah/eax: (addr handle cell) <- get rest, left
3769   # copy
3770   var dest/edi: (addr handle cell) <- index array, offset
3771   copy-object val-ah, dest
3772   # return nothing
3775 fn apply-render-image _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3776   trace-text trace, "eval", "apply 'img'"
3777   var args-ah/eax: (addr handle cell) <- copy _args-ah
3778   var _args/eax: (addr cell) <- lookup *args-ah
3779   var args/esi: (addr cell) <- copy _args
3780   {
3781     var args-type/eax: (addr int) <- get args, type
3782     compare *args-type, 0/pair
3783     break-if-=
3784     error trace, "args to 'img' are not a list"
3785     return
3786   }
3787   var empty-args?/eax: boolean <- nil? args
3788   compare empty-args?, 0/false
3789   {
3790     break-if-=
3791     error trace, "'img' needs 6 args but got 0"
3792     return
3793   }
3794   # screen = args->left
3795   var first-ah/eax: (addr handle cell) <- get args, left
3796   var first/eax: (addr cell) <- lookup *first-ah
3797   {
3798     var first-type/eax: (addr int) <- get first, type
3799     compare *first-type, 5/screen
3800     break-if-=
3801     error trace, "first arg for 'img' is not a screen"
3802     return
3803   }
3804   var screen-ah/eax: (addr handle screen) <- get first, screen-data
3805   var _screen/eax: (addr screen) <- lookup *screen-ah
3806   var screen/edi: (addr screen) <- copy _screen
3807   # x1 = args->right->left->value
3808   var rest-ah/eax: (addr handle cell) <- get args, right
3809   var _rest/eax: (addr cell) <- lookup *rest-ah
3810   var rest/esi: (addr cell) <- copy _rest
3811   {
3812     var rest-type/eax: (addr int) <- get rest, type
3813     compare *rest-type, 0/pair
3814     break-if-=
3815     error trace, "'img' encountered non-pair"
3816     return
3817   }
3818   {
3819     var rest-nil?/eax: boolean <- nil? rest
3820     compare rest-nil?, 0/false
3821     break-if-=
3822     error trace, "'img' needs 6 args but got 1"
3823     return
3824   }
3825   var second-ah/eax: (addr handle cell) <- get rest, left
3826   var second/eax: (addr cell) <- lookup *second-ah
3827   {
3828     var second-type/eax: (addr int) <- get second, type
3829     compare *second-type, 3/stream
3830     break-if-=
3831     error trace, "second arg for 'img' is not a stream (image data in ascii netpbm)"
3832     return
3833   }
3834   var img-data-ah/eax: (addr handle stream byte) <- get second, text-data
3835   var img-data/eax: (addr stream byte) <- lookup *img-data-ah
3836   var img-h: (handle cell)
3837   var img-ah/ecx: (addr handle cell) <- address img-h
3838   new-image img-ah, img-data
3839   # x = rest->right->left->value
3840   var rest-ah/eax: (addr handle cell) <- get rest, right
3841   var _rest/eax: (addr cell) <- lookup *rest-ah
3842   rest <- copy _rest
3843   {
3844     var rest-type/eax: (addr int) <- get rest, type
3845     compare *rest-type, 0/pair
3846     break-if-=
3847     error trace, "'img' encountered non-pair"
3848     return
3849   }
3850   {
3851     var rest-nil?/eax: boolean <- nil? rest
3852     compare rest-nil?, 0/false
3853     break-if-=
3854     error trace, "'img' needs 6 args but got 2"
3855     return
3856   }
3857   var third-ah/eax: (addr handle cell) <- get rest, left
3858   var third/eax: (addr cell) <- lookup *third-ah
3859   {
3860     var third-type/eax: (addr int) <- get third, type
3861     compare *third-type, 1/number
3862     break-if-=
3863     error trace, "third arg for 'img' is not a number (screen x coordinate of top left)"
3864     return
3865   }
3866   var third-value/eax: (addr float) <- get third, number-data
3867   var x/ebx: int <- convert *third-value
3868   # y = rest->right->left->value
3869   var rest-ah/eax: (addr handle cell) <- get rest, right
3870   var _rest/eax: (addr cell) <- lookup *rest-ah
3871   var rest/esi: (addr cell) <- copy _rest
3872   {
3873     var rest-type/eax: (addr int) <- get rest, type
3874     compare *rest-type, 0/pair
3875     break-if-=
3876     error trace, "'img' encountered non-pair"
3877     return
3878   }
3879   {
3880     var rest-nil?/eax: boolean <- nil? rest
3881     compare rest-nil?, 0/false
3882     break-if-=
3883     error trace, "'img' needs 6 args but got 3"
3884     return
3885   }
3886   var fourth-ah/eax: (addr handle cell) <- get rest, left
3887   var fourth/eax: (addr cell) <- lookup *fourth-ah
3888   {
3889     var fourth-type/eax: (addr int) <- get fourth, type
3890     compare *fourth-type, 1/number
3891     break-if-=
3892     error trace, "fourth arg for 'img' is not a number (screen x coordinate of end point)"
3893     return
3894   }
3895   var fourth-value/eax: (addr float) <- get fourth, number-data
3896   var y/ecx: int <- convert *fourth-value
3897   # w = rest->right->left->value
3898   var rest-ah/eax: (addr handle cell) <- get rest, right
3899   var _rest/eax: (addr cell) <- lookup *rest-ah
3900   rest <- copy _rest
3901   {
3902     var rest-type/eax: (addr int) <- get rest, type
3903     compare *rest-type, 0/pair
3904     break-if-=
3905     error trace, "'img' encountered non-pair"
3906     return
3907   }
3908   {
3909     var rest-nil?/eax: boolean <- nil? rest
3910     compare rest-nil?, 0/false
3911     break-if-=
3912     error trace, "'img' needs 6 args but got 4"
3913     return
3914   }
3915   var fifth-ah/eax: (addr handle cell) <- get rest, left
3916   var fifth/eax: (addr cell) <- lookup *fifth-ah
3917   {
3918     var fifth-type/eax: (addr int) <- get fifth, type
3919     compare *fifth-type, 1/number
3920     break-if-=
3921     error trace, "fifth arg for 'img' is not a number (screen y coordinate of end point)"
3922     return
3923   }
3924   var fifth-value/eax: (addr float) <- get fifth, number-data
3925   var tmp/eax: int <- convert *fifth-value
3926   var w: int
3927   copy-to w, tmp
3928   # h = rest->right->left->value
3929   var rest-ah/eax: (addr handle cell) <- get rest, right
3930   var _rest/eax: (addr cell) <- lookup *rest-ah
3931   rest <- copy _rest
3932   {
3933     var rest-type/eax: (addr int) <- get rest, type
3934     compare *rest-type, 0/pair
3935     break-if-=
3936     error trace, "'img' encountered non-pair"
3937     return
3938   }
3939   {
3940     var rest-nil?/eax: boolean <- nil? rest
3941     compare rest-nil?, 0/false
3942     break-if-=
3943     error trace, "'img' needs 6 args but got 5"
3944     return
3945   }
3946   var sixth-ah/eax: (addr handle cell) <- get rest, left
3947   var sixth/eax: (addr cell) <- lookup *sixth-ah
3948   {
3949     var sixth-type/eax: (addr int) <- get sixth, type
3950     compare *sixth-type, 1/number
3951     break-if-=
3952     error trace, "sixth arg for 'img' is not an int (height)"
3953     return
3954   }
3955   var sixth-value/eax: (addr float) <- get sixth, number-data
3956   var tmp/eax: int <- convert *sixth-value
3957   var h: int
3958   copy-to h, tmp
3959   #
3960   var img-cell-ah/eax: (addr handle cell) <- address img-h
3961   var img-cell/eax: (addr cell) <- lookup *img-cell-ah
3962   var img-ah/eax: (addr handle image) <- get img-cell, image-data
3963   var img/eax: (addr image) <- lookup *img-ah
3964   render-image screen, img, x y, w h
3965   # return nothing
3968 fn apply-abort _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
3969   abort "aa"