File: OperatorTable.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (154 lines) | stat: -rw-r--r-- 4,908 bytes parent folder | download
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
  }
}