That was sort of closer to what I was trying to do, and oddly I was getting strange results where arguments where all out of whack.. but now all of a sudden it appears to be working ... :icon_confused:
What I was busy doing in any event is the following:
I've changed the way the OO layer in UASM works, so now two backing classes are created, one for the vtable itself, and one for the static members and properties. This means that an actual instance need only keep the vtbl pointer where-as before it had the full vtable in it. That was very inefficient, imagine 100k vector instances, where the properties amount to 16bytes, but each instance has 10 methods (*8 bytes) etc.. I also used the opportuinity to clean up the code produced and optimise it when object pointers are already in rcx it doesn't bother copying the value into rcx etc.
The other advantage to this approach was that now the COM invocation and OO invocation are identical / compatible so i've removed _VCOM and _VCOMINVOKE, and they can all share the same _V and _VINVOKE macro library functions.
I also added support for & (address-of) to both C style calls and the object method calls.
While I was doing all of this I though it would be super useful to extend the pointer operator -> to allow multiple occurences, so something like: myObject->myOtherObject->MyMethod(1,2,3.0)
Basically creating a de-referencing chain.. so the new macros i've create to implement the de-referencing are _DEREF and _DEREFI. Because of how I'm trying to implement this entire thing as a front-end shim so all the heavy lifting is done by the pre-existing macro engine in terms of evaluating parameters, handling nesting requires that whatever I do must be expanded from a single line, into another single line. I don't have the luxury of being able to use AddLineQueueX to expand the statements fully.
So the new macros look like this:
_DEREF MACRO itype:REQ, proc:REQ, args:REQ, derefs:VARARG
LOCAL i, ptrstr, typestr
i = 0
FOR dref, <derefs>
IF i MOD 2 EQ 0
ptrstr TEXTEQU <&dref&>
ELSE
typestr TEXTEQU <&dref&>
IF i EQ 1
% IF(OPATTR(ptrstr)) EQ 0x30
% mov rcx, &ptrstr&
ELSE
% mov rcx, @CatStr(<[>, <&ptrstr&>, <].>, <&typestr&>)
ENDIF
ELSE
% mov rcx, @CatStr(<[>, <&ptrstr&>, <].>, <&typestr&>)
ENDIF
ENDIF
i = i + 1
ENDM
IFNB <args>
% _VINVOKE rcx, itype, proc, <&args&>
ELSE
_VINVOKE rcx, itype, proc
ENDIF
ENDM
_DEREFI MACRO itype:REQ, proc:REQ, args:REQ, derefs:VARARG
LOCAL i, ptrstr, typestr
i = 0
FOR dref, <derefs>
IF i MOD 2 EQ 0
ptrstr TEXTEQU <&dref&>
ELSE
typestr TEXTEQU <&dref&>
IF i EQ 1
% IF(OPATTR(ptrstr)) EQ 0x30
% mov rcx, &ptrstr&
ELSE
% mov rcx, @CatStr(<[>, <&ptrstr&>, <].>, <&typestr&>)
ENDIF
ELSE
% mov rcx, @CatStr(<[>, <&ptrstr&>, <].>, <&typestr&>)
ENDIF
ENDIF
i = i + 1
ENDM
IFNB <args>
% EXITM<_V(rcx, itype, proc, <&args&>)>
ELSE
% EXITM<_V(rcx, itype, proc)>
ENDIF
ENDM
Then all the pre-parse has to do is evaluate the invocation and generate a new line as follows:
(This also allows support for direct register assumed as pointer, or indirect register assumed as pointer to type.
(Test-cases):
;person1->Calc(2.0)
_DEREF Person, Calc, <2.0>, person1, Person
;mov rcx,[person1].Person
;_VINVOKE rcx, Person, Calc, <2.0>
;person1->lpComp->Func(2.0)
_DEREF Company, Func, <2.0>, person1, Person, <rcx>, Person.lpComp
;mov rcx,[person1].Person
;mov rcx,[rcx].Person.lpComp
;_VINVOKE rcx, Company, Func, <2.0>
;assume rsi:PTR Person
lea rsi,person1
;[rsi]->Calc(3.0)
;assume rsi:nothing
_DEREF Person, Calc, <3.0>, <[rsi]>, Person
;mov rcx,[rsi].Person
;_VINVOKE rcx, Person, Calc, <3.0>
;assume rsi:PTR Person
lea rsi,person1
;[rsi]->lpComp->Func(2.0)
;assume rsi:nothing
_DEREF Company, Func, <2.0>, <[rsi]>, Person, <rcx>, Person.lpComp
;mov rcx,[rsi].Person
;mov rcx,[rcx].Person.lpComp
;_VINVOKE rcx, Company, Func, <2.0>
mov rsi,person1
;rsi->Calc(3.0)
_DEREF Person, Calc, <3.0>, <rsi>, Person
;mov rcx,rsi
;_VINVOKE rcx, Person, Calc, <3.0>
mov rsi,person1
;rsi->lpComp->Func(2.0)
_DEREF Company, Func, <2.0>, <rsi>, Person, <rcx>, Person.lpComp
;mov rcx,rsi
;mov rcx,[rcx].Person.lpComp
;_VINVOKE rcx, Company, Func, <2.0>
;assume rsi:PTR Person
lea rsi,person1
xor rax,rax
;[rsi+rax]->Calc(3.0)
;assume rsi:nothing
_DEREF Person, Calc, <3.0>, <[rsi+rax]>, Person
;mov rcx,[rsi+rax].Person
;_VINVOKE rcx, Person, Calc, <3.0>
;person1->Calc( person2->Calc(1.0) )
;person1->Calc( _DEREFI(Person, Calc, <1.0>, person2, Person) )
;person1->Calc( _V(person2, Person, Calc, 1.0) )
_DEREF Person, Calc, _DEREFI(Person, Calc, <1.0>, person2, Person), person1, Person
;mov rcx,[person1].Person
;_VINVOKE rcx, Person, Calc, <_V(person2, Person, Calc, 1.0)>
;normal proc to method
;person1->Calc( NormalProc(2.0) )
;person1->Calc( arginvoke? )
_DEREF Person, Calc, arginvoke(1,1,NormalProc,<2.0>), person1, Person
;mov rcx,[person1].Person
;_VINVOKE rcx, Person, Calc, <_V(person2, Person, Calc, 1.0)>
;method to normal proc
;NormalProc( person1->Calc(2.0) )
;NormalProc2( eax, person1->Calc(2.0) )
NormalProc( _DEREFI(Person, Calc, <2.0>, person1, Person) )
NormalProc2( eax, _DEREFI(Person, Calc, <2.0>, person1, Person) )