-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[libSyntax] Make parsing of attributes more structured #16117
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
@swift-ci Please smoke test |
@swift-ci Please smoke test |
If the attribute takes arguments, the closing parenthesis. | ||
'''), | ||
# TokenList to gather remaining tokens of invalid attributes | ||
Child('TokenList', kind='TokenList', is_optional=True), |
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.
Is it possible to make TokenList
be a choice of Child('Argument')
?
I mean, invalid argument could be constructed as '@' identifier ('(' token-list ')')?
.
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 actually like to get rid of TokenList
completely. It is only used here and for closure capture items. Maybe I should add a FIXME instead.
node_choices=[ | ||
Child('Identifier', kind='IdentifierToken'), | ||
Child('String', kind='StringLiteralToken'), | ||
Child('Integer', kind='IntegerLiteralToken'), |
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.
Which attribute uses IntegerLiteralToken
as the argument?
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.
@_alignment
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! Could you add a test case?
lib/Parse/SyntaxParsingContext.cpp
Outdated
@@ -189,6 +190,8 @@ void SyntaxParsingContext::createNodeInPlace(SyntaxKind Kind) { | |||
case SyntaxKind::MemberTypeIdentifier: | |||
case SyntaxKind::FunctionCallExpr: | |||
case SyntaxKind::SubscriptExpr: | |||
case SyntaxKind::AvailabilitySpecList: | |||
case SyntaxKind::AvailabilityArgument: |
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 don't think these are used. Am I missing something?
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.
AvailabilityArgument
are the children of AvailabilitySpecList
and AvailabilitySpecList
is one of the options for Attribute.Arguments
or AvailabilityCondition
.
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.
Ah, sorry. I meant createNodeInPlace(SyntaxKind::AvailabilitySpecList)
is not used, nor AvailabilityArgument
.
This switch
is not supposed to be exhaustive.
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.
Ah, OK. I added them while trying to fix it and will remove them again.
lib/Parse/ParseDecl.cpp
Outdated
StringRef AttrName = "_specialize"; | ||
AvailableAttr *Parser::parseExtendedAvailabilitySpecList( | ||
SourceLoc AtLoc, SourceLoc AttrStartLoc, StringRef Platform, | ||
StringRef AttrName, SourceLoc AttrLoc, bool &DiscardAttribute) { |
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 function returns the attribute itself, naming
parseExtendedAvailabilityAttribute
might be more relevant IMO. - Return
ParserResult<AvailableAttr>
withoutbool &DiscardAttribute
likeparseImplementsAttribute
. AttrLoc
andAttrStartLoc
is the same. Please consolidate them.Platform
can be retrieved withTok.getText()
inside the function.
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 motivation for factoring out this function was that it could create a SyntaxParsingContext
with kind AvailabilitySpecList
for its entire scope so we don't have to create a code block that for that context that spans nearly 200 lines of code. That's why it also doesn't parse the trailing )
.
I will implement 2, 3, and 4. Thanks.
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.
Have you tried collectNodesInPlace(SyntaxKind::AvailabilitySpecList)
without creating SyntaxParsingContext
in parseExtendedAvailabilitySpecList
?
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.
Actually, AtLoc
andAttrLoc
are different, AtLoc
refers to where the @
is, AttrLoc
where the name of the attribute starts.
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, that doesn't work because the opening (
is still on the stack of items to be parsed and doesn't fit into the AvailabilitySpecList
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.
AtLoc
!= AttrLoc
but AttrStartLoc
== AttrLoc
, right?
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. Sorry, misread your comment. You're right of course
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, that doesn't work because the opening
(
is still on the stack of items
It should work. For example, in parseDeclEnumCase()
, collectNodesInPlace(SyntaxKind::EnumCaseElementList)
turns
{ 'case', element, element, element ...}
into { 'case', element-list }
.
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.
OK, it does seem to work. I'm pretty sure I tried before and it didn't but maybe I'm mixing things up. It's not needed though since I keep the parsing logic for )
outside of the refactored function.
lib/Parse/ParseDecl.cpp
Outdated
|
||
AttrRange = SourceRange(Loc, Tok.getLoc()); | ||
auto AvailabilityAttr = parseExtendedAvailabilitySpecList( | ||
AtLoc, Loc, Platform, AttrName, Loc, DiscardAttribute); | ||
|
||
if (!consumeIf(tok::r_paren)) { |
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.
IMO, )
should be parsed in the refactored function.
I guess you leave it here because (
is parsed in this function, but still... What do you think?
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.
Combining comments above, the call-site can be something like:
ParserResult<AvailableAttr> Attr =
parseExtendedAvailabilityAttribute(AtLoc, Loc, AttrName);
if (Attr.isNonNull()) {
Attributes.add(Attr.get());
}
break;
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.
See above
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.
Thinking about it, I would leave it as it is. The parsing of @available
attributes is slightly weird because there are the two variants @available(*, …)
and @available(iOS 10, *)
that are handled inside the switch. I don't want to parse )
inside the refactored function and (
outside and everything else would require ripping apart the entire parsing logic and I don't think it's worth it.
a5ac617
to
7a49737
Compare
@swift-ci Please smoke test |
This also fixes several issues where attribute arguments could not be parsed as a TokenList since some of its arguments already had structure and were not tokens
@swift-ci Please smoke test |
@rintaro Unless you have any further comments, I'll be merging this tonight. |
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.
Looks good!
Add significantly more structure to the way the attributes are parsed in libSyntax by no longer parsing the arguments as a
TokenList
. This way we can also parse@_specialize
attributes correctly which can have aGenericWhereClause
as one of its arguments.