今天我們要引入第 2 個 library SwiftSyntax
,
並且會稍微帶過三個元件,分別是:
這邊 SwiftSyntax 的版本號比較特殊 508.0.0
,對應到 swift 5.8
// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "LeakDetect",
dependencies: [
.package(url: "https://github.com/jpsim/SourceKitten", from: "0.34.1"),
.package(
url: "https://github.com/apple/swift-syntax",
from: "508.0.0"
),
],
targets: [
.target(
name: "LeakDetectKit",
dependencies: [
.product(name: "SourceKittenFramework", package: "SourceKitten"),
.product(name: "SwiftSyntax", package: "swift-syntax"),
.product(name: "SwiftParser", package: "swift-syntax"),
]
),
]
)
Parser 將 source code 解析成 AST
import SwiftParser
import SwiftSyntax
import PathKit
let path = "My.swift"
let code = try Path(path).read()
let sourceFile = Parser.parse(source: code)
我們可以透過自定義 Visitor
去訪問特定的語法節點(Syntax Node)
final class MyVisitor: SyntaxVisitor {
override final func visit(
_ node: IdentifierExprSyntax
) -> SyntaxVisitorContinueKind {
return .visitChildren
}
}
let visitor = MyVisitor(viewMode: .sourceAccurate)
visitor.walk(sourceFile)
SourceLocationConverter
可以將 語法節點
的 offset
轉換成 SourceLocation
let node: IdentifierExprSyntax = xxx
let converter = SourceLocationConverter(file: path, tree: sourceFile)
let location: SourceLocation = converter.location(
for: node.positionAfterSkippingLeadingTrivia
)
SourceLocation
可以取得兩項重要屬性分別是
line
column
在掃瞄完畢後,我們可透過這樣的格式 path:line:col
輸出位置,讓 VSCode 快速導引
/home/My.swift:10:20
/// Represents a source location in a Swift file.
public struct SourceLocation: Hashable, Codable, CustomDebugStringConvertible {
/// Line and column that can be computed on demand.
private var compLoc: ComputedLocation?
/// The UTF-8 byte offset into the file where this location resides.
public let offset: Int
/// The line in the file where this location resides. 1-based.
public var line: Int? {
return compLoc?.line
}
/// The UTF-8 byte offset from the beginning of the line where this location
/// resides. 1-based.
public var column: Int? {
return compLoc?.column
}
/// The file in which this location resides.
public var file: String? {
return compLoc?.file
}
}