-
Notifications
You must be signed in to change notification settings - Fork 460
Introduce tokenSpecSetType and syntaxChoicesType for child nodes in CodeGeneration
#2011
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
Conversation
ac4c0b0 to
529ccd1
Compare
| /// The name of the child. | ||
| /// | ||
| /// The first character of the name is always uppercase. | ||
| public let name: 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.
I've been thinking about privatizing the name property as proposed in the original discussion but we are using it in the role of id to identify children in tests ValidateSyntaxNodes.swift for example: https://github.com/apple/swift-syntax/blob/e340af46cd6725e1567c42adcbb1ec979bf7f7b4/CodeGeneration/Tests/ValidateSyntaxNodes/ValidateSyntaxNodes.swift#L83-L85
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.
You should be able to do type.description == other.type.description instead of name == other.name here.
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.
Done
| let childType: TypeSyntax = child.kind.isNodeChoicesEmpty ? child.syntaxNodeKind.syntaxType : "\(raw: child.name)" | ||
| let type = child.isOptional ? TypeSyntax("\(raw: childType)?") : TypeSyntax("\(raw: childType)") | ||
| let childType: TypeSyntax = child.kind.isNodeChoicesEmpty ? child.syntaxNodeKind.syntaxType : "\(child.type)" | ||
| let type = child.isOptional ? TypeSyntax("\(childType)?") : TypeSyntax("\(childType)") |
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.
Can be shortened a little bit more to
| let type = child.isOptional ? TypeSyntax("\(childType)?") : TypeSyntax("\(childType)") | |
| let type = child.isOptional ? TypeSyntax("\(childType)?") : childType |
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.
Nice catch! Thanks. Done.
| if i == 0 { | ||
| unexpectedName = "UnexpectedBefore\(child.name)" | ||
| unexpectedDeprecatedName = child.deprecatedName.map { "UnexpectedBefore\($0)" } | ||
| unexpectedName = "UnexpectedBefore\(child.type)" |
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.
I would prefer to do child.name.withFirstLetterUppercased when building the unexpected name. I know that the result is the same as if we used the type name, but that’s more of a coincidence right now. What we’re intending to do here is to stitch the names together and the code should reflect that in my opinion. Otherwise every time I read this, I would wonder: What has the type name to do with the property name here.
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.
I fully agree with you. I guess I was trying too hard to change the code base in order to make child.name private.
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.
Done
| /// If the child has been renamed, its old, now deprecated, name. | ||
| private let deprecatedName: 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.
Any reason why you changed the order of deprecatedName and 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.
Oh yeah :/ - habit from all my projects where we are trying to separate public properties from private ones. Should I revert the changes?
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.
I'm gonna use deprecatedName not deprecatedType to create unexpected nodes names in the same way as you proposed using name instead of type here: #2011 (comment). So I'm gonna revers changes with making deprecatedName private and reordering
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.
Done
| /// The name of the child. | ||
| /// | ||
| /// The first character of the name is always uppercase. | ||
| public let name: 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.
You should be able to do type.description == other.type.description instead of name == other.name here.
529ccd1 to
deda831
Compare
| unexpectedName = "UnexpectedBefore\(child.name)" | ||
| unexpectedDeprecatedName = child.deprecatedName.map { "UnexpectedBefore\($0)" } | ||
| unexpectedName = "UnexpectedBefore\(childName)" | ||
| unexpectedDeprecatedName = child.deprecatedType.map { "UnexpectedBefore\($0)" } |
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.
Just like we do child.name.withFirstCharacterUppercased, we should also do child.deprecatedName.withFirstCharacterUppercased.
And I think below are couple usages of deprecatedName that need to be uppercased once we lowercase deprecatedName.
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.
At least one Child has a deprecated name that begins with a lowercase letter, which is inconsistent with the majority that starts with uppercase. This has led to the generation of an unexpected node name like UnexpectedBeforedeprecatedName. If we want to avoid changing the API, it seems we must adhere to this implementation.
And I think below are couple usages of
deprecatedNamethat need to be uppercased once we lowercase deprecatedName.
Actually, I've not considered changing deprecatedName before. Do you think that we should do that?
I guess it's necessary if we are changing name. But what would be the best course of action regarding the aforementioned edge case?
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.
At least one
Childhas a deprecated name that begins with a lowercase
Oh, that’s a bug. The deprecated name of FunctionType.paramters should be uppercased. Fixing in #2023.
Actually, I've not considered changing
deprecatedNamebefore.
Yes, absolutely, we should also lowercase deprecatedName.
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.
Done
| /// A type of this child. | ||
| public var type: TypeSyntax { | ||
| return "\(raw: name.withFirstCharacterUppercased)" | ||
| } |
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.
Sorry, after reading this PR again, I noticed that this isn’t actually the type of the child, unless it has multiple node choices. What this technically is, is the name that a nested SyntaxChoices type gets, if it gets created. With this in mind, a better name would be syntaxChoicesType and it should fail if the child doesn’t have kind == .nodeChoices to prevent misuse.
| /// A type of this child. | |
| public var type: TypeSyntax { | |
| return "\(raw: name.withFirstCharacterUppercased)" | |
| } | |
| /// If this child has node choices, the type that the nested `SyntaxChildChoices` type should get. | |
| /// | |
| /// For any other kind of child nodes, accessing this property crashes. | |
| public var syntaxChoicesType: TypeSyntax { | |
| precondition(kind.isNodeChoices, "Cannot get syntaxChoicesType for node that doesn’t have nodeChoices") | |
| return "\(raw: name.withFirstCharacterUppercased)" | |
| } |
And I think most of the uses of type in ValidateSyntaxNodes should be varOrCaseName or, where necessary varOrCaseName.description.
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.
It seems very reasonable. I just wondering what about places like this one: https://github.com/apple/swift-syntax/blob/83348e7eb826b978896421b2a233a4290596eb58/CodeGeneration/Sources/generate-swiftsyntax/templates/swiftparser/ParserTokenSpecSetFile.swift#L23C4-L29 ? Do we wanna use name.withFirstCharacterUppercased instead of syntaxChoicesType?
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.
I would introduce a new member on Child. We should really stop sticking type names together in CodeGeneration like this
/// If this child only has tokens, the type that the generated `TokenSpecSet` should get.
///
/// For any other kind of child nodes, accessing this property crashes.
public var syntaxChoicesType: TypeSyntax {
precondition(kind.isToken /* <- you need to write this property, I think */, "Cannot get syntaxChoicesType for node that isn’t a token")
return "\(raw: name.withFirstCharacterUppercased)Options"
}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.
@ahoppen I'm sorry, but I got lost. Could you please summarize once more what we want to achieve?
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.
Did you mean introducing two new properties on Child: one for kind.isNodeChoices and the other for kind.isToken?
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.
Yes, exactly.
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.
Done
deda831 to
aeb8180
Compare
syntaxTokenType and syntaxChoicesType for child nodes in CodeGeneration
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.
Wow, this is a lot nicer. I have one naming suggestion (and I was probably the one who suggested the old name that I now dislike, so sorry for that), otherwise this looks great.
| /// If this child only has tokens, the type that the generated `TokenSpecSet` should get. | ||
| /// | ||
| /// For any other kind of child nodes, accessing this property crashes. | ||
| public var syntaxTokenType: TypeSyntax { |
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.
I’m not sure if I suggested syntaxTokenType but in light of syntaxChoicesType, I think tokenSpecSetType would be a better name.
Also remember to update the precondition below.
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.
Thanks. Done
5850462 to
d8d9a43
Compare
syntaxTokenType and syntaxChoicesType for child nodes in CodeGenerationtokenSpecSetType and syntaxChoicesType for child nodes in CodeGeneration
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.
Thanks for doing this @Matejkob!
|
@swift-ci Please test |
|
@Matejkob Looks like there are some casing issues in the CodeGeneration package. You should be able to reproduce them locally by opening the CodeGeneration package and running the tests in there |
Head branch was pushed to by a user without write access
d8d9a43 to
0381d8f
Compare
Oh, something went wrong during the merge. Now everything should work fine. |
|
@swift-ci Please test |
|
@swift-ci Please test |
This PR ties back to our discussion in #1908. Specifically, @ahoppen proposed this approach:
Here are the tweaks I made:
typeproperty toChild. This returns aTypeSyntaxbuilt from the capitalized child name. @ahoppen initially suggested usingtypeName, but I felt thattypeofTypeSyntaxtype fit better. I'm open to feedback though – should we stick totypeNameof typeTokenSyntax?nametotypein some scenarios:enum accessorSpecifierOptions: TokenSpecSet, and then when used as types, e.g.,ElseBodyforIfExprSyntax.deprecatedTypeandhasDeprecatedNameproperties. This aligns with other parts ofChild, and it means we can makedeprecatedNameprivate, improving encapsulation.