-
Notifications
You must be signed in to change notification settings - Fork 529
Expand file tree
/
Copy pathOperatorTable+Semantics.swift
More file actions
187 lines (165 loc) · 5.79 KB
/
Copy pathOperatorTable+Semantics.swift
File metadata and controls
187 lines (165 loc) · 5.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#if compiler(>=6)
public import SwiftSyntax
#else
import SwiftSyntax
#endif
extension PrecedenceGroup {
/// Form the semantic definition of a precedence group given its syntax.
///
/// TODO: This ignores all semantic errors.
init(from syntax: PrecedenceGroupDeclSyntax) {
self.name = syntax.name.text
self.syntax = syntax
for attr in syntax.groupAttributes {
switch attr {
// Relation (lowerThan, higherThan)
case .precedenceGroupRelation(let relation):
let isLowerThan = relation.higherThanOrLowerThanLabel.tokenKind == .keyword(.lowerThan)
for otherGroup in relation.precedenceGroups {
let otherGroupName = otherGroup.name.text
let relationKind: PrecedenceRelation.Kind =
isLowerThan
? .lowerThan
: .higherThan
let relation = PrecedenceRelation(
kind: relationKind,
groupName: otherGroupName,
syntax: otherGroup
)
self.relations.append(relation)
}
// Assignment
case .precedenceGroupAssignment(let assignment):
self.assignment = assignment.value.tokenKind == .keyword(.true)
// Associativity
case .precedenceGroupAssociativity(let associativity):
switch associativity.value.tokenKind {
case .keyword(.left):
self.associativity = .left
case .keyword(.right):
self.associativity = .right
case .keyword(.none):
self.associativity = .none
default:
break
}
#if RESILIENT_LIBRARIES
@unknown default:
fatalError()
#endif
}
}
}
}
extension Operator {
/// Form the semantic definition of an operator given its syntax.
///
/// TODO: This ignores all semantic errors.
init(from syntax: OperatorDeclSyntax) {
self.syntax = syntax
kind = OperatorKind(rawValue: syntax.fixitySpecifier.text) ?? .infix
name = syntax.name.text
precedenceGroup = syntax.operatorPrecedenceAndTypes?.precedenceGroup.text
}
}
extension OperatorTable {
/// Integrate the operator and precedence group declarations from the given
/// source file into the operator precedence tables.
public mutating func addSourceFile(
_ sourceFile: SourceFileSyntax,
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows {
class OperatorAndGroupVisitor: SyntaxAnyVisitor {
var opPrecedence: OperatorTable
var errors: [OperatorError] = []
init(opPrecedence: OperatorTable) {
self.opPrecedence = opPrecedence
super.init(viewMode: .fixedUp)
}
private func errorHandler(error: OperatorError) {
errors.append(error)
}
override func visit(
_ node: OperatorDeclSyntax
) -> SyntaxVisitorContinueKind {
opPrecedence.record(
Operator(from: node),
errorHandler: errorHandler
)
return .skipChildren
}
override func visit(
_ node: PrecedenceGroupDeclSyntax
) -> SyntaxVisitorContinueKind {
opPrecedence.record(
PrecedenceGroup(from: node),
errorHandler: errorHandler
)
return .skipChildren
}
// Only visit top-level entities to find operators and precedence groups.
override func visit(
_ node: SourceFileSyntax
) -> SyntaxVisitorContinueKind {
return .visitChildren
}
override func visit(
_ node: CodeBlockItemListSyntax
) -> SyntaxVisitorContinueKind {
return .visitChildren
}
override func visit(
_ node: CodeBlockItemSyntax
) -> SyntaxVisitorContinueKind {
return .visitChildren
}
// Everything else stops the visitation.
override func visitAny(_ node: Syntax) -> SyntaxVisitorContinueKind {
return .skipChildren
}
}
let visitor = OperatorAndGroupVisitor(opPrecedence: self)
visitor.walk(sourceFile)
try visitor.errors.forEach(errorHandler)
self = visitor.opPrecedence
}
/// Determine the precedence of one precedence group relative to another.
///
/// - Parameters:
/// - firstGroupName: The precedence group whose position is being queried.
/// - secondGroupName: The precedence group being compared against.
/// - syntax: A syntax node used as the reference location when reporting
/// errors encountered while walking the precedence-group relationships.
/// - errorHandler: A handler invoked when an inconsistency is found in
/// the precedence-group relationships. By default the underlying
/// `OperatorError` is re-thrown.
/// - Returns: ``Precedence/higherThan`` if `firstGroupName` has higher
/// precedence than `secondGroupName`, ``Precedence/lowerThan`` if it has
/// lower precedence, and ``Precedence/unrelated`` otherwise (including
/// when both names refer to the same precedence group).
public func precedence(
of firstGroupName: PrecedenceGroupName,
relativeTo secondGroupName: PrecedenceGroupName,
referencedFrom syntax: Syntax,
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows -> Precedence {
return try precedenceGraph.precedence(
relating: firstGroupName,
to: secondGroupName,
startSyntax: syntax,
endSyntax: syntax,
errorHandler: errorHandler
)
}
}