about summary refs log blame commit diff stats
path: root/shell/primitives.mu
blob: e955b53166d0ca7838f98afc742eecd8d6b414e8 (plain) (tree)
2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460


                                                               






                                                     
                            







                               
                                



                              
                              



                               
                                










                                  
                               
                                
                                
                                 
                                 

                                 

                                     




                                 

                                 

                                
                                   
                                
                               

                              




                                      

                                                                           

                                                                             
                                      

                                                          
                                     
                                               



                                                                                                                            
                                                                                                                                              




                                                                                                                          
                                                                                                                                     




                                                                                                                       
                                                                                                                                                  




                                                                                                                         
                                                                                                                                  

                                          
                                                                                                                                  
                
                                          
                                                                                                                                     




                                                                                                                        
                                                                                                                                             



                                                                                                    






                                                                                                                        







                                               
                                      
                                    
                                              
                                
                                                                                                       

                                
                                                                                                    
                                                                                                       

                                

                                                                                                            

                                

                                                                                                                 

                                


                                                                                                                                 

                                
                                                                                                      

                                
                                                                                                                                   

                                

                                                                                                           

                                

                                                                                                    

                                
                                                                                             

                                
                                                                                                  
                                                                                                               

                                
                                                                                               

                                
                                                                                                     
                                                                                                    

                                

                                                                                                                   







                                                                                                            










                                                          

                                                 




































































                                                                                                                                              












                                                                             










































                                                                 






                                                                 






                                                        

                                                                  
              
                                             

























































































































                                                                    






                                                          






                                                            






                                                            






                                                              






                                                              













                                                              













                                                                  




















                                                                 













                                                              






                                                            






                                                                  






                                                            






                                                          






                                                                 













                                                                                         
   
                                                   




                                           









                                                        
   

                                                     






                                                             
                                                
   
                                                     











                                           

                                                          
   

                                                       










                                                               
























                                                                                         
                                                                                                                


            




                                                                                              
   
                                                   




                                           









                                                        
   

                                                     







                                                             
   
                                                     











                                           

                                                          
   

                                                       















                                                                                              
   
                                                   




                                           









                                                        
   

                                                     







                                                             
   
                                                     











                                           

                                                          
   

                                                       















                                                                                            
   
                                                   




                                           









                                                        
   

                                                     







                                                             
   
                                                     











                                           

                                                          
   

                                                       










                                                               




                                                                                               
   
                                                   




                                           









                                                        
   

                                                     







                                                             
   
                                                     











                                           

                                                          
   

                                                       
















                                                               




                                                                                                 
   
                                                   




                                              









                                                        
   

                                                     



                                               
                                                             









                                                                                         
   
                                                   




                                             









                                                        
   

                                                     






















                                                                                         
   
                                                   




                                             









                                                        
   

                                                     































                                                                                         
   
                                                   




                                             







                                            
                                                        
                                                
   

                                                     



                                            







                                       









                                                                                         
   
                                                   




                                             







                                            
                                                        
                                                
   

                                                     



                                            







                                       









                                                                                          
   
                                                   




                                                











                                                         
   
                                                     











                                                




                                                          





                                                                                                
                                                   














                                                        
   

                                                     






                    































                                                                                         









                                                   























                                                          
 







                                                                           
                                                                                                     



                                                      
   
                                                   




                                             











                                                         
   
                                                     











                                             















                                                                                         
                                         


                                                      
   
                                                   




                                               



                                           
                                              
















                                                                                           
                                           


                                                      
   
                                                   




                                                 



                                           
                                                



                                                            
                                                            












                                                                                       
   
                                                   




                                             











                                                         
   
                                                     











                                             



                                                          
   

                                                     






                                                             
   

                                                       
              
                                                     
















                                                                                       
   
                                                   




                                             











                                                         
   
                                                     











                                             



                                                          
   

                                                     






                                                             
   

                                                       
              
                                                     
















                                                                                        
   
                                                   




                                              











                                                         
   
                                                     











                                              



                                                          
   

                                                     






                                                             
   

                                                       
              
                                                      
















                                                                                        
   
                                                   




                                              











                                                         
   
                                                     











                                              



                                                          
   

                                                     






                                                             
   

                                                       
              
                                                      












                                                                                           
                                           


                                                      
   
                                                   




                                                 



                                           
                                                 




                                                        
   

                                                     









                                                                   
   
                                                     











                                                 









                                                                                              
                                           


                                                      
   
                                                   




                                                 










                                                        
                               
   
               



                                                                             

          









                                                                     


                                                                                        
                                        


                                                      
   
                                                   




                                              









                                                        
   

                                                     















                                                                                          
   
                                                   




                                                









                                                        
   

                                                     















                                                                                          
   
                                                   




                                                









                                                        
   

                                                     















                                                                                           
   
                                                   




                                                 









                                                        
   

                                                     















                                                                                        
   
                                                   




                                              









                                                        
   

                                                     











                                                                                           
                                           


                                                      
   
                                                   




                                                 



                                           
                                                 




                                                        
   

                                                     










                                                                   
   
                                                   











                                                 

                                                         
   

                                                       









                                                                      
   
                                                   











                                                 

                                                        
   

                                                     









                                                                     
   
                                                   











                                                 

                                                         
   

                                                       









                                                                        






















































































































































































                                                                                             























































































































































                                                                                             























































































































































                                                                                             























































































































































                                                                                            






















































































































































































































































                                                                                                 
                                                                                                  
                                         


                                                      
   
                                                   




                                               



                                           
                                              




                                                        
   

                                                     
































                                                                                            
                                           


                                                      
   
                                                   




                                                 



                                           
                                                 




                                                        
   

                                                     









                                                                           
   
                                                     











                                                 

                                                          
   

                                                       
              
                                                                  










                                                               





                                                                                            
                                                   














                                                        
   

                                                     
















                                                                                          
                                                   














                                                        
   

                                                     












                                                                           
                                                                                           
                                           


                                                      
   
                                                   




                                                 



                                           
                                                




                                                        
   

                                                     














                                                                   
                                                                                             
                                             


                                                      
   
                                                   




                                                   



                                           
                                                  




                                                        
   

                                                     















                                                                                           
                                           


                                                      
   
                                                   




                                                 



                                           
                                                




                                                        
   

                                                     
















                                                                                            
                                            


                                                      
   
                                                   




                                                  



                                           
                                                 




                                                        
   

                                                     














                                                                   




























































































































                                                                                                
                                    

                       
 



































                                                                                               

































































                                                                                                  






































                                                                                           
         

















                                                               
                                              

                                                                           
   

                                   
              





                                                   






                                                                    



























































                                                                                          
                                            




                                          
                                                  



























                                                                   
































































































































































































                                                                                                  


                                                                                           
# Primitives are functions that are implemented directly in Mu.
# They always evaluate all their arguments.

fn initialize-primitives _self: (addr global-table) {
  var self/esi: (addr global-table) <- copy _self
  # for numbers
  append-primitive self, "+"
  append-primitive self, "-"
  append-primitive self, "*"
  append-primitive self, "/"
  append-primitive self, "%"
  append-primitive self, "sqrt"
  append-primitive self, "abs"
  append-primitive self, "sgn"
  append-primitive self, "<"
  append-primitive self, ">"
  append-primitive self, "<="
  append-primitive self, ">="
  # generic
  append-primitive self, "apply"
  append-primitive self, "="
  append-primitive self, "no"
  append-primitive self, "not"
  append-primitive self, "dbg"
  append-primitive self, "len"
  # for pairs
  append-primitive self, "car"
  append-primitive self, "cdr"
  append-primitive self, "cons"
  append-primitive self, "cons?"
  # for screens
  append-primitive self, "print"
  append-primitive self, "clear"
  append-primitive self, "lines"
  append-primitive self, "columns"
  append-primitive self, "up"
  append-primitive self, "down"
  append-primitive self, "left"
  append-primitive self, "right"
  append-primitive self, "cr"
  append-primitive self, "pixel"
  append-primitive self, "line"
  append-primitive self, "hline"
  append-primitive self, "vline"
  append-primitive self, "circle"
  append-primitive self, "bezier"
  append-primitive self, "width"
  append-primitive self, "height"
  append-primitive self, "new_screen"
  append-primitive self, "blit"
  # for keyboards
  append-primitive self, "key"
  # for streams
  append-primitive self, "stream"
  append-primitive self, "write"
  append-primitive self, "read"
  append-primitive self, "rewind"
  # for arrays
  append-primitive self, "array"
  append-primitive self, "populate"
  append-primitive self, "index"
  append-primitive self, "iset"
  # for images
  append-primitive self, "img"
  # misc
  append-primitive self, "abort"
  # keep sync'd with render-primitives
}

# Slightly misnamed; renders primitives as well as special forms that don't
# evaluate all their arguments.
fn render-primitives screen: (addr screen), xmin: int, xmax: int, ymax: int {
  var y/ecx: int <- copy ymax
  y <- subtract 0x11/primitives-border
  clear-rect screen, xmin, y, xmax, ymax, 0xdc/bg=green-bg
  y <- increment
  var right-min/edx: int <- copy xmax
  right-min <- subtract 0x1e/primitives-divider
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "primitives", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  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
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "booleans", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "  = and or not", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "lists", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  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
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "numbers", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "  + - * / %", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "  < > <= >=", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "  sqrt abs sgn", right-min, y, xmax, ymax, 0x2a/fg=orange, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "arrays", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  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
  y <- increment
  var tmpx/eax: int <- copy right-min
  tmpx <- draw-text-rightward screen, "  populate", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": int _ -> array", tmpx, xmax, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  set-cursor-position screen, right-min, y
  draw-text-wrapping-right-then-down-from-cursor screen, "images", right-min, y, xmax, ymax, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy right-min
  tmpx <- draw-text-rightward screen, "  img", tmpx, xmax, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen stream x y w h", tmpx, xmax, y, 7/fg=grey, 0xdc/bg=green-bg
#?   {
#?     compare screen, 0
#?     break-if-!=
#?     var foo/eax: byte <- read-key 0/keyboard
#?     compare foo, 0
#?     loop-if-=
#?   }
  y <- copy ymax
  y <- subtract 0x10/primitives-border
  var left-max/edx: int <- copy xmax
  left-max <- subtract 0x20/primitives-divider
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "cursor graphics", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  print", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen _ -> _", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  lines columns", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen -> number", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  up down left right", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  cr", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen   ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, "# move cursor down and to left margin", tmpx, left-max, y, 0x38/fg=trace, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "pixel graphics", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  circle bezier line hline vline pixel", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  width height", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen -> number", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  clear", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": screen", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "input", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  key", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": keyboard -> grapheme?", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "streams", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  stream", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": -> stream ", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  write", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": stream grapheme -> stream", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  rewind clear", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": stream", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
  y <- increment
  var tmpx/eax: int <- copy xmin
  tmpx <- draw-text-rightward screen, "  read", tmpx, left-max, y, 0x2a/fg=orange, 0xdc/bg=green-bg
  tmpx <- draw-text-rightward screen, ": stream -> grapheme", tmpx, left-max, y, 7/fg=grey, 0xdc/bg=green-bg
}

fn primitive-global? _x: (addr global) -> _/eax: boolean {
  var x/eax: (addr global) <- copy _x
  var value-ah/eax: (addr handle cell) <- get x, value
  var value/eax: (addr cell) <- lookup *value-ah
  compare value, 0/null
  {
    break-if-!=
    return 0/false
  }
  var primitive?/eax: boolean <- primitive? value
  return primitive?
}

fn append-primitive _self: (addr global-table), name: (addr array byte) {
  var self/esi: (addr global-table) <- copy _self
  compare self, 0
  {
    break-if-!=
    abort "append primitive"
    return
  }
  var final-index-addr/ecx: (addr int) <- get self, final-index
  increment *final-index-addr
  var curr-index/ecx: int <- copy *final-index-addr
  var data-ah/eax: (addr handle array global) <- get self, data
  var data/eax: (addr array global) <- lookup *data-ah
  var curr-offset/esi: (offset global) <- compute-offset data, curr-index
  var curr/esi: (addr global) <- index data, curr-offset
  var curr-name-ah/eax: (addr handle array byte) <- get curr, name
  copy-array-object name, curr-name-ah
  var curr-value-ah/eax: (addr handle cell) <- get curr, value
  new-primitive-function curr-value-ah, curr-index
}

# a little strange; goes from value to name and selects primitive based on name
fn apply-primitive _f: (addr cell), args-ah: (addr handle cell), out: (addr handle cell), _globals: (addr global-table), trace: (addr trace) {
  var f/esi: (addr cell) <- copy _f
  var f-index-a/ecx: (addr int) <- get f, index-data
  var f-index/ecx: int <- copy *f-index-a
  var globals/eax: (addr global-table) <- copy _globals
  compare globals, 0
  {
    break-if-!=
    abort "apply primitive"
    return
  }
  var global-data-ah/eax: (addr handle array global) <- get globals, data
  var global-data/eax: (addr array global) <- lookup *global-data-ah
  var f-offset/ecx: (offset global) <- compute-offset global-data, f-index
  var f-value/ecx: (addr global) <- index global-data, f-offset
  var f-name-ah/ecx: (addr handle array byte) <- get f-value, name
  var f-name/eax: (addr array byte) <- lookup *f-name-ah
  {
    var add?/eax: boolean <- string-equal? f-name, "+"
    compare add?, 0/false
    break-if-=
    apply-add args-ah, out, trace
    return
  }
  {
    var subtract?/eax: boolean <- string-equal? f-name, "-"
    compare subtract?, 0/false
    break-if-=
    apply-subtract args-ah, out, trace
    return
  }
  {
    var multiply?/eax: boolean <- string-equal? f-name, "*"
    compare multiply?, 0/false
    break-if-=
    apply-multiply args-ah, out, trace
    return
  }
  {
    var divide?/eax: boolean <- string-equal? f-name, "/"
    compare divide?, 0/false
    break-if-=
    apply-divide args-ah, out, trace
    return
  }
  # '%' is the remainder operator, because modulo isn't really meaningful for
  # non-integers
  #
  # I considered calling this operator 'rem', but I want to follow Arc in
  # using 'rem' for filtering out elements from lists.
  #   https://arclanguage.github.io/ref/list.html#rem
  {
    var remainder?/eax: boolean <- string-equal? f-name, "%"
    compare remainder?, 0/false
    break-if-=
    apply-remainder args-ah, out, trace
    return
  }
  {
    var square-root?/eax: boolean <- string-equal? f-name, "sqrt"
    compare square-root?, 0/false
    break-if-=
    apply-square-root args-ah, out, trace
    return
  }
  {
    var abs?/eax: boolean <- string-equal? f-name, "abs"
    compare abs?, 0/false
    break-if-=
    apply-abs args-ah, out, trace
    return
  }
  {
    var sgn?/eax: boolean <- string-equal? f-name, "sgn"
    compare sgn?, 0/false
    break-if-=
    apply-sgn args-ah, out, trace
    return
  }
  {
    var car?/eax: boolean <- string-equal? f-name, "car"
    compare car?, 0/false
    break-if-=
    apply-car args-ah, out, trace
    return
  }
  {
    var cdr?/eax: boolean <- string-equal? f-name, "cdr"
    compare cdr?, 0/false
    break-if-=
    apply-cdr args-ah, out, trace
    return
  }
  {
    var cons?/eax: boolean <- string-equal? f-name, "cons"
    compare cons?, 0/false
    break-if-=
    apply-cons args-ah, out, trace
    return
  }
  {
    var cons-check?/eax: boolean <- string-equal? f-name, "cons?"
    compare cons-check?, 0/false
    break-if-=
    apply-cons-check args-ah, out, trace
    return
  }
  {
    var len?/eax: boolean <- string-equal? f-name, "len"
    compare len?, 0/false
    break-if-=
    apply-len args-ah, out, trace
    return
  }
  {
    var cell-isomorphic?/eax: boolean <- string-equal? f-name, "="
    compare cell-isomorphic?, 0/false
    break-if-=
    apply-cell-isomorphic args-ah, out, trace
    return
  }
  {
    var not?/eax: boolean <- string-equal? f-name, "no"
    compare not?, 0/false
    break-if-=
    apply-not args-ah, out, trace
    return
  }
  {
    var not?/eax: boolean <- string-equal? f-name, "not"
    compare not?, 0/false
    break-if-=
    apply-not args-ah, out, trace
    return
  }
  {
    var debug?/eax: boolean <- string-equal? f-name, "dbg"
    compare debug?, 0/false
    break-if-=
    apply-debug args-ah, out, trace
    return
  }
  {
    var lesser?/eax: boolean <- string-equal? f-name, "<"
    compare lesser?, 0/false
    break-if-=
    apply-< args-ah, out, trace
    return
  }
  {
    var greater?/eax: boolean <- string-equal? f-name, ">"
    compare greater?, 0/false
    break-if-=
    apply-> args-ah, out, trace
    return
  }
  {
    var lesser-or-equal?/eax: boolean <- string-equal? f-name, "<="
    compare lesser-or-equal?, 0/false
    break-if-=
    apply-<= args-ah, out, trace
    return
  }
  {
    var greater-or-equal?/eax: boolean <- string-equal? f-name, ">="
    compare greater-or-equal?, 0/false
    break-if-=
    apply->= args-ah, out, trace
    return
  }
  {
    var print?/eax: boolean <- string-equal? f-name, "print"
    compare print?, 0/false
    break-if-=
    apply-print args-ah, out, trace
    return
  }
  {
    var clear?/eax: boolean <- string-equal? f-name, "clear"
    compare clear?, 0/false
    break-if-=
    apply-clear args-ah, out, trace
    return
  }
  {
    var lines?/eax: boolean <- string-equal? f-name, "lines"
    compare lines?, 0/false
    break-if-=
    apply-lines args-ah, out, trace
    return
  }
  {
    var columns?/eax: boolean <- string-equal? f-name, "columns"
    compare columns?, 0/false
    break-if-=
    apply-columns args-ah, out, trace
    return
  }
  {
    var up?/eax: boolean <- string-equal? f-name, "up"
    compare up?, 0/false
    break-if-=
    apply-up args-ah, out, trace
    return
  }
  {
    var down?/eax: boolean <- string-equal? f-name, "down"
    compare down?, 0/false
    break-if-=
    apply-down args-ah, out, trace
    return
  }
  {
    var left?/eax: boolean <- string-equal? f-name, "left"
    compare left?, 0/false
    break-if-=
    apply-left args-ah, out, trace
    return
  }
  {
    var right?/eax: boolean <- string-equal? f-name, "right"
    compare right?, 0/false
    break-if-=
    apply-right args-ah, out, trace
    return
  }
  {
    var cr?/eax: boolean <- string-equal? f-name, "cr"
    compare cr?, 0/false
    break-if-=
    apply-cr args-ah, out, trace
    return
  }
  {
    var pixel?/eax: boolean <- string-equal? f-name, "pixel"
    compare pixel?, 0/false
    break-if-=
    apply-pixel args-ah, out, trace
    return
  }
  {
    var line?/eax: boolean <- string-equal? f-name, "line"
    compare line?, 0/false
    break-if-=
    apply-line args-ah, out, trace
    return
  }
  {
    var hline?/eax: boolean <- string-equal? f-name, "hline"
    compare hline?, 0/false
    break-if-=
    apply-hline args-ah, out, trace
    return
  }
  {
    var vline?/eax: boolean <- string-equal? f-name, "vline"
    compare vline?, 0/false
    break-if-=
    apply-vline args-ah, out, trace
    return
  }
  {
    var circle?/eax: boolean <- string-equal? f-name, "circle"
    compare circle?, 0/false
    break-if-=
    apply-circle args-ah, out, trace
    return
  }
  {
    var bezier?/eax: boolean <- string-equal? f-name, "bezier"
    compare bezier?, 0/false
    break-if-=
    apply-bezier args-ah, out, trace
    return
  }
  {
    var width?/eax: boolean <- string-equal? f-name, "width"
    compare width?, 0/false
    break-if-=
    apply-width args-ah, out, trace
    return
  }
  {
    var height?/eax: boolean <- string-equal? f-name, "height"
    compare height?, 0/false
    break-if-=
    apply-height args-ah, out, trace
    return
  }
  {
    var screen?/eax: boolean <- string-equal? f-name, "new_screen"
    compare screen?, 0/false
    break-if-=
    apply-new-screen args-ah, out, trace
    return
  }
  {
    var blit?/eax: boolean <- string-equal? f-name, "blit"
    compare blit?, 0/false
    break-if-=
    apply-blit args-ah, out, trace
    return
  }
  {
    var wait-for-key?/eax: boolean <- string-equal? f-name, "key"
    compare wait-for-key?, 0/false
    break-if-=
    apply-wait-for-key args-ah, out, trace
    return
  }
  {
    var stream?/eax: boolean <- string-equal? f-name, "stream"
    compare stream?, 0/false
    break-if-=
    apply-stream args-ah, out, trace
    return
  }
  {
    var write?/eax: boolean <- string-equal? f-name, "write"
    compare write?, 0/false
    break-if-=
    apply-write args-ah, out, trace
    return
  }
  {
    var rewind?/eax: boolean <- string-equal? f-name, "rewind"
    compare rewind?, 0/false
    break-if-=
    apply-rewind args-ah, out, trace
    return
  }
  {
    var read?/eax: boolean <- string-equal? f-name, "read"
    compare read?, 0/false
    break-if-=
    apply-read args-ah, out, trace
    return
  }
  {
    var array?/eax: boolean <- string-equal? f-name, "array"
    compare array?, 0/false
    break-if-=
    apply-array args-ah, out, trace
    return
  }
  {
    var populate?/eax: boolean <- string-equal? f-name, "populate"
    compare populate?, 0/false
    break-if-=
    apply-populate args-ah, out, trace
    return
  }
  {
    var index?/eax: boolean <- string-equal? f-name, "index"
    compare index?, 0/false
    break-if-=
    apply-index args-ah, out, trace
    return
  }
  {
    var iset?/eax: boolean <- string-equal? f-name, "iset"
    compare iset?, 0/false
    break-if-=
    apply-iset args-ah, out, trace
    return
  }
  {
    var render-image?/eax: boolean <- string-equal? f-name, "img"
    compare render-image?, 0/false
    break-if-=
    apply-render-image args-ah, out, trace
    return
  }
  {
    var abort?/eax: boolean <- string-equal? f-name, "abort"
    compare abort?, 0/false
    break-if-=
    apply-abort args-ah, out, trace
    return
  }
  abort "unknown primitive function"
}

fn apply-add _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply +"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to + are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "+ needs 2 args but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for + is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  # args->right->left->value
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "+ encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "+ needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for + is not a number"
    return
  }
  var second-value/edx: (addr float) <- get second, number-data
  # add
  var result/xmm0: float <- copy *first-value
  result <- add *second-value
  new-float out, result
}

fn test-evaluate-missing-arg-in-add {
  var t-storage: trace
  var t/edi: (addr trace) <- address t-storage
  initialize-trace t, 0x100/max-depth, 0x100/capacity, 0/visible  # we don't use trace UI
  #
  var nil-storage: (handle cell)
  var nil-ah/ecx: (addr handle cell) <- address nil-storage
  allocate-pair nil-ah
  var one-storage: (handle cell)
  var one-ah/edx: (addr handle cell) <- address one-storage
  new-integer one-ah, 1
  var add-storage: (handle cell)
  var add-ah/ebx: (addr handle cell) <- address add-storage
  new-symbol add-ah, "+"
  # input is (+ 1)
  var tmp-storage: (handle cell)
  var tmp-ah/esi: (addr handle cell) <- address tmp-storage
  new-pair tmp-ah, *one-ah, *nil-ah
  new-pair tmp-ah, *add-ah, *tmp-ah
#?   dump-cell tmp-ah
  #
  var globals-storage: global-table
  var globals/edx: (addr global-table) <- address globals-storage
  initialize-globals globals
  #
  evaluate tmp-ah, tmp-ah, *nil-ah, globals, t, 0/no-screen, 0/no-keyboard, 0/definitions-created, 0/call-number
  # no crash
}

fn apply-subtract _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply -"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to - are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "- needs 2 args but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for - is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  # args->right->left->value
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "- encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "- needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for - is not a number"
    return
  }
  var second-value/edx: (addr float) <- get second, number-data
  # subtract
  var result/xmm0: float <- copy *first-value
  result <- subtract *second-value
  new-float out, result
}

fn apply-multiply _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply *"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to * are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "* needs 2 args but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for * is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  # args->right->left->value
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "* encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "* needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for * is not a number"
    return
  }
  var second-value/edx: (addr float) <- get second, number-data
  # multiply
  var result/xmm0: float <- copy *first-value
  result <- multiply *second-value
  new-float out, result
}

fn apply-divide _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply /"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to / are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "/ needs 2 args but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for / is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  # args->right->left->value
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "/ encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "/ needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for / is not a number"
    return
  }
  var second-value/edx: (addr float) <- get second, number-data
  # divide
  var result/xmm0: float <- copy *first-value
  result <- divide *second-value
  new-float out, result
}

fn apply-remainder _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply %"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to % are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "% needs 2 args but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for % is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  # args->right->left->value
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "% encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "% needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for % is not a number"
    return
  }
  var second-value/edx: (addr float) <- get second, number-data
  # divide
  var quotient/xmm0: float <- copy *first-value
  quotient <- divide *second-value
  var quotient-int/eax: int <- truncate quotient
  quotient <- convert quotient-int
  var sub-result/xmm1: float <- copy quotient
  sub-result <- multiply *second-value
  var result/xmm0: float <- copy *first-value
  result <- subtract sub-result
  new-float out, result
}

fn apply-square-root _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply sqrt"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to sqrt are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "sqrt needs 1 arg but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "arg for sqrt is not a number"
    return
  }
  var first-value/eax: (addr float) <- get first, number-data
  # square-root
  var result/xmm0: float <- square-root *first-value
  new-float out, result
}

fn apply-abs _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply abs"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to abs are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "abs needs 1 arg but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "arg for abs is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  #
  var result/xmm0: float <- copy *first-value
  var zero: float
  compare result, zero
  {
    break-if-float>=
    var neg1/eax: int <- copy -1
    var neg1-f/xmm1: float <- convert neg1
    result <- multiply neg1-f
  }
  new-float out, result
}

fn apply-sgn _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply sgn"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to sgn are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "sgn needs 1 arg but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "arg for sgn is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  #
  var result/xmm0: float <- copy *first-value
  var zero: float
  $apply-sgn:core: {
    compare result, zero
    break-if-=
    {
      break-if-float>
      var neg1/eax: int <- copy -1
      result <- convert neg1
      break $apply-sgn:core
    }
    {
      break-if-float<
      var one/eax: int <- copy 1
      result <- convert one
      break $apply-sgn:core
    }
  }
  new-float out, result
}

fn apply-car _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply car"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to car are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "car needs 1 arg but got 0"
    return
  }
  # args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 0/pair
    break-if-=
    error trace, "arg for car is not a pair"
    return
  }
  # nil? return nil
  {
    var nil?/eax: boolean <- nil? first
    compare nil?, 0/false
    break-if-=
    copy-object first-ah, out
    return
  }
  # car
  var result/eax: (addr handle cell) <- get first, left
  copy-object result, out
}

fn apply-cdr _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply cdr"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to cdr are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "cdr needs 1 arg but got 0"
    return
  }
  # args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 0/pair
    break-if-=
    error trace, "arg for cdr is not a pair"
    return
  }
  # nil? return nil
  {
    var nil?/eax: boolean <- nil? first
    compare nil?, 0/false
    break-if-=
    copy-object first-ah, out
    return
  }
  # cdr
  var result/eax: (addr handle cell) <- get first, right
  copy-object result, out
}

fn apply-cons _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply cons"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'cons' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "cons needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'cons' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'cons' needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  # cons
  new-pair out, *first-ah, *second-ah
}

fn apply-cons-check _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply cons?"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to cons? are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "cons? needs 1 arg but got 0"
    return
  }
  # args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 0/pair
    break-if-=
    nil out
    return
  }
  new-integer out, 1
}

fn apply-len _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply len"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to len are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "len needs 1 arg but got 0"
    return
  }
  # args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    {
      var first-pair?/eax: boolean <- pair? first
      compare first-pair?, 0/false
    }
    break-if-=
    var result/eax: int <- list-length first
    new-integer out, result
    return
  }
  {
    {
      var first-array?/eax: boolean <- array? first
      compare first-array?, 0/false
    }
    break-if-=
    var result/eax: int <- array-length first
    new-integer out, result
    return
  }
  nil out
}

fn list-length in: (addr cell) -> _/eax: int {
  var curr/ecx: (addr cell) <- copy in
  var result/edi: int <- copy 0
  {
    var pair?/eax: boolean <- pair? curr
    {
      compare pair?, 0/false
      break-if-!=
      abort "len: ran into a non-cons"
    }
    var nil?/eax: boolean <- nil? curr
    compare nil?, 0/false
    break-if-!=
    result <- increment
    var next-ah/eax: (addr handle cell) <- get curr, right
    var next/eax: (addr cell) <- lookup *next-ah
    curr <- copy next
    loop
  }
  return result
}

fn array-length _in: (addr cell) -> _/eax: int {
  var in/esi: (addr cell) <- copy _in
  var in-data-ah/eax: (addr handle array handle cell) <- get in, array-data
  var in-data/eax: (addr array handle cell) <- lookup *in-data-ah
  var result/eax: int <- length in-data
  return result
}

fn apply-cell-isomorphic _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply '='"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to '=' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'=' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'=' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'=' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  # compare
  var _first/eax: (addr cell) <- lookup *first-ah
  var first/ecx: (addr cell) <- copy _first
  var second/eax: (addr cell) <- lookup *second-ah
  var match?/eax: boolean <- cell-isomorphic? first, second, trace
  compare match?, 0/false
  {
    break-if-!=
    nil out
    return
  }
  new-integer out, 1/true
}

fn apply-not _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'not'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'not' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'not' needs 1 arg but got 0"
    return
  }
  # args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  # not
  var nil?/eax: boolean <- nil? first
  compare nil?, 0/false
  {
    break-if-!=
    nil out
    return
  }
  new-integer out, 1
}

fn apply-debug _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'debug'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'debug' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'debug' needs 1 arg but got 0"
    return
  }
  # dump args->left uglily to screen and wait for a keypress
  var first-ah/eax: (addr handle cell) <- get args, left
  dump-cell-from-cursor-over-full-screen first-ah, 7/fg 0/bg
  {
    var foo/eax: byte <- read-key 0/keyboard
    compare foo, 0
    loop-if-=
  }
  # return nothing
}

fn apply-< _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply '<'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to '<' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'<' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'<' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'<' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  # compare
  var _first/eax: (addr cell) <- lookup *first-ah
  var first/ecx: (addr cell) <- copy _first
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for '<' is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  var first-float/xmm0: float <- copy *first-value
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for '<' is not a number"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  compare first-float, *second-value
  {
    break-if-float<
    nil out
    return
  }
  new-integer out, 1/true
}

fn apply-> _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply '>'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to '>' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'>' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'>' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'>' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  # compare
  var _first/eax: (addr cell) <- lookup *first-ah
  var first/ecx: (addr cell) <- copy _first
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for '>' is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  var first-float/xmm0: float <- copy *first-value
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for '>' is not a number"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  compare first-float, *second-value
  {
    break-if-float>
    nil out
    return
  }
  new-integer out, 1/true
}

fn apply-<= _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply '<='"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to '<=' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'<=' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'<=' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'<=' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  # compare
  var _first/eax: (addr cell) <- lookup *first-ah
  var first/ecx: (addr cell) <- copy _first
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for '<=' is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  var first-float/xmm0: float <- copy *first-value
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for '<=' is not a number"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  compare first-float, *second-value
  {
    break-if-float<=
    nil out
    return
  }
  new-integer out, 1/true
}

fn apply->= _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply '>='"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to '>=' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'>=' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'>=' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'>=' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  # compare
  var _first/eax: (addr cell) <- lookup *first-ah
  var first/ecx: (addr cell) <- copy _first
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for '>=' is not a number"
    return
  }
  var first-value/ecx: (addr float) <- get first, number-data
  var first-float/xmm0: float <- copy *first-value
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for '>=' is not a number"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  compare first-float, *second-value
  {
    break-if-float>=
    nil out
    return
  }
  new-integer out, 1/true
}

fn apply-print _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'print'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'print' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'print' needs 2 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'print' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/ecx: (addr screen) <- copy _screen
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'print' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'print' needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var stream-storage: (stream byte 0x100)
  var stream/edi: (addr stream byte) <- address stream-storage
  print-cell second-ah, stream, trace
  draw-stream-wrapping-right-then-down-from-cursor-over-full-screen screen, stream, 7/fg, 0/bg
  # return what was printed
  copy-object second-ah, out
}

fn apply-clear _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'clear'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'clear' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'clear' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  var first-type/ecx: (addr int) <- get first, type
  compare *first-type, 3/stream
  {
    break-if-!=
    var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
    var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
    var stream-data/ebx: (addr stream byte) <- copy _stream-data
    clear-stream stream-data
    return
  }
  compare *first-type, 5/screen
  {
    break-if-!=
    var screen-ah/eax: (addr handle screen) <- get first, screen-data
    var _screen/eax: (addr screen) <- lookup *screen-ah
    var screen/ecx: (addr screen) <- copy _screen
    clear-screen screen
    return
  }
  error trace, "first arg for 'clear' is not a screen or a stream"
}

fn apply-up _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'up'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'up' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'up' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'up' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/ecx: (addr screen) <- copy _screen
  #
  move-cursor-up screen
}

fn apply-down _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'down'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'down' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'down' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'down' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/ecx: (addr screen) <- copy _screen
  #
  move-cursor-down screen
}

fn apply-left _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'left'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'left' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'left' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'left' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/ecx: (addr screen) <- copy _screen
  #
  move-cursor-left screen
}

fn apply-right _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'right'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'right' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'right' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'right' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/ecx: (addr screen) <- copy _screen
  #
  move-cursor-right screen
}

fn apply-cr _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'cr'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'cr' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'cr' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'cr' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/ecx: (addr screen) <- copy _screen
  #
  move-cursor-to-left-margin-of-next-line screen
}

fn apply-pixel _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'pixel'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'pixel' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'pixel' needs 4 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'pixel' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # x = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'pixel' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'pixel' needs 4 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'pixel' is not an int (x coordinate)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var x/edx: int <- convert *second-value
  # y = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'pixel' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'pixel' needs 4 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'pixel' is not an int (y coordinate)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var y/ebx: int <- convert *third-value
  # color = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'pixel' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'pixel' needs 4 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'pixel' is not an int (color; 0..0xff)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var color/eax: int <- convert *fourth-value
  pixel screen, x, y, color
  # return nothing
}

fn apply-line _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'line'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'line' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'line' needs 6 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'line' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # x1 = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'line' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'line' needs 6 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'line' is not a number (screen x coordinate of start point)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var x1/edx: int <- convert *second-value
  # y1 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'line' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'line' needs 6 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'line' is not a number (screen y coordinate of start point)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var y1/ebx: int <- convert *third-value
  # x2 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'line' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'line' needs 6 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'line' is not a number (screen x coordinate of end point)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var x2/ecx: int <- convert *fourth-value
  # y2 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'line' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'line' needs 6 args but got 4"
    return
  }
  var fifth-ah/eax: (addr handle cell) <- get rest, left
  var fifth/eax: (addr cell) <- lookup *fifth-ah
  {
    var fifth-type/eax: (addr int) <- get fifth, type
    compare *fifth-type, 1/number
    break-if-=
    error trace, "fifth arg for 'line' is not a number (screen y coordinate of end point)"
    return
  }
  var fifth-value/eax: (addr float) <- get fifth, number-data
  var tmp/eax: int <- convert *fifth-value
  var y2: int
  copy-to y2, tmp
  # color = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'line' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'line' needs 6 args but got 5"
    return
  }
  var sixth-ah/eax: (addr handle cell) <- get rest, left
  var sixth/eax: (addr cell) <- lookup *sixth-ah
  {
    var sixth-type/eax: (addr int) <- get sixth, type
    compare *sixth-type, 1/number
    break-if-=
    error trace, "sixth arg for 'line' is not an int (color; 0..0xff)"
    return
  }
  var sixth-value/eax: (addr float) <- get sixth, number-data
  var color/eax: int <- convert *sixth-value
  draw-line screen, x1, y1, x2, y2, color
  # return nothing
}

fn apply-hline _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'hline'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'hline' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'hline' needs 5 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'hline' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # y = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'hline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'hline' needs 5 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'hline' is not a number (screen y coordinate)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var y/edx: int <- convert *second-value
  # x1 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'hline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'hline' needs 5 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'hline' is not a number (screen x coordinate of start point)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var x1/ebx: int <- convert *third-value
  # x2 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'hline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'hline' needs 5 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'hline' is not a number (screen x coordinate of end point)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var x2/ecx: int <- convert *fourth-value
  # color = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'hline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'hline' needs 5 args but got 5"
    return
  }
  var fifth-ah/eax: (addr handle cell) <- get rest, left
  var fifth/eax: (addr cell) <- lookup *fifth-ah
  {
    var fifth-type/eax: (addr int) <- get fifth, type
    compare *fifth-type, 1/number
    break-if-=
    error trace, "fifth arg for 'hline' is not an int (color; 0..0xff)"
    return
  }
  var fifth-value/eax: (addr float) <- get fifth, number-data
  var color/eax: int <- convert *fifth-value
  draw-horizontal-line screen, y, x1, x2, color
  # return nothing
}

fn apply-vline _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'vline'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'vline' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'vline' needs 5 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'vline' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # x = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'vline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'vline' needs 5 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'vline' is not a number (screen x coordinate)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var x/edx: int <- convert *second-value
  # y1 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'vline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'vline' needs 5 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'vline' is not a number (screen y coordinate of start point)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var y1/ebx: int <- convert *third-value
  # y2 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'vline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'vline' needs 5 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'vline' is not a number (screen y coordinate of end point)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var y2/ecx: int <- convert *fourth-value
  # color = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'vline' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'vline' needs 5 args but got 5"
    return
  }
  var fifth-ah/eax: (addr handle cell) <- get rest, left
  var fifth/eax: (addr cell) <- lookup *fifth-ah
  {
    var fifth-type/eax: (addr int) <- get fifth, type
    compare *fifth-type, 1/number
    break-if-=
    error trace, "fifth arg for 'vline' is not an int (color; 0..0xff)"
    return
  }
  var fifth-value/eax: (addr float) <- get fifth, number-data
  var color/eax: int <- convert *fifth-value
  draw-vertical-line screen, x, y1, y2, color
  # return nothing
}

fn apply-circle _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'circle'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'circle' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'circle' needs 5 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'circle' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # cx = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'circle' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'circle' needs 5 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'circle' is not a number (screen x coordinate of center)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var cx/edx: int <- convert *second-value
  # cy = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'circle' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'circle' needs 5 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'circle' is not a number (screen y coordinate of center)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var cy/ebx: int <- convert *third-value
  # r = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'circle' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'circle' needs 5 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'circle' is not a number (screen radius)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var r/ecx: int <- convert *fourth-value
  # color = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'circle' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'circle' needs 5 args but got 5"
    return
  }
  var fifth-ah/eax: (addr handle cell) <- get rest, left
  var fifth/eax: (addr cell) <- lookup *fifth-ah
  {
    var fifth-type/eax: (addr int) <- get fifth, type
    compare *fifth-type, 1/number
    break-if-=
    error trace, "fifth arg for 'circle' is not an int (color; 0..0xff)"
    return
  }
  var fifth-value/eax: (addr float) <- get fifth, number-data
  var color/eax: int <- convert *fifth-value
  draw-circle screen, cx, cy, r, color
  # return nothing
}

fn apply-bezier _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'bezier'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'bezier' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'bezier' needs 8 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'bezier' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # x0 = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'bezier' is not a number (screen x coordinate of start point)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var x0/edx: int <- convert *second-value
  # y0 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'bezier' is not a number (screen y coordinate of start point)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var y0/ebx: int <- convert *third-value
  # x1 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'bezier' is not a number (screen x coordinate of control point)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var tmp/eax: int <- convert *fourth-value
  var x1: int
  copy-to x1, tmp
  # y1 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 4"
    return
  }
  var fifth-ah/eax: (addr handle cell) <- get rest, left
  var fifth/eax: (addr cell) <- lookup *fifth-ah
  {
    var fifth-type/eax: (addr int) <- get fifth, type
    compare *fifth-type, 1/number
    break-if-=
    error trace, "fifth arg for 'bezier' is not a number (screen y coordinate of control point)"
    return
  }
  var fifth-value/eax: (addr float) <- get fifth, number-data
  var tmp/eax: int <- convert *fifth-value
  var y1: int
  copy-to y1, tmp
  # x2 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 3"
    return
  }
  var sixth-ah/eax: (addr handle cell) <- get rest, left
  var sixth/eax: (addr cell) <- lookup *sixth-ah
  {
    var sixth-type/eax: (addr int) <- get sixth, type
    compare *sixth-type, 1/number
    break-if-=
    error trace, "sixth arg for 'bezier' is not a number (screen x coordinate of end point)"
    return
  }
  var sixth-value/eax: (addr float) <- get sixth, number-data
  var tmp/eax: int <- convert *sixth-value
  var x2: int
  copy-to x2, tmp
  # y2 = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 4"
    return
  }
  var seventh-ah/eax: (addr handle cell) <- get rest, left
  var seventh/eax: (addr cell) <- lookup *seventh-ah
  {
    var seventh-type/eax: (addr int) <- get seventh, type
    compare *seventh-type, 1/number
    break-if-=
    error trace, "seventh arg for 'bezier' is not a number (screen y coordinate of end point)"
    return
  }
  var seventh-value/eax: (addr float) <- get seventh, number-data
  var tmp/eax: int <- convert *seventh-value
  var y2: int
  copy-to y2, tmp
  # color = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'bezier' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'bezier' needs 8 args but got 5"
    return
  }
  var eighth-ah/eax: (addr handle cell) <- get rest, left
  var eighth/eax: (addr cell) <- lookup *eighth-ah
  {
    var eighth-type/eax: (addr int) <- get eighth, type
    compare *eighth-type, 1/number
    break-if-=
    error trace, "eighth arg for 'bezier' is not an int (color; 0..0xff)"
    return
  }
  var eighth-value/eax: (addr float) <- get eighth, number-data
  var color/eax: int <- convert *eighth-value
  draw-monotonic-bezier screen, x0, y0, x1, y1, x2, y2, color
  # return nothing
}

fn apply-wait-for-key _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'key'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'key' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'key' needs 1 arg but got 0"
    return
  }
  # keyboard = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 6/keyboard
    break-if-=
    error trace, "first arg for 'key' is not a keyboard"
    return
  }
  var keyboard-ah/eax: (addr handle gap-buffer) <- get first, keyboard-data
  var _keyboard/eax: (addr gap-buffer) <- lookup *keyboard-ah
  var keyboard/ecx: (addr gap-buffer) <- copy _keyboard
  var result/eax: int <- wait-for-key keyboard
  # return key typed
  new-integer out, result
}

fn wait-for-key keyboard: (addr gap-buffer) -> _/eax: int {
  # if keyboard is 0, use real keyboard
  {
    compare keyboard, 0/real-keyboard
    break-if-!=
    var key/eax: byte <- read-key 0/real-keyboard
    var result/eax: int <- copy key
    return result
  }
  # otherwise read from fake keyboard
  var g/eax: grapheme <- read-from-gap-buffer keyboard
  var result/eax: int <- copy g
  return result
}

fn apply-stream _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply stream"
  allocate-stream out
}

fn apply-write _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'write'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'write' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'write' needs 2 args but got 0"
    return
  }
  # stream = args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 3/stream
    break-if-=
    error trace, "first arg for 'write' is not a stream"
    return
  }
  var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
  var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
  var stream-data/ebx: (addr stream byte) <- copy _stream-data
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'write' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'write' needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'write' is not a number/grapheme"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var x-float/xmm0: float <- copy *second-value
  var x/eax: int <- convert x-float
  var x-grapheme/eax: grapheme <- copy x
  write-grapheme stream-data, x-grapheme
  # return the stream
  copy-object first-ah, out
}

fn apply-rewind _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'rewind'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'rewind' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'rewind' needs 1 arg but got 0"
    return
  }
  # stream = args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 3/stream
    break-if-=
    error trace, "first arg for 'rewind' is not a stream"
    return
  }
  var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
  var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
  var stream-data/ebx: (addr stream byte) <- copy _stream-data
  rewind-stream stream-data
  copy-object first-ah, out
}

fn apply-read _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'read'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'read' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'read' needs 1 arg but got 0"
    return
  }
  # stream = args->left
  var first-ah/edx: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 3/stream
    break-if-=
    error trace, "first arg for 'read' is not a stream"
    return
  }
  var stream-data-ah/eax: (addr handle stream byte) <- get first, text-data
  var _stream-data/eax: (addr stream byte) <- lookup *stream-data-ah
  var stream-data/ebx: (addr stream byte) <- copy _stream-data
#?   rewind-stream stream-data
  var result-grapheme/eax: grapheme <- read-grapheme stream-data
  var result/eax: int <- copy result-grapheme
  new-integer out, result
}

fn apply-lines _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'lines'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'lines' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'lines' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'lines' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edx: (addr screen) <- copy _screen
  # compute dimensions
  var dummy/eax: int <- copy 0
  var height/ecx: int <- copy 0
  dummy, height <- screen-size screen
  var result/xmm0: float <- convert height
  new-float out, result
}

fn apply-columns _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'columns'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'columns' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'columns' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'columns' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edx: (addr screen) <- copy _screen
  # compute dimensions
  var width/eax: int <- copy 0
  var dummy/ecx: int <- copy 0
  width, dummy <- screen-size screen
  var result/xmm0: float <- convert width
  new-float out, result
}

fn apply-width _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'width'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'width' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'width' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'width' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edx: (addr screen) <- copy _screen
  # compute dimensions
  var width/eax: int <- copy 0
  var dummy/ecx: int <- copy 0
  width, dummy <- screen-size screen
  width <- shift-left 3/log2-font-width
  var result/xmm0: float <- convert width
  new-float out, result
}

fn apply-height _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'height'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'height' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'height' needs 1 arg but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'height' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edx: (addr screen) <- copy _screen
  # compute dimensions
  var dummy/eax: int <- copy 0
  var height/ecx: int <- copy 0
  dummy, height <- screen-size screen
  height <- shift-left 4/log2-font-height
  var result/xmm0: float <- convert height
  new-float out, result
}

fn apply-new-screen _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'screen'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'screen' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'screen' needs 2 args but got 0"
    return
  }
  # args->left->value
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for 'screen' is not a number (screen width in pixels)"
    return
  }
  var first-value-a/ecx: (addr float) <- get first, number-data
  var first-value/ecx: int <- convert *first-value-a
  # args->right->left->value
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'screen' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'screen' needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'screen' is not a number (screen height in pixels)"
    return
  }
  var second-value-a/edx: (addr float) <- get second, number-data
  var second-value/edx: int <- convert *second-value-a
  # create fake screen
  new-fake-screen out, first-value, second-value, 1/pixel-graphics
}

fn apply-blit _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'blit'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'blit' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'blit' needs 2 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'blit' is not a screen"
    return
  }
  var src-ah/eax: (addr handle screen) <- get first, screen-data
  var _src/eax: (addr screen) <- lookup *src-ah
  var src/ecx: (addr screen) <- copy _src
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'blit' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'blit' needs 2 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get right, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 5/screen
    break-if-=
    error trace, "second arg for 'blit' is not a screen"
    return
  }
  var dest-ah/eax: (addr handle screen) <- get second, screen-data
  var dest/eax: (addr screen) <- lookup *dest-ah
  #
  convert-screen-cells-to-pixels src
  copy-pixels src, dest
}

fn apply-array _args-ah: (addr handle cell), _out-ah: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'array'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'array' are not a list"
    return
  }
  var capacity/eax: int <- list-length args
  var out-ah/edi: (addr handle cell) <- copy _out-ah
  new-array out-ah, capacity
  var out/eax: (addr cell) <- lookup *out-ah
  var out-data-ah/eax: (addr handle array handle cell) <- get out, array-data
  var _out-data/eax: (addr array handle cell) <- lookup *out-data-ah
  var out-data/edi: (addr array handle cell) <- copy _out-data
  var i/ecx: int <- copy 0
  {
    var done?/eax: boolean <- nil? args
    compare done?, 0/false
    break-if-!=
    var curr-ah/eax: (addr handle cell) <- get args, left
    var dest-ah/edx: (addr handle cell) <- index out-data, i
    copy-object curr-ah, dest-ah
    # update loop variables
    i <- increment
    var next-ah/eax: (addr handle cell) <- get args, right
    var next/eax: (addr cell) <- lookup *next-ah
    args <- copy next
    loop
  }
}

fn apply-populate _args-ah: (addr handle cell), _out-ah: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'populate'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'populate' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'populate' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'populate' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'populate' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  #
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 1/number
    break-if-=
    error trace, "first arg for 'populate' is not a number"
    return
  }
  var first-value/eax: (addr float) <- get first, number-data
  var capacity/ecx: int <- convert *first-value
  var out-ah/edi: (addr handle cell) <- copy _out-ah
  new-array out-ah, capacity
  var out/eax: (addr cell) <- lookup *out-ah
  var data-ah/eax: (addr handle array handle cell) <- get out, array-data
  var data/eax: (addr array handle cell) <- lookup *data-ah
  var i/ebx: int <- copy 0
  {
    compare i, capacity
    break-if->=
    var curr-ah/ecx: (addr handle cell) <- index data, i
    copy-object second-ah, curr-ah
    i <- increment
    loop
  }
}

fn apply-index _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'index'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'index' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'index' needs 2 args but got 0"
    return
  }
  # args->left
  var first-ah/ecx: (addr handle cell) <- get args, left
  # args->right->left
  var right-ah/eax: (addr handle cell) <- get args, right
  var right/eax: (addr cell) <- lookup *right-ah
  {
    var right-type/eax: (addr int) <- get right, type
    compare *right-type, 0/pair
    break-if-=
    error trace, "'index' encountered non-pair"
    return
  }
  {
    var nil?/eax: boolean <- nil? right
    compare nil?, 0/false
    break-if-=
    error trace, "'index' needs 2 args but got 1"
    return
  }
  var second-ah/edx: (addr handle cell) <- get right, left
  # index
  var _first/eax: (addr cell) <- lookup *first-ah
  var first/ecx: (addr cell) <- copy _first
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 7/array
    break-if-=
    error trace, "first arg for 'index' is not an array"
    return
  }
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'index' is not a number"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var index/edx: int <- truncate *second-value
  var data-ah/eax: (addr handle array handle cell) <- get first, array-data
  var data/eax: (addr array handle cell) <- lookup *data-ah
  {
    var len/eax: int <- length data
    compare index, len
    break-if-<
    error trace, "index: too few elements in array"
    compare index, len
    {
      break-if-<=
      error trace, "foo"
    }
    return
  }
  var offset/edx: (offset handle cell) <- compute-offset data, index
  var src/eax: (addr handle cell) <- index data, offset
  copy-object src, out
}

fn apply-iset _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'iset'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'iset' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'iset' needs 3 args but got 0"
    return
  }
  # array = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 7/array
    break-if-=
    error trace, "first arg for 'iset' is not an array"
    return
  }
  var array-ah/eax: (addr handle array handle cell) <- get first, array-data
  var _array/eax: (addr array handle cell) <- lookup *array-ah
  var array/ecx: (addr array handle cell) <- copy _array
  # idx = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'iset' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'iset' needs 3 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 1/number
    break-if-=
    error trace, "second arg for 'iset' is not an int (index)"
    return
  }
  var second-value/eax: (addr float) <- get second, number-data
  var idx/eax: int <- truncate *second-value
  # offset based on idx after bounds check
  var max/edx: int <- length array
  compare idx, max
  {
    break-if-<
    error trace, "iset: too few elements in array"
    return
  }
  var offset/edx: (offset handle cell) <- compute-offset array, idx
  # val = rest->right->left
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'iset' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'iset' needs 3 args but got 2"
    return
  }
  var val-ah/eax: (addr handle cell) <- get rest, left
  # copy
  var dest/edi: (addr handle cell) <- index array, offset
  copy-object val-ah, dest
  # return nothing
}

fn apply-render-image _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  trace-text trace, "eval", "apply 'img'"
  var args-ah/eax: (addr handle cell) <- copy _args-ah
  var _args/eax: (addr cell) <- lookup *args-ah
  var args/esi: (addr cell) <- copy _args
  {
    var args-type/eax: (addr int) <- get args, type
    compare *args-type, 0/pair
    break-if-=
    error trace, "args to 'img' are not a list"
    return
  }
  var empty-args?/eax: boolean <- nil? args
  compare empty-args?, 0/false
  {
    break-if-=
    error trace, "'img' needs 6 args but got 0"
    return
  }
  # screen = args->left
  var first-ah/eax: (addr handle cell) <- get args, left
  var first/eax: (addr cell) <- lookup *first-ah
  {
    var first-type/eax: (addr int) <- get first, type
    compare *first-type, 5/screen
    break-if-=
    error trace, "first arg for 'img' is not a screen"
    return
  }
  var screen-ah/eax: (addr handle screen) <- get first, screen-data
  var _screen/eax: (addr screen) <- lookup *screen-ah
  var screen/edi: (addr screen) <- copy _screen
  # x1 = args->right->left->value
  var rest-ah/eax: (addr handle cell) <- get args, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'img' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'img' needs 6 args but got 1"
    return
  }
  var second-ah/eax: (addr handle cell) <- get rest, left
  var second/eax: (addr cell) <- lookup *second-ah
  {
    var second-type/eax: (addr int) <- get second, type
    compare *second-type, 3/stream
    break-if-=
    error trace, "second arg for 'img' is not a stream (image data in ascii netpbm)"
    return
  }
  var img-data-ah/eax: (addr handle stream byte) <- get second, text-data
  var img-data/eax: (addr stream byte) <- lookup *img-data-ah
  var img-h: (handle cell)
  var img-ah/ecx: (addr handle cell) <- address img-h
  new-image img-ah, img-data
  # x = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'img' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'img' needs 6 args but got 2"
    return
  }
  var third-ah/eax: (addr handle cell) <- get rest, left
  var third/eax: (addr cell) <- lookup *third-ah
  {
    var third-type/eax: (addr int) <- get third, type
    compare *third-type, 1/number
    break-if-=
    error trace, "third arg for 'img' is not a number (screen x coordinate of top left)"
    return
  }
  var third-value/eax: (addr float) <- get third, number-data
  var x/ebx: int <- convert *third-value
  # y = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  var rest/esi: (addr cell) <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'img' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'img' needs 6 args but got 3"
    return
  }
  var fourth-ah/eax: (addr handle cell) <- get rest, left
  var fourth/eax: (addr cell) <- lookup *fourth-ah
  {
    var fourth-type/eax: (addr int) <- get fourth, type
    compare *fourth-type, 1/number
    break-if-=
    error trace, "fourth arg for 'img' is not a number (screen x coordinate of end point)"
    return
  }
  var fourth-value/eax: (addr float) <- get fourth, number-data
  var y/ecx: int <- convert *fourth-value
  # w = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'img' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'img' needs 6 args but got 4"
    return
  }
  var fifth-ah/eax: (addr handle cell) <- get rest, left
  var fifth/eax: (addr cell) <- lookup *fifth-ah
  {
    var fifth-type/eax: (addr int) <- get fifth, type
    compare *fifth-type, 1/number
    break-if-=
    error trace, "fifth arg for 'img' is not a number (screen y coordinate of end point)"
    return
  }
  var fifth-value/eax: (addr float) <- get fifth, number-data
  var tmp/eax: int <- convert *fifth-value
  var w: int
  copy-to w, tmp
  # h = rest->right->left->value
  var rest-ah/eax: (addr handle cell) <- get rest, right
  var _rest/eax: (addr cell) <- lookup *rest-ah
  rest <- copy _rest
  {
    var rest-type/eax: (addr int) <- get rest, type
    compare *rest-type, 0/pair
    break-if-=
    error trace, "'img' encountered non-pair"
    return
  }
  {
    var rest-nil?/eax: boolean <- nil? rest
    compare rest-nil?, 0/false
    break-if-=
    error trace, "'img' needs 6 args but got 5"
    return
  }
  var sixth-ah/eax: (addr handle cell) <- get rest, left
  var sixth/eax: (addr cell) <- lookup *sixth-ah
  {
    var sixth-type/eax: (addr int) <- get sixth, type
    compare *sixth-type, 1/number
    break-if-=
    error trace, "sixth arg for 'img' is not an int (height)"
    return
  }
  var sixth-value/eax: (addr float) <- get sixth, number-data
  var tmp/eax: int <- convert *sixth-value
  var h: int
  copy-to h, tmp
  #
  var img-cell-ah/eax: (addr handle cell) <- address img-h
  var img-cell/eax: (addr cell) <- lookup *img-cell-ah
  var img-ah/eax: (addr handle image) <- get img-cell, image-data
  var img/eax: (addr image) <- lookup *img-ah
  render-image screen, img, x y, w h
  # return nothing
}

fn apply-abort _args-ah: (addr handle cell), out: (addr handle cell), trace: (addr trace) {
  abort "aa"
}