Typescript编译原理(一)

栏目: 服务器 · 编程工具 · 发布时间: 5年前

内容简介:首先,其中分为以下几个关键部分,每个部分在源文件中均有独立文件,稍后会解释这些部分在编译过程中所起到的左右。

首先, ts github 地址: github.com/Microsoft/T… 。各位可先行下载。其编译部分位于 src/compiler 目录下。

其中分为以下几个关键部分,

  • Scanner 扫描器scanner.ts
  • Parser 解析器parser.ts
  • Binder 绑定器binder.ts
  • Checker 检查器checker.ts
  • Emitter 发射器emitter.ts

每个部分在源文件中均有独立文件,稍后会解释这些部分在编译过程中所起到的左右。

概览

Typescript编译原理(一)

上图简单说明 TypeScript 编译器如何将上述几个关键部分组合在一起:

  1. 源码 ~ scanner(扫描器) ~ token数据流 ~ parser(解析器) -> AST(抽象语法树)
  2. AST(抽象语法树) ~ binder(绑定器) -> symbols(符号)
  3. AST(抽象语法树) + symbols ~ checker(检查器) -> 类型检查功能
  4. AST(抽象语法树) + checker(检查器) ~ emitter(发射器) -> js代码

流程

源码 ~ scanner(扫描器) ~ token数据流 ~ parser(解析器) -> AST(抽象语法树)

typescript的扫描器位于 scanner.ts ,解析器位于 parser.ts ,在内部,由 parser解析器 控制 scanner扫描器 源码 转化为 抽象语法树(AST) 。流程如下:

Typescript编译原理(一)

若以常见的AST生成过程类比,可简单类比上述的 扫描器阶段 可对应为 词法分析过程 解析器阶段 可对应为 语法分析过程

Typescript编译原理(一)

有关 AST抽象语法树 可参考AST抽象语法树。

Parser 解析器对 Scanner 扫描器的使用

通过 parseSourceFile 设置初始状态并将工作交给 parseSourceFileWorker 函数。

parseSourceFile

export function parseSourceFile(fileName: string, sourceText: string, languageVersion: ScriptTarget, syntaxCursor: IncrementalParser.SyntaxCursor | undefined, setParentNodes = false, scriptKind?: ScriptKind): SourceFile {
            scriptKind = ensureScriptKind(fileName, scriptKind);

            //初始化状态
            if (scriptKind === ScriptKind.JSON) {
                const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
                convertToObjectWorker(result, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
                result.referencedFiles = emptyArray;
                result.typeReferenceDirectives = emptyArray;
                result.libReferenceDirectives = emptyArray;
                result.amdDependencies = emptyArray;
                result.hasNoDefaultLib = false;
                result.pragmas = emptyMap;
                return result;
            }

            //专备好扫描器状态
            initializeState(sourceText, languageVersion, syntaxCursor, scriptKind);
            
            //将工作交给 parseSourceFileWorker
            const result = parseSourceFileWorker(fileName, languageVersion, setParentNodes, scriptKind);

            clearState();

            return result;
        }
复制代码

parseSourceFileWorker

该函数先创建一个 SourceFile AST 节点 ,然后从 parseStatement 函数开始解析源代码。一旦返回结果,就用额外信息(例如 nodeCount , identifierCount 等) 完善 SourceFile 节点。

function parseSourceFileWorker(fileName: string, languageVersion: ScriptTarget, setParentNodes: boolean, scriptKind: ScriptKind): SourceFile {
            const isDeclarationFile = isDeclarationFileName(fileName);
            if (isDeclarationFile) {
                contextFlags |= NodeFlags.Ambient;
            }

            // 先创造一个  SourceFile AST 节点
            sourceFile = createSourceFile(fileName, languageVersion, scriptKind, isDeclarationFile);
            sourceFile.flags = contextFlags;

            // Prime the scanner.
            nextToken();
            // A member of ReadonlyArray<T> isn't assignable to a member of T[] (and prevents a direct cast) - but this is where we set up those members so they can be readonly in the future
            processCommentPragmas(sourceFile as {} as PragmaContext, sourceText);
            processPragmasIntoFields(sourceFile as {} as PragmaContext, reportPragmaDiagnostic);

            // 调用 parseStatement 函数解析源码
            sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement);
            Debug.assert(token() === SyntaxKind.EndOfFileToken);

            // 至871行 均为完善 sourcefile AST 节点
            sourceFile.endOfFileToken = addJSDocComment(parseTokenNode());

            setExternalModuleIndicator(sourceFile);

            sourceFile.nodeCount = nodeCount;
            sourceFile.identifierCount = identifierCount;
            sourceFile.identifiers = identifiers;
            sourceFile.parseDiagnostics = parseDiagnostics;

            if (setParentNodes) {
                fixupParentReferences(sourceFile);
            }

            return sourceFile;

            function reportPragmaDiagnostic(pos: number, end: number, diagnostic: DiagnosticMessage) {
                parseDiagnostics.push(createFileDiagnostic(sourceFile, pos, end, diagnostic));
            }
        }
复制代码

节点创建:parseStatement/parseEmptyStatement/parseExpected等

其中 parseStatement 函数,它根据扫描器返回的当前 token 来切换(调用相应的 parseXXX 函数),生成AST节点。例如:如果当前 token 是一个 SemicolonToken(分号标记) ,就会调用 paserEmptyStatement 为空语句创建一个 AST 节点。

function parseStatement(): Statement {

            // 此处 token 为 scanner扫描器 返回的 当前token流,  SyntaxKind为AST的常量枚举类型,根据不同的类型创建不同的节点
            switch (token()) {
                // 类型为 SemicolonToken,调用parseEmptyStatement
                case SyntaxKind.SemicolonToken:
                    return parseEmptyStatement();
                case SyntaxKind.OpenBraceToken:
                    return parseBlock(/*ignoreMissingOpenBrace*/ false);
                case SyntaxKind.VarKeyword:
                    return parseVariableStatement(<VariableStatement>createNodeWithJSDoc(SyntaxKind.VariableDeclaration));
                case SyntaxKind.LetKeyword:
                    if (isLetDeclaration()) {
                        return parseVariableStatement(<VariableStatement>createNodeWithJSDoc(SyntaxKind.VariableDeclaration));
                    }
                    break;
                case SyntaxKind.FunctionKeyword:
                    return parseFunctionDeclaration(<FunctionDeclaration>createNodeWithJSDoc(SyntaxKind.FunctionDeclaration));
                case SyntaxKind.ClassKeyword:
                    return parseClassDeclaration(<ClassDeclaration>createNodeWithJSDoc(SyntaxKind.ClassDeclaration));
                case SyntaxKind.IfKeyword:
                    return parseIfStatement();
                case SyntaxKind.DoKeyword:
                    return parseDoStatement();
                case SyntaxKind.WhileKeyword:
                    return parseWhileStatement();
                case SyntaxKind.ForKeyword:
                    return parseForOrForInOrForOfStatement();
                case SyntaxKind.ContinueKeyword:
                    return parseBreakOrContinueStatement(SyntaxKind.ContinueStatement);
                case SyntaxKind.BreakKeyword:
                    return parseBreakOrContinueStatement(SyntaxKind.BreakStatement);
                case SyntaxKind.ReturnKeyword:
                    return parseReturnStatement();
                case SyntaxKind.WithKeyword:
                    return parseWithStatement();
                case SyntaxKind.SwitchKeyword:
                    return parseSwitchStatement();
                case SyntaxKind.ThrowKeyword:
                    return parseThrowStatement();
                case SyntaxKind.TryKeyword:
                // Include 'catch' and 'finally' for error recovery.
                case SyntaxKind.CatchKeyword:
                case SyntaxKind.FinallyKeyword:
                    return parseTryStatement();
                case SyntaxKind.DebuggerKeyword:
                    return parseDebuggerStatement();
                case SyntaxKind.AtToken:
                    return parseDeclaration();
                case SyntaxKind.AsyncKeyword:
                case SyntaxKind.InterfaceKeyword:
                case SyntaxKind.TypeKeyword:
                case SyntaxKind.ModuleKeyword:
                case SyntaxKind.NamespaceKeyword:
                case SyntaxKind.DeclareKeyword:
                case SyntaxKind.ConstKeyword:
                case SyntaxKind.EnumKeyword:
                case SyntaxKind.ExportKeyword:
                case SyntaxKind.ImportKeyword:
                case SyntaxKind.PrivateKeyword:
                case SyntaxKind.ProtectedKeyword:
                case SyntaxKind.PublicKeyword:
                case SyntaxKind.AbstractKeyword:
                case SyntaxKind.StaticKeyword:
                case SyntaxKind.ReadonlyKeyword:
                case SyntaxKind.GlobalKeyword:
                    if (isStartOfDeclaration()) {
                        return parseDeclaration();
                    }
                    break;
            }
            return parseExpressionOrLabeledStatement();
        }
复制代码

以上所述就是小编给大家介绍的《Typescript编译原理(一)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

重新定义管理

重新定义管理

[美]布赖恩·罗伯逊 / 中信出版社 / 2015-10-1 / 45

还没听说过合弄制?你一定会听说的。终于,迎来了一本合弄制创建者的著作,讲解了这一公司经营方式的革命性新系统及其实施方法。 今天的商界,情况瞬息万变。但在绝大多数组织中,最具资格响应变化的人们却几乎都没有权力去做出改变。相反,他们不得不遵守那些由领导们设立的亘古不变的战略,而且这些领导们仍然相信“预测和控制”才是有效管理的关键。 合弄制向你展示了怎样让组织中工作的每一个人都成为一名领导,......一起来看看 《重新定义管理》 这本书的介绍吧!

在线进制转换器
在线进制转换器

各进制数互转换器

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具