Skip to content

Commit 8b49a3b

Browse files
committed
Record prefix and postfix operators in the operator table.
At present, this only ends up checking for duplicate definitions.
1 parent e102660 commit 8b49a3b

File tree

3 files changed

+61
-11
lines changed

3 files changed

+61
-11
lines changed

Sources/SwiftOperatorPrecedence/OperatorPrecedenceError+Diagnostics.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ extension OperatorPrecedenceError : DiagnosticMessage {
2828
return "unknown precedence group '\(groupName)'"
2929

3030
case .operatorAlreadyExists(let existing, _):
31-
return "redefinition of infix operator '\(existing.name)'"
31+
return "redefinition of \(existing.kind) operator '\(existing.name)'"
3232

3333
case .missingOperator(let operatorName, _):
3434
return "unknown infix operator '\(operatorName)'"

Sources/SwiftOperatorPrecedence/OperatorTable.swift

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ import SwiftSyntax
2121
/// syntax tree.
2222
public struct OperatorTable {
2323
var precedenceGraph: PrecedenceGraph = .init()
24-
var operators: [OperatorName : Operator] = [:]
24+
var infixOperators: [OperatorName : Operator] = [:]
25+
var prefixOperators: [OperatorName : Operator] = [:]
26+
var postfixOperators: [OperatorName : Operator] = [:]
2527

2628
public init() { }
2729

@@ -40,19 +42,33 @@ public struct OperatorTable {
4042
}
4143
}
4244

43-
/// Record the operator, if it matters.
44-
mutating func record(
45+
/// Record the operator in the given operator array.
46+
private func record(
4547
_ op: Operator,
48+
in table: inout [OperatorName : Operator],
4649
errorHandler: OperatorPrecedenceErrorHandler = { throw $0 }
4750
) rethrows {
48-
// FIXME: Could do operator-already-exists checking for prefix/postfix
49-
// operators as well, since we parse them.
50-
if op.kind != .infix { return }
51-
52-
if let existing = operators[op.name] {
51+
if let existing = table[op.name] {
5352
try errorHandler(.operatorAlreadyExists(existing: existing, new: op))
5453
} else {
55-
operators[op.name] = op
54+
table[op.name] = op
55+
}
56+
}
57+
58+
/// Record the operator.
59+
mutating func record(
60+
_ op: Operator,
61+
errorHandler: OperatorPrecedenceErrorHandler = { throw $0 }
62+
) rethrows {
63+
switch op.kind {
64+
case .infix:
65+
return try record(op, in: &infixOperators, errorHandler: errorHandler)
66+
67+
case .prefix:
68+
return try record(op, in: &prefixOperators, errorHandler: errorHandler)
69+
70+
case .postfix:
71+
return try record(op, in: &postfixOperators, errorHandler: errorHandler)
5672
}
5773
}
5874

@@ -72,7 +88,7 @@ extension OperatorTable {
7288
referencedFrom syntax: Syntax?,
7389
errorHandler: OperatorPrecedenceErrorHandler = { throw $0 }
7490
) rethrows -> PrecedenceGroupName? {
75-
guard let op = operators[operatorName] else {
91+
guard let op = infixOperators[operatorName] else {
7692
try errorHandler(
7793
.missingOperator(operatorName, referencedFrom: syntax))
7894
return nil

Tests/SwiftOperatorPrecedenceTest/OperatorTable.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,40 @@ public class OperatorPrecedenceTests: XCTestCase {
220220
_ = existingGroup
221221
}
222222

223+
func testUnaryErrors() throws {
224+
let sources =
225+
"""
226+
prefix operator +
227+
prefix operator +
228+
229+
postfix operator -
230+
prefix operator -
231+
232+
postfix operator*
233+
postfix operator*
234+
"""
235+
236+
let parsedOperatorPrecedence = try Parser.parse(source: sources)
237+
238+
var opPrecedence = OperatorTable()
239+
var errors: [OperatorPrecedenceError] = []
240+
opPrecedence.addSourceFile(parsedOperatorPrecedence) { error in
241+
errors.append(error)
242+
}
243+
244+
XCTAssertEqual(errors.count, 2)
245+
guard case let .operatorAlreadyExists(existing, new) = errors[0] else {
246+
XCTFail("expected an 'operator already exists' error")
247+
return
248+
}
249+
250+
XCTAssertEqual(errors[0].message, "redefinition of prefix operator '+'")
251+
252+
XCTAssertEqual(errors[1].message, "redefinition of postfix operator '*'")
253+
_ = existing
254+
_ = new
255+
}
256+
223257
func testFoldErrors() throws {
224258
let parsedOperatorPrecedence = try Parser.parse(source:
225259
"""

0 commit comments

Comments
 (0)