微信号:learnSwift

介绍:每天推送一篇精品Swift文章,无偿翻译,共同学习.;;

SwiftSyntax

2019-01-27 22:24 Mattt

译者:jojotov;校对:numbbbbb,Yousanflics,pmst;定稿:Forelax

SwiftSyntax 是一个可以分析、生成以及转换 Swift 源代码的 Swift 库。它是基于 libSyntax 库开发的,并于 2017 年 8 月 从 Swift 语言的主仓库中分离出来,单独建立了一个仓库。

总的来说,这些库都是为了给结构化编辑(structured editing)提供安全、正确且直观的工具。关于结构化编辑,在 thusly 中有具体的描述:

什么是结构化编辑?结构化编辑是一种编辑的策略,它对源代码的结构更加敏感,而源代码的表示(例如字符或者字节)则没那么重要。这可以细化为以下几个部分:替换标识符,将对全局方法的调用转为对方法的调用,或者根据已定的规则识别并格式化整个源文件。

在写这篇文章时,SwiftSyntax 仍处于在开发中并进行 API 调整的阶段。不过目前你已经可以使用它对 Swift 代码进行一些编程工作。

目前,Swift Migrator 已经在使用 SwiftSyntax 了,并且在对内和对外层面上,对 SwiftSyntax 的接入也在不断地努力着。

SwiftSyntax 如何工作?

为了明白 SwiftSyntax 如何工作,我们首先要回头看看 Swift 编译器的架构:

Swift 编译器的主要职责是把 Swift 代码转换为可执行的机器代码。整个过程可以划分为几个离散的步骤,一开始,语法分析器 会生成一个抽象语法树(AST)。之后,语义分析器会进行工作并生成一个通过类型检查的 AST。至此步骤,代码会降级到 Swift 中间层语言;随后 SIL 会继续转换并优化自身,降级为 LLVM IR,并最终编译为机器代码。

对于我们的讨论来说,最重要的关键点是 SwiftSyntax 的操作目标是编译过程第一步所生成的 AST。但也由于这样,SwiftSyntax 无法告知你任何关于代码的语义或类型信息。

与 SwiftSyntax 相反,一些如 SourceKit 之类的工具,操作的目标为更容易理解的 Swift 代码。这可以帮助此类工具实现一些编辑器相关的特性,例如代码补全或者文件之间的跳转。虽然 SwiftSyntax 不能像 SourceKit 一样实现跳转或者补全的功能,但在语法层面上也有很多应用场景,例如代码格式化和语法高亮。

揭秘 AST

抽象语法树在抽象层面上比较难以理解。因此我们先生成一个示例来一睹其貌。

留意一下如下的一行 Swift 代码,它声明了一个名为 one() 的函数,函数返回值为 1

func one() -> Int { return 1 }

在命令行中对此文件运行 swiftc 命令并传入 -frontend -emit-syntax 参数:

shell
$ xcrun swiftc -frontend -emit-syntax ./One.swift

运行的结果为一串 JSON 格式的 AST。当你用 JSON 格式来展示时,AST 的结构会表现的更加清晰:

json
{
    "kind""SourceFile",
    "layout": [{
        "kind""CodeBlockItemList",
        "layout": [{
            "kind""CodeBlockItem",
            "layout": [{
                "kind""FunctionDecl",
                "layout": [nullnull, {
                    "tokenKind": {
                        "kind""kw_func"
                    },
                    "leadingTrivia": [],
                    "trailingTrivia": [{
                        "kind""Space",
                        "value"1
                    }],
                    "presence""Present"
                }, {
                    "tokenKind": {
                        "kind""identifier",
                        "text""one"
                    },
                    "leadingTrivia": [],
                    "trailingTrivia": [],
                    "presence""Present"
                }, ...

Python 中的 json.tool 模块提供了便捷地格式化 JSON 的能力。且几乎所有的 macOS 系统都已经集成了此模块,因此每个人都可以使用它。举个例子,你可以使用如下的命令对编译的输出结果使用 json.tool 格式化:

shell
$ xcrun swiftc -frontend -emit-syntax ./One.swift | python -m json.tool

在最外层,可以看到 SourceFile,它由 CodeBlockItemList 以及 CodeBlockItemList 内部的 CodeBlockItem 这几个部分组成。对于这个示例来说,仅有一个 CodeBlockItem 对应函数的定义(FunctionDecl),其自身包含了几个子组件如函数签名、参数闭包和返回闭包。