Skip to content

Commit 15a04fc

Browse files
authored
Merge pull request #15873 from rintaro/syntax-precedencegroup
[Syntax] Parse 'precedencegroup' declaration syntax
2 parents dad8b73 + b457500 commit 15a04fc

File tree

5 files changed

+173
-4
lines changed

5 files changed

+173
-4
lines changed

lib/Parse/ParseDecl.cpp

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,6 +2522,7 @@ Parser::parseDecl(ParseDeclOptions Flags,
25222522
DeclResult = parseDeclOperator(Flags, Attributes);
25232523
break;
25242524
case tok::kw_precedencegroup:
2525+
DeclParsingContext.setCreateSyntax(SyntaxKind::PrecedenceGroupDecl);
25252526
DeclResult = parseDeclPrecedenceGroup(Flags, Attributes);
25262527
break;
25272528
case tok::kw_protocol:
@@ -6414,6 +6415,14 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
64146415
diagnose(Tok, diag::expected_precedencegroup_lbrace);
64156416
return createInvalid();
64166417
}
6418+
// Empty body.
6419+
if (Tok.is(tok::r_brace)) {
6420+
// Create empty attribute list.
6421+
SyntaxParsingContext(SyntaxContext,
6422+
SyntaxKind::PrecedenceGroupAttributeList);
6423+
rbraceLoc = consumeToken(tok::r_brace);
6424+
return makeParserResult(create());
6425+
}
64176426

64186427
auto abortBody = [&] {
64196428
skipUntilDeclRBrace();
@@ -6435,8 +6444,9 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
64356444
}
64366445
};
64376446

6447+
64386448
// Parse the attributes in the body.
6439-
while (!consumeIf(tok::r_brace, rbraceLoc)) {
6449+
while (!Tok.is(tok::r_brace)) {
64406450
if (!Tok.is(tok::identifier)) {
64416451
diagnose(Tok, diag::expected_precedencegroup_attribute);
64426452
return abortBody();
@@ -6445,6 +6455,8 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
64456455
auto attrName = Tok.getText();
64466456

64476457
if (attrName == "associativity") {
6458+
SyntaxParsingContext AttrCtxt(SyntaxContext,
6459+
SyntaxKind::PrecedenceGroupAssociativity);
64486460
// "associativity" is considered as a contextual keyword.
64496461
TokReceiver->registerTokenKindChange(Tok.getLoc(),
64506462
tok::contextual_keyword);
@@ -6471,6 +6483,8 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
64716483
}
64726484

64736485
if (attrName == "assignment") {
6486+
SyntaxParsingContext AttrCtxt(SyntaxContext,
6487+
SyntaxKind::PrecedenceGroupAssignment);
64746488
parseAttributePrefix(assignmentKeywordLoc);
64756489

64766490
// "assignment" is considered as a contextual keyword.
@@ -6490,6 +6504,8 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
64906504
bool isLowerThan = false;
64916505
if (attrName == "higherThan" ||
64926506
(isLowerThan = (attrName == "lowerThan"))) {
6507+
SyntaxParsingContext AttrCtxt(SyntaxContext,
6508+
SyntaxKind::PrecedenceGroupRelation);
64936509
// "lowerThan" and "higherThan" are contextual keywords.
64946510
TokReceiver->registerTokenKindChange(Tok.getLoc(),
64956511
tok::contextual_keyword);
@@ -6498,20 +6514,28 @@ Parser::parseDeclPrecedenceGroup(ParseDeclOptions flags,
64986514
auto &relations = (isLowerThan ? lowerThan : higherThan);
64996515

65006516
do {
6517+
SyntaxParsingContext NameCtxt(SyntaxContext,
6518+
SyntaxKind::PrecedenceGroupNameElement);
65016519
if (!Tok.is(tok::identifier)) {
65026520
diagnose(Tok, diag::expected_precedencegroup_relation, attrName);
65036521
return abortBody();
65046522
}
65056523
auto name = Context.getIdentifier(Tok.getText());
65066524
auto loc = consumeToken();
65076525
relations.push_back({loc, name, nullptr});
6508-
} while (consumeIf(tok::comma));
6526+
if (!consumeIf(tok::comma))
6527+
break;
6528+
} while (true);
6529+
SyntaxContext->collectNodesInPlace(SyntaxKind::PrecedenceGroupNameList);
65096530
continue;
65106531
}
65116532

65126533
diagnose(Tok, diag::unknown_precedencegroup_attribute, attrName);
65136534
return abortBody();
65146535
}
6536+
SyntaxContext->collectNodesInPlace(SyntaxKind::PrecedenceGroupAttributeList);
6537+
rbraceLoc = consumeToken(tok::r_brace);
6538+
65156539

65166540
auto result = create();
65176541
if (invalid) result->setInvalid();

lib/Syntax/Status.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@
6767
* DestructorDecl
6868
* EnumDecl
6969
* EnumCaseDecl
70+
* PrecedenceGroupDecl
7071

7172
### Not-started (UnknownDecl):
72-
* PrecedenceGroupDecl
7373
* InfixOperatorDecl
7474
* PrefixOperatorDecl
7575
* PostfixOperatorDecl

test/Syntax/Outputs/round_trip_parse_gen.swift.withkinds

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,4 +459,17 @@ enum E1 <TypeInheritanceClause>: <InheritedType><SimpleTypeIdentifier>String </S
459459
indirect </DeclModifier><DeclModifier>private </DeclModifier>enum E2<GenericParameterClause><<GenericParameter>T</GenericParameter>></GenericParameterClause><TypeInheritanceClause>: <InheritedType><SimpleTypeIdentifier>String </SimpleTypeIdentifier></InheritedType></TypeInheritanceClause><GenericWhereClause>where <ConformanceRequirement><SimpleTypeIdentifier>T</SimpleTypeIdentifier>: <SimpleTypeIdentifier>SomeProtocol </SimpleTypeIdentifier></ConformanceRequirement></GenericWhereClause><MemberDeclBlock>{<EnumCaseDecl>
460460
case <EnumCaseElement>foo, </EnumCaseElement><EnumCaseElement>bar, </EnumCaseElement><EnumCaseElement>baz</EnumCaseElement></EnumCaseDecl>
461461
}</MemberDeclBlock></EnumDecl>
462-
}</MemberDeclBlock></EnumDecl>
462+
}</MemberDeclBlock></EnumDecl><PrecedenceGroupDecl>
463+
464+
precedencegroup FooPrecedence {<PrecedenceGroupRelation>
465+
higherThan: <PrecedenceGroupNameElement>DefaultPrecedence, </PrecedenceGroupNameElement><PrecedenceGroupNameElement>UnknownPrecedence</PrecedenceGroupNameElement></PrecedenceGroupRelation><PrecedenceGroupAssignment>
466+
assignment: false</PrecedenceGroupAssignment><PrecedenceGroupAssociativity>
467+
associativity: none</PrecedenceGroupAssociativity>
468+
}</PrecedenceGroupDecl><PrecedenceGroupDecl>
469+
precedencegroup BarPrecedence {}</PrecedenceGroupDecl><PrecedenceGroupDecl>
470+
precedencegroup BazPrecedence {<PrecedenceGroupAssociativity>
471+
associativity: left</PrecedenceGroupAssociativity><PrecedenceGroupAssignment>
472+
assignment: true</PrecedenceGroupAssignment><PrecedenceGroupAssociativity>
473+
associativity: right</PrecedenceGroupAssociativity><PrecedenceGroupRelation>
474+
lowerThan: <PrecedenceGroupNameElement>DefaultPrecedence</PrecedenceGroupNameElement></PrecedenceGroupRelation>
475+
}</PrecedenceGroupDecl>

test/Syntax/round_trip_parse_gen.swift

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,16 @@ enum E1 : String {
460460
case foo, bar, baz
461461
}
462462
}
463+
464+
precedencegroup FooPrecedence {
465+
higherThan: DefaultPrecedence, UnknownPrecedence
466+
assignment: false
467+
associativity: none
468+
}
469+
precedencegroup BarPrecedence {}
470+
precedencegroup BazPrecedence {
471+
associativity: left
472+
assignment: true
473+
associativity: right
474+
lowerThan: DefaultPrecedence
475+
}

utils/gyb_syntax_support/DeclNodes.py

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,4 +591,123 @@
591591
The cases and other members of this enum.
592592
''')
593593
]),
594+
595+
# precedence-group-decl -> attributes? modifiers? 'precedencegroup'
596+
# identifier '{' precedence-group-attribute-list
597+
# '}'
598+
Node('PrecedenceGroupDecl', kind='Decl', traits=['IdentifiedDecl'],
599+
description='A Swift `precedencegroup` declaration.',
600+
children=[
601+
Child('Attributes', kind='AttributeList', is_optional=True,
602+
description='''
603+
The attributes applied to the 'precedencegroup' declaration.
604+
'''),
605+
Child('Modifiers', kind='ModifierList', is_optional=True,
606+
description='''
607+
The declaration modifiers applied to the 'precedencegroup'
608+
declaration.
609+
'''),
610+
Child('PrecedencegroupKeyword', kind='PrecedencegroupToken'),
611+
Child('Identifier', kind='IdentifierToken',
612+
description='''
613+
The name of this precedence group.
614+
'''),
615+
Child('LeftBrace', kind='LeftBraceToken'),
616+
Child('GroupAttributes', kind='PrecedenceGroupAttributeList',
617+
description='''
618+
The characteristics of this precedence group.
619+
'''),
620+
Child('RightBrace', kind='RightBraceToken'),
621+
]),
622+
623+
# precedence-group-attribute-list ->
624+
# (precedence-group-relation | precedence-group-assignment |
625+
# precedence-group-associativity )*
626+
Node('PrecedenceGroupAttributeList', kind='SyntaxCollection',
627+
element='Syntax',
628+
element_choices=[
629+
'PrecedenceGroupRelation',
630+
'PrecedenceGroupAssignment',
631+
'PrecedenceGroupAssociativity'
632+
]),
633+
634+
# precedence-group-relation ->
635+
# ('higherThan' | 'lowerThan') ':' precedence-group-name-list
636+
Node('PrecedenceGroupRelation', kind='Syntax',
637+
description='''
638+
Specify the new precedence group's relation to existing precedence
639+
groups.
640+
''',
641+
children=[
642+
Child('HigherThanOrLowerThan', kind='IdentifierToken',
643+
text_choices=[
644+
'higherThan', 'lowerThan',
645+
],
646+
description='''
647+
The relation to specified other precedence groups.
648+
'''),
649+
Child('Colon', kind='ColonToken'),
650+
Child('OtherNames', kind='PrecedenceGroupNameList',
651+
description='''
652+
The name of other precedence group to which this precedence
653+
group relates.
654+
'''),
655+
]),
656+
657+
# precedence-group-name-list ->
658+
# identifier (',' identifier)*
659+
Node('PrecedenceGroupNameList', kind='SyntaxCollection',
660+
element='PrecedenceGroupNameElement'),
661+
Node('PrecedenceGroupNameElement', kind='Syntax',
662+
children=[
663+
Child('Name', kind='IdentifierToken'),
664+
Child('TrailingComma', kind='CommaToken',
665+
is_optional=True),
666+
]),
667+
668+
# precedence-group-assignment ->
669+
# 'assignment' ':' ('true' | 'false')
670+
Node('PrecedenceGroupAssignment', kind='Syntax',
671+
description='''
672+
Specifies the precedence of an operator when used in an operation
673+
that includes optional chaining.
674+
''',
675+
children=[
676+
Child('AssignmentKeyword', kind='IdentifierToken',
677+
text_choices=['assignment']),
678+
Child('Colon', kind='ColonToken'),
679+
Child('Flag', kind='Token',
680+
token_choices=[
681+
'TrueToken',
682+
'FalseToken',
683+
],
684+
description='''
685+
When true, an operator in the corresponding precedence group
686+
uses the same grouping rules during optional chaining as the
687+
assignment operators from the standard library. Otherwise,
688+
operators in the precedence group follows the same optional
689+
chaining rules as operators that don't perform assignment.
690+
'''),
691+
]),
692+
693+
# precedence-group-associativity ->
694+
# 'associativity' ':' ('left' | 'right' | 'none')
695+
Node('PrecedenceGroupAssociativity', kind='Syntax',
696+
description='''
697+
Specifies how a sequence of operators with the same precedence level
698+
are grouped together in the absence of grouping parentheses.
699+
''',
700+
children=[
701+
Child('AssociativityKeyword', kind='IdentifierToken',
702+
text_choices=['associativity']),
703+
Child('Colon', kind='ColonToken'),
704+
Child('Value', kind='IdentifierToken',
705+
text_choices=['left', 'right', 'none'],
706+
description='''
707+
Operators that are `left`-associative group left-to-right.
708+
Operators that are `right`-associative group right-to-left.
709+
Operators that are specified with an associativity of `none`
710+
don't associate at all
711+
'''),
712+
]),
594713
]

0 commit comments

Comments
 (0)