Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

重学js —— modules:源文本模块记录 #91

Open
lizhongzhen11 opened this issue Mar 22, 2020 · 0 comments
Open

重学js —— modules:源文本模块记录 #91

lizhongzhen11 opened this issue Mar 22, 2020 · 0 comments
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN

Comments

@lizhongzhen11
Copy link
Owner

lizhongzhen11 commented Mar 22, 2020

modules:源文本模块记录

源文本模块记录 用来表示 从ECMAScript 源文本 定义且使用 目标符号 Module 解析的模块信息。其字段包含有关模块导入的名称的摘要信息,其具体方法使用此摘要链接,链接和求值模块。

源文本模块记录可以和抽象 模块记录 类型的其它子类一起出现在模块图中,可以和 循环模块记录 类型的其它子类一起参与循环。

下面的字段在 ParseModule 时初始化设置。

源文本模块记录额外字段
字段名 值类型 含义
[[ECMAScriptCode]] 解析节点 解析该模块(使用 Module 作为 目标符号)源文本的结果
[[Context]] ECMAScript 执行上下文 与该模块关联的 执行上下文
[[ImportEntries]] ImportEntry RecordList 从此模块的代码派生的 ImportEntry 记录 List
[[LocalExportEntries]] ExportEntry RecordList 从此模块的代码派生的 ExportEntry 记录 List,这些记录与模块中出现的声明相对应。
[[IndirectExportEntries]] ExportEntry RecordList 从此模块的代码派生的 ExportEntry 记录 List,这些记录与模块中出现的重新导出的导入或从 export * as namespace 声明的导出相对应。
[[StarExportEntries]] ExportEntry RecordList 从此模块的代码派生的 ExportEntry 记录 List,这些记录与模块中出现的 export * 声明相对应,不包含 export * as namespace 声明!

ImportEntry Record 是一种用于摘要有关单个声明性导入的信息的 Record。每个 ImportEntry Record 有下表中定义的字段:

ImportEntry Record字段
字段名 值类型 含义
[[ModuleRequest]] String ImportDeclarationModuleSpecifier 的字符串值
[[ImportName]] String [[ModuleRequest]] 标识的模块导出所需绑定的名称。"*" 值表示导入请求是针对目标模块的命名空间对象
[[LocalName]] String 用于从导入模块内部本地访问导入值的名称

注意:下表给出了用于表示语法导入形式的ImportEntry记录字段的示例:

导入语句形式 [[ModuleRequest]] [[ImportName]] [[LocalName]]
import v from "mod"; "mod" "default" "v"
import * as ns from "mod"; "mod" "*" "ns"
import {x} from "mod"; "mod" "x" "x"
import {x as v} from "mod"; "mod" "x" "v"
import "mod"; 没有创建 ImportEntry Record

ExportEntry Record 是一种用于摘要有关单个声明性导出信息的 Record。每个 ExportEntry Record 有下表中定义的字段:

ExportEntry Record字段
 字段名 值类型 含义
[[ExportName]] String / null 由该模块导出的命名绑定
[[ModuleRequest]] String / null ExportDeclarationModuleSpecifier 的字符串值。如果 ExportDeclaration 没有 ModuleSpecifier,则为 null
[[ImportName]] String / null [[ModuleRequest]] 标识的模块导出所需绑定的名称。如果 ExportDeclaration 没有 ModuleSpecifier,则为 null"*" 表示对所有被导出的绑定的 导出请求
[[LocalName]] String / null 用于从导入模块内部本地访问导入值的名称。如果不能从模块内部本地访问导出值,则为 null

注意:下表给出了用于表示语法导入形式的ExportEntry记录字段的示例:

ExportEntry Record示例
导出语句形式 [[ExportName]] [[ModuleRequest]] [[ImportName]] [[LocalName]]
export var v; "v" null null "v"
export default function f() {} "default" null null "f"
export default function () {} "default" null null "*default*"
export default 42; "default" null null "*default*"
export {x}; "x" null null "x"
export {v as x}; "x" null null "v"
export {x} from "mod"; "x" "mod" "x" null
export {v as x} from "mod"; "x" "mod" "v" null
export * from "mod"; null "mod" "*" null
export * as ns from "mod"; "ns" "mod" "*" null

ParseModule(sourceText, realm, hostDefined)

基于将 sourceText 解析为 Module 的结果创建 源文本模块记录

  1. 断言:sourceText 是 ECMAScript 源文本
  2. 使用 Module 作为 目标符号 解析 sourceText。分析任何早期错误情况的解析结果。如果解析成功且没有早期错误,定义 body 为结果解析树。否则,定义 body 为包含一个或多个 SyntaxError 对象的 List,这些对象表示解析错误和早期错误。解析和 早期错误 检测可以以依赖于实现的方式进行交织。如果存在多个解析错误或 早期错误,该list中错误对象的数量和顺序依赖于实现,但是至少存在一个。
  3. 如果 body 是一个错误 List,返回 body
  4. 定义 requestedModulesbodyModuleRequests
  5. 定义 importEntriesbodyImportEntries
  6. 定义 importedBoundNamesImportedLocalNames(importEntries)
  7. 定义 indirectExportEntries 为一个新的空 List
  8. 定义 localExportEntries 为一个新的空 List
  9. 定义 starExportEntries 为一个新的空 List
  10. 定义 exportEntriesbodyExportEntries
  11. 遍历 exportEntries 中的每个 ExportEntry Record ee (别名)
    1. 如果 ee.[[ModuleRequest]]null
      1. 如果 ee.[[LocalName]] 不是 importedBoundNames 的元素
        1. ee 加入 localExportEntries
      2. 否则,
        1. 定义 ieimportEntries 的元素,其 [[LocalName]]ee.[[LocalName]] 相同
        2. 如果 ie.[[ImportName]]"*"
          1. 注意:这里是对一个导入模块命名空间对象的重新导出
          2. ee 加入到 localExportEntries
        3. 否则,
          1. 注意:这里是对一个单独命名的重新导出
          2. ExportEntry Record { [[ModuleRequest]]: ie.[[ModuleRequest]], [[ImportName]]: ie.[[ImportName]], [[LocalName]]: null, [[ExportName]]: ee.[[ExportName]] } 加入到 indirectExportEntries
    2. 否则如果 ee.[[ImportName]]"*"ee.[[ExportName]]null
      1. ee 加入到 starExportEntries
    3. 否则,
      1. ee 加入到 indirectExportEntries
  12. 返回 源文本模块记录 { [[Realm]]: realm, [[Environment]]: undefined, [[Namespace]]: undefined, [[Status]]: unlinked, [[EvaluationError]]: undefined, [[HostDefined]]: hostDefined, [[ECMAScriptCode]]: body, [[Context]]: empty, [[RequestedModules]]: requestedModules, [[ImportEntries]]: importEntries, [[LocalExportEntries]]: localExportEntries, [[IndirectExportEntries]]: indirectExportEntries, [[StarExportEntries]]: starExportEntries, [[DFSIndex]]: undefined, [[DFSAncestorIndex]]: undefined }.

GetExportedNames( [ exportStarSet ] ) 具体方法

实现 模块记录 中对应的抽象方法。

  1. 如果 exportStarSet 不存在,将 exportStarSet 设置为一个新的空 List
  2. 断言:exportStarSet源文本模块记录List
  3. 定义 module源文本模块记录
  4. 如果 exportStarSet 包含 module
    1. 断言:我们已经到了 export * 循环的起点
    2. 返回一个新的空 List
  5. module 加入到 exportStarSet
  6. 定义 exportedNames 为一个新的空 List
  7. 遍历 module.[[LocalExportEntries]] 中的每个 ExportEntry Record e
    1. 断言:module 为该导出提供直接绑定
    2. e.[[ExportName]] 加入到 exportedNames
  8. 遍历 module.[[IndirectExportEntries]] 中的每个 ExportEntry Record e
    1. 断言:module 为该导出引入了一个指定的绑定
    2. e.[[ExportName]] 加入到 exportedNames
  9. 遍历 module.[[StarExportEntries]] 中每个 ExportEntry Record e
    1. 定义 requestedModule? HostResolveImportedModule(module, e.[[ModuleRequest]])
    2. 定义 starNames? requestedModule.GetExportedNames(exportStarSet)
    3. 遍历 starNames 中的每个元素 n
      1. 如果 SameValue(n, "default") 为 false
        1. 如果 n 不是 exportedNames 的元素,
          1. n 加入到 exportedNames
  10. 返回 exportedNames

ResolveExport(exportName [, resolveSet]) 具体方法

实现 模块记录 中对应的抽象方法。

该方法尝试将导入的绑定解析为实际的定义模块和本地绑定名称。该定义模块可能是调用此方法的 模块记录 表示的模块,也可能是该模块导入的其他模块。参数 resolveSet 用于检测未解析的循环导入/导出路径。如果已到达由 resolveSet 中的特定 模块记录exportName 组成的对,可能遇到循环导入。递归调用 ResolveExport 之前,由 moduleexportName 组成的对会被加入到 resolveSet

如果发现定义模块,返回 ResolvedBinding Record { [[Module]], [[BindingName]] }。该记录标识原先请求导出的解析绑定,除非是没有本地绑定的命名导出。在这种情况下,[[BindingName]] 会被设置为 "*namespace*"。如果没有定义模块或发现循环请求,则会返回 null。如果发现请求不明确,返回字符串 "ambiguous"

  1. 如果 resolveSet 不存在,将 resolveSet 设为一个新的空 List
  2. 断言:resolveSet 是一个含有 Record { [[Module]], [[ExportName]] } 的 List
  3. 定义 module源文本模块记录
  4. 遍历 resolveSet 中每个 Record { [[Module]], [[ExportName]] } r
    1. 如果 moduler.[[Module]] 是同一个 模块记录SameValue(exportName, r.[[ExportName]]) 为 true
      1. 断言:这里是循环导入请求
      2. 返回 null
  5. Record { [[Module]]: module, [[ExportName]]: exportName } 加入到 resolveSet
  6. 遍历 module.[[LocalExportEntries]] 中的每个 ExportEntry Record e
    1. 如果 SameValue(exportName, e.[[ExportName]]) 为 true
      1. 断言:module 提供该导出的直接绑定
      2. 返回 ResolvedBinding Record { [[Module]]: module, [[BindingName]]: e.[[LocalName]] }
  7. 遍历 module.[[IndirectExportEntries]] 中的每个 ExportEntry Record e
    1. 如果 SameValue(exportName, e.[[ExportName]]) 为 true
      1. 定义 importedModule? HostResolveImportedModule(module, e.[[ModuleRequest]])
      2. 如果 e.[[ImportName]]"*"
        1. 断言:module 不提供该导出的直接绑定
        2. 返回 ResolvedBinding Record { [[Module]]: importedModule, [[BindingName]]: "*namespace*" }
      3. 否则,
        1. 断言:module 为该导出提供特定绑定
        2. 返回 importedModule.ResolveExport(e.[[ImportName]], resolveSet)
  8. 如果 SameValue(exportName, "default") 为 true
    1. 断言:该模块没有明确定义 default 导出
    2. 返回 null
    3. 注意:default 导出不能由 export *export * from "mod" 声明提供
  9. 定义 starResolutionnull
  10. 遍历 module.[[StarExportEntries]] 中每个 ExportEntry Record e
    1. 定义 importedModule? HostResolveImportedModule(module, e.[[ModuleRequest]])
    2. 定义 resolution? importedModule.ResolveExport(exportName, resolveSet)
    3. 如果 resolution"ambiguous",返回 "ambiguous"
    4. 如果 resolution 不为 null
      1. 断言:resolutionResolvedBinding Record
      2. 如果 starResolutionnull,将其设置为 resolution
      3. 否则,
        1. 断言:有多个 * 导入包含请求的名称
        2. 如果 resolution.[[Module]]starResolution.[[Module]] 不是同一个 模块记录SameValue(resolution.[[BindingName]], starResolution.[[BindingName]]) 为 false,返回 "ambiguous"
  11. 返回 starResolution

太多了,其他方法见下一章!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js基础 Good for newcomers 重学js 重学js系列 规范+MDN
Projects
None yet
Development

No branches or pull requests

1 participant