; traditionalClassesDemo.asm
;
; A program that demonstrates protocols in MASM.

            option     casemap:none
            include    aoaTypes.inc
            include    aoaMacros.inc
	include	   traditionalClasses.asm
            include    aoalib.inc
            includelib aoalib.lib
            
            .const

; Program title:

             align  word
ttlStr       byte   "Traditional Classes Demo", 0



; Here's an example of a "pure" protocol,
; containing only virtual method definitions.
; You don't create a VMT for pure protocols,
; and you don't call the methods (so you don't
; write any methods for these, either.

proto123    protocol ()
            virtual  proc1
            virtual  proc2
            virtual  proc3
            endpr
	

; Here's a second pure protocol, to demonstrate
; "multiple inheritance" of protocols:

proto1a	protocol ()	;Does not inherit pureProto!
	virtual  proc1
	endpr
	
proto1b	protocol ()	;Does not inherit pureProto!
	virtual  proc1
	endpr
	


; Here's a specific protocol for the 
; "protoClass" class based on the
; proto123 protocol. Note that it
; overrides all the methods in the
; pure prototype.
            
protoClass$proto123 protocol (proto123)
            override proc1, protoClass$proc1 
            override proc2, protoClass$proc2 
            override proc3, protoClass$proc3 
            endpr 
	
; Here's a class-specific protocol for the
; "proto1a" protocol. Note that we have
; to map proto1a.proc1 to a different
; name than protoClass$proc1, which already
; exists (from protoClass$proto123).

protoClass$proto1a protocol (proto1a)
	       override proc1, protoClass$proc4
	       endpr  
            

protoClass$proto1b	protocol (proto1b)
	        override proc1, protoClass$proc4
	        endpr  
            
            
; A sample class that uses a protocol.
; It adds one additional function that
; is not part of the protocol.

protoClass  class    (protoClass$proto123, protoClass$proto1a, protoClass$proto1b)
            virtual  protoClass$pcFunc
protoClass	endc	 ()     

protoClass$ textequ  <(protoClass ptr [rsi])>

_protoClass macro   field
            namespace (&field, <create>, <protoClass$create>)
            namespace (&field, <proc1>,  <protoClass$proc1>)
            namespace (&field, <proc2>,  <protoClass$proc2>)
            namespace (&field, <proc3>,  <protoClass$proc3>)
            namespace (&field, <proc4>,  <protoClass$proc4>)
            namespace (&field, <pcFunc>, <protoClass$pcFunc>)
            echo    ***********************************
            echo    Error:unexpected _protoClass member
%           echo    function=field
            echo    ***********************************
            exitm   <.err>
            endm
            
            
; A second class that uses the proto123 protocol.

protoClass2$proto4pc4   protocol (proto123)
                        override proc1, protoClass2$proc1 
                        override proc2, protoClass2$proc2 
                        override proc3, protoClass2$proc3 
                        endpr   


protoClass2  class    (protoClass2$proto4pc4)
             virtual  protoClass$pcFunc
protoClass2  endc     ()
	 
protoClass2$ textequ  <(protoClass2 ptr [rsi])>

_protoClass2 macro   field
             namespace (&field, <create>, <protoClass2$create>)
             namespace (&field, <proc1>, <protoClass2$proc1>)
             namespace (&field, <proc2>, <protoClass2$proc2>)
             namespace (&field, <proc3>, <protoClass2$proc3>)
             namespace (&field, <pcFunc>, <protoClass2$pcFunc>)
             echo    ************************************
             echo    Error:unexpected _protoClass2 member
%            echo    function=field
             echo    ************************************
             exitm   <.err>
             endm
            
 
; Emit the VMTs for these classes.

	.const
	
            emitVMT protoClass$proto123
            emitVMT protoClass$proto1a
            emitVMT protoClass$proto1b
	emitVMT protoClass2$proto4pc4
            emitVMT protoClass     
            emitVMT protoClass2     
            
            .data

pc          protoClass  {}
pc2         protoClass2 {}

            
            
            .code

            include mallocFree.inc


;---------------------------------------------------
;
; Constructor code for protoClass:
;

protoClass$create proc
                  push rax
                  test rsi, rsi        ;NULL?
                  jnz  notNULL
                       
; If RSI was NULL on entry, allocate storage for
; a "protoClass" object on the heap:

                  mov  eax, sizeof protoClass
                  call mem$alloc
                  mov  rsi, rax
                  test rsi, rsi
                  jz   failure
                       
; Initialize the VMT pointer for the proto field
; in protoClass:

notNULL:          lea  rdi, vmtAdrs(protoClass$proto123)
                  mov  protoClass$.vmtPtr(protoClass$proto123), rdi
               
; Initialize the protoClass VMT pointer:

                  lea  rdi, vmtAdrs(protoClass)
                  mov  protoClass$.VMT, rdi
failure:          pop  rax
                  ret
protoClass$create endp



; Constructor code for protoClass2:
;

protoClass2$create proc
                   push rax
                   test rsi, rsi        ;NULL?
                   jnz  notNULL
                       
; If RSI was NULL on entry, allocate storage for
; a "protoClass2" object on the heap:

                   mov  eax, sizeof protoClass2
                   call mem$alloc
                   mov  rsi, rax
                   test rsi, rsi
                   jz   failure
                       
; Initialize the VMT pointer for the proto field
; in protoClass2:

notNULL:           lea  rdi, vmtAdrs(protoClass2$proto4pc4)
                   mov  protoClass2$.vmtPtr(protoClass2$proto4pc4), rdi
               
; Initialize the protoClass2 VMT pointer:

                   lea  rdi, vmtAdrs(protoClass2)
                   mov  protoClass2$.VMT, rdi
failure:           pop  rax
                   ret
protoClass2$create endp



;---------------------------------------------------
;
; Procedures for the protoClass class:

protoClass$pcFunc proc
                  call print
                  byte "Inside protoClass$pcFunc"
                  byte nl, 0
                  ret
protoClass$pcFunc endp

protoClass$proc1  proc
                  call print
                  byte "Inside protoClass$proc1", nl, 0
                  ret
protoClass$proc1  endp
              

protoClass$proc2  proc
                  call print
                  byte "Inside protoClass$proc2", nl, 0
                  ret
protoClass$proc2  endp
              

protoClass$proc3 proc
                 call  print
                 byte  "Inside protoClass$proc3", nl, 0
                 ret
protoClass$proc3 endp
              

protoClass$proc4 proc
                 call  print
                 byte  "Inside protoClass$proc4", nl, 0
                 ret
protoClass$proc4 endp
              
 
        
;---------------------------------------------------
;
; Procedures for the protoClass2 class:

protoClass2$pcFunc proc
                   call print
                   byte "Inside protoClass2$pcFunc"
                   byte nl, 0
                   ret
protoClass2$pcFunc endp

protoClass2$proc1  proc
                   call print
                   byte "Inside protoClass2$proc1", nl, 0
                   ret
protoClass2$proc1  endp
              

protoClass2$proc2  proc
                   call print
                   byte "Inside protoClass2$proc2", nl, 0
                   ret
protoClass2$proc2  endp
              

protoClass2$proc3  proc
                   call  print
                   byte  "Inside protoClass2$proc3", nl, 0
                   ret
protoClass2$proc3  endp
              
 
        
;--------------------------------------------------
;
; Here is the main assembly language function.

            
            public  asmMain
asmMain     proc
saveRBX     textequ <[rbp-8]>
saveRSI     textequ <[rbp-16]>
saveRDI     textequ <[rbp-24]>
            
            push    rbp
            mov     rbp, rsp
            sub     rsp, 128
            and     rsp, -16
            
            mov     saveRBX, rbx
            mov     saveRSI, rsi
            mov     saveRDI, rdi

            
; Initialize the pc/pc2 class objects:

            lea     rsi, pc
            call    protoClass$create
            
            lea     rsi, pc2
            call    protoClass2$create
            
            
; Directly call the methods in pc, just to demonstrate
; that they work:

            call    print
            byte    "Calling protoClass.pcFunc", nl, 0
            inv     protoClass, _protoClass(pcFunc), \
			RSI, RDI
            call    print
            byte    nl
            byte    "Calling protoClass.protoClass$proto123"
	byte	"functions", nl, 0

            inv     protoClass, _protoClass(proc1), rsi,\
			protoClass$.vmtPtr(protoClass$proto123)  
            inv     protoClass, _protoClass(proc2), rsi,\
			protoClass$.vmtPtr(protoClass$proto123)  
            inv     protoClass, _protoClass(proc3), rsi,\
			protoClass$.vmtPtr(protoClass$proto123)
            inv     protoClass, _protoClass(proc1), rsi,\
			protoClass$.vmtPtr(protoClass$proto1a)
			
; Given a generic pointer, call the protocol functions 
; across both classes:

	lea	rsi, pc
            inv	proto123, proc1, rsi, \
			protoClass$.vmtPtr(protoClass$proto123)
			
	lea	rsi, pc2
            inv	proto123, proc1, rsi, \
			protoClass2$.vmtPtr(protoClass2$proto4pc4)
	
	            
            mov     rbx, saveRBX
            mov     rsi, saveRSI
            mov     rdi, saveRDI
            leave
            ret     ;Returns to caller
        
asmMain     endp
            end