about summary refs log blame commit diff stats
path: root/apps/calls.subx
blob: 1c8fcdeb30590b2b5586b5edf06c6210535671e7 (plain) (tree)


























































































                                                                                                   
                                     


















































                                                            
                        








































                                                                            
                             
























                                                        
                        


                 
                                                                                                  






                                                               
                                                                       


                                                                  
                                                                 






















                                                              



                                                                                               





                                                      

                                          


                                          
                                          












                                         



                              








                                                        





                                                                                                     

                                                                   

















                                                                                                        
                                                                       
















                                                                                                    
                                                                       






                                                                                                     

                                                                                      
                                            
                                                                                                                 













                                                       
                                                                                          






                                            













                                                                                                             
                                                    

                                        


                                                                                      



















                                                                                                     

                                                                          













                                                                                                         


                                                                                                  
                                                    
                                       
                                                                                      





                                                                                                 
                            

                                            
                                                                      



                                                            










                                                     



                                                                        

                                                          
              
                                 
                      
                               


                                       
                        
              
                                    
                      
                               

                                   

                        
              
                                 
                      
                               

                     
                        
              
                        
                      
                               
                        


                               





                                                                                            

                                                                              
              
                                 
                      
                               


                                       
                        
              
                                    
                      
                               

                                   

                        
              
                                 
                      
                               

                     
                        
              
                        
                      
                               
                        


                               


                                                        


                                                                                          

                                                                            
              
                                 
                      
                               


                                       
                        
              
                                    
                      
                               

                                    

                        
              
                                 
                      
                               

                     
                        
              
                        
                      
                               
                        


                               


                                                        


                                                                               

                                                                 
              
                                 
                      
                               


                                       
                        
              
                                    
                      
                               

                                   

                        
              
                                 
                      
                               

                     
                        
              
                        
                      
                               
                        


                               

                     
                                                        


                                                                            

                                                              
              
                                 
                      
                               


                                       
                        
              
                                    
                      
                               

                                    

                        
              
                                 
                      
                               

                     
                        
              
                        
                      
                               
                        


                               




                                                     
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                       

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               

                                                        


                                                                                                          
                            
              
                                   
                      
                                 


                                                                       

                                                                                   
                                                

                                                     

               
                                   
                      
                                 


                                                                     

                                                                                 
                                              

                                                     

               
                                   
                      
                                 
              
                        





                                                                           
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                        

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               

                                                        


                                                                                                                                
                            
              
                                   
                      
                                 


                                                                       

                                                                                                         
                                                

                                                     

               
                                   
                      
                                 


                                                                     

                                                                                                       
                                              

                                                     

               
                                   
                      
                                 
              
                        





                                                                                
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        



                                                                                
                                    
              
                                                                  
                      
                               

                                                         

                                                                                                            
                                        

                                                          

               
                                   
                      
                                 
              
                        





                                                                            
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                            

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               


                                                                       

                                                                                                          
                                                

                                                     

               
                                   
                      
                                 


                                                                     

                                                                                                        
                                              

                                                     

               
                                   
                      
                                 
              
                        





                                                                                 
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                              

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               


                                                                       

                                                                                                               
                                                

                                                     

               
                                   
                      
                                 


                                                                     

                                                                                                             
                                              

                                                     

               
                                   
                      
                                 
              
                        





                                                                              
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                           

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               


                                                                       

                                                                                                            
                                                

                                                     

               
                                   
                      
                                 


                                                                     

                                                                                                          
                                              

                                                     

               
                                   
                      
                                 
              
                        


                 


                                                                                         
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                      

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               

                                            

                                                                                                                       
                        
              
                                   
                      
                                 

                                          

                                                                                                                     
                            
              
                                   
                      
                                 
              
                        





                                                                                                
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                            

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               

                                            
                                                                                                                              
                   
                        
              
                                   
                      
                                 

                                          























































                                                                                                                              
                   
                            
              
                                   
                      
                                 
              
                        


                 


                                                                          
                        


                                        
                                    
              
                               
                      
                               
                            

                         
                        

                                              

                                    
              
                        
                      
                               


                                                                                
                                    
              
                                                                  
                      
                               


                                                                       

                                                                                                        
                                                

                                                     

               
                                   
                      
                                 


                                                                     

                                                                                                      
                                              

                                                     

               
                                   
                      
                                 
              
                        


                 
                            
# Function calls in a single line.
#
# To run (on Linux):
#   $ ./ntranslate 0*.subx apps/subx-common.subx apps/calls.subx
#   $ mv a.elf apps/calls
#   $ chmod +x apps/calls
#
# Example 1:
#   $ echo '(foo %eax)'                         |  apps/calls
#   # . (foo %eax)                                      # output has comments
#   ff 6/subop/push %eax                                # push
#   e8/call foo/disp32                                  # call
#   81 0/subop/add %esp 4/imm32                         # undo push
#
# Example 2:
#   $ echo '(foo Var1 *(eax + 4) "blah")'       |  apps/calls
#   # . (foo Var1 *(eax + 4) "blah")
#   68/push "blah"/imm32
#   ff 6/subop/push *(eax + 4)                          # push args in..
#   68/push Var1/imm32                                  # ..reverse order
#   e8/call foo/disp32
#   81 0/subop/add %esp 4/imm32                         # undo pushes
#
# Calls always begin with '(' as the first non-whitespace on a line.

== code

Entry:  # run tests if necessary, convert stdin if not
    # . prolog
    89/<- %ebp 4/r32/esp

    # initialize heap
    # . Heap = new-segment(Heap-size)
    # . . push args
    68/push Heap/imm32
    ff 6/subop/push *Heap-size
    # . . call
    e8/call new-segment/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32

    # - if argc > 1 and argv[1] == "test", then return run_tests()
    # if (argc <= 1) goto run-main
    81 7/subop/compare *ebp 1/imm32
    7e/jump-if-lesser-or-equal $run-main/disp8
    # if (!kernel-string-equal?(argv[1], "test")) goto run-main
    # . eax = kernel-string-equal?(argv[1], "test")
    # . . push args
    68/push "test"/imm32
    ff 6/subop/push *(ebp+8)
    # . . call
    e8/call kernel-string-equal?/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . if (eax == 0) goto run-main
    3d/compare-eax-and 0/imm32
    74/jump-if-equal $run-main/disp8
    # run-tests()
    e8/call run-tests/disp32
    # syscall(exit, *Num-test-failures)
    8b/-> *Num-test-failures 3/r32/ebx
    eb/jump $main:end/disp8
$run-main:
    # - otherwise convert stdin
    # convert(Stdin, Stdout)
    # . . push args
    68/push Stdout/imm32
    68/push Stdin/imm32
    # . . call
    e8/call convert/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # syscall(exit, 0)
    bb/copy-to-ebx 0/imm32
$main:end:
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8

convert:  # in : (address buffered-file), out : (address buffered-file) -> <void>
    # pseudocode:
    #   var line = new-stream(512, 1)
    #   var words : (address stream slice) = new-stream(16, 8)  # at most function name and 15 args
    #   while true
    #     clear-stream(line)
    #     read-line-buffered(in, line)
    #     if (line->write == 0) break                           # end of file
    #     skip-chars-matching-whitespace(line)
    #     if line->data[line->read] != '('
    #       write-stream-data(out, line)
    #       continue
    #     # emit comment
    #     write-buffered(out, "# . ")
    #     write-stream-data(out, line)
    #     # emit code
    #     ++line->read  # skip '('
    #     clear-stream(words)
    #     words = parse-line(line)
    #     emit-call(out, words)
    #   flush(out)
    #
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    # var line/ecx : (address stream byte) = stream(512)
    81 5/subop/subtract %esp 0x200/imm32
    68/push 0x200/imm32/length
    68/push 0/imm32/read
    68/push 0/imm32/write
    89/<- %ecx 4/r32/esp
    # var words/edx : (address stream slice) = stream(16, 8)
    81 5/subop/subtract %esp 0x80/imm32
    68/push 0x80/imm32/length
    68/push 0/imm32/read
    68/push 0/imm32/write
    89/<- %edx 4/r32/esp
$convert:loop:
    # clear-stream(line)
    # . . push args
    51/push-ecx
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # read-line-buffered(in, line)
    # . . push args
    51/push-ecx
    ff 6/subop/push *(ebp+8)
    # . . call
    e8/call read-line-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
$convert:check0:
    # if (line->write == 0) break
    81 7/subop/compare *ecx 0/imm32
    0f 84/jump-if-equal $convert:break/disp32
    # TODO
    e9/jump $convert:loop/disp32
$convert:break:
    # flush(out)
    # . . push args
    ff 6/subop/push *(ebp+0xc)
    # . . call
    e8/call flush/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
$convert:end:
    # . reclaim locals
    81 0/subop/add %esp 0x298/imm32  # 0x20c + 0x8c
    # . restore registers
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

parse-line:  # line : (address stream byte), words : (address stream slice)
    # pseudocode:
    #   var word-slice : (address slice)
    #   while true
    #     word-slice = next-word-string-or-expression-without-metadata(line)
    #     if slice-empty?(word-slice)
    #       break                                 # end of line
    #     write-int(words, word-slice->start)
    #     write-int(words, word-slice->end)
    #
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$parse-line:end:
    # . reclaim locals
    # . restore registers
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

emit-call:  # out : (address buffered-file), words : (address stream slice)
    # pseudocode:
    #   if (words->write < 8) abort
    #   curr = &words->data[words->write-8]
    #   min = words->data
    #   # emit pushes
    #   while true
    #     if (curr <= min) break
    #     if *curr in '%' '*'
    #       write-buffered(out, "ff 6/subop/push ")
    #       write-slice-buffered(out, curr)
    #       write-buffered(out, "/imm32\n")
    #     else
    #       write-buffered(out, "68/push ")
    #       write-slice-buffered(out, curr)
    #       write-buffered(out, "/imm32\n")
    #     curr -= 8
    #   # emit call
    #   write-buffered(out, "e8/call ")
    #   write-slice-buffered(out, curr)
    #   write-buffered(out, "/disp32\n")
    #   # emit pops
    #   write-buffered(out, "81 0/subop/add %esp ")
    #   print-int32-buffered(out, words->write >> 1 - 4)
    #   write-buffered(out, "/imm32\n")
    #
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
$emit-call:end:
    # . reclaim locals
    # . restore registers
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

next-word-string-or-expression-without-metadata:  # line : (address stream), out : (address slice)
    # pseudocode:
    #   skip-chars-matching(line, ' ')
    #   if line->read >= line->write              # end of line
    #     out = {0, 0}
    #     return
    #   out->start = &line->data[line->read]
    #   if line->data[line->read] == '#'          # comment
    #     out->end = &line->data[line->write]     # skip to end of line
    #     return
    #   if line->data[line->read] == '"'          # string literal
    #     skip-string(line)
    #     out->end = &line->data[line->read]        # no metadata
    #     return
    #   if line->data[line->read] == '*'          # expression
    #     if line->data[line->read + 1] == ' '
    #       abort
    #     if line->data[line->read + 1] == '('
    #       skip-until-close-paren(line)
    #       if (line->data[line->read] != ')'
    #         abort
    #       ++line->data[line->read] to skip ')'
    #     out->end = &line->data[line->read]
    #     return
    #   if line->data[line->read] == ')'
    #     ++line->read to skip ')'
    #     # make sure there's nothing else of importance
    #     if line->read >= line->write
    #       out = {0, 0}
    #       return
    #     if line->data[line->read] != ' '
    #       abort
    #     skip-chars-matching-whitespace(line)
    #     if line->read >= line->write
    #       out = {0, 0}
    #       return
    #     if line->data[line->read] == '#'        # only thing permitted after ')' is a comment
    #       out = {0, 0}
    #       return
    #     abort
    #   # default case: read a word -- but no metadata
    #   while true
    #     if line->read >= line->write
    #       break
    #     if line->data[line->read] == ' '
    #       break
    #     if line->data[line->read] == ')'
    #       break
    #     if line->data[line->read] == '/'
    #       abort
    #     ++line->read
    #   out->end = &line->data[line->read]
    #
    # registers:
    #   ecx: often line->read
    #   eax: often line->data[line->read]
    #
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # . save registers
    50/push-eax
    51/push-ecx
    56/push-esi
    57/push-edi
    # esi = line
    8b/-> *(ebp+8) 6/r32/esi
    # edi = out
    8b/-> *(ebp+0xc) 7/r32/edi
    # skip-chars-matching(line, ' ')
    # . . push args
    68/push 0x20/imm32/space
    ff 6/subop/push *(ebp+8)
    # . . call
    e8/call skip-chars-matching/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
$next-word-string-or-expression-without-metadata:check0:
    # if (line->read >= line->write) return out = {0, 0}
    # . ecx = line->read
    8b/-> *(esi+4) 1/r32/ecx
    # . if (ecx >= line->write) return out = {0, 0}
    3b/compare *esi 1/r32/ecx
    0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32
$next-word-string-or-expression-without-metadata:check-for-comment:
    # out->start = &line->data[line->read]
    8d/copy-address *(esi+ecx+0xc) 0/r32/eax
    89/<- *edi 0/r32/eax
    # if (line->data[line->read] != '#') goto next check
    # . eax = line->data[line->read]
    31/xor %eax 0/r32/eax
    8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
    # . if (eax != '#') goto next check
    3d/compare-eax-and 0x23/imm32/pound
    75/jump-if-not-equal $next-word-string-or-expression-without-metadata:check-for-string-literal/disp8
$next-word-string-or-expression-without-metadata:comment:
    # out->end = &line->data[line->write]
    8b/-> *esi 0/r32/eax
    8d/copy-address *(esi+eax+0xc) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
    # line->read = line->write  # skip rest of line
    8b/-> *esi 0/r32/eax
    89/<- *(esi+4) 0/r32/eax
    # return
    e9/jump $next-word-string-or-expression-without-metadata:end/disp32
$next-word-string-or-expression-without-metadata:check-for-string-literal:
    # if (line->data[line->read] != '"') goto next check
    3d/compare-eax-and 0x22/imm32/dquote
    75/jump-if-not-equal $next-word-string-or-expression-without-metadata:check-for-expression/disp8
$next-word-string-or-expression-without-metadata:string-literal:
    # skip-string(line)
    # . . push args
    56/push-esi
    # . . call
    e8/call skip-string/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # out->end = &line->data[line->read]
    8b/-> *(esi+4) 1/r32/ecx
    8d/copy-address *(esi+ecx+0xc) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
    # return
    e9/jump $next-word-string-or-expression-without-metadata:end/disp32
$next-word-string-or-expression-without-metadata:check-for-expression:
    # if (line->data[line->read] != '*') goto next check
    3d/compare-eax-and 0x2a/imm32/asterisk
    75/jump-if-not-equal $next-word-string-or-expression-without-metadata:check-for-end-of-call/disp8
    # if (line->data[line->read + 1] == ' ') goto error1
    8a/copy-byte *(esi+ecx+0xd) 0/r32/AL
    3d/compare-eax-and 0x20/imm32/space
    0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:error1/disp32
    # if (line->data[line->read + 1] != '(') goto regular-word
    3d/compare-eax-and 0x28/imm32/open-paren
    0f 85/jump-if-not-equal $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp32
$next-word-string-or-expression-without-metadata:paren:
    # skip-until-close-paren(line)
    # . . push args
    56/push-esi
    # . . call
    e8/call skip-until-close-paren/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # if (line->data[line->read] != ')') goto error2
    # . eax = line->data[line->read]
    8b/-> *(esi+4) 1/r32/ecx
    8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
    # . if (eax != ')') goto error2
    3d/compare-eax-and 0x29/imm32/close-paren
    0f 85/jump-if-not-equal $next-word-string-or-expression-without-metadata:error2/disp32
    # skip ')'
    ff 0/subop/increment *(esi+4)
    # out->end = &line->data[line->read]
    8b/-> *(esi+4) 1/r32/ecx
    8d/copy-address *(esi+ecx+0xc) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
    # return
    e9/jump $next-word-string-or-expression-without-metadata:end/disp32
$next-word-string-or-expression-without-metadata:check-for-end-of-call:
    # if (line->data[line->read] != ')') goto next check
    3d/compare-eax-and 0x29/imm32/close-paren
    75/jump-if-not-equal $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp8
    # ++line->read to skip ')'
    ff 0/subop/increment *(esi+4)
    # - error checking: make sure there's nothing else of importance on the line
    # if (line->read >= line->write) return out = {0, 0}
    # . ecx = line->read
    8b/-> *(esi+4) 1/r32/ecx
    # . if (ecx >= line->write) return {0, 0}
    3b/compare *esi 1/r32/ecx
    0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32
    # if (line->data[line->read] == '/') goto error3
    # . eax = line->data[line->read]
    8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
    # . if (eax == '/') goto error3
    3d/compare-eax-and 0x2f/imm32/slash
    0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:error3/disp32
    # skip-chars-matching-whitespace(line)
    # . . push args
    56/push-esi
    # . . call
    e8/call skip-chars-matching-whitespace/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # if (line->read >= line->write) return out = {0, 0}
    # . ecx = line->read
    8b/-> *(esi+4) 1/r32/ecx
    # . if (ecx >= line->write) return {0, 0}
    3b/compare *esi 1/r32/ecx
    0f 8d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:return-eol/disp32
    # if (line->data[line->read] == '#') return out = {0, 0}
    # . eax = line->data[line->read]
    8b/-> *(esi+4) 1/r32/ecx
    8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
    # . if (eax == '#') return out = {0, 0}
    3d/compare-eax-and 0x23/imm32/pound
    74/jump-if-equal $next-word-string-or-expression-without-metadata:return-eol/disp8
    # otherwise goto error4
    e9/jump $next-word-string-or-expression-without-metadata:error4/disp32
$next-word-string-or-expression-without-metadata:regular-word-without-metadata:
    # if (line->read >= line->write) break
    # . ecx = line->read
    8b/-> *(esi+4) 1/r32/ecx
    # . if (ecx >= line->write) break
    3b/compare *esi 1/r32/ecx
    7d/jump-if-greater-or-equal $next-word-string-or-expression-without-metadata:regular-word-break/disp8
    # if (line->data[line->read] == ' ') break
    # . eax = line->data[line->read]
    8b/-> *(esi+4) 1/r32/ecx
    8a/copy-byte *(esi+ecx+0xc) 0/r32/AL
    # . if (eax == ' ') break
    3d/compare-eax-and 0x20/imm32/space
    74/jump-if-equal $next-word-string-or-expression-without-metadata:regular-word-break/disp8
    # if (line->data[line->read] == ')') break
    3d/compare-eax-and 0x29/imm32/close-paren
    0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:regular-word-break/disp32
    # if (line->data[line->read] == '/') goto error5
    3d/compare-eax-and 0x2f/imm32/slash
    0f 84/jump-if-equal $next-word-string-or-expression-without-metadata:error5/disp32
    # ++line->read
    ff 0/subop/increment *(esi+4)
    # loop
    e9/jump $next-word-string-or-expression-without-metadata:regular-word-without-metadata/disp32
$next-word-string-or-expression-without-metadata:regular-word-break:
    # out->end = &line->data[line->read]
    8b/-> *(esi+4) 1/r32/ecx
    8d/copy-address *(esi+ecx+0xc) 0/r32/eax
    89/<- *(edi+4) 0/r32/eax
    eb/jump $next-word-string-or-expression-without-metadata:end/disp8
$next-word-string-or-expression-without-metadata:return-eol:
    # return out = {0, 0}
    c7 0/subop/copy *edi 0/imm32
    c7 0/subop/copy *(edi+4) 0/imm32
$next-word-string-or-expression-without-metadata:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    59/pop-to-ecx
    58/pop-to-eax
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

$next-word-string-or-expression-without-metadata:error1:
    # print(stderr, "error: no space allowed after '*' in '" line "'")
    # . write-buffered(Stderr, "error: no space allowed after '*' in '")
    # . . push args
    68/push "error: no space allowed after '*' in '"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-stream-data(Stderr, line)
    # . . push args
    56/push-esi
    68/push Stderr/imm32
    # . . call
    e8/call write-stream-data/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-buffered(Stderr, "'")
    # . . push args
    68/push "'"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . flush(Stderr)
    # . . push args
    68/push Stderr/imm32
    # . . call
    e8/call flush/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # . syscall(exit, 1)
    bb/copy-to-ebx 1/imm32
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8
    # never gets here

$next-word-string-or-expression-without-metadata:error2:
    # print(stderr, "error: *(...) expression must be all on a single line in '" line "'")
    # . write-buffered(Stderr, "error: *(...) expression must be all on a single line in '")
    # . . push args
    68/push "error: *(...) expression must be all on a single line in '"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-stream-data(Stderr, line)
    # . . push args
    56/push-esi
    68/push Stderr/imm32
    # . . call
    e8/call write-stream-data/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-buffered(Stderr, "'")
    # . . push args
    68/push "'"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . flush(Stderr)
    # . . push args
    68/push Stderr/imm32
    # . . call
    e8/call flush/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # . syscall(exit, 1)
    bb/copy-to-ebx 1/imm32
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8
    # never gets here

$next-word-string-or-expression-without-metadata:error3:
    # print(stderr, "error: no metadata after calls; just use a comment (in '" line "')")
    # . write-buffered(Stderr, "error: no metadata after calls; just use a comment (in '")
    # . . push args
    68/push "error: no metadata after calls; just use a comment (in '"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-stream-data(Stderr, line)
    # . . push args
    56/push-esi
    68/push Stderr/imm32
    # . . call
    e8/call write-stream-data/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-buffered(Stderr, "')")
    # . . push args
    68/push "')"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . flush(Stderr)
    # . . push args
    68/push Stderr/imm32
    # . . call
    e8/call flush/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # . syscall(exit, 1)
    bb/copy-to-ebx 1/imm32
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8
    # never gets here

$next-word-string-or-expression-without-metadata:error4:
    # print(stderr, "error: unexpected text after end of call in '" line "'")
    # . write-buffered(Stderr, "error: unexpected text after end of call in '")
    # . . push args
    68/push "error: unexpected text after end of call in '"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-stream-data(Stderr, line)
    # . . push args
    56/push-esi
    68/push Stderr/imm32
    # . . call
    e8/call write-stream-data/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-buffered(Stderr, "'")
    # . . push args
    68/push "'"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . flush(Stderr)
    # . . push args
    68/push Stderr/imm32
    # . . call
    e8/call flush/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # . syscall(exit, 1)
    bb/copy-to-ebx 1/imm32
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8
    # never gets here

$next-word-string-or-expression-without-metadata:error5:
    # print(stderr, "error: no metadata anywhere in calls (in '" line "')")
    # . write-buffered(Stderr, "error: no metadata anywhere in calls (in '")
    # . . push args
    68/push "error: no metadata anywhere in calls (in '"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-stream-data(Stderr, line)
    # . . push args
    56/push-esi
    68/push Stderr/imm32
    # . . call
    e8/call write-stream-data/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . write-buffered(Stderr, "')")
    # . . push args
    68/push "')"/imm32
    68/push Stderr/imm32
    # . . call
    e8/call write-buffered/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # . flush(Stderr)
    # . . push args
    68/push Stderr/imm32
    # . . call
    e8/call flush/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # . syscall(exit, 1)
    bb/copy-to-ebx 1/imm32
    b8/copy-to-eax 1/imm32/exit
    cd/syscall 0x80/imm8
    # never gets here

test-next-word-string-or-expression-without-metadata:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, "  ab")
    # . . push args
    68/push "  ab"/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(_test-input-stream->read, 4, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata/updates-stream-read-correctly"/imm32
    68/push 4/imm32
    b8/copy-to-eax _test-input-stream/imm32
    ff 6/subop/push *(eax+4)
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
    # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata: start"/imm32
    68/push 0xe/imm32
    # . . push slice->start - _test-input-stream
    8b/-> *ecx 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
    # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata: end"/imm32
    68/push 0x10/imm32
    # . . push slice->end - _test-input-stream
    8b/-> *(ecx+4) 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-returns-whole-comment:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, "  # a")
    # . . push args
    68/push "  # a"/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(_test-input-stream->read, 5, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment/updates-stream-read-correctly"/imm32
    68/push 5/imm32
    b8/copy-to-eax _test-input-stream/imm32
    ff 6/subop/push *(eax+4)
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->start - _test-input-stream->data, 2, msg)
    # . check-ints-equal(slice->start - _test-input-stream, 14, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment: start"/imm32
    68/push 0xe/imm32
    # . . push slice->start - _test-input-stream
    8b/-> *ecx 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end - _test-input-stream->data, 5, msg)
    # . check-ints-equal(slice->end - _test-input-stream, 17, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-comment: end"/imm32
    68/push 0x11/imm32
    # . . push slice->end - _test-input-stream
    8b/-> *(ecx+4) 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-returns-empty-slice-on-eof:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write nothing to _test-input-stream
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->end - slice->start, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-empty-expression-on-eof"/imm32
    68/push 0/imm32
    # . . push slice->end - slice->start
    8b/-> *(ecx+4) 0/r32/eax
    2b/subtract-> *ecx 0/r32/eax  # subtract *ecx from eax
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-returns-string-literal:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " \"a b\" ")
    # . . push args
    68/push " \"a b\" "/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
    # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-literal: start"/imm32
    68/push 0xd/imm32
    # . . push slice->start - _test-input-stream
    8b/-> *ecx 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end - _test-input-stream->data, 6, msg)
    # . check-ints-equal(slice->end - _test-input-stream, 18, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-literal: end"/imm32
    68/push 0x12/imm32
    # . . push slice->end - _test-input-stream
    8b/-> *(ecx+4) 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-returns-string-with-escapes:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " \"a\\\"b\"")
    # . . push args
    68/push " \"a\\\"b\""/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
    # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: start"/imm32
    68/push 0xd/imm32
    # . . push slice->start - _test-input-stream
    8b/-> *ecx 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end - _test-input-stream->data, 7, msg)
    # . check-ints-equal(slice->end - _test-input-stream, 19, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-string-with-escapes: end"/imm32
    68/push 0x13/imm32
    # . . push slice->end - _test-input-stream
    8b/-> *(ecx+4) 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-returns-whole-expression:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " *(a b) ")
    # . . push args
    68/push " *(a b) "/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
    # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-expression: start"/imm32
    68/push 0xd/imm32
    # . . push slice->start - _test-input-stream
    8b/-> *ecx 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end - _test-input-stream->data, 7, msg)
    # . check-ints-equal(slice->end - _test-input-stream, 19, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-whole-expression: end"/imm32
    68/push 0x13/imm32
    # . . push slice->end - _test-input-stream
    8b/-> *(ecx+4) 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " ) ")
    # . . push args
    68/push " ) "/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: start"/imm32
    68/push 0/imm32
    ff 6/subop/push *ecx
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-returns-eol-on-trailing-close-paren: end"/imm32
    68/push 0/imm32
    ff 6/subop/push *(ecx+4)
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " ) # abc ")
    # . . push args
    68/push " ) # abc "/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: start"/imm32
    68/push 0/imm32
    ff 6/subop/push *ecx
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-handles-comment-after-trailing-close-paren: end"/imm32
    68/push 0/imm32
    ff 6/subop/push *(ecx+4)
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " )\n")
    # . . push args
    68/push " )\n"/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: start"/imm32
    68/push 0/imm32
    ff 6/subop/push *ecx
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end, 0, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-handles-newline-after-trailing-close-paren: end"/imm32
    68/push 0/imm32
    ff 6/subop/push *(ecx+4)
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

test-next-word-string-or-expression-without-metadata-stops-at-close-paren:
    # . prolog
    55/push-ebp
    89/<- %ebp 4/r32/esp
    # setup
    # . clear-stream(_test-input-stream)
    # . . push args
    68/push _test-input-stream/imm32
    # . . call
    e8/call clear-stream/disp32
    # . . discard args
    81 0/subop/add %esp 4/imm32
    # var slice/ecx = {0, 0}
    68/push 0/imm32/end
    68/push 0/imm32/start
    89/<- %ecx 4/r32/esp
    # write(_test-input-stream, " abc) # def")
    # . . push args
    68/push " abc) # def"/imm32
    68/push _test-input-stream/imm32
    # . . call
    e8/call write/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # next-word-string-or-expression-without-metadata(_test-input-stream, slice)
    # . . push args
    51/push-ecx
    68/push _test-input-stream/imm32
    # . . call
    e8/call next-word-string-or-expression-without-metadata/disp32
    # . . discard args
    81 0/subop/add %esp 8/imm32
    # check-ints-equal(slice->start - _test-input-stream->data, 1, msg)
    # . check-ints-equal(slice->start - _test-input-stream, 13, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-stops-at-close-paren: start"/imm32
    68/push 0xd/imm32
    # . . push slice->start - _test-input-stream
    8b/-> *ecx 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # check-ints-equal(slice->end - _test-input-stream->data, 4, msg)
    # . check-ints-equal(slice->end - _test-input-stream, 16, msg)
    # . . push args
    68/push "F - test-next-word-string-or-expression-without-metadata-stops-at-close-paren: end"/imm32
    68/push 0x10/imm32
    # . . push slice->end - _test-input-stream
    8b/-> *(ecx+4) 0/r32/eax
    81 5/subop/subtract %eax _test-input-stream/imm32
    50/push-eax
    # . . call
    e8/call check-ints-equal/disp32
    # . . discard args
    81 0/subop/add %esp 0xc/imm32
    # . epilog
    89/<- %esp 5/r32/ebp
    5d/pop-to-ebp
    c3/return

# . . vim:nowrap:textwidth=0