Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions Sources/SwiftOperators/OperatorTable+Semantics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,33 @@ extension OperatorTable {
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
)
}
}
4 changes: 2 additions & 2 deletions Sources/SwiftOperators/PrecedenceGraph.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ import SwiftSyntax
#endif

/// Describes the relative precedence of two groups.
enum Precedence: Sendable {
public enum Precedence: Sendable {
case unrelated
case higherThan
case lowerThan

/// Flip the precedence order around.
var flipped: Precedence {
public var flipped: Precedence {
switch self {
case .unrelated:
return .unrelated
Expand Down
55 changes: 55 additions & 0 deletions Tests/SwiftOperatorsTest/OperatorTableTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -441,4 +441,59 @@ class OperatorPrecedenceTests: XCTestCase {
let folded = try OperatorTable.standardOperators.foldAll(original)
XCTAssertEqual(original.description, folded.description)
}

func testPrecedenceGroupComparison() throws {
let opPrecedence = OperatorTable.standardOperators
let syntax = Syntax(ExprSyntax("x"))

// MultiplicationPrecedence has "higherThan: AdditionPrecedence" in the
// standard operators, so comparing the two groups directly should return
// the corresponding relationship in both directions.
XCTAssertEqual(
try opPrecedence.precedence(
of: "MultiplicationPrecedence",
relativeTo: "AdditionPrecedence",
referencedFrom: syntax
),
.higherThan
)
XCTAssertEqual(
try opPrecedence.precedence(
of: "AdditionPrecedence",
relativeTo: "MultiplicationPrecedence",
referencedFrom: syntax
),
.lowerThan
)

// Comparing a group to itself should always be reported as unrelated.
XCTAssertEqual(
try opPrecedence.precedence(
of: "AdditionPrecedence",
relativeTo: "AdditionPrecedence",
referencedFrom: syntax
),
.unrelated
)

// Two groups that both sit above `TernaryPrecedence` but have no direct
// or transitive relationship to each other should be reported as unrelated.
// In the standard operator table, `DefaultPrecedence` and
// `LogicalDisjunctionPrecedence` are both declared `higherThan:
// TernaryPrecedence` with no other links between them.
XCTAssertEqual(
try opPrecedence.precedence(
of: "DefaultPrecedence",
relativeTo: "LogicalDisjunctionPrecedence",
referencedFrom: syntax
),
.unrelated
)
}

func testPrecedenceGroupFlipped() {
XCTAssertEqual(Precedence.higherThan.flipped, .lowerThan)
XCTAssertEqual(Precedence.lowerThan.flipped, .higherThan)
XCTAssertEqual(Precedence.unrelated.flipped, .unrelated)
}
}