此页面描述了 Swift 解析器的实现,重点介绍了它如何将 Swift 源代码转换为抽象语法树(AST)。解析器是 Swift 编译器前端的关键组成部分,它在词法分析和语义分析之间架起了桥梁。有关词法分析的信息,请参阅词法分析器文档;有关 AST 结构本身的信息,请参阅 抽象语法树 (AST)。
Swift 解析器实现为一种递归下降解析器,它从词法分析器中消耗令牌并生成 AST。该解析器设计得非常健壮,具有良好的错误恢复能力,即使在存在语法错误的情况下也能提供有用的诊断信息。
来源: lib/Parse/Parser.cpp17-26 include/swift/Parse/Parser.h120-188
解析器在逻辑上分为多个组件,每个组件负责解析不同的语言结构。主 Parser 类充当入口点并协调这些组件。
来源: include/swift/Parse/Parser.h120-188 lib/Parse/ParseDecl.cpp1-15 lib/Parse/ParseExpr.cpp1-15 lib/Parse/ParseStmt.cpp1-15 lib/Parse/ParseType.cpp1-15 lib/Parse/ParsePattern.cpp1-15
Parser 类包含几个管理其状态和功能的关键组件
| 组件 | 类型 | 目的 |
|---|---|---|
SourceMgr | SourceManager & | 管理源文件缓冲区和位置 |
Diags | DiagnosticEngine & | 处理诊断信息的发出 |
SF | SourceFile & | 表示正在解析的源文件 |
L | Lexer * | 提供令牌的词法分析器 |
上下文 | ASTContext & | 用于节点分配的 AST 上下文 |
Tok | 标记 | 当前正在处理的令牌 |
PreviousLoc | SourceLoc | 上一个令牌的位置 |
CurDeclContext | DeclContext * | 当前声明上下文 |
状态管理 | PersistentParserState * | 持久化解析器状态 |
TokReceiver | ConsumeTokenReceiver * | 已消耗令牌的可选接收器 |
来源: include/swift/Parse/Parser.h130-216
解析源文件的主要入口点是 parseTopLevelItems 方法,该方法处理令牌直到到达文件末尾。根据令牌的类型,解析器会分派到专门的方法来解析声明、语句和其他 Swift 结构。
来源: lib/Parse/ParseDecl.cpp175-249
parseTopLevelItems 方法parseTopLevelItems 方法是 Swift 源文件的主要解析循环。
void Parser::parseTopLevelItems(SmallVectorImpl<ASTNode> &items) {
// Prime the lexer.
if (Tok.is(tok::NUM_TOKENS))
consumeTokenWithoutFeedingReceiver();
// Parse the body of the file.
while (!Tok.is(tok::eof)) {
// Skip SIL declarations for now
if (isStartOfSILDecl()) {
skipSILUntilSwiftDecl();
continue;
}
// Determine parsing mode based on source file kind
BraceItemListKind braceItemListKind;
switch (SF.Kind) {
case SourceFileKind::Main:
braceItemListKind = BraceItemListKind::TopLevelCode;
break;
case SourceFileKind::Library:
case SourceFileKind::Interface:
case SourceFileKind::SIL:
braceItemListKind = BraceItemListKind::TopLevelLibrary;
break;
case SourceFileKind::MacroExpansion:
case SourceFileKind::DefaultArgument:
braceItemListKind = BraceItemListKind::MacroExpansion;
break;
}
parseBraceItems(items, braceItemListKind);
// Handle misplaced conditional compilation directives
if (Tok.is(tok::pound_else) || Tok.is(tok::pound_elseif) ||
Tok.is(tok::pound_endif)) {
diagnose(Tok.getLoc(),
diag::unexpected_conditional_compilation_block_terminator);
consumeToken();
}
}
// Optionally validate parser output for new parser diagnostics
#if SWIFT_BUILD_SWIFT_SYNTAX
// Code for validating the new parser diagnostics output
#endif
}
来源: lib/Parse/ParseDecl.cpp175-249
解析器将各种 Swift 语言结构的解析委托给专门的方法。每个方法负责解析特定类型的结构并构建相应的 AST 节点。
表达式由 parseExpr 及其相关方法解析,这些方法处理各种表达式,包括字面量、运算符、函数调用、闭包等。
来源: lib/Parse/ParseExpr.cpp44-375
语句由 parseStmt 及其相关方法解析,这些方法处理各种语句类型,如 if、for、while、switch、return 等。
声明由 parseDecl 及其相关方法解析,这些方法处理各种声明类型,如函数、变量、类型、协议等。
类型由 parseType 及其相关方法解析,这些方法处理各种类型形式,包括简单类型、函数类型、元组类型等。
模式由 parsePattern 及其相关方法解析,这些方法处理在绑定上下文和模式匹配中使用的各种模式形式。
来源: lib/Parse/ParsePattern.cpp
Parser 类在解析期间管理几个状态方面
解析器维护当前令牌 (Tok) 和上一个令牌的位置 (PreviousLoc),这些在消耗令牌时会更新。
解析器使用 consumeToken()、consumeIf() 和 skipUntil() 等方法来消耗令牌。这些方法会推进解析器的位置并更新当前令牌。
bool Parser::consumeIf(tok Kind) {
if (Tok.is(Kind)) {
consumeToken(Kind);
return true;
}
return false;
}
void Parser::consumeToken() {
assert(Tok.isNot(tok::eof) && "Lexing past eof!");
if (TokReceiver)
TokReceiver->receive(Tok);
PreviousLoc = Tok.getLoc();
L->lex(Tok);
}
来源: include/swift/Parse/Parser.h770-900
解析器跟踪当前声明上下文 (CurDeclContext),用于名称查找和上下文敏感的解析。 ContextChange 类提供了 RAII 风格的上下文管理。
class ContextChange {
protected:
Parser &P;
DeclContext *OldContext;
public:
ContextChange(Parser &P, DeclContext *DC)
: P(P), OldContext(P.CurDeclContext) {
assert(DC && "Can't change to a null context!");
P.CurDeclContext = DC;
}
~ContextChange() {
P.CurDeclContext = OldContext;
}
};
来源: include/swift/Parse/Parser.h236-260
解析器包含强大的错误处理和恢复机制,以便在遇到语法错误后继续解析。
来源: include/swift/AST/DiagnosticsParse.def lib/Parse/Parser.cpp
为了提高性能,解析器可以延迟解析函数体和其他大型结构,直到需要为止。
bool Parser::isDelayedParsingEnabled() const {
// Delayed parsing is disabled for primary files to ensure that errors in
// the primary files are discovered during the first parse.
if (SF.isPrimary())
return false;
// Otherwise, use the global flag.
return Context.LangOpts.DelayedParsing;
}
来源: include/swift/Parse/Parser.h170-180
解析器使用 ParserResult<T> 模板来跟踪解析状态,包括错误和代码补全。
来源: include/swift/Parse/ParserResult.h
解析器有时可以超前查看多个令牌以确定适当的解析策略,或者在尝试解析不匹配输入的结构后进行回溯。
Parser::BacktrackingScope::~BacktrackingScope() {
// If this was a successful parse, do not backtrack.
if (Backtrack) {
// Restore the token position and parser lexing/context.
P.L->backtrackToPosition(BacktrackState);
P.ConsumeMultiTok(StartingToks);
}
}
来源: include/swift/Parse/Parser.h650-670
当解析器处理源代码时,它会构建一个 AST,该 AST 代表代码的结构和语义。不同的解析器方法构建不同种类的 AST 节点。
来源: lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseStmt.cpp lib/Parse/ParseType.cpp lib/Parse/ParsePattern.cpp
解析器会针对解析过程中遇到的语法错误和其他问题发出诊断信息。诊断信息定义在 include/swift/AST/DiagnosticsParse.def 中,并使用 diagnose 方法发出。
void Parser::diagnose(SourceLoc Loc, Diagnostic<> ID) {
Diags.diagnose(Loc, ID);
}
template<typename ...DiagArgTypes, typename ...ArgTypes>
void Parser::diagnose(SourceLoc Loc, Diagnostic<DiagArgTypes...> ID,
ArgTypes &&...Args) {
Diags.diagnose(Loc, ID, std::forward<ArgTypes>(Args)...);
}
常见的诊断类别包括:
来源: include/swift/AST/DiagnosticsParse.def lib/Parse/Parser.cpp
在 SIL 模式下,解析器也支持解析 Swift 中间语言 (SIL)。parseTopLevelSIL 方法负责解析 SIL 声明。
bool Parser::parseTopLevelSIL() {
assert(SIL && isInSILMode());
// Prime the lexer.
if (Tok.is(tok::NUM_TOKENS))
consumeTokenWithoutFeedingReceiver();
auto skipToNextSILDecl = [&]() {
while (!Tok.is(tok::eof) && !isStartOfSILDecl())
skipSingle();
};
auto hadError = false;
while (!Tok.is(tok::eof)) {
// Skip Swift decls, only parse SIL decls
if (isStartOfSwiftDecl()) {
skipToNextSILDecl();
continue;
}
// Handle different SIL declaration kinds
switch (Tok.getKind()) {
case tok::kw_sil:
case tok::kw_sil_stage:
case tok::kw_sil_vtable:
// ... other SIL keywords ...
// Parse the specific SIL declaration
break;
default:
diagnose(Tok, diag::expected_sil_keyword);
skipToNextSILDecl();
hadError = true;
break;
}
}
return hadError;
}
来源: lib/Parse/ParseDecl.cpp252-307 lib/SIL/Parser/ParseSIL.cpp
Swift 解析器是 Swift 编译器中一个复杂但结构良好的组件。它采用递归下降方法来解析 Swift 源代码,并构建一个捕获代码语法和语义结构的 AST。解析器包含强大的错误处理和恢复机制,能够产生有用的诊断信息,并在存在语法错误时继续解析。
该解析器设计得灵活且可扩展,支持各种源文件类型、条件编译和特殊的语言特性。它与词法分析器集成以消耗标记,并与 AST 上下文集成以构建抽象语法树节点。