Metamorphing Machine I rather be this walking metamorphosis
than having that old formed opinion about everything!

Let's build a transpiler! Part 43

This is the forty third post in a series of building a transpiler.
You can find the previous ones here.

Oops!... I did it again

Even though I said it would be a distraction, I couldn't help myself. I had to try a VB6 LINQ version.
LINQ stands for Language Integrated Native Query, so I choose to call my version PINQ, or Poorly Integrated Native Query.
What follows below is its standalone first raw draft. You can see that one can project/Select_ wich properties to keep in this version.
Later I specialized it to be used in our project and Select_ was gone along with Pretender.
I also made it implement KeyedList "interface" so it could act as a collection, too
Take a look at the code in bold. It is pretty functional (in the sense that it works) and readable!

Public Module Program
Option Explicit

Public Sub Main()
Dim P1 As Person
Dim P2 As Person
Dim P3 As Person
Dim P As Variant
Dim Ps As Variant

Set P1 = New Person
P1.ID = 1
P1.Name = "Andrej Biasic"
P1.DOB = #2/12/2020#

Set P2 = New Person
P2.ID = 2
P2.Name = "Roderick Marmelade"
P2.DOB = #7/1/2020#

Set P3 = New Person
P3.ID = 3
P3.Name = "Halcyon Dairy"
P3.DOB = #7/1/2020#

Ps = Array(P3, P2, P1)

With New PINQ
For Each P In _
.From(Ps). _
Select_(!Name, !DOB). _
Where(!Name, [Like], "Hal*", [Or], !DOB, [=], #2/12/2020#). _
OrderBy(!DOB, !Name, Desc)
Debug.Print P!Name
Next
End With
End Sub
End Module


Public Class Person
Option Explicit

Public ID As Long
Public Name As String
Public DOB As Date
End Class


Public Class Field
Public Default Name As String
End Class


Public Class Pretender
Option Explicit

Private Props_ As Collection

Public Default Property Get Item(ByVal Name As String) As Variant
Name = UCase$(Name)

If IsObject(Props_(Name)) Then
Set Item = Props_(Name)
Else
Item = Props_(Name)
End If
End Property

Friend Property Set Props(ByVal Value As Collection)
Set Props_ = Value
End Property
End Class


Public Class PINQ
Option Explicit

Public Enum Operators
[>]
[>=]
[=]
[<=]
[<]
[<>]
[Like]
[And]
[Or]
[Desc]
End Enum

Private Src_ As Collection


Private Sub Class_Initialize()
Set Src_ = New Collection
End Sub


Public Property Get From(ByVal Value As Variant) As PINQ
Dim Item As Variant

If IsObject(Value) Then
Set Src_ = Value
Else
Set Src_ = New Collection

For Each Item In Value
Src_.Add Item
Next
End If

Set From = Me
End Property


Public Property Get Select_(ParamArray Fields() As Variant) As PINQ
Dim Obj As Object
Dim Field As Variant
Dim Props As Collection
Dim Result As Collection
Dim Prt As Pretender

Set Result = New Collection

For Each Obj In Src_
Set Props = New Collection

For Each Field In Fields
Field = UCase$(Field)

If TypeOf Obj Is Pretender Then
Props.Add Obj(Field), Field
Else
Props.Add CallByName(Obj, Field, VbGet), Field
End If
Next

Set Prt = New Pretender
Set Prt.Props = Props
Result.Add Prt
Next

Set Src_ = Result
Set Select_ = Me
End Property


Public Property Get Where(ParamArray Conditions() As Variant) As PINQ
Dim Keep As Boolean
Dim IsFirst As Boolean
Dim Idx As Long
Dim Jdx As Long
Dim Udx As Long
Dim Field As Variant
Dim Obj As Object
Dim Value As Variant
Dim Prop As Variant
Dim Op As Operators
Dim Connect As Operators

IsFirst = True
Idx = -1
Udx = UBound(Conditions)
ReDim Keeps(1 To Src_.Count) As Boolean

Do
Keep = False
Idx = Idx + 1
If Idx > Udx Then Err.Raise 5, "PINQ", "Expected: Field name or expression"
Idx = Idx + 1
If Idx > Udx Then Err.Raise 5, "PINQ", "Expected: Comparison operator"
Idx = Idx + 1
If Idx > Udx Then Err.Raise 5, "PINQ", "Expected: Field name of expression"

Op = Conditions(Idx)

For Each Obj In Src_
If TypeOf Conditions(Idx - 2) Is Field Then
If TypeOf Obj Is Pretender Then
Field = Obj(UCase$(Conditions(Idx - 2)))
Else
Field = CallByName(Obj, UCase$(Conditions(Idx - 2)), VbGet)
End If
Else
Field = Conditions(Idx - 2)
End If

If TypeOf Conditions(Idx) Is Field Then
If TypeOf Obj Is Pretender Then
Value = Obj(UCase$(Conditions(Idx)))
Else
Value = CallByName(Obj, UCase$(Conditions(Idx)), VbGet)
End If
Else
Value = Conditions(Idx)
End If

Select Case Op
Case [>=]
Keep = Field >= Value

Case [>]
Keep = Field > Value

Case [=]
Keep = Field = Value

Case [<]
Keep = Field < Value

Case [<=]
Keep = Field <= Value

Case [<>]
Keep = Field <> Value

Case [Like]
Keep = Field Like Value
End Select

Jdx = Jdx + 1

If IsFirst Then
Keeps(Jdx) = Keep

ElseIf Connect = [And] Then
Keeps(Jdx) = Keeps(Jdx) And Keep

ElseIf Connect = [Or] Then
Keeps(Jdx) = Keeps(Jdx) Or Keep

Else
Err.Raise 5, "PINQ", "Invalid operator"
End If
Next

IsFirst = False
Jdx = 0
Idx = Idx + 1
If Idx > Udx Then Exit Do
Connect = Conditions(Idx)
Loop

For Idx = Src_.Count To 1 Step -1
If Not Keeps(Idx) Then Src_.Remove Idx
Next

Set Where = Me
End Property


Public Property Get OrderBy(ParamArray Fields() As Variant) As PINQ
Dim IsDesc As Boolean
Dim Swap As Boolean
Dim Idx As Long
Dim Length As Long
Dim Udx As Long
Dim Jdx As Long
Dim Field As String
Dim LHS As Variant
Dim RHS As Variant

Udx = UBound(Fields)
Length = Src_.Count

Do
Swap = False

For Idx = 2 To Length
Jdx = 0

Do
IsDesc = False
Field = Fields(Jdx)

If Jdx <= Udx Then _
If Fields(Jdx + 1) = [Desc] Then _
Jdx = Jdx + 1: IsDesc = True

If TypeOf Src_(Idx - 1) Is Pretender Then
LHS = Src_(Idx - 1)(Field)
Else
LHS = CallByName(Src_(Idx - 1), Field, VbGet)
End If

If TypeOf Src_(Idx) Is Pretender Then
RHS = Src_(Idx)(Field)
Else
RHS = CallByName(Src_(Idx), Field, VbGet)
End If

Swap = False

If LHS < RHS Then
Swap = IsDesc
If Not Swap Then Exit Do

ElseIf LHS > RHS Then
Swap = Not IsDesc
If Not Swap Then Exit Do
End If

Jdx = Jdx + 1
Loop Until Jdx >= Udx Or Swap

If Swap Then
Src_.Add Src_(Idx - 1), , , Idx
Src_.Remove Idx - 1
Exit For
End If
Next
Loop While Swap

Set OrderBy = Me
End Property


Public Default Property Get Item(ByVal Name As String) As Field
Dim Result As Field

Set Result = New Field
Result.Name = Name
Set Item = Result
End Property


Public Iterator Function NewEnum() As IUnknown
Set NewEnum = Src_.[_NewEnum]
End Function
End Class

Back to business

Last time I said we would start validating identifiers.
Let me say that I'm walking on uncharted territory here. I have never progressed so far before in pursue of building a transpiler.
I guess the commitment of having it "documented" through this series of posts kept pushing me forward.
By this time I'd usually wander off implementing the standard library and would end up either stuck in something or abandoning the project.

So, back to validating identifiers: I'm in a loop now. I try something, it does not work. I try something different, if feels weird. Rinse and repeat.
What happened though, is while trying to validate some identifiers, they happened to be VB internal functions or constants, like TypeName, for instance. As they were nowhere to be found, I've got errors. This annoyed the hell out of me!
That's why I created "interfaces" for VB's "standard library."

They follow below:

Public Module StdOLE
Public Type GUID
Data1 As `U´Long
Data2 As `U´Integer
Data3 As `U´Integer
Data4(0 To 7) As Byte
End Type
End Module


Public Class IUnknown
Public Sub QueryInterface(ByRef riid As GUID, ByRef ppvObject As LongPtr`<-Should be Any´)
End Sub

Public Function AddRef() As Long
Attribute IsCOM=False
End Function

Public Function Release() As `U´Long
Attribute IsCOM=False
End Function
End Class


Public Class IEnumVARIANT
Public Sub Clone(ByRef ppEnum As IEnumVARIANT)
End Sub

Public Sub [Next](ByRef celt As `U´Long, ByRef rgvar As Variant, ByRef pcellFetched As `U´Long)
End Sub

Public Sub Reset()
End Sub

Public Sub Skip(ByRef celt As `U´Long)
End Sub
End Class


Public Module Constants
Option Explicit

Public Const vbDay = "d"
Public Const vbDayOfYear = "y"
Public Const vbHour = "h"
Public Const vbMinute = "n"
Public Const vbMonth = "m"
Public Const vbQuarter = "q"
Public Const vbSecond = "s"
Public Const vbWeekday = "w"
Public Const vbWeekOfYear = "ww"
Public Const vbYear = "yyyy"

Public Enum AppWinStyle
vbHide
vbNormalFocus
vbMinimizedFocus
vbMaximizedFocus
vbNormalNoFocus
vbMinimizedNoFocus = 6
End Enum

Public Enum VbCalendar
vbCalGreg
vbCalHijri
End Enum

Public Enum VbCallType
VbMethod = 1
VbGet = 2
VbLet = 4
VbSet = 8
End Enum

Public Enum VbCompareMethod
vbBinaryCompare
vbTextCompare
vbDatabaseCompare
End Enum

Public Enum VbDateTimeFormat
vbGeneralDate
vbLongDate
vbShortDate
vbLongTime
vbShortTime
End Enum

Public Enum VbDayOfWeek
vbUseSystemDayOfWeek
vbSunday
vbMonday
vbTuesday
vbWednesday
vbThursday
vbFriday
vbSaturday
End Enum

Public Enum FileAttribute
vbNormal = 0
vbReadOnly = 1
vbHidden = 2
vbSystem = 4
vbVolume = 8
vbDirectory = 16
vbArchive = 32
vbAlias = 64
End Enum

Public Enum FirstWeekOfYear
vbUseSystem
vbFirstJan1
vbFirstFourDays
vbFirstFullWeek
End Enum

Public Enum MsgBoxResult
vbOK = 1
vbCancel
vbAbort
vbRetry
vbIgnore
vbYes
vbNo
End Enum

Public Enum MsgBoxStyle
vbOKOnly
vbOKCancel
vbAbortRetryIgnore
vbYesNoCancel
vbYesNo
vbRetryCancel

vbCritical = 16
vbQuestion = 32
vbExclamation = 48
vbInformation = 64

vbDefaultButton1 = 0
vbDefaultButton2 = 256
vbDefaultButton3 = 512
vbDefaultButton4 = 768

vbApplicationModal = 0
vbSystemModal = 4096
vbMsgBoxSetForeground = 65536
vbMsgBoxRight = 524288
vbMsgBoxRtlReading = 1048576
vbMsgBoxHelpButton = 16384
End Enum

Public Enum TriState
vbUseDefault = -2
vbTrue
vbFalse
End Enum

Public Enum VariantType
vbEmpty
vbNull
vbInteger
vbLong
vbSingle
vbDouble
vbCurrency
vbDate
vbString
vbObject
vbError
vbBoolean
vbVariant
vbDataObject
vbDecimal
vbByte = 17
vbLongLong = 20
vbUserDefinedType = 36
vbLongPtr = 37
vbArray = 8192
vbByReference = 16384
End Enum

Public Enum VbStrConv
vbUpperCase = 1
vbLowerCase = 2
vbProperCase = 3
vbWide = 4
vbNarrow = 8
vbKatakana = 16
vbHiragana = 32
vbUnicode = 64
vbFromUnicode = 128
End Enum
End Module


Public Module Conversion
Option Explicit

Public Function Bin(ByRef Number As Variant) As Variant
End Function

Public Function Bin$(ByRef Number As Variant)
End Function

Public Function CBool(ByRef Expression As Variant) As Boolean
End Function

Public Function CByte(ByRef Expression As Variant) As Byte
End Function

Public Function CCur(ByRef Expression As Variant) As Currency
End Function

Public Function CDate(ByRef Expression As Variant) As Date
End Function

Public Function CDbl(ByRef Expression As Variant) As Double
End Function

Public Function CDec(ByRef Expression As Variant) As Variant
End Function

Public Function CInt(ByRef Expression As Variant) As Integer
End Function

Public Function CLng(ByRef Expression As Variant) As Long
End Function

Public Function CObj(ByRef Obj As Variant) As Object
End Function

Public Function CSng(ByRef Expression As Variant) As Single
End Function

Public Function CStr(ByRef Expression As Variant) As String
End Function

Public Function CVar(ByRef Expression As Variant) As Variant
End Function

Public Function CVDate(ByRef Expression As Variant) As Variant
End Function

Public Function CVErr(ByRef ErrorNumber As Variant) As Variant
End Function

Public Function Error(Optional ByRef ErrorNumber As Variant) As Variant
End Function

Public Function Error$(Optional ByRef ErrorNumber As Variant)
End Function

Public Function Fix(ByRef Number As Variant) As Variant
End Function

Public Function Hex(ByRef Number As Variant) As Variant
End Function

Public Function Hex$(ByRef Number As Variant)
End Function

Public Function Int(ByRef Number As Variant) As Variant
End Function

Public Function Oct(ByRef Number As Variant) As Variant
End Function

Public Function Oct$(ByRef Number As Variant)
End Function

Public Function Str(ByRef Number As Variant) As Variant
End Function

Public Function Str$(ByRef Number As Variant)
End Function

Public Function Val(ByRef StringValue As String) As Double
End Function
End Module


Public Module DateTime
Option Explicit
Private Calendar_ As VbCalendar

Public Property Get Calendar() As VbCalendar
Calendar = Calendar_
End Property

Public Property Let Calendar(ByRef Value As VbCalendar)
Calendar_ = Value
End Property

Public Property Get Date() As Variant
End Property

Public Property Let Date(ByRef Value As Variant)
End Property

Public Property Get Date$()
End Property

Public Property Let Date$(ByRef Value As Variant)
End Property

Public Function DateAdd(ByRef Interval As String, ByRef Number As Double, ByRef DateValue As Variant) As Variant
End Function

Public Function DateDiff( _
ByRef Interval As String, _
ByRef Date1 As Variant, _
ByRef Date2 As Variant, _
Optional ByRef FirstDayOfWeek As VbDayOfWeek = vbSunday, _
Optional ByRef FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1 _
) As Variant
End Function

Public Function DatePart( _
ByRef Interval As String, _
ByRef DateValue As Variant, _
Optional ByRef FirstDayOfWeek As VbDayOfWeek = vbSunday, _
Optional ByRef FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1 _
) As Variant
End Function

Public Function DateSerial(ByRef Year As Integer, ByRef Month As Integer, ByRef Day As Integer) As Variant
End Function

Public Function DateValue(ByRef Value As String) As Variant
End Function

Public Function Day(ByRef DateValue As Variant) As Variant
End Function

Public Function Hour(ByRef Time As Variant) As Variant
End Function

Public Function Minute(ByRef Time As Variant) As Variant
End Function

Public Function Month(ByRef DateValue As Variant) As Variant
End Function

Public Property Get Now() As Variant
End Property

Public Property Let Now(ByRef Value As Variant)
End Property

Public Function Second(ByRef Time As Variant) As Variant
End Function

Public Property Get Time() As Variant
End Property

Public Property Let Time(ByRef Value As Variant)
End Property

Public Property Get Time$()
End Property

Public Property Let Time$(ByRef Value As Variant)
End Property

Public Property Get Timer() As Single
End Property

Public Function TimeSerial(ByRef Hour As Integer, ByRef Minute As Integer, ByRef Second As Integer) As Variant
End Function

Public Function TimeValue(ByRef Time As String) As Variant
End Function

Public Function Weekday(ByRef DateValue As Variant, Optional ByRef FirstDayOfWeek As VbDayOfWeek = vbSunday) As Variant
End Function

Public Function Year(ByRef DateValue As Variant) As Variant
End Function
End Module


Public Module FileSystem
Option Explicit

Public Sub ChDir(ByRef Path As String)
End Sub

Public Sub ChDrive(ByRef Drive As String)
End Sub

Public Function CurDir(Optional ByRef Drive As Variant) As Variant
End Function

Public Function CurDir$(Optional ByRef Drive As Variant)
End Function

Public Function Dir(Optional ByRef PathName As Variant, Optional ByRef Attributes As VbFileAttribute = vbNormal) As String
End Function

Public Function EOF(ByRef FileNumber As Integer) As Boolean
End Function

Public Function FileAttr(ByRef FileNumber As Integer, Optional ByRef ReturnType As Integer = 1) As Long
End Function

Public Sub FileCopy(ByRef Source As String, ByRef Destination As String)
End Sub

Public Function FileDateTime(ByRef PathName As String) As Variant
End Function

Public Function FileLen(ByRef PathName As String) As Long
End Function

Public Function FreeFile(Optional ByRef RangeNumber As Variant) As Integer
End Function

Public Function GetAttr(ByRef PathName As String) As VbFileAttribute
End Function

Public Sub Kill(ByRef PathName As Variant)
End Sub

Public Function Loc(ByRef FileNumber As Integer) As Long
End Function

Public Function LOF(ByRef FileNumber As Integer) As Long
End Function

Public Sub MkDir(ByRef Path As String)
End Sub

Public Sub Reset()
End Sub

Public Sub RmDir(ByRef Path As Variant)
End Sub

Public Function [Seek](ByRef FileNumber As Integer) As Long
End Function

Public Sub SetAttr(ByRef PathName As String, ByRef Attributes As VbFileAttribute)
End Sub
End Module


Public Module Financial
Option Explicit

Public Function DDB( _
ByRef Cost As Double, _
ByRef Salvage As Double, _
ByRef Life As Double, _
ByRef Period As Double, _
Optional ByRef Factor As Variant _
) As Double
End Function

Public Function FV( _
ByRef Rate As Double, _
ByRef NPer As Double, _
ByRef Pmt As Double, _
Optional ByRef PV As Variant, _
Optional ByRef Due As Variant _
) As Double
End Function

Public Function IPmt( _
ByRef Rate As Double, _
ByRef Per As Double, _
ByRef NPer As Double, _
ByRef PV As Double, _
Optional ByRef FV As Variant, _
Optional ByRef Due As Variant _
) As Double
End Function

Public Function IRR(ByRef ValueArray() As Double, Optional ByRef Guess As Variant) As Double
End Function

Public Function MIRR(ByRef ValueArray() As Double, ByRef FinanceRate As Double, ByRef ReinvestRate As Double) As Double
End Function

Public Function NPer( _
ByRef Rate As Double, _
ByRef Pmt As Double, _
ByRef PV As Double, _
Optional ByRef FV As Variant, _
Optional ByRef Due As Variant _
) As Double
End Function

Public Function NPV(ByRef Rate As Double, ByRef ValueArray() As Double) As Double
End Function

Public Function Pmt( _
ByRef Rate As Double, _
ByRef NPer As Double, _
ByRef PV As Double, _
Optional ByRef FV As Variant, _
Optional ByRef Due As Variant _
) As Double
End Function

Public Function PPmt( _
ByRef Rate As Double, _
ByRef Per As Double, _
ByRef NPer As Double, _
ByRef PV As Double, _
Optional ByRef FV As Variant, _
Optional ByRef Due As Variant _
) As Double
End Function

Public Function PV( _
ByRef Rate As Double, _
ByRef NPer As Double, _
ByRef Pmt As Double, _
Optional ByRef FV As Variant, _
Optional ByRef Due As Variant _
) As Double
End Function

Public Function Rate( _
ByRef NPer As Double, _
ByRef Pmt As Double, _
ByRef PV As Double, _
Optional ByRef FV As Variant, _
Optional ByRef Due As Variant, _
Optional ByRef Guess As Variant _
) As Double
End Function

Public Function SLN(ByRef Cost As Double, ByRef Salvage As Double, ByRef Life As Double) As Double
End Function

Public Function SYD(ByRef Cost As Double, ByRef Salvage As Double, ByRef Life As Double, ByRef Period As Double) As Double
End Function
End Module


Public Module [Global]
Option Explicit

Public Function Array(ParamArray ArgList() As Variant) As Variant
End Function

Public Sub Load(ByRef ObjectValue As Object)
End Sub

Public Function LoadPicture( _
Optional ByRef FileName As Variant, _
Optional ByRef Size As Variant, _
Optional ByRef ColorDepth As Variant, _
Optional ByRef X As Variant, _
Optional ByRef Y As Variant _
) As IPictureDisp
End Function

Public Function LoadResData(ByRef Id As Variant, ByRef ResType As Variant) As Variant
End Function

Public Function LoadResPicture(ByRef Id As Variant, ByRef ResType As Integer) As IPictureDisp
End Function

Public Function LoadResString(ByRef Id As Long) As String
End Function

Public Sub SavePicture(ByRef Picture As IPictureDisp, ByRef FileName As String)
End Sub

Public Sub [Stop]()
End Sub

Public Sub Unload(ByRef ObjectValue As Variant)
End Sub
End Module


Public Module Information
Option Explicit

Public Function Err() As ErrObject
End Function

Public Function IMEStatus() As VbIMEStatus
End Function

Public Function IsArray(ByRef VarName As Variant) As Boolean
End Function

Public Function IsDate(ByRef VarName As Variant) As Boolean
End Function

Public Function IsEmpty(ByRef VarName As Variant) As Boolean
End Function

Public Function IsError(ByRef VarName As Variant) As Boolean
End Function

Public Function IsMissing(ByRef VarName As Variant) As Boolean
End Function

Public Function IsNull(ByRef VarName As Variant) As Boolean
End Function

Public Function IsNothing(ByRef VarName As Variant) As Boolean
End Function

Public Function IsNumeric(ByRef VarName As Variant) As Boolean
End Function

Public Function IsObject(ByRef VarName As Variant) As Boolean
End Function

Public Function LBound(ByRef ArrayName As Variant, Optional ByRef Dimension As Long = 1) As Long
End Function

Public Function QBColor(ByRef Color As Integer) As Long
End Function

Public Function RGB(ByRef Red As Integer, ByRef Green As Integer, ByRef Blue As Integer) As Long
End Function

Public Function TypeName(ByRef VarName As Variant) As String
End Function

Public Function UBound(ByRef ArrayName As Variant, Optional ByRef Dimension As Integer = 1)
End Function

Public Function VarType(ByRef VarName As Variant) As VbVarType
End Function

Public Function StrPtr(ByRef Ptr As String) As LongPtr
End Function

Public Function ObjPtr(ByRef Ptr As IUnknown) As LongPtr
End Function

Public Function VarPtr(ByRef Ptr As Variant`<-Should be Any´) As LongPtr
End Function
End Module


Public Module Interaction
Option Explicit

Public Sub AppActivate(ByRef Title As Variant, Optional ByRef Wait As Boolean)
End Sub

Public Sub Beep()
End Sub

Public Function CallByName( _
ByRef ObjectValue As Object, _
ByRef ProcName As String, _
ByRef CallType As VbCallType, _
ByRef Args() As Variant _
) As Variant
End Function

Public Function Choose(ByRef Index As Single, ParamArray Choices() As Variant) As Variant
End Function

Public Function Command() As Variant
End Function

Public Function Command$()
End Function

Public Function CreateObject(ByRef ClassValue As String, Optional ByRef ServerName As String) As Variant
End Function

Public Sub DeleteSetting(ByRef AppName As String, ByRef Section As Variant, Optional ByRef Key As Variant)
End Sub

Public Function DoEvents() As Integer
End Function

Public Function Environ(ByRef Expression As Variant) As Variant
End Function

Public Function Environ$(ByRef Expression As Variant)
End Function

Public Function GetAllSettings(ByRef AppName As String, ByRef Section As String) As Variant
End Function

Public Function GetObject(Optional ByRef PathName As Variant, Optional ByRef ClassValue As Variant) As Variant
End Function

Public Function GetSetting( _
ByRef AppName As String, _
ByRef Section As String, _
ByRef Key As String, _
Optional ByRef DefaultValue As Variant _
) As String
End Function

Public Function IIf(ByRef Expression As Variant, ByRef TruePart As Variant, ByRef FalsePart As Variant) As Variant
End Function

Public Function InputBox( _
ByRef Prompt As Variant, _
Optional ByRef Title As Variant, _
Optional ByRef DefaultValue As Variant, _
Optional ByRef XPos As Variant, _
Optional ByRef YPos As Variant, _
Optional ByRef HelpFile As Variant, _
Optional ByRef Context As Variant _
) As String
End Function

Public Function MsgBox( _
ByRef Prompt As Variant, _
Optional ByRef Buttons As VbMsgBoxStyle = vbOKOnly, _
Optional ByRef Title As Variant, _
Optional ByRef HelpFile As Variant, _
Optional ByRef Context As Variant _
) As VbMsgBoxResult
End Function

Public Function Partition( _
ByRef Number As Variant, _
ByRef StartValue As Variant, _
ByRef StopValue As Variant, _
ByRef Interval As Variant _
) As Variant
End Function

Public Sub SaveSetting(ByRef AppName As String, ByRef Section As String, ByRef Key As String, ByRef Setting As String)
End Sub

Public Sub SendKeys(ByRef StringValue As String, Optional ByRef Wait As Boolean)
End Sub

Public Function Shell(ByRef PathName As Variant, Optional ByRef WindowStyle As VbAppWinStyle = vbMinimizedFocus) As Double
End Function

Public Function Switch(ParamArray VarExpr() As Variant) As Variant
End Function
End Module


Public Module Math
Option Explicit

Public Function Abs(ByRef Number As Variant) As Variant
End Function

Public Function Atn(ByRef Number As Double) As Double
End Function

Public Function Cos(ByRef Number As Double) As Double
End Function

Public Function Exp(ByRef Number As Double) As Double
End Function

Public Function Log(ByRef Number As Double) As Double
End Function

Public Sub Randomize(Optional ByRef Number As Variant)
End Sub

Public Function Rnd(Optional ByRef Number As Variant) As Single
End Function

Public Function Round(ByRef Number As Variant, Optional ByRef NumDigitsAfterDecimal As Long) As Variant
End Function

Public Function Sgn(ByRef Number As Variant) As Variant
End Function

Public Function Sin(ByRef Number As Double) As Double
End Function

Public Function Sqr(ByRef Number As Double) As Double
End Function

Public Function Tan(ByRef Number As Double) As Double
End Function
End Module


Public Module Strings
Option Explicit

Public Function Asc(ByRef StringValue As String) As Integer
End Function

Public Function AscB(ByRef StringValue As Variant) As Byte
End Function

Public Function AscW(ByRef StringValue As String) As Integer
End Function

Public Function Chr(ByRef CharCode As Long) As Variant
End Function

Public Function Chr$(ByRef CharCode As Long)
End Function

Public Function ChrB(ByRef CharCode As Byte) As Variant
End Function

Public Function ChrB$(ByRef CharCode As Byte)
End Function

Public Function ChrW(ByRef CharCode As Long) As Variant
End Function

Public Function ChrW$(ByRef CharCode As Long)
End Function

Public Function Filter( _
ByRef SourceArray As Variant, _
ByRef Match As String, _
Optional ByRef Include As Boolean = True, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As Variant
End Function

Public Function Format( _
ByRef Expression As Variant, _
Optional ByRef Fmt As Variant, _
Optional ByRef FirstDayOfWeek As VbDayOfWeek = vbSunday, _
Optional ByRef FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1 _
) As Variant
End Function

Public Function Format$( _
ByRef Expression As Variant, _
Optional ByRef Fmt As Variant, _
Optional ByRef FirstDayOfWeek As VbDayOfWeek = vbSunday, _
Optional ByRef FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1 _
)
End Function

Public Function FormatCurrency( _
ByRef Expression As Variant, _
Optional ByRef NumDigitsAfterDecimal As Long = -1, _
Optional ByRef IncludeLeadingDigit As VbTriState = vbUseDefault, _
Optional ByRef UseParensForNegativeNumbers As VbTriState = vbUseDefault, _
Optional ByRef GroupDigits As VbTriState = vbUseDefault _
) As String
End Function

Public Function FormatDateTime( _
ByRef Expression As Variant, _
Optional ByRef NamedFormat As VbDateTimeFormat = vbGeneralDate _
) As String
End Function

Public Function FormatNumber( _
ByRef Expression As Variant, _
Optional ByRef NumDigitsAfterDecimal As Long = -1, _
Optional ByRef IncludeLeadingDigit As VbTriState = vbUseDefault, _
Optional ByRef UseParensForNegativeNumbers As VbTriState = vbUseDefault, _
Optional ByRef GroupDigits As VbTriState = vbUseDefault _
) As String
End Function

Public Function FormatPercent( _
ByRef Expression As Variant, _
Optional ByRef NumDigitsAfterDecimal As Long = -1, _
Optional ByRef IncludeLeadingDigit As VbTriState = vbUseDefault, _
Optional ByRef UseParensForNegativeNumbers As VbTriState = vbUseDefault, _
Optional ByRef GroupDigits As VbTriState = vbUseDefault _
) As String
End Function

Public Function InStr( _
ByRef Start As Variant, _
Optional ByRef String1 As Variant, _
Optional ByRef String2 As Variant, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As Variant
End Function

Public Function InStrB( _
ByRef Start As Variant, _
Optional ByRef String1 As Variant, _
Optional ByRef String2 As Variant, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As Variant
End Function

Public Function InstrRev( _
ByRef StringCheck As String, _
ByRef StringMatch As String, _
Optional ByRef Start As Long = -1, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As Long
End Function

Public Function Join(ByRef SourceArray As Variant, Optional ByRef Delimiter As Variant) As String
End Function

Public Function LCase(ByRef StringValue As Variant) As Variant
End Function

Public Function LCase$(ByRef StringValue As Variant)
End Function

Public Function Left(ByRef StringValue As Variant, ByRef Length As Long) As Variant
End Function

Public Function Left$(ByRef StringValue As Variant, ByRef Length As Long)
End Function

Public Function LeftB(ByRef StringValue As Variant, ByRef Length As Long) As Variant
End Function

Public Function LeftB$(ByRef StringValue As Variant, ByRef Length As Long)
End Function

Public Function Len(ByRef Expression As Variant) As Variant
End Function

Public Function LenB(ByRef Expression As Variant) As Variant
End Function

Public Function LTrim(ByRef StringValue As Variant) As Variant
End Function

Public Function LTrim$(ByRef StringValue As Variant)
End Function

Public Function Mid(ByRef StringValue As Variant, ByRef Start As Long, Optional ByRef Length As Variant) As Variant
End Function

Public Function Mid$(ByRef StringValue As Variant, ByRef Start As Long, Optional ByRef Length As Variant)
End Function

Public Function MidB(ByRef StringValue As Variant, ByRef Start As Long, Optional ByRef Length As Variant) As Variant
End Function

Public Function MidB$(ByRef StringValue As Variant, ByRef Start As Long, Optional ByRef Length As Variant)
End Function

Public Function MonthName(ByRef Month As Long, Optional ByRef Abbreviate As Boolean = False) As String
End Function

Public Function Replace( _
ByRef Expression As String, _
ByRef Find As String, _
ByRef ReplaceWith As String, _
Optional ByRef Start As Long = -1, _
Optional ByRef Count As Long = -1, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As String
End Function

Public Function Right(ByRef StringValue As Variant, ByRef Length As Variant) As Variant
End Function

Public Function Right$(ByRef StringValue As Variant, ByRef Length As Variant)
End Function

Public Function RightB(ByRef StringValue As Variant, ByRef Length As Variant) As Variant
End Function

Public Function RightB$(ByRef StringValue As Variant, ByRef Length As Variant)
End Function

Public Function RTrim(ByRef StringValue As Variant) As Variant
End Function

Public Function RTrim$(ByRef StringValue As Variant)
End Function

Public Function Space(ByRef Number As Long) As Variant
End Function

Public Function Space$(ByRef Number As Long)
End Function

Public Function Split( _
ByRef Expression As String, _
Optional ByRef Delimiter As Variant, _
Optional ByRef Limit As Long = -1, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As Variant
End Function

Public Function StrComp( _
ByRef String1 As Variant, _
ByRef String2 As Variant, _
Optional ByRef Compare As VbCompareMethod = vbBinaryCompare _
) As Variant
End Function

Public Function StrConv(ByRef StringValue As Variant, ByRef Conversion As VbStrConv, Optional ByRef LocaleID As Long) As Variant
End Function

Public Function [String](ByRef Number As Long, ByRef Character As Variant) As Variant
End Function

Public Function [String]$(ByRef Number As Long, ByRef Character As Variant)
End Function

Public Function StrReverse(ByRef Expression As String) As String
End Function

Public Function Trim(ByRef StringValue As Variant) As Variant
End Function

Public Function Trim$(ByRef StringValue As Variant)
End Function

Public Function UCase(ByRef StringValue As Variant) As Variant
End Function

Public Function UCase$(ByRef StringValue As Variant)
End Function

Public Function WeekdayName( _
ByRef Weekday As Long, _
Optional ByRef Abbreviate As Boolean = False, _
Optional ByRef FirstDayOfWeek As VbDayOfWeek = vbUseSystemDayOfWeek _
) As String
End Function
End Module

In doing that, I've stumbled into three issues. The first one is that it became clear that I did not plan to deal with the dollar-functions/properties.
When parsing them, we find its non-dollar versions and barfs about duplicated identifiers. I had to special-case them to solve it.

The second is non-supported data types. Some Types and procedures use unsigned longs but VB6 does not support them, nor do we (...yet?)
In this case I'm telling "white-lies", stating they are signed Longs.

Then we have two procedures (QueryInterface and VarPtr) having a parameter that should be As Any, but we only allow Any in Declares.
I'm not sure what to do yet. I'll have to think it over. For now I'm using LongPtr and Variant respectively

Another thing that stood up is I'm not really dealing with three keywords: Debug, Circle, and PSet.
This is something I'm adding to my to-do list.

On the one hand, I'm adding items to my to-do list but on the other hand, I'm removing at least one from it: I created a proper "interface" inspired in the Visitor pattern and made Reverter implement it.
(I say "inspired" because probably it is not a proper visitor pattern. I did not add an Accept method to all thoses classes being visited by Reverter, as I could not see any value in doing that.)
This way, a future transpiler class can implement it too, and we would choose which class to use based on an command-line argument.
I'm not releasing it now because it is still in flux, though. It's not in the shape I would like it to be yet.

One thought that occurred to me is that sometime in the future, maybe would be a good idea to remove all those Vb prefixes... just in case.

Next week we go ahead of ourselves for no good reason.

Andrej Biasic
2021-07-14