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
|
//===----------------------------------------------------------------------===//
//
// 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 swift(>=6)
internal import SwiftSyntax
#else
import SwiftSyntax
#endif
/// Maintains and validates information about all operators in a Swift program.
///
/// The operator table keep track of the various operator and precedence group
/// declarations within a program. Its core operations involve processing the
/// operator and precedence group declarations from a source tree into a
/// semantic representation, validating the correctness of those declarations,
/// and "folding" sequence expression syntax into a structured expression
/// syntax tree.
public struct OperatorTable: Sendable {
var precedenceGraph: PrecedenceGraph = .init()
var infixOperators: [OperatorName: Operator] = [:]
var prefixOperators: [OperatorName: Operator] = [:]
var postfixOperators: [OperatorName: Operator] = [:]
public init() {}
/// Initialize the operator precedence instance with a given set of
/// operators and precedence groups.
@_optimize(none)
public init(
precedenceGroups: [PrecedenceGroup],
operators: [Operator],
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows {
for group in precedenceGroups {
try record(group, errorHandler: errorHandler)
}
for op in operators {
try record(op, errorHandler: errorHandler)
}
}
/// Record the operator in the given operator array.
private func record(
_ op: Operator,
in table: inout [OperatorName: Operator],
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows {
if let existing = table[op.name] {
try errorHandler(.operatorAlreadyExists(existing: existing, new: op))
} else {
table[op.name] = op
}
}
/// Record the operator.
mutating func record(
_ op: Operator,
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows {
switch op.kind {
case .infix:
return try record(op, in: &infixOperators, errorHandler: errorHandler)
case .prefix:
return try record(op, in: &prefixOperators, errorHandler: errorHandler)
case .postfix:
return try record(op, in: &postfixOperators, errorHandler: errorHandler)
}
}
/// Record the precedence group.
mutating func record(
_ group: PrecedenceGroup,
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows {
try precedenceGraph.add(group, errorHandler: errorHandler)
}
}
extension OperatorTable {
/// Returns the ``Operator`` corresponding to the given infix operator, or
/// `nil` if it is not defined in the operator table.
public func infixOperator(named operatorName: OperatorName) -> Operator? {
return infixOperators[operatorName]
}
/// Returns the ``Operator`` corresponding to the given prefix operator, or
/// `nil` if it is not defined in the operator table.
public func prefixOperator(named operatorName: OperatorName) -> Operator? {
return prefixOperators[operatorName]
}
/// Returns the ``Operator`` corresponding to the given prefix operator, or
/// `nil` if it is not defined in the operator table.
public func postfixOperator(named operatorName: OperatorName) -> Operator? {
return postfixOperators[operatorName]
}
/// Look for the precedence group corresponding to the given operator.
func lookupOperatorPrecedenceGroupName(
_ operatorName: OperatorName,
referencedFrom syntax: Syntax,
errorHandler: OperatorErrorHandler = { throw $0 }
) rethrows -> PrecedenceGroupName? {
guard let op = infixOperator(named: operatorName) else {
try errorHandler(
.missingOperator(operatorName, referencedFrom: syntax)
)
return nil
}
return op.precedenceGroup
}
}
extension OperatorTable: CustomStringConvertible {
/// The description of an operator table is the source code that produces it.
public var description: String {
var result = ""
// Turn all of the dictionary values into their string representations.
func add<Key: Comparable, Value: CustomStringConvertible>(
_ dict: [Key: Value]
) {
if dict.isEmpty {
return
}
result.append(
contentsOf: dict.sorted { $0.key < $1.key }
.map { $0.value.description }
.joined(separator: "\n")
)
result += "\n"
}
add(precedenceGraph.precedenceGroups)
add(prefixOperators)
add(postfixOperators)
add(infixOperators)
return result
}
}
|