解析器
解析器实现为一个单例(其原因类似扫描器,如果能重新初始化就不重新构建)。实际实现成 namespace Parser
,包含解析器的各种状态变量和单例扫描器(const scanner
)。该扫描器由解析器函数管理。
解析器由程序间接驱动(通过之前提到过的 CompilerHost
)。基本上,简化的调用栈如下所示:
parseSourceFile
不仅准备好解析器的状态,还调用 initializeState
准备好扫描器的状态。然后使用 parseSourceFileWorker
继续解析源代码。
深入解析器的内部之前,这里有个使用 TypeScript 解析器的示例,(使用 ts.createSourceFile
)获取一个源文件的 AST 并打印它。
该段代码会打印以下内容:
如果把头向左倾,这个看起来像棵(右侧)树
如前所述,parseSourceFile
设置初始状态并将工作交给 parseSourceFileWorker
函数。
该函数先创建一个 SourceFile
AST 节点,然后从 parseStatements
函数开始解析源代码。一旦返回结果,就用额外信息(例如 , identifierCount
等) 完善 SourceFile
节点。
解析器有一系列 parseXXX
函数用来创建相应类型为XXX
的节点,通常在相应类型的节点出现时被(其他解析器函数)调用。该过程的典型示例是解析空语句(例如 ;;;;;
)时要用的 parseEmptyStatement()
函数。下面是其全部代码:
它展示了 3 个关键函数 createNode
, parseExpected
和 .
createNode
解析器函数 function createNode(kind: SyntaxKind, pos?: number): Node
负责创建节点,设置节点的 SyntaxKind
(语法类别),和初始位置(默认使用当前扫描器状态提供的位置信息)。
parseExpected
解析器的 parseExpected
函数 function parseExpected(kind: SyntaxKind, diagnosticMessage?: DiagnosticMessage): boolean
会检查解析器状态中的当前 token 是否与指定的 SyntaxKind
匹配。如果不匹配,会报告传入的 diagnosticMessage
(诊断消息),未传入则使用某种通用形式 xxx expected
进行报告。该函数内部用 parseErrorAtPosition
函数(使用扫描位置)提供良好的错误报告。