-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implementing a structured traverser so the writer can have the full state #49
Implementing a structured traverser so the writer can have the full state #49
Conversation
The cursor tree support is a bit verbose as I ensured it could build full trees for all the Windows SDK files. Most of the information isn't used anywhere yet as I preserved the existing behavior/handling that the writer had (so no changes if you regenerate ClangSharp or LLVMSharp). |
Another way of looking at this is it is taking the |
private readonly Dictionary<string, OutputBuilder> _outputBuilders; | ||
private readonly Stack<CXCursor> _processingCursors; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to track most of this state anymore.
|
||
switch (cursor.Kind) | ||
private string EscapeName(string name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The helper functions for generating names are the same as before, but pulling from the Cursor
types rather than directly from CXCursor
.
{ | ||
return "ushort"; | ||
Unhandled(decl, pointeeType); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Handling BinaryOperator
is really simple now that we are directly tracking the LhsExpr
and RhsExpr
{ | ||
return "ushort"; | ||
Unhandled(decl, pointeeType); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Likewise for ParenExpr
, plus we don't need to track how deep we are in the expression tree anymore.
{ | ||
return "ushort"; | ||
Unhandled(decl, pointeeType); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This handles nested declarations, if they exist and places them just after the list of fields.
|
||
case CXCursorKind.CXCursor_FieldDecl: | ||
{ | ||
var fieldDecl = GetOrAddChild<FieldDecl>(childHandle); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most code paths in these types aren't consumed by generating LLVMSharp or ClangSharp, but they can be used for generating things like the Windows SDK.
Child cursors that represent useful information for a given cursor kind can be exposed directly to the writer, such as the FieldDecl
here. The writer can then handle that data first before falling back to normal processing for any remaining children.
{ | ||
Debug.Assert(handle.Kind == CXCursorKind.CXCursor_IntegerLiteral); | ||
|
||
_rawValue = new Lazy<string>(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also relegate cursor specific logic, like extracting the raw text for an IntegerLiteral
to the type itself, since it isn't really related to the writer.
|
||
set | ||
{ | ||
Debug.Assert(_expr is null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are also able to do additional sanity checks, such as an UnaryOperator
only having a single expression (which can itself have sub-expressions).
LGTM, took a while to review. |
Thanks, and sorry for the big PR. Subsequent ones should hopefully be smaller now and should mostly be restricted to the writer understanding more metadata from the traversed tree. |
This splits apart the visitor and the writer into two separate passes. Ultimately, this means that when writing files out to disk, we have the full state of the structure available for use.
During the initial traversal which builds the cursor tree, we are able to do some introspection about the cursor, such as being able to track the lhs and rhs of a binary operator, or being able to explicitly track function parameters or field declarations separately from other child cursors.
The writer then can worry about managing less state and only needs to track the output builders themselves plus which cursors have been visited.
This should also make it easier to process more complex expressions or statements in the writer.