; Listing8-4.asm
;
; A program that demonstrates declaring thunks
; outside a procedure's body.


            option     casemap:none
            .nolist
            include    aoalib.inc
            include    aoaProcs.inc
            include    aoaTypes.inc
            includelib aoalib.lib
            .list
            
            .const

; Program title:

             align  word
ttlStr       byte   "Listing 8-4", 0



            .code


; ifexpr
; ( 
;      expressionValue:byte, 
;      execIfTrue:thunk, 
;      execIfFalse:thunk
; )

parms ifexpr, rsp, 8,               \
            expr:byte,              \
            trueStmts:thunk_t,      \
            falseStmts:thunk_t

ifexpr      proc    

; If the expression value passed to this function is
; true, execute the trueStmts code, otherwise
; execute the falseStmts code:

            movzx   edx, ifexpr$expr
            call    print
            byte    "in ifexpr, expr=%d", nl, 0
            
            test    edx, edx
            je      elsePart
            
            call    print
            byte    "calling trueStmts", nl, 0
            
            mov     rcx, ifexpr$trueStmts.environment
            call    ifexpr$trueStmts.procedure
            jmp     ifdone
            
elsePart:   call    print
            byte    "calling falseStmts", nl, 0

            mov     rcx, ifexpr$falseStmts.environment
            call    ifexpr$falseStmts.procedure
ifdone:     ret
ifexpr      endp

;--------------------------------------------------
;
; Here is the main assembly language function.
            
            public  asmMain
                    
            locals  asmMain,        \
                    c:dword,        \
                    d:dword,        \
                    s1:thunk_t,     \
                    s2:thunk_t
   
s1          proc
            push    rbp
            mov     rbp, rcx
            call    print
            byte    "in stmt1", nl, 0
            mov     eax, asmMain$c
            inc     asmMain$c
            pop     rbp
            ret
s1          endp

s2          proc
            push    rbp
            mov     rbp, rcx
            call    print
            byte    "in stmt2", nl, 0
            mov     eax, asmMain$d
            dec     asmMain$d
            pop     rbp
            ret
s2          endp

asmMain     proc
            push    rbp
            mov     rbp, rsp
            sub     rsp, 64
            
            mov     asmMain$c, 10   ;Automatic, must initialize
            mov     asmMain$d, 20
            
            
; Set up the "procedures" to call for "ifexpr(0/1)"

            lea     rcx, s1
            mov     asmMain$s1.procedure, rcx
            mov     asmMain$s1.environment, rbp
            
            lea     rcx, s2
            mov     asmMain$s2.procedure, rcx
            mov     asmMain$s2.environment, rbp
                        
            mov     edx, asmMain$c
            mov     r8d, asmMain$d
            call    print
            byte    "Before ifexpr(0), c=%d, d=%d", nl, 0

; Call ifexpr with a false expression:

            mov     byte ptr [rsp], 0       ;Expr=false
            copyTh  [rsp+8], asmMain$s1     ;True thunk
            copyTh  [rsp+24], asmMain$s2    ;False thunk
            call    ifexpr
            
            mov     edx, eax
            mov     r8d, asmMain$c
            mov     r9d, asmMain$d
            call    print
            byte    "ifexpr(0) returned %d, c=%d, d=%d", nl, 0
            
; Call ifexpr with a true expression

            mov     byte ptr [rsp], 1       ;Expr=true
            copyTh  [rsp+8], asmMain$s1     ;True thunk
            copyTh  [rsp+24], asmMain$s2    ;False thunk
            call    ifexpr
            
            mov     edx, eax
            mov     r8d, asmMain$c
            mov     r9d, asmMain$d
            call    print
            byte    "ifexpr(1) returned %d, c=%d, d=%d", nl, 0
        

            leave
            ret
        
asmMain     endp
            end