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

Let's build a transpiler! Part 19

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

Last time I said we would parse Enums.
As when we parsed consts, we'll need a class to represent an Enum but this time we will need one more class to represent Enum's members (or enumerands):

Class EnumConstruct
Private Enumerands_ As Dictionary

Public Access As Accessibility
Public Name As Token

Private Sub Class_Initialize()
Set Enumerands_ = New Dictionary
Enumerands_.CompareMode = vbTextCompare
End Sub

Public Property Get Enumerands() As Dictionary
Set Enumerands = Enumerands_
End Property
End Class


Class EnumerandConstruct
Public Access As Accessibility
Public Name As Token
Public Value As Token
End Class

Let's change the Entity class to bear its Enums:

Class Entity
Private Consts_ As Dictionary
Private Enums_ As Dictionary

Public IsClass As Boolean
Public Accessibility As Accessibility
Public Name As Token
Public OptionBase As Integer
Public OptionCompare As VbCompareMethod
Public OptionExplicit As Boolean

Private Sub Class_Initialize()
Set Consts_ = New Dictionary
Consts_.CompareMode = vbTextCompare

Set Enums_ = New Dictionary
Enums_.CompareMode = vbTextCompare
End Sub

Public Property Get Consts() As Dictionary
Set Consts = Consts_
End Property

Public Property Get Enums() As Dictionary
Set Enums = Enums_
End Property
End Class

And now let's adapt ParseDeclarationArea to deal with Enums.
Add the highlighted lines to it in the proper place:

(...)

ElseIf IsKw(Token, vConst) Then
If Access = AccessLocal Then Access = AccessPublic
ParseConsts Access, Entity
Access = AccessLocal

ElseIf IsKw(Token, vEnum) Then
ParseEnum Access, Entity
Access = AccessLocal

ElseIf IsKw(Token, vEnd) Then
Exit Do

(...)

Finally, let's implement ParseEnum:

Private Sub ParseEnum(ByVal Access As Accessibility, ByVal Entity As Entity)
Dim Token As Token
Dim Enm As EnumConstruct
Dim Emd As EnumerandConstruct

Set Token = NextToken

If Not IsId(Token) Then
Fail Token, "Rule: [Public | Private] Enum identifier linebreak", "identifier"
End If

If Token.Suffix <> vbNullChar Then
Fail Token, "Enum cannot have a type-declaration character"
End If

Set Enm = New EnumConstruct
If Access = AccessLocal Then Access = AccessPublic
Enm.Access = Access
Set Enm.Name = Token

Set Token = NextToken

If Not IsBreak(Token) Then
Fail Token, "Rule: [Public | Private] Enum identifier linebreak", "line break"
End If

Do
Set Token = SkipLineBreaks
If IsKw(Token, vEnd) Then Exit Do

If Not IsId(Token) Then
Fail Token, "Rule: identifier [= expression] linebreak", "identifier"
End If

If Token.Suffix <> vbNullChar Then
Fail Token, "Enum member cannot have a type-declaration character"
End If

Set Emd = New EnumerandConstruct
Emd.Access = Access
Set Emd.Name = Token

Set Token = NextToken

If IsOp(Token, "=") Then
Set Emd.Value = GetExpression

Set Token = NextToken
End If

If Enm.Enumerands.Exists(Emd.Name.Text) Then
Fail Emd.Name, "Ambiguous name detected: " & Emd.Name.Text
End If

Enm.Enumerands.Add Emd.Name.Text, Emd
Loop While IsBreak(Token)

If Not IsKw(Token, vEnd) Then Fail Token, "End Enum", "End"

Set Token = NextToken
If Not IsKw(Token, vEnum) Then Fail Token, "End Enum", "Enum"
MustEatLineBreak

If Enm.Enumerands.Count = 0 Then
Fail Enm, "Enum without members is not allowed"
End If

If Entity.Enums.Exists(Enm.Name.Text) Then
Fail Enm.Name, "Ambiguous name detected: " & Enm.Name.Text
End If

Entity.Enums.Add Enm.Name.Text, Enm
End Sub


Next week we'll parse Declares.

Andrej Biasic
2020-11-25