解析器

    解析器实现为一个单例(其原因类似扫描器,如果能重新初始化就不重新构建)。实际实现成 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 函数(使用扫描位置)提供良好的错误报告。

    finishNode