-
Notifications
You must be signed in to change notification settings - Fork 441
/
Copy pathTokenSyntax.swift
225 lines (201 loc) · 7.31 KB
/
TokenSyntax.swift
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// MARK: TokenSyntax
/// A Syntax node representing a single token.
///
/// All source code of a syntax tree is represented by tokens – layout nodes
/// never contain any source code by themselves.
///
/// A token consists of leading ``Trivia``, i.e. whitespaces before the actual
/// token contents, the token’s `text` and trailing ``Trivia`` after the token’s
/// content.
public struct TokenSyntax: SyntaxProtocol, SyntaxHashable {
/// The ``Syntax`` node that provides the underlying data.
///
/// Don’t access this. Use `Syntax(token)` instead.
public let _syntaxNode: Syntax
/// The ``RawSyntaxTokenView`` of this token that allows accessing raw
/// properties of the token.
@_spi(RawSyntax)
public var tokenView: RawSyntaxTokenView {
return raw.tokenView!
}
/// If `node` is a token, return the ``TokenSyntax`` that represents it.
/// Otherwise, return `nil`.
public init?<S: SyntaxProtocol>(_ node: S) {
guard node.raw.kind == .token else { return nil }
self._syntaxNode = Syntax(node)
}
@_transparent
init(unsafeCasting node: Syntax) {
self._syntaxNode = node
}
/// Construct a new token with the given `kind`, `leadingTrivia`,
/// `trailingTrivia` and `presence`.
public init(
_ kind: TokenKind,
leadingTrivia: Trivia = [],
trailingTrivia: Trivia = [],
presence: SourcePresence
) {
let arena = RawSyntaxArena()
let raw = RawSyntax.makeMaterializedToken(
kind: kind,
leadingTrivia: leadingTrivia,
trailingTrivia: trailingTrivia,
presence: presence,
tokenDiagnostic: nil,
arena: arena
)
self = Syntax.forRoot(raw, rawNodeArena: RetainedRawSyntaxArena(arena)).cast(TokenSyntax.self)
}
/// Whether the token is present or missing.
public var presence: SourcePresence {
get {
return tokenView.presence
}
set {
self = Syntax(self).withPresence(newValue, rawAllocationArena: RawSyntaxArena()).cast(TokenSyntax.self)
}
}
/// The text of the token as written in the source code, without any trivia.
public var text: String {
return tokenKind.text
}
@_spi(RawSyntax)
public var rawText: SyntaxText {
return tokenView.rawText
}
/// The leading trivia (spaces, newlines, etc.) associated with this token.
public var leadingTrivia: Trivia {
get {
return tokenView.formLeadingTrivia()
}
set {
self = Syntax(self).withLeadingTrivia(newValue, rawAllocationArena: RawSyntaxArena()).cast(TokenSyntax.self)
}
}
/// The trailing trivia (spaces, newlines, etc.) associated with this token.
public var trailingTrivia: Trivia {
get {
return tokenView.formTrailingTrivia()
}
set {
self = Syntax(self).withTrailingTrivia(newValue, rawAllocationArena: RawSyntaxArena()).cast(TokenSyntax.self)
}
}
/// The kind of token this node represents.
public var tokenKind: TokenKind {
get {
return tokenView.formKind()
}
set {
guard raw.kind == .token else {
fatalError("TokenSyntax must have token as its raw")
}
let arena = RawSyntaxArena()
let newRaw = tokenView.withKind(newValue, arena: arena)
self = Syntax(self)
.replacingSelf(newRaw, rawNodeArena: RetainedRawSyntaxArena(arena), rawAllocationArena: arena)
.cast(TokenSyntax.self)
}
}
@_spi(RawSyntax)
public var rawTokenKind: RawTokenKind {
return tokenView.rawKind
}
/// The length this node takes up spelled out in the source, excluding its
/// leading or trailing trivia.
public var trimmedLength: SourceLength {
return tokenView.trimmedLength
}
/// The length this node's leading trivia takes up spelled out in source.
public var leadingTriviaLength: SourceLength {
return tokenView.leadingTriviaLength
}
/// The length this node's trailing trivia takes up spelled out in source.
public var trailingTriviaLength: SourceLength {
return tokenView.trailingTriviaLength
}
/// The length of this node including all of its trivia.
public var totalLength: SourceLength {
return raw.totalLength
}
/// An identifier created from `self`.
public var identifier: Identifier? {
switch self.tokenKind {
case .identifier, .dollarIdentifier:
return Identifier(self)
default:
return nil
}
}
/// A token by itself has no structure, so we represent its structure by an
/// empty layout node.
///
/// Every syntax node that contains a token will have a
/// ``SyntaxNodeStructure/SyntaxChoice/token(_:)`` case for the token and those
/// choices represent the token kinds the token might have.
public static var structure: SyntaxNodeStructure {
return .layout([])
}
/// If the token has a lexical error, the type of the error.
public var tokenDiagnostic: TokenDiagnostic? {
return tokenView.tokenDiagnostic
}
/// Checks if the current leaf syntax node can be cast to a different specified type.
///
/// - Returns: `false` since the leaf node cannot be cast to a different specified type.
///
/// - Note: This method overloads the general `is` method and is marked as deprecated to produce a warning,
/// informing the user that the cast will always fail.
@available(*, deprecated, message: "This cast will always fail")
public func `is`<S: SyntaxProtocol>(_ syntaxType: S.Type) -> Bool {
return false
}
/// Attempts to cast the current leaf syntax node to a different specified type.
///
/// - Returns: `nil` since the leaf node cannot be cast to a different specified type.
///
/// - Note: This method overloads the general `as` method and is marked as deprecated to produce a warning,
/// informing the user that the cast will always fail.
@available(*, deprecated, message: "This cast will always fail")
public func `as`<S: SyntaxProtocol>(_ syntaxType: S.Type) -> S? {
return nil
}
/// Force-casts the current leaf syntax node to a different specified type.
///
/// - Returns: This method will always trigger a runtime crash and never return.
///
/// - Note: This method overloads the general `cast` method and is marked as deprecated to produce a warning,
/// informing the user that the cast will always fail.
/// - Warning: Invoking this method will lead to a fatal error.
@available(*, deprecated, message: "This cast will always fail")
public func cast<S: SyntaxProtocol>(_ syntaxType: S.Type) -> S {
fatalError("\(Self.self) cannot be cast to \(S.self)")
}
}
extension TokenSyntax: CustomReflectable {
/// A custom mirror that shows the token properties in a simpler form, making
/// the debug output of the token easier to read.
public var customMirror: Mirror {
return Mirror(
self,
children: [
"text": text,
"leadingTrivia": leadingTrivia,
"trailingTrivia": trailingTrivia,
"tokenKind": tokenKind,
]
)
}
}