; Listing8-2.asm
;
; A program that demonstrates deferred execution of a statement
; using thunks.


            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-2", 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    "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$trueStmts.environment
            call    ifexpr$falseStmts.procedure
ifdone:     ret
ifexpr      endp

;--------------------------------------------------
;
; Here is the main assembly language function.
            
            public  asmMain
                    
            locals  asmMain, c:dword, d:dword
                
asmMain     proc
            push    rbp
            mov     rbp, rsp
            sub     rsp, 64
            
            mov     asmMain$c, 10   ;Automatic, must initialize
            mov     asmMain$d, 20
            
            mov     edx, asmMain$c
            mov     r8d, asmMain$d
            call    print
            byte    "Before ifexpr(0), c=%d, d=%d", nl, 0
            
; Set up the "procedures" to call for "ifexpr(0/1)"

            jmp     overStmt1and2 
            
stmt1:      push    rbp
            mov     rbp, rcx
            call    print
            byte    "in stmt1", nl, 0
            mov     eax, asmMain$c
            inc     asmMain$c
            pop     rbp
            ret

stmt2:      push    rbp
            mov     rbp, rcx
            call    print
            byte    "in stmt2", nl, 0
            mov     eax, asmMain$d
            dec     asmMain$d
            pop     rbp
            ret

; Call ifexpr with a false expression:

overStmt1and2:  
            mov     byte ptr [rsp], 0       ;Expr=false
            
            mov     [rsp+8], rbp            ;Pass thunk
            lea     rax, stmt1              ; stmt1
            mov     [rsp+16], rax
            
            mov     [rsp+24], rbp           ;Pass thunk
            lea     rax, stmt2              ; stmt2
            mov     [rsp+32], rax
            
            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
            
            mov     [rsp+8], rbp            ;Pass thunk
            lea     rax, stmt1              ; stmt1
            mov     [rsp+16], rax
            
            mov     [rsp+24], rbp           ;Pass thunk
            lea     rax, stmt2              ; stmt2
            mov     [rsp+32], rax
            
            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