SwiftSyntax概述

SwiftSyntax是一个在libSyntax之上提供Swift抽象的库,它公开了一组API,这些API使得诸如访问,重写和从swift源的语法结构中检索信息等操作成为可能。
因此,在今天的文章中,我们将试玩一下SwiftSyntax库,以更多地了解它的工作原理以及如何使用它来创建可以帮助解决一些问题的东西。

所以,让我们潜入……

编译器

在深入探讨SwiftSyntax之前,我们需要至少从高层次上了解有关编译器流程的一些知识。

swift编译器采用Swift源代码,将其处理为手动编码的Lexer,将其标记化并将其转换为抽象语法树(AST),然后是语义分析(Sema),其中编译器采用由XML生成的AST。解析器,并进行类型检查的AST并检查其上的语义问题。 然后,Swift中级语言生成(SILGen)阶段将通过语义分析生成的AST转换为他们所谓的原始SIL,在对原始SIL进行了一些优化(如通用专业化,ARC优化等)之后……它生成了他们所谓的规范SIL。然后将其交给IRGen生成中间表示(IR),该中间表示将传递给LLVM以使其继续工作并生成目标文件(.o),该文件随后将由链接器粘合在一起并生成用于任何给定的平台。

这是对编译器管道的简要概述。 在这里,我们将更多地关注AST,因为在SwiftSyntax上,我们基本上以语法节点的形式来表示它。 因此,要了解本文中的术语,我们只需要知道AST就是树形结构形式的源代码语法的表示。

让我们看一个简单的例子:

上图是树形式的代码示例的表示形式,我们可以注意到,它表示经过类型检查的AST,但仍然没有语义信息,只有语法信息。 请注意,在顶部,我们有一个struct_decl ,内部是子结构,我们有var_declfunc_decl ,它们可以包含自己的子结构,依此类推……等等,还有语法标记,如brace_stmt

SwiftSyntax以Syntax节点的形式提供了这种表示形式,我们可以使用Visitors浏览它,也可以使用Rewriters对该结构进行更改(我们将在本文的后面讨论它们)。 每种结构都有类型表示形式,例如struct_decl具有SwiftSyntax结构StructDeclSyntax类型,将其表示为语法节点。

现在我们知道了AST的基本概念,下面我们来谈谈SwiftSyntax \ o /

lib语法

我们可以说SwiftSyntax是一个swift程序包,它在libSyntax之上提供了一组swift绑定,libSyntax是在其中处理swift源的实现,结构和逻辑。

在libSyntax上阅读:

该库实现了用于处理Swift语法的数据结构和算法,力求安全,正确和直观地使用。 该库强调不可变的,线程安全的数据结构,源的全保真表示以及结构化编辑的便利。

换句话说,它将为我们提供一个必要的基本块,以使我们能够通过良好而便捷的API对快速的源语法结构进行安全可靠的分析和编辑。

SwiftSyntax API

我们不会在这里深入探讨如何在libSyntax中内部表示源数据,因此,我们将更多地关注SwiftSyntax提供的高级swift API(用作客户端)。

libSyntax自述文件的“内部”部分中有详细的文档。 而且,Harlan Haskins的演讲中有关于尝试的部分! Swift NYC 2017 [3]关于libSyntax如何在内部表示语法树。

但简短的摘要是,libSyntax将AST的表示划分为:

语法 :或语法节点是为公共API提供的表示形式。

RawSyntax :是所有语法的内部原始不可变后备存储 像令牌种类一样存储数据,并且还表示子树结构。

RawTokenSyntaxRawSyntax的特殊情况,表示语法中的所有RawSyntax

Trivia :表示对源没有任何语义含义的所有语法部分,例如空格,换行符和注释。

SyntaxData :它用一些附加信息包装RawSyntax节点:指向父级的指针,该节点在其父级中出现的位置以及缓存的子级。

高级API

在这里,我们将看到一些可以在SwiftSyntax上使用的高级API,以及一些有关如何使用它的示例代码。

语法工厂

提供一个简单易用的API,以单行方式创建任何SyntaxNode。 因此,我们没有使用每个Syntax类上的许多构造函数,而是使用factory类。

使用API

每个SyntaxNode都有with方法,这些方法允许我们仅通过with部分修改就可以从另一个节点创建一个节点。 因此,由于语法节点具有不变性的概念,因此它使用与调用它的节点相同的数据创建了一个新节点,但是替换了with部分。

语法访问者

使用SyntaxVisitor,我们可以遍历语法树。 当我们想要提取一些信息以对源进行分析时,这很有用。

返回值是一种继续类型,指示是继续并访问语法树上的子节点(SyntaxVisitorContinueKind.visitChildren)还是跳过它(SyntaxVisitorContinueKind.skipChildren)。

语法重写器

SyntaxRewriter使我们可以通过仅重写visit(某些语法…)方法并根据规则返回新节点来修改树的结构。
注意 :所有节点都是不可变的,因此我们不修改节点,而是创建另一个节点(使用带有API的API)并将其返回以替换当前节点。

在上面的示例中,我们将代码中的所有字符串文字替换为🐱。

公共API还有很多,但是我认为这些是使我们能够开始使用SwiftSyntax的主要基本API。

结论

尽管SwiftSyntax自述文件中有一条注释说:

注意:SwiftSyntax仍在开发中,并且不保证该API稳定。 如有更改,恕不另行通知。

我们已经可以用它做一些很棒的事情,并且已经有很多人在使用由SwiftSyntax支持的工具。 有用于代码格式化,检测未使用的代码的工具,甚至Swift压力测试器都建立在其之上,并且还有很多其他工具。

总结本文,尽管仍在进行中,但仍涉及正在进行libSyntax和SwiftSyntax的团队和人员的镜头,令人惊奇的是我们可以使用它进行操作的可能性,因此祝贺所涉及的团队和人员。

在下一篇文章中,我们将探索一个示例,说明如何使用SwiftSyntax和SPM创建一个非常简单的工具。

这就是本文的全部内容\ o /

如果您有任何意见或疑问,请告诉我。 您的反馈意见非常重要,因此我们可以改善此问题以及将来的帖子,很高兴收到它:))

您可以在Twitter上@ LucianoPassos11找到我。

感谢您阅读🙂

参考文献

  1. Swift语法回购。 https://github.com/apple/swift-syntax
  2. apple / swift / lib / Syntax文档和示例。 https://github.com/apple/swift/tree/master/lib/语法
  3. 尝试! Swift NYC 2017 —使用libSyntax改进Swift工具。 https://www.youtube.com/watch?v=5ivuYGxW_3M
  4. Swift论坛。 https://forums.swift.org