在前面的第四天,我們已經學會了如何取得特定 Module
的 file list
。現在,我們將進一步使用另一個 library,稱為 SwiftSyntax,通過它,我們可以訪問 Swift 的抽象語法樹(AST)。
首先,讓我們了解一下編譯程式碼的過程。程式碼在編譯過程中會經過多個步驟,我們可以參考以下文章 Day3.編譯器運作流程介紹 中的圖示:
通過這張圖,我們可以看到,在獲得 AST 之前,程式碼必須經過兩個主要步驟,即 Lex
和 語法分析
。
Lex
步驟將我們的程式碼進行 token 化,將程式碼拆分為一系列的 token:
let code = """
let test = process(x)
"""
func lex(_ code: String) -> [String] {...}
lex(code)
/*
"let"
"test"
"="
"process"
"("
"x"
")"
*/
在進行 語法分析
之前,我們需要定義一些簡單的語法結構,這些結構將幫助我們轉換程式碼為 AST:
這個範例將能夠解析語法,變數宣告以及函式呼叫。
indirect enum Expr {
case idDecl(id: String)
case varDecl(
letKeyword: Keyword,
varName: Expr,
equal: Operator,
content: Expr
)
case functionCall(
functionName: Expr,
leftParent: String,
args: [Expr],
rightParent: String,
)
}
enum Keyword {
case `let`
}
enum Operator {
case equal
}
然後,我們可以將程式碼轉換為 AST:
/// let test = process(x)
func parse(_ tokens: [String]) -> [Expr] {...}
let ast: [Expr] = [
.varDecl(
letKeyword: .let,
varName: .id("test"),
equal: .equal,
content: .functionCall(
functionName: .id("process"),
leftParent: "(",
args: [.id("x")],
rightParent: ")",
)
)
]
最終,我們獲得了一個樹狀結構,稱為抽象語法樹(AST),如下所示:
如果我們將葉子節點(leaf)連接起來,就會獲得剛剛的程式碼:
let test = process(x)