Skip to content

Commit

Permalink
Fix parsing of subtract operators with parameter type disambiguation
Browse files Browse the repository at this point in the history
  • Loading branch information
d-ronnqvist committed Dec 14, 2023
1 parent d4371a8 commit 3827762
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import SymbolKit
/// All known symbol kind identifiers.
///
/// This is used to identify parsed path components as kind information.
private let knownSymbolKinds: Set<String> = {
private let knownSymbolKinds: Set<Substring> = {
// We don't want to register these extended symbol kinds because that makes them available for decoding from symbol graphs which isn't expected.
return Set(
(SymbolGraph.Symbol.KindIdentifier.allCases + [
Expand All @@ -24,7 +24,7 @@ private let knownSymbolKinds: Set<String> = {
.extendedEnumeration,
.unknownExtendedType,
.extendedModule
]).map(\.identifier)
]).map { $0.identifier[...] }
)
}()

Expand Down Expand Up @@ -89,7 +89,7 @@ extension PathHierarchy.PathParser {
return index > 0
}

if knownSymbolKinds.contains(String(disambiguation)) {
if knownSymbolKinds.contains(disambiguation) {
// The parsed hash value is a symbol kind. If the last disambiguation is a kind, then the path component doesn't contain a hash disambiguation.
return PathComponent(full: full, name: name, disambiguation: .kindAndHash(kind: disambiguation, hash: nil))
}
Expand All @@ -101,7 +101,7 @@ extension PathHierarchy.PathParser {
if let dashIndex = name.lastIndex(of: "-") {
let kind = name[dashIndex...].dropFirst()
let name = name[..<dashIndex]
if knownSymbolKinds.contains(String(kind)) {
if knownSymbolKinds.contains(kind) {
return PathComponent(full: full, name: name, disambiguation: .kindAndHash(kind: kind, hash: disambiguation))
} else if let languagePrefix = knownLanguagePrefixes.first(where: { kind.starts(with: $0) }) {
let kindWithoutLanguage = kind.dropFirst(languagePrefix.count)
Expand Down Expand Up @@ -162,14 +162,32 @@ extension PathHierarchy.PathParser {

return result
}

static func parseOperatorName(_ component: Substring) -> Substring? {
guard
// Operators start with at least one operator head character
let first = component.unicodeScalars.first,
first.isValidOperatorHead,
// Followed by either a list of parameters or additional operator head characters
let second = component.unicodeScalars.dropFirst().first,
second == "(" || second.isValidOperatorHead
else {
return nil
}

guard let operatorEndIndex = component.firstIndex(of: PathComponentScanner.operatorEnd) else {
return component
}
return component[...operatorEndIndex]
}
}

private struct PathComponentScanner {
private var remaining: Substring

static let separator: Character = "/"
private static let anchorSeparator: Character = "#"
private static let operatorEnd: Character = ")"
static let operatorEnd: Character = ")"

init(_ original: Substring) {
remaining = original
Expand All @@ -181,14 +199,9 @@ private struct PathComponentScanner {

mutating func scanPathComponent() -> Substring {
// If the next component is an operator, parse the full operator before splitting on "/" ("/" may appear in the operator name)
if remaining.unicodeScalars.prefix(3).allSatisfy(\.isValidOperatorHead) {
guard let operatorEndIndex = remaining.firstIndex(of: Self.operatorEnd) else {
defer { remaining.removeAll() }
return remaining
}

var component = remaining[..<operatorEndIndex]
remaining = remaining[operatorEndIndex...]
if let operatorName = PathHierarchy.PathParser.parseOperatorName(remaining) {
var component = operatorName
remaining = remaining[operatorName.endIndex...]

guard let index = remaining.firstIndex(of: Self.separator) else {
defer { remaining.removeAll() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,15 @@ extension PathHierarchy.PathParser {
// │
// return type(s) Result

let possibleDisambiguationText: Substring
if let name = parseOperatorName(original) {
possibleDisambiguationText = original[name.endIndex...]
} else {
possibleDisambiguationText = original
}

// Look for the start of the parameter disambiguation.
if let parameterStartRange = original.range(of: "-(") {
if let parameterStartRange = possibleDisambiguationText.range(of: "-(") {
let name = original[..<parameterStartRange.lowerBound]
var scanner = StringScanner(original[parameterStartRange.upperBound...])

Expand All @@ -74,7 +81,7 @@ extension PathHierarchy.PathParser {
let returnTypes = scanner.scanArguments() // The return types (tuple or not) can be parsed the same as the arguments
return PathComponent(full: String(original), name: name, disambiguation: .typeSignature(parameterTypes: parameterTypes, returnTypes: returnTypes))
}
} else if let parameterStartRange = original.range(of: "->") {
} else if let parameterStartRange = possibleDisambiguationText.range(of: "->") {
let name = original[..<parameterStartRange.lowerBound]
var scanner = StringScanner(original[parameterStartRange.upperBound...])

Expand Down

0 comments on commit 3827762

Please sign in to comment.