Skip to content

Commit a1ba72c

Browse files
committed
ASTGen: Translate precedence group declarations
1 parent a8db87a commit a1ba72c

File tree

6 files changed

+224
-0
lines changed

6 files changed

+224
-0
lines changed

include/swift/AST/CASTBridging.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,24 @@ void *OperatorDecl_create(BridgedASTContext cContext,
434434
BridgedIdentifier cPrecedenceGroupName,
435435
BridgedSourceLoc cPrecedenceGroupLoc);
436436

437+
typedef enum ENUM_EXTENSIBILITY_ATTR(closed) {
438+
BridgedAssociativityNone,
439+
BridgedAssociativityLeft,
440+
BridgedAssociativityRight,
441+
} BridgedAssociativity;
442+
443+
void *PrecedenceGroupDecl_create(
444+
BridgedDeclContext cDeclContext,
445+
BridgedSourceLoc cPrecedencegroupKeywordLoc, BridgedIdentifier cName,
446+
BridgedSourceLoc cNameLoc, BridgedSourceLoc cLeftBraceLoc,
447+
BridgedSourceLoc cAssociativityKeywordLoc,
448+
BridgedSourceLoc cAssociativityValueLoc,
449+
BridgedAssociativity cAssociativity, BridgedSourceLoc cAssignmentKeywordLoc,
450+
BridgedSourceLoc cAssignmentValueLoc, _Bool isAssignment,
451+
BridgedSourceLoc cHigherThanKeywordLoc, BridgedArrayRef cHigherThanNames,
452+
BridgedSourceLoc cLowerThanKeywordLoc, BridgedArrayRef cLowerThanNames,
453+
BridgedSourceLoc cRightBraceLoc);
454+
437455
typedef enum ENUM_EXTENSIBILITY_ATTR(open) {
438456
BridgedImportKindModule,
439457
BridgedImportKindType,

lib/AST/CASTBridging.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,48 @@ void *OperatorDecl_create(BridgedASTContext cContext,
807807
return static_cast<Decl *>(decl);
808808
}
809809

810+
void *PrecedenceGroupDecl_create(
811+
BridgedDeclContext cDeclContext,
812+
BridgedSourceLoc cPrecedencegroupKeywordLoc, BridgedIdentifier cName,
813+
BridgedSourceLoc cNameLoc, BridgedSourceLoc cLeftBraceLoc,
814+
BridgedSourceLoc cAssociativityKeywordLoc,
815+
BridgedSourceLoc cAssociativityValueLoc,
816+
BridgedAssociativity cAssociativity, BridgedSourceLoc cAssignmentKeywordLoc,
817+
BridgedSourceLoc cAssignmentValueLoc, bool isAssignment,
818+
BridgedSourceLoc cHigherThanKeywordLoc, BridgedArrayRef cHigherThanNames,
819+
BridgedSourceLoc cLowerThanKeywordLoc, BridgedArrayRef cLowerThanNames,
820+
BridgedSourceLoc cRightBraceLoc) {
821+
822+
SmallVector<PrecedenceGroupDecl::Relation, 2> higherThanNames;
823+
for (auto &pair :
824+
convertArrayRef<BridgedIdentifierAndSourceLoc>(cHigherThanNames)) {
825+
higherThanNames.push_back({convertSourceLoc(pair.nameLoc),
826+
convertIdentifier(pair.name), nullptr});
827+
}
828+
829+
SmallVector<PrecedenceGroupDecl::Relation, 2> lowerThanNames;
830+
for (auto &pair :
831+
convertArrayRef<BridgedIdentifierAndSourceLoc>(cLowerThanNames)) {
832+
lowerThanNames.push_back({convertSourceLoc(pair.nameLoc),
833+
convertIdentifier(pair.name), nullptr});
834+
}
835+
836+
auto *decl = PrecedenceGroupDecl::create(
837+
convertDeclContext(cDeclContext),
838+
convertSourceLoc(cPrecedencegroupKeywordLoc), convertSourceLoc(cNameLoc),
839+
convertIdentifier(cName), convertSourceLoc(cLeftBraceLoc),
840+
convertSourceLoc(cAssociativityKeywordLoc),
841+
convertSourceLoc(cAssociativityValueLoc),
842+
static_cast<Associativity>(cAssociativity),
843+
convertSourceLoc(cAssignmentKeywordLoc),
844+
convertSourceLoc(cAssignmentValueLoc), isAssignment,
845+
convertSourceLoc(cHigherThanKeywordLoc), higherThanNames,
846+
convertSourceLoc(cLowerThanKeywordLoc), lowerThanNames,
847+
convertSourceLoc(cRightBraceLoc));
848+
849+
return static_cast<Decl *>(decl);
850+
}
851+
810852
void *ImportDecl_create(BridgedASTContext cContext,
811853
BridgedDeclContext cDeclContext,
812854
BridgedSourceLoc cImportKeywordLoc,

lib/ASTGen/Sources/ASTGen/ASTGen.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,15 @@ extension ASTGenVisitor {
242242

243243
return self.visit(node)
244244
}
245+
246+
@inline(__always)
247+
func visit(_ node: PrecedenceGroupNameListSyntax?) -> BridgedArrayRef {
248+
guard let node else {
249+
return .init()
250+
}
251+
252+
return self.visit(node)
253+
}
245254
}
246255

247256
extension Collection {

lib/ASTGen/Sources/ASTGen/Decls.swift

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,116 @@ extension ASTGenVisitor {
350350
}
351351
}
352352

353+
// MARK: - PrecedenceGroupDecl
354+
355+
extension BridgedAssociativity {
356+
fileprivate init?(from tokenKind: TokenKind) {
357+
switch tokenKind {
358+
case .keyword(.none): self = .none
359+
case .keyword(.left): self = .left
360+
case .keyword(.right): self = .right
361+
default: return nil
362+
}
363+
}
364+
}
365+
366+
extension ASTGenVisitor {
367+
func visit(_ node: PrecedenceGroupDeclSyntax) -> ASTNode {
368+
let (name, nameLoc) = node.name.bridgedIdentifierAndSourceLoc(in: self)
369+
370+
struct PrecedenceGroupBody {
371+
var associativity: PrecedenceGroupAssociativitySyntax? = nil
372+
var assignment: PrecedenceGroupAssignmentSyntax? = nil
373+
var higherThanRelation: PrecedenceGroupRelationSyntax? = nil
374+
var lowerThanRelation: PrecedenceGroupRelationSyntax? = nil
375+
}
376+
377+
func diagnoseDuplicateSyntax(_ duplicate: some SyntaxProtocol, original: some SyntaxProtocol) {
378+
self.diagnose(Diagnostic(node: duplicate, message: DuplicateSyntaxError(duplicate: duplicate, original: original)))
379+
}
380+
381+
let body = node.groupAttributes.reduce(into: PrecedenceGroupBody()) { body, element in
382+
switch element {
383+
case .precedenceGroupRelation(let relation):
384+
let keyword = relation.higherThanOrLowerThanLabel
385+
switch keyword.tokenKind {
386+
case .keyword(.higherThan):
387+
if let current = body.higherThanRelation {
388+
diagnoseDuplicateSyntax(relation, original: current)
389+
} else {
390+
body.higherThanRelation = relation
391+
}
392+
case .keyword(.lowerThan):
393+
if let current = body.lowerThanRelation {
394+
diagnoseDuplicateSyntax(relation, original: current)
395+
} else {
396+
body.lowerThanRelation = relation
397+
}
398+
default:
399+
return self.diagnose(Diagnostic(node: keyword, message: UnexpectedTokenKindError(token: keyword)))
400+
}
401+
case .precedenceGroupAssignment(let assignment):
402+
if let current = body.assignment {
403+
diagnoseDuplicateSyntax(assignment, original: current)
404+
} else {
405+
body.assignment = assignment
406+
}
407+
case .precedenceGroupAssociativity(let associativity):
408+
if let current = body.associativity {
409+
diagnoseDuplicateSyntax(node, original: current)
410+
} else {
411+
body.associativity = associativity
412+
}
413+
}
414+
}
415+
416+
let associativityValue: BridgedAssociativity
417+
if let token = body.associativity?.value {
418+
if let value = BridgedAssociativity(from: token.tokenKind) {
419+
associativityValue = value
420+
} else {
421+
self.diagnose(Diagnostic(node: token, message: UnexpectedTokenKindError(token: token)))
422+
associativityValue = .none
423+
}
424+
} else {
425+
associativityValue = .none
426+
}
427+
428+
let assignmentValue: Bool
429+
if let token = body.assignment?.value {
430+
if token.tokenKind == .keyword(.true) {
431+
assignmentValue = true
432+
} else {
433+
self.diagnose(Diagnostic(node: token, message: UnexpectedTokenKindError(token: token)))
434+
assignmentValue = false
435+
}
436+
} else {
437+
assignmentValue = false
438+
}
439+
440+
return .decl(
441+
PrecedenceGroupDecl_create(
442+
self.declContext,
443+
self.bridgedSourceLoc(for: node.precedencegroupKeyword),
444+
name,
445+
nameLoc,
446+
self.bridgedSourceLoc(for: node.leftBrace),
447+
self.bridgedSourceLoc(for: body.associativity?.associativityLabel),
448+
self.bridgedSourceLoc(for: body.associativity?.value),
449+
associativityValue,
450+
self.bridgedSourceLoc(for: body.assignment?.assignmentLabel),
451+
self.bridgedSourceLoc(for: body.assignment?.value),
452+
assignmentValue,
453+
self.bridgedSourceLoc(for: body.higherThanRelation?.higherThanOrLowerThanLabel),
454+
self.visit(body.higherThanRelation?.precedenceGroups),
455+
self.bridgedSourceLoc(for: body.lowerThanRelation?.higherThanOrLowerThanLabel),
456+
self.visit(body.lowerThanRelation?.precedenceGroups),
457+
self.bridgedSourceLoc(for: node.rightBrace)
458+
)
459+
)
460+
}
461+
}
462+
353463
// MARK: - ImportDecl
354464

355465
extension BridgedImportKind {
@@ -406,4 +516,11 @@ extension ASTGenVisitor {
406516
func visit(_ node: InheritedTypeListSyntax) -> BridgedArrayRef {
407517
node.lazy.map { self.visit($0.type).rawValue }.bridgedArray(in: self)
408518
}
519+
520+
@inline(__always)
521+
func visit(_ node: PrecedenceGroupNameListSyntax) -> BridgedArrayRef {
522+
node.lazy.map {
523+
$0.name.bridgedIdentifierAndSourceLoc(in: self) as BridgedIdentifierAndSourceLoc
524+
}.bridgedArray(in: self)
525+
}
409526
}

lib/ASTGen/Sources/ASTGen/Diagnostics.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,30 @@ struct MissingChildTokenError: ASTGenError {
6666
"""
6767
}
6868
}
69+
70+
/// An error emitted when a syntax collection entry is encountered that is considered a duplicate of a previous entry
71+
/// per the language grammar.
72+
struct DuplicateSyntaxError: ASTGenError {
73+
let duplicate: Syntax
74+
let original: Syntax
75+
76+
init(duplicate: some SyntaxProtocol, original: some SyntaxProtocol) {
77+
precondition(duplicate.kind == original.kind, "Expected duplicate and original to be of same kind")
78+
79+
guard let duplicateParent = duplicate.parent, let originalParent = original.parent, duplicateParent == originalParent, duplicateParent.kind.isSyntaxCollection else {
80+
preconditionFailure("Expected a shared syntax collection parent")
81+
}
82+
83+
self.duplicate = Syntax(duplicate)
84+
self.original = Syntax(original)
85+
}
86+
87+
var message: String {
88+
"""
89+
unexpected duplicate syntax in list:
90+
\(duplicate.debugDescription(indentString: " "))
91+
previous syntax:
92+
\(original.debugDescription(indentString: " "))
93+
"""
94+
}
95+
}

test/ASTGen/verify-parse.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,3 +191,14 @@ operator
191191

192192
postfix
193193
operator ⎩^-^⎩
194+
195+
196+
precedencegroup Precedence1 {
197+
}
198+
199+
precedencegroup Precedence2 {
200+
lowerThan: BitwiseShiftPrecedence, MultiplicationPrecedence
201+
higherThan: Precedence1, AdditionPrecedence
202+
associativity: left
203+
assignment: true
204+
}

0 commit comments

Comments
 (0)