///|
const MODULE_NAMESPACE_BINDING_NAME = "*namespace*"
///|
const MODULE_DEFAULT_BINDING_NAME = "*default*"
///|
priv struct ResolvedModuleExport {
value : Value
module_specifier : String
binding_name : String
}
///|
fn ResolvedModuleExport::ResolvedModuleExport(
value : Value,
module_specifier : String,
binding_name : String,
) -> ResolvedModuleExport {
{ value, module_specifier, binding_name }
}
///|
priv enum ModuleExportResolution {
Resolved(ResolvedModuleExport)
NotFound
Ambiguous
}
///|
priv enum ModuleImportTarget {
ImportedBinding(String, String)
ImportedNamespace(String)
}
///|
priv enum ModuleDefaultExportBinding {
LocalDefaultBinding(String)
SyntheticDefaultBinding
}
///|
priv enum ModuleResolutionRequest {
Record(ModuleRunRecord, String)
Source(String, String)
ImportTarget(ModuleImportTarget)
}
///|
priv enum ModuleResolutionContinuation {
AfterExplicit(ModuleRunRecord, String)
AfterStarSource(Array[String], String, Int, ModuleExportResolution)
}
///|
priv enum ModuleResolutionControl {
Descend(ModuleResolutionRequest)
Return(ModuleExportResolution)
}
///|
fn Interpreter::predeclare_module_export_tdz(
self : Interpreter,
export_name : String,
) -> Unit {
if !self.module_exports.contains(export_name) {
self.module_exports[export_name] = make_module_tdz_marker(export_name)
}
}
///|
fn Interpreter::predeclare_module_export_cell(
self : Interpreter,
export_name : String,
local_name : String,
env : Environment,
) -> Unit {
if !self.module_exports.contains(export_name) {
self.module_exports[export_name] = make_module_export_cell(
export_name, local_name, env,
)
}
}
///|
fn Interpreter::predeclare_decl_exports(
self : Interpreter,
decl : @ast.Stmt,
env : Environment,
) -> Unit {
for current in flatten_module_stmt_carriers(decl) {
match current {
VarDecl(_, name, _, _) =>
self.predeclare_module_export_cell(name, name, env)
FuncDecl(name, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
FuncDeclExt(name, _, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
GeneratorDecl(name, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
GeneratorDeclExt(name, _, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
AsyncFuncDecl(name, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
AsyncFuncDeclExt(name, _, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
AsyncGeneratorDecl(name, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
AsyncGeneratorDeclExt(name, _, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
ClassDecl(name, _, _, _, _) =>
self.predeclare_module_export_cell(name, name, env)
DestructureDecl(_, pattern, _, _) =>
for name in @static_semantics.bound_names(pattern) {
self.predeclare_module_export_cell(name, name, env)
}
_ => ()
}
}
}
///|
fn Interpreter::predeclare_module_exports(
self : Interpreter,
stmts : Array[@ast.Stmt],
env : Environment,
) -> Unit raise Error {
for root in stmts {
for stmt in flatten_module_stmt_carriers(root) {
match stmt {
ExportNamedDecl(decl, specifiers, source, _, _) => {
match decl {
Some(inner_decl) => self.predeclare_decl_exports(inner_decl, env)
None => ()
}
match source {
Some(_) =>
for spec in specifiers {
self.predeclare_module_export_tdz(spec.exported)
}
None =>
for spec in specifiers {
self.predeclare_module_export_cell(
spec.exported,
spec.local_name,
env,
)
}
}
}
ExportDefaultDecl(expr, _) =>
if !self.predeclare_default_function_export(expr, env) {
match module_default_export_binding(expr) {
LocalDefaultBinding(local_name) =>
self.predeclare_module_export_cell("default", local_name, env)
SyntheticDefaultBinding =>
self.predeclare_module_export_tdz("default")
}
}
ExportAllDecl(Some(ns_name), _, _, _) =>
self.predeclare_module_export_tdz(ns_name)
_ => ()
}
}
}
}
///|
fn Interpreter::materialize_module_exports(
self : Interpreter,
) -> Map[String, Value] raise Error {
let materialized : Map[String, Value] = Map([])
self.module_exports.each(fn(k, v) raise {
if !is_private_module_export_entry(k, v) {
materialized[k] = resolve_module_export_value(v)
}
})
materialized
}
///|
fn Interpreter::new_module_environment(
self : Interpreter,
) -> Environment raise Error {
let env = Environment::new(parent=Some(self.global))
env.is_var_scope = true
env.def("this", Undefined, ConstBinding)
env
}
///|
fn[T] Interpreter::with_module_exports(
self : Interpreter,
exports_map : Map[String, Value],
body : () -> T raise Error,
) -> T raise Error {
let saved_exports = self.module_exports
let saved_bindings = self.module_export_bindings
self.module_exports = exports_map
self.module_export_bindings = []
try {
let result = body()
self.module_exports = saved_exports
self.module_export_bindings = saved_bindings
result
} catch {
e => {
self.module_exports = saved_exports
self.module_export_bindings = saved_bindings
raise e
}
}
}
///|
fn Interpreter::instantiate_module_record(
self : Interpreter,
record : ModuleRunRecord,
) -> Unit raise Error {
self.with_module_exports(record.exports, fn() raise {
with_cleared_active_callee_realm(self.realm_state, fn() raise {
self.validate_block_early_errors(record.stmts, true)
self.hoist_declarations(record.stmts, record.env, strict=true)
hoist_block_tdz(record.stmts, record.env)
self.predeclare_module_exports(record.stmts, record.env)
})
})
}
///|
fn Interpreter::module_exports_for_source(
self : Interpreter,
source : String,
loc : @token.Loc,
) -> Map[String, Value] raise Error {
match self.module_registry.get(source) {
Some(exports) => exports
None =>
match self.host.module_loader {
Some(ModuleLoader(load)) => {
let exports = load(source)
self.module_registry[source] = exports
exports
}
None =>
raise @errors.SyntaxError(
message="Cannot find module '\{source}' at line \{loc.line}, col \{loc.col}",
)
}
}
}
///|
fn Interpreter::instantiate_indirect_exports_from_stmt(
self : Interpreter,
stmt : @ast.Stmt,
records_by_specifier : Map[String, ModuleRunRecord],
) -> Unit raise Error {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ExportNamedDecl(None, specifiers, Some(source), _, loc) =>
for spec in specifiers {
let value = match
self.resolve_module_export_from_source(
source,
spec.local_name,
records_by_specifier,
@set.Set::default(),
) {
Resolved(resolved) => resolved.value
Ambiguous =>
raise @errors.SyntaxError(
message="Ambiguous export '\{spec.local_name}' from module '\{source}' at line \{loc.line}, col \{loc.col}",
)
NotFound =>
raise @errors.SyntaxError(
message="Module '\{source}' does not export '\{spec.local_name}' at line \{loc.line}, col \{loc.col}",
)
}
self.module_exports[spec.exported] = value
}
ExportAllDecl(Some(ns_name), source, _, loc) => {
let src_exports = self.module_exports_for_source(source, loc)
self.module_exports[ns_name] = self.create_module_namespace_object(
src_exports,
)
}
ExportAllDecl(None, _, _, _) => ()
_ => ()
}
}
}
///|
fn Interpreter::instantiate_module_star_exports(
self : Interpreter,
record : ModuleRunRecord,
records_by_specifier : Map[String, ModuleRunRecord],
) -> Unit raise Error {
for
name in self.module_get_exported_names(
record,
records_by_specifier,
@set.Set::default(),
) {
if name != "default" {
match
self.resolve_module_export(
record,
name,
records_by_specifier,
@set.Set::default(),
) {
Resolved(resolved) => self.module_exports[name] = resolved.value
NotFound | Ambiguous => ()
}
}
}
}
///|
fn Interpreter::instantiate_module_indirect_exports(
self : Interpreter,
record : ModuleRunRecord,
records_by_specifier : Map[String, ModuleRunRecord],
) -> Unit raise Error {
self.with_module_exports(record.exports, fn() raise {
with_cleared_active_callee_realm(self.realm_state, fn() raise {
for stmt in record.stmts {
self.instantiate_indirect_exports_from_stmt(stmt, records_by_specifier)
}
self.instantiate_module_star_exports(record, records_by_specifier)
})
})
}
///|
fn Interpreter::instantiate_imports_from_stmt(
self : Interpreter,
stmt : @ast.Stmt,
env : Environment,
) -> Unit raise Error {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ImportDecl(default_import, specifiers, namespace_import, source, _, loc) =>
ignore(
self.exec_import(
default_import, specifiers, namespace_import, source, env, loc,
),
)
_ => ()
}
}
}
///|
fn Interpreter::instantiate_module_imports(
self : Interpreter,
record : ModuleRunRecord,
) -> Unit raise Error {
self.with_module_exports(record.exports, fn() raise {
with_cleared_active_callee_realm(self.realm_state, fn() raise {
for stmt in record.stmts {
self.instantiate_imports_from_stmt(stmt, record.env)
}
})
})
}
///|
fn collect_module_dependency_edges_from_stmt(
stmt : @ast.Stmt,
edges : Array[(String, Bool)],
) -> Unit {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ImportDecl(_, _, _, source, _, _) => edges.push((source, true))
ExportNamedDecl(_, _, Some(source), _, _) => edges.push((source, false))
ExportAllDecl(_, source, _, _) => edges.push((source, false))
_ => ()
}
}
}
///|
fn ModuleRunRecord::dependency_edges(
self : ModuleRunRecord,
) -> Array[(String, Bool)] {
let edges : Array[(String, Bool)] = []
for stmt in self.stmts {
collect_module_dependency_edges_from_stmt(stmt, edges)
}
edges
}
///|
fn ModuleRunRecord::dependencies(self : ModuleRunRecord) -> Array[String] {
let deps : Array[String] = []
for edge in self.dependency_edges() {
deps.push(edge.0)
}
deps
}
///|
fn module_export_resolution_same(
a : ModuleExportResolution,
b : ModuleExportResolution,
) -> Bool {
match (a, b) {
(Resolved(av), Resolved(bv)) =>
av.module_specifier == bv.module_specifier &&
av.binding_name == bv.binding_name
_ => false
}
}
///|
fn add_module_export_name(
names : Array[String],
seen : @set.Set[String],
name : String,
) -> Unit {
if !seen.contains(name) {
seen.add(name)
names.push(name)
}
}
///|
fn decl_exports_name(decl : @ast.Stmt, export_name : String) -> Bool {
for current in flatten_module_stmt_carriers(decl) {
let found = match current {
VarDecl(_, name, _, _) => name == export_name
FuncDecl(name, _, _, _, _) => name == export_name
FuncDeclExt(name, _, _, _, _, _) => name == export_name
GeneratorDecl(name, _, _, _, _) => name == export_name
GeneratorDeclExt(name, _, _, _, _, _) => name == export_name
AsyncFuncDecl(name, _, _, _, _) => name == export_name
AsyncFuncDeclExt(name, _, _, _, _, _) => name == export_name
AsyncGeneratorDecl(name, _, _, _, _) => name == export_name
AsyncGeneratorDeclExt(name, _, _, _, _, _) => name == export_name
ClassDecl(name, _, _, _, _) => name == export_name
DestructureDecl(_, pattern, _, _) => {
let mut matches = false
for name in @static_semantics.bound_names(pattern) {
if name == export_name {
matches = true
break
}
}
matches
}
_ => false
}
if found {
return true
}
}
false
}
///|
fn collect_decl_export_names(
decl : @ast.Stmt,
names : Array[String],
seen : @set.Set[String],
) -> Unit {
for current in flatten_module_stmt_carriers(decl) {
match current {
VarDecl(_, name, _, _)
| FuncDecl(name, _, _, _, _)
| FuncDeclExt(name, _, _, _, _, _)
| GeneratorDecl(name, _, _, _, _)
| GeneratorDeclExt(name, _, _, _, _, _)
| AsyncFuncDecl(name, _, _, _, _)
| AsyncFuncDeclExt(name, _, _, _, _, _)
| AsyncGeneratorDecl(name, _, _, _, _)
| AsyncGeneratorDeclExt(name, _, _, _, _, _)
| ClassDecl(name, _, _, _, _) => add_module_export_name(names, seen, name)
DestructureDecl(_, pattern, _, _) =>
for name in @static_semantics.bound_names(pattern) {
add_module_export_name(names, seen, name)
}
_ => ()
}
}
}
///|
fn module_import_target_from_stmt(
stmt : @ast.Stmt,
local_name : String,
) -> ModuleImportTarget? {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ImportDecl(default_import, specifiers, namespace_import, source, _, _) => {
match default_import {
Some(name) if name == local_name =>
return Some(ImportedBinding(source, "default"))
_ => ()
}
for spec in specifiers {
if spec.local_name == local_name {
return Some(ImportedBinding(source, spec.imported))
}
}
match namespace_import {
Some(name) if name == local_name =>
return Some(ImportedNamespace(source))
_ => ()
}
}
_ => ()
}
}
None
}
///|
fn ModuleRunRecord::import_target_for_local_name(
self : ModuleRunRecord,
local_name : String,
) -> ModuleImportTarget? {
for stmt in self.stmts {
match module_import_target_from_stmt(stmt, local_name) {
Some(target) => return Some(target)
None => ()
}
}
None
}
///|
fn module_default_export_binding(
expr : @ast.Expr,
) -> ModuleDefaultExportBinding {
match expr {
FuncExpr(Some(name), _, _, _, _)
| FuncExprExt(Some(name), _, _, _, _, _)
| GeneratorExpr(Some(name), _, _, _, _)
| GeneratorExprExt(Some(name), _, _, _, _, _)
| AsyncFuncExpr(Some(name), _, _, _, _)
| AsyncFuncExprExt(Some(name), _, _, _, _, _)
| AsyncGeneratorExpr(Some(name), _, _, _, _)
| AsyncGeneratorExprExt(Some(name), _, _, _, _, _)
| ClassExpr(Some(name), _, _, _, _) => LocalDefaultBinding(name)
_ => SyntheticDefaultBinding
}
}
///|
fn module_default_export_binding_name(expr : @ast.Expr) -> String {
match module_default_export_binding(expr) {
LocalDefaultBinding(name) => name
SyntheticDefaultBinding => MODULE_DEFAULT_BINDING_NAME
}
}
///|
fn module_direct_export_binding_name_from_stmt(
record : ModuleRunRecord,
stmt : @ast.Stmt,
export_name : String,
) -> String? {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ExportNamedDecl(Some(decl), _, _, _, _) =>
if decl_exports_name(decl, export_name) {
return Some(export_name)
}
ExportNamedDecl(None, specifiers, None, _, _) =>
for spec in specifiers {
if spec.exported == export_name {
match record.import_target_for_local_name(spec.local_name) {
Some(_) => return None
None => return Some(spec.local_name)
}
}
}
ExportDefaultDecl(expr, _) =>
if export_name == "default" {
return Some(module_default_export_binding_name(expr))
}
_ => ()
}
}
None
}
///|
fn module_record_direct_export_binding_name(
record : ModuleRunRecord,
export_name : String,
) -> String? {
for stmt in record.stmts {
match
module_direct_export_binding_name_from_stmt(record, stmt, export_name) {
Some(binding_name) => return Some(binding_name)
None => ()
}
}
None
}
///|
fn collect_module_direct_export_names_from_stmt(
stmt : @ast.Stmt,
names : Array[String],
seen : @set.Set[String],
) -> Unit {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ExportNamedDecl(Some(decl), _, _, _, _) =>
collect_decl_export_names(decl, names, seen)
ExportNamedDecl(None, specifiers, _, _, _) =>
for spec in specifiers {
add_module_export_name(names, seen, spec.exported)
}
ExportDefaultDecl(_, _) => add_module_export_name(names, seen, "default")
ExportAllDecl(Some(ns_name), _, _, _) =>
add_module_export_name(names, seen, ns_name)
_ => ()
}
}
}
///|
fn module_export_names_from_exports_map(
exports_map : Map[String, Value],
) -> Array[String] {
let names : Array[String] = []
exports_map.each(fn(k, v) {
if !is_private_module_export_entry(k, v) {
names.push(k)
}
})
names
}
///|
fn collect_module_star_sources_from_stmt(
stmt : @ast.Stmt,
sources : Array[String],
) -> Unit {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ExportAllDecl(None, source, _, _) => sources.push(source)
_ => ()
}
}
}
///|
fn ModuleRunRecord::star_sources(self : ModuleRunRecord) -> Array[String] {
let sources : Array[String] = []
for stmt in self.stmts {
collect_module_star_sources_from_stmt(stmt, sources)
}
sources
}
///|
priv enum ModuleExportedNamesRequest {
ExportedNamesRecord(ModuleRunRecord)
ExportedNamesSource(String)
}
///|
priv struct ModuleExportedNamesContinuation {
names : Array[String]
seen_names : @set.Set[String]
sources : Array[String]
next_index : Int
}
///|
fn Interpreter::module_get_exported_names_driver(
self : Interpreter,
initial : ModuleExportedNamesRequest,
records_by_specifier : Map[String, ModuleRunRecord],
seen_modules : @set.Set[String],
) -> Array[String] raise Error {
let continuations : Array[ModuleExportedNamesContinuation] = []
let mut request = initial
let mut returned : Array[String]? = None
for ;; {
match returned {
None =>
match request {
ExportedNamesSource(source) =>
match records_by_specifier.get(source) {
Some(record) => request = ExportedNamesRecord(record)
None =>
returned = Some(
module_export_names_from_exports_map(
self.module_exports_for_source(
source,
@token.Loc::default(),
),
),
)
}
ExportedNamesRecord(record) => {
if seen_modules.contains(record.specifier) {
returned = Some([])
continue
}
seen_modules.add(record.specifier)
let names : Array[String] = []
let seen_names = @set.Set::default()
for stmt in record.stmts {
collect_module_direct_export_names_from_stmt(
stmt, names, seen_names,
)
}
let sources = record.star_sources()
if sources.length() == 0 {
returned = Some(names)
} else {
continuations.push({ names, seen_names, sources, next_index: 1 })
request = ExportedNamesSource(sources[0])
}
}
}
Some(child_names) =>
match continuations.pop() {
None => return child_names
Some(continuation) => {
for name in child_names {
if name != "default" {
add_module_export_name(
continuation.names,
continuation.seen_names,
name,
)
}
}
if continuation.next_index >= continuation.sources.length() {
returned = Some(continuation.names)
} else {
let next_index = continuation.next_index
continuations.push({ ..continuation, next_index: next_index + 1 })
request = ExportedNamesSource(continuation.sources[next_index])
returned = None
}
}
}
}
}
}
///|
#warnings("-unused_value")
fn Interpreter::module_get_exported_names_from_source(
self : Interpreter,
source : String,
records_by_specifier : Map[String, ModuleRunRecord],
seen : @set.Set[String],
) -> Array[String] raise Error {
self.module_get_exported_names_driver(
ExportedNamesSource(source),
records_by_specifier,
seen,
)
}
///|
fn Interpreter::module_get_exported_names(
self : Interpreter,
record : ModuleRunRecord,
records_by_specifier : Map[String, ModuleRunRecord],
seen_modules : @set.Set[String],
) -> Array[String] raise Error {
self.module_get_exported_names_driver(
ExportedNamesRecord(record),
records_by_specifier,
seen_modules,
)
}
///|
fn Interpreter::resolve_module_export_from_source(
self : Interpreter,
source : String,
export_name : String,
records_by_specifier : Map[String, ModuleRunRecord],
resolve_set : @set.Set[String],
) -> ModuleExportResolution raise Error {
self.resolve_module_export_driver(
Source(source, export_name),
records_by_specifier,
resolve_set,
)
}
///|
#warnings("-unused_value")
fn Interpreter::resolve_module_import_target(
self : Interpreter,
target : ModuleImportTarget,
records_by_specifier : Map[String, ModuleRunRecord],
resolve_set : @set.Set[String],
) -> ModuleExportResolution raise Error {
self.resolve_module_export_driver(
ImportTarget(target),
records_by_specifier,
resolve_set,
)
}
///|
fn module_explicit_resolution_request(
record : ModuleRunRecord,
stmt : @ast.Stmt,
export_name : String,
) -> ModuleResolutionRequest? {
for current in flatten_module_stmt_carriers(stmt) {
match current {
ExportNamedDecl(None, specifiers, Some(source), _, _) =>
for spec in specifiers {
if spec.exported == export_name {
return Some(Source(source, spec.local_name))
}
}
ExportNamedDecl(None, specifiers, None, _, _) =>
for spec in specifiers {
if spec.exported == export_name {
match record.import_target_for_local_name(spec.local_name) {
Some(target) => return Some(ImportTarget(target))
None => ()
}
}
}
ExportAllDecl(Some(namespace_name), source, _, _) =>
if namespace_name == export_name {
return Some(ImportTarget(ImportedNamespace(source)))
}
_ => ()
}
}
None
}
///|
fn Interpreter::resolve_module_export_driver(
self : Interpreter,
initial : ModuleResolutionRequest,
records_by_specifier : Map[String, ModuleRunRecord],
resolve_set : @set.Set[String],
) -> ModuleExportResolution raise Error {
let continuations : Array[ModuleResolutionContinuation] = []
let mut control = Descend(initial)
while true {
match control {
Descend(request) =>
match request {
Source(source, export_name) =>
match records_by_specifier.get(source) {
Some(record) => control = Descend(Record(record, export_name))
None =>
control = Return(
match
module_export_map_get_public(
self.module_exports_for_source(
source,
@token.Loc::default(),
),
export_name,
) {
Some(value) =>
Resolved(ResolvedModuleExport(value, source, export_name))
None => NotFound
},
)
}
ImportTarget(target) =>
match target {
ImportedBinding(source, binding_name) =>
control = Descend(Source(source, binding_name))
ImportedNamespace(source) => {
let exports = self.module_exports_for_source(
source,
@token.Loc::default(),
)
control = Return(
Resolved(
ResolvedModuleExport(
self.create_module_namespace_object(exports),
source,
MODULE_NAMESPACE_BINDING_NAME,
),
),
)
}
}
Record(record, export_name) => {
let resolve_key = record.specifier + "\u0000" + export_name
if resolve_set.contains(resolve_key) {
control = Return(NotFound)
continue
}
resolve_set.add(resolve_key)
match
module_record_direct_export_binding_name(record, export_name) {
Some(binding_name) => {
control = Return(
match
module_export_map_get_public(record.exports, export_name) {
Some(value) =>
Resolved(
ResolvedModuleExport(
value,
record.specifier,
binding_name,
),
)
None => NotFound
},
)
continue
}
None => ()
}
match
module_explicit_resolution_request(
record,
StmtList(record.stmts, @token.Loc::default()),
export_name,
) {
Some(child) => {
continuations.push(AfterExplicit(record, export_name))
control = Descend(child)
}
None =>
if export_name == "default" {
control = Return(NotFound)
} else {
let sources = record.star_sources()
if sources.length() == 0 {
control = Return(NotFound)
} else {
continuations.push(
AfterStarSource(sources, export_name, 1, NotFound),
)
control = Descend(Source(sources[0], export_name))
}
}
}
}
}
Return(result) =>
match continuations.pop() {
None => return result
Some(AfterExplicit(record, export_name)) =>
match result {
Resolved(_) | Ambiguous => control = Return(result)
NotFound =>
if export_name == "default" {
control = Return(NotFound)
} else {
let sources = record.star_sources()
if sources.length() == 0 {
control = Return(NotFound)
} else {
continuations.push(
AfterStarSource(sources, export_name, 1, NotFound),
)
control = Descend(Source(sources[0], export_name))
}
}
}
Some(AfterStarSource(sources, export_name, next_index, accumulator)) => {
let next_accumulator = match result {
Ambiguous => Ambiguous
NotFound => accumulator
Resolved(_) =>
match accumulator {
NotFound => result
Resolved(_) =>
if module_export_resolution_same(accumulator, result) {
accumulator
} else {
Ambiguous
}
Ambiguous => Ambiguous
}
}
if next_accumulator is Ambiguous || next_index >= sources.length() {
control = Return(next_accumulator)
} else {
continuations.push(
AfterStarSource(
sources,
export_name,
next_index + 1,
next_accumulator,
),
)
control = Descend(Source(sources[next_index], export_name))
}
}
}
}
}
NotFound
}
///|
fn Interpreter::resolve_module_export(
self : Interpreter,
record : ModuleRunRecord,
export_name : String,
records_by_specifier : Map[String, ModuleRunRecord],
resolve_set : @set.Set[String],
) -> ModuleExportResolution raise Error {
self.resolve_module_export_driver(
Record(record, export_name),
records_by_specifier,
resolve_set,
)
}
///|
fn module_dependency_path_exists(
start : String,
target : String,
records_by_specifier : Map[String, ModuleRunRecord],
seen : @set.Set[String],
) -> Bool {
let pending = [start]
while pending.length() > 0 {
let current = pending.pop().unwrap()
if current == target {
return true
}
if seen.contains(current) {
continue
}
seen.add(current)
match records_by_specifier.get(current) {
Some(record) => {
let dependencies = record.dependencies()
for i = dependencies.length() - 1; i >= 0; i = i - 1 {
pending.push(dependencies[i])
}
}
None => ()
}
}
false
}
///|
fn should_skip_weak_module_back_edge(
record : ModuleRunRecord,
dependency : String,
strong : Bool,
records_by_specifier : Map[String, ModuleRunRecord],
) -> Bool {
!strong &&
module_dependency_path_exists(
dependency,
record.specifier,
records_by_specifier,
@set.Set::default(),
)
}
///|
fn Interpreter::visit_module_dependencies_first(
self : Interpreter,
record : ModuleRunRecord,
records_by_specifier : Map[String, ModuleRunRecord],
state : Map[String, Int],
action : (Interpreter, ModuleRunRecord) -> Unit raise Error,
) -> Unit raise Error {
match state.get(record.specifier) {
Some(2) => return
Some(1) => return
_ => ()
}
state[record.specifier] = 1
let records = [record]
let edges_by_frame = [record.dependency_edges()]
let next_indices = [0]
while records.length() > 0 {
let frame_index = records.length() - 1
let current = records[frame_index]
let edges = edges_by_frame[frame_index]
let edge_index = next_indices[frame_index]
if edge_index >= edges.length() {
action(self, current)
state[current.specifier] = 2
ignore(records.pop())
ignore(edges_by_frame.pop())
ignore(next_indices.pop())
continue
}
next_indices[frame_index] = edge_index + 1
let edge = edges[edge_index]
let dependency = edge.0
let strong = edge.1
if should_skip_weak_module_back_edge(
current, dependency, strong, records_by_specifier,
) {
continue
}
match records_by_specifier.get(dependency) {
Some(dep_record) =>
match state.get(dep_record.specifier) {
Some(1) | Some(2) => ()
_ => {
state[dep_record.specifier] = 1
records.push(dep_record)
edges_by_frame.push(dep_record.dependency_edges())
next_indices.push(0)
}
}
None => ()
}
}
}
///|
fn Interpreter::evaluate_module_record(
self : Interpreter,
record : ModuleRunRecord,
) -> Map[String, Value] raise Error {
self.with_module_exports(record.exports, fn() raise {
with_cleared_active_callee_realm(self.realm_state, fn() raise {
let module_ctx : ExecContext = { strict: true, current_generator: None }
for stmt in record.stmts {
match stmt {
ImportDecl(_, _, _, _, _, _) => ()
ExportNamedDecl(None, _, Some(_), _, _) => ()
ExportAllDecl(_, _, _, _) => ()
_ =>
match self.exec_stmt(module_ctx, stmt, record.env) {
Normal(_) => ()
ReturnSignal(_) =>
raise @errors.SyntaxError(
message="return statement outside of function",
)
sig => raise_if_break_continue(sig)
}
}
}
// Resolve deferred export bindings from module environment. If
// instantiation already installed a live export cell, keep it live for
// dependents that execute later in the same module graph; final facade
// results are materialized only after graph evaluation completes.
for pair in self.module_export_bindings {
let (export_name, local_name) = pair
match self.module_exports.get(export_name) {
Some(value) if module_export_entry_is_live_cell(value) => ()
_ => self.module_exports[export_name] = record.env.get(local_name)
}
}
self.module_exports
})
})
}
///|
fn Interpreter::materialize_module_record(
self : Interpreter,
record : ModuleRunRecord,
) -> Map[String, Value] raise Error {
self.with_module_exports(record.exports, fn() raise {
self.materialize_module_exports()
})
}
///|
fn Interpreter::run_module_into(
self : Interpreter,
stmts : Array[@ast.Stmt],
exports_map : Map[String, Value],
) -> Map[String, Value] raise Error {
let record = {
specifier: "",
stmts,
exports: exports_map,
env: self.new_module_environment(),
}
self.instantiate_module_record(record)
self.instantiate_module_indirect_exports(record, Map([]))
self.instantiate_module_imports(record)
ignore(self.evaluate_module_record(record))
self.materialize_module_record(record)
}
///|
/// Run a module source and return its exports
pub fn Interpreter::run_module(
self : Interpreter,
stmts : Array[@ast.Stmt],
) -> Map[String, Value] raise Error {
self.run_module_into(stmts, Map([]))
}
///|
/// Run multiple modules with all specifiers registered before evaluation.
/// The graph pass evaluates provided dependencies before importers while still
/// letting self-imports and simple cyclic fixtures resolve through the registry.
pub fn Interpreter::run_modules(
self : Interpreter,
modules : Array[(String, String)],
) -> Map[String, Value] raise Error {
let records : Array[ModuleRunRecord] = []
let registrations : Array[(String, Map[String, Value])] = []
for pair in modules {
let (specifier, source) = pair
let prog = @parser.parse(source)
let exports : Map[String, Value] = Map([])
let record = {
specifier,
stmts: prog.stmts,
exports,
env: self.new_module_environment(),
}
records.push(record)
registrations.push((specifier, exports))
}
for pair in registrations {
let (specifier, exports) = pair
self.register_module(specifier, exports)
}
for record in records {
self.instantiate_module_record(record)
}
let records_by_specifier : Map[String, ModuleRunRecord] = Map([])
for record in records {
records_by_specifier[record.specifier] = record
}
let indirect_state : Map[String, Int] = Map([])
for record in records {
self.visit_module_dependencies_first(
record,
records_by_specifier,
indirect_state,
fn(interp, rec) raise {
interp.instantiate_module_indirect_exports(rec, records_by_specifier)
},
)
}
for record in records {
self.instantiate_module_imports(record)
}
let evaluation_state : Map[String, Int] = Map([])
for record in records {
self.visit_module_dependencies_first(
record,
records_by_specifier,
evaluation_state,
fn(interp, rec) raise { ignore(interp.evaluate_module_record(rec)) },
)
}
match records.last() {
Some(last_record) => self.materialize_module_record(last_record)
None => Map([])
}
}