I have an alpha-quality RealStudio project that does this. I stopped working on it because I can’t think of a use for it that wouldn’t violate the Xojo EULA. Here it is examining its own .rbvcp file:
At the root of the class hierarchy is the BaseTag class, representing a single Xojo text format #tag entry. The project file class is a subclass, as are top-level siblings like ClassTag and MethodTag. Class-like project items inherit from the ClassTag class; method-like project items inherit from the MethodTag class. etc.
BaseTag
|-ProjectFile
|-MethodTag
| +-EventTag
| +-DelegateTag
| -ClassTag
| +-WindowTag
| +-ControlTag
etc.
The BaseTag class has computed properties that call protected methods of the BaseTag class which are then overridden by subclasses as necessary.
So, for example, the BaseTag class has a property called Signature As String, which calls Tag.GetSignature() As String, which is overridden by the ClassTag, MethodTag, etc. subclasses to return an appropriately-formatted signature (Protected Class Foo, Private Sub Bar(i As Integer), etc.)
Each subclass knows how to parse its particular type of project item. The ProjectFile class knows about file-level items like classes, modules, build automation, etc. that are listed in the project manifest. For each of these it creates an appropriate subclass of BaseTag, which then takes over parsing and which may or may not itself create subclasses of BaseTag for its own sub-items.
So, ProjectFile.ParseNow() encounters a class file, and calls ClassTag.Constructor to parse the whole file. ClassTag.Constructor encounters methods and properties of the class and calls MethodTag.Constructor and PropertyTag.Constructor to parse those items and store them as a property of the ClassTag.
Once parsed, you can do interesting things, almost like Introspection but with the source code (extrospection?):
Dim prj As New RBParse.ProjectFile(TheProjectAsFolderItem)
prj.ParseNow()
Dim tagtypes() As Integer = Array(TAG_TYPE_PROPERTY, TAG_TYPE_COMPUTED)
Dim props() As RBParse.Tag = prj.GetTagsByType(tagtypes)
For i As Integer = 0 To UBound(props)
If props(i).Scope = "Protected" Then ' .Scope inherited from BaseTag
' etc.
Methods like GetTagsByType, GetTagsByName, and GetTagsByContents, and properties like Scope As String and RichSignature As String are inherited from BaseTag and can be called on any subclass.
IDK if that’s the best way to do it, but it does work. The code is not public because of the previously-mentioned EULA concerns, but if anyone’s interested in looking at it I can add them to the private Github repo. I’ve also uploaded a Windows build in case anyone wants to play with it. No EULA concerns since it’s read-only.