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

Let's build a transpiler! Part 16

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

Last time I said we would start parsing whatever is inside classes and modules.

There are two different areas inside a class or a module.
The first is called the declaration area. It is there that we introduce new elements like Consts, Enums, Types, Declares, and Events.
It is there also that we set Options and Deftypes, declare variables with class, module, or global scope, and state Implements.

The second area does not have a formal name, but we'll call it the procedure area.
It is there that we implement Subs, Functions, and Propertys.
The procedure area follows the declaration area and ends it.

Any declaration area element can appear in any order, but there are interdependencies between some of them.
Deftypes must precede any variable declarations because the former may or may not affect the latter.
Option Base must precede any array variable declaration because - again - it may or may not affect them.

We'll start simple/naive and refactor our code along the way, as we deal with more complex situations.
Let's start with the options. There are three of them:
We need to add three more properties to class Entity: OptionBase, OptionCompare, and OptionExplicit:

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

We will create a utility function to check if a token is a specific keyword:

Private Function IsKw(ByVal Token As Token, ByVal Name As String) As Boolean
If Token.Suffix <> vbNullChar Then Exit Function
If Token.Kind <> tkKeyword Then Exit Function
If Token.Text <> Name Then Exit Function
IsKw = True
End Function

Now, we'll create a ParseDeclarationArea function to deal with the declaration area elements, starting with Options:

Private Function ParseDeclarationArea(ByVal Entity As Entity) As Token
Dim HadBase As Boolean
Dim HadCompare As Boolean
Dim Token As Token

Set Token = SkipLineBreaks

If IsKw(Token, "Option") Then
Set Token = NextToken

If IsKw(Token, "Base") Then
If HadBase Then Fail Token, "Duplicate Option statement"
HadBase = True

Set Token = NextToken

If Token.Kind <> tkIntegerNumber Or (Token.Text <> "0" And Token.Text <> "1") Then
Fail Token, "Option Base (0 | 1)", "0 or 1"
End If

Entity.OptionBase = IIf(Token.Text = "0", 0, 1)

ElseIf IsKw(Token, "Compare") Then
If HadCompare Then Fail Token, "Duplicate Option statement"
HadCompare = True

Set Token = NextToken

If IsKw(Token, "Binary") Then
Entity.OptionCompare = vbBinaryCompare

ElseIf IsKw(Token, "Text") Then
Entity.OptionCompare = vbTextCompare

Fail Token, "Option Compare (Binary | Text)", "Binary or Text"
End If

ElseIf IsKw(Token, "Explicit") Then
If Entity.OptionExplicit Then Fail Token, "Duplicate Option statement"
Entity.OptionExplicit = True

Fail Token, "Rule: Option (Base | Compare | Explicit)", "Option"
End If

ElseIf IsKw(Token, "End") Then
Exit Do

Fail Token, "Rule: Option (Base | Compare | Explicit)", "Option"
End If

Set ParseDeclarationArea = Token
End Function

Next week we'll parse Deftypes.

Andrej Biasic