Skip to content

Commit 1fe6d90

Browse files
authored
Merge pull request #2576 from adammcarter/adamcarter93/separate-backtick-tokens
Add Identifier wrapper that strips backticks from token text
2 parents 83ee689 + 53234d8 commit 1fe6d90

File tree

5 files changed

+118
-0
lines changed

5 files changed

+118
-0
lines changed

Release Notes/601.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
- Issue: https://github.com/apple/swift-syntax/issues/405
88
- Pull Request: https://github.com/apple/swift-syntax/pull/2605
99

10+
- `TokenSyntax.identifier`
11+
- Description: Adds an `identifier` property to `TokenSyntax` which returns a canonicalized representation of an identifier that strips away backticks.
12+
- Pull request: https://github.com/apple/swift-syntax/pull/2576
13+
1014
## API Behavior Changes
1115

1216
## Deprecations

Sources/SwiftSyntax/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ add_swift_syntax_library(SwiftSyntax
1515
CommonAncestor.swift
1616
Convenience.swift
1717
CustomTraits.swift
18+
Identifier.swift
1819
MemoryLayout.swift
1920
MissingNodeInitializers.swift
2021
SourceEdit.swift

Sources/SwiftSyntax/Identifier.swift

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
/// A canonicalized representation of an identifier that strips away backticks.
14+
public struct Identifier: Equatable, Hashable, Sendable {
15+
/// The sanitized `text` of a token.
16+
public var name: String {
17+
String(syntaxText: raw.name)
18+
}
19+
20+
@_spi(RawSyntax)
21+
public let raw: RawIdentifier
22+
23+
private let arena: SyntaxArenaRef
24+
25+
public init?(_ token: TokenSyntax) {
26+
guard case .identifier = token.tokenKind else {
27+
return nil
28+
}
29+
30+
self.raw = RawIdentifier(token.tokenView)
31+
self.arena = token.tokenView.raw.arenaReference
32+
}
33+
}
34+
35+
@_spi(RawSyntax)
36+
public struct RawIdentifier: Equatable, Hashable, Sendable {
37+
public let name: SyntaxText
38+
39+
@_spi(RawSyntax)
40+
fileprivate init(_ raw: RawSyntaxTokenView) {
41+
let backtick = SyntaxText("`")
42+
if raw.rawText.count > 2 && raw.rawText.hasPrefix(backtick) && raw.rawText.hasSuffix(backtick) {
43+
let startIndex = raw.rawText.index(after: raw.rawText.startIndex)
44+
let endIndex = raw.rawText.index(before: raw.rawText.endIndex)
45+
self.name = SyntaxText(rebasing: raw.rawText[startIndex..<endIndex])
46+
} else {
47+
self.name = raw.rawText
48+
}
49+
}
50+
}

Sources/SwiftSyntax/TokenSyntax.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,16 @@ public struct TokenSyntax: SyntaxProtocol, SyntaxHashable {
153153
}
154154
}
155155

156+
/// An identifier created from `self`.
157+
public var identifier: Identifier? {
158+
switch self.tokenKind {
159+
case .identifier, .dollarIdentifier:
160+
return Identifier(self)
161+
default:
162+
return nil
163+
}
164+
}
165+
156166
/// A token by itself has no structure, so we represent its structure by an
157167
/// empty layout node.
158168
///
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2024 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
@_spi(RawSyntax) import SwiftSyntax
14+
import XCTest
15+
16+
class IdentifierTests: XCTestCase {
17+
public func testIdentifierInit() {
18+
let someToken = TokenSyntax(stringLiteral: "someToken")
19+
XCTAssertNotNil(Identifier(someToken))
20+
21+
let nonIdentifierToken = DeclSyntax("let a = 1").firstToken(viewMode: .all)!
22+
XCTAssertNil(Identifier(nonIdentifierToken))
23+
}
24+
25+
public func testName() {
26+
let basicToken = TokenSyntax(stringLiteral: "basicToken")
27+
XCTAssertEqual(Identifier(basicToken)?.name, "basicToken")
28+
29+
let backtickedToken = TokenSyntax(stringLiteral: "`backtickedToken`")
30+
XCTAssertEqual(Identifier(backtickedToken)?.name, "backtickedToken")
31+
32+
let multiBacktickedToken = TokenSyntax(stringLiteral: "```multiBacktickedToken```")
33+
XCTAssertEqual(Identifier(multiBacktickedToken)?.name, "``multiBacktickedToken``")
34+
35+
let unicodeNormalizedToken = TokenSyntax(stringLiteral: "\u{e0}") // "a`"
36+
XCTAssertEqual(Identifier(unicodeNormalizedToken)?.name, "\u{61}\u{300}") // "à"
37+
}
38+
39+
public func testIdentifier() {
40+
let token = TokenSyntax(stringLiteral: "sometoken")
41+
withExtendedLifetime(token) { token in
42+
XCTAssertEqual(token.identifier?.raw.name, SyntaxText("sometoken"))
43+
}
44+
}
45+
46+
public func testTokenSyntaxIdentifier() throws {
47+
let tokenSyntax = TokenSyntax(stringLiteral: "sometoken")
48+
XCTAssertEqual(tokenSyntax.identifier, Identifier(tokenSyntax))
49+
50+
let nonIdentifierToken = try XCTUnwrap(DeclSyntax("let a = 1").firstToken(viewMode: .all))
51+
XCTAssertNil(nonIdentifierToken.identifier)
52+
}
53+
}

0 commit comments

Comments
 (0)