-
Notifications
You must be signed in to change notification settings - Fork 439
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
@@ -58,16 +58,14 @@ public enum ChildKind { | |||
/// A child of a node, that may be declared optional or a token with a | |||
/// restricted subset of acceptable kinds or texts. | |||
public class Child { | |||
/// If the child has been renamed, its old, now deprecated, name. | |||
private let deprecatedName: String? | |||
|
|||
/// 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.
@@ -118,14 +118,14 @@ public class Node { | |||
let unexpectedDeprecatedName: String? | |||
|
|||
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
@@ -58,16 +58,14 @@ public enum ChildKind { | |||
/// A child of a node, that may be declared optional or a token with a | |||
/// restricted subset of acceptable kinds or texts. | |||
public class Child { | |||
/// If the child has been renamed, its old, now deprecated, name. | |||
private let deprecatedName: String? | |||
|
|||
/// 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
deprecatedName
that 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
Child
has 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
deprecatedName
before.
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:
type
property toChild
. This returns aTypeSyntax
built from the capitalized child name. @ahoppen initially suggested usingtypeName
, but I felt thattype
ofTypeSyntax
type fit better. I'm open to feedback though – should we stick totypeName
of typeTokenSyntax
?name
totype
in some scenarios:enum accessorSpecifierOptions: TokenSpecSet
, and then when used as types, e.g.,ElseBody
forIfExprSyntax
.deprecatedType
andhasDeprecatedName
properties. This aligns with other parts ofChild
, and it means we can makedeprecatedName
private, improving encapsulation.