///|
/// Execute an import declaration
fn Interpreter::exec_import(
self : Interpreter,
default_import : String?,
specifiers : Array[@ast.ImportSpecifier],
namespace_import : String?,
source : String,
env : Environment,
loc : @token.Loc,
) -> Signal raise Error {
// Look up module in registry; fall back to module_loader if provided
let module_exports = match self.module_registry.get(source) {
Some(exports) => exports
None =>
match self.host.module_loader {
Some(ModuleLoader(load)) => {
let exports = load(source)
// Cache the result so repeated imports of the same specifier are free
self.module_registry[source] = exports
exports
}
None =>
raise @errors.SyntaxError(
message="Cannot find module '\{source}' at line \{loc.line}, col \{loc.col}",
)
}
}
// import defaultExport from 'source'
match default_import {
Some(name) =>
match module_export_map_get_public(module_exports, "default") {
Some(_) =>
env.def(
name,
make_module_import_cell("default", module_exports),
ConstBinding,
)
None =>
raise @errors.SyntaxError(
message="Module '\{source}' does not have a default export at line \{loc.line}, col \{loc.col}",
)
}
None => ()
}
// import { name1, name2 as alias } from 'source'
for spec in specifiers {
match module_export_map_get_public(module_exports, spec.imported) {
Some(_) =>
env.def(
spec.local_name,
make_module_import_cell(spec.imported, module_exports),
ConstBinding,
)
None =>
raise @errors.SyntaxError(
message="Module '\{source}' does not export '\{spec.imported}' at line \{loc.line}, col \{loc.col}",
)
}
}
// import * as namespace from 'source'
match namespace_import {
Some(name) =>
env.def(
name,
self.create_module_namespace_object(module_exports),
ConstBinding,
)
None => ()
}
Normal(Undefined)
}
///|
/// Execute a named export declaration
fn Interpreter::exec_export_named(
self : Interpreter,
ctx : ExecContext,
decl : @ast.Stmt?,
specifiers : Array[@ast.ExportSpecifier],
source : String?,
env : Environment,
loc : @token.Loc,
) -> Signal raise Error {
// export let/const/var/function/class ...
match decl {
Some(inner_decl) => {
let signal = self.exec_stmt(ctx, inner_decl, env)
// Record declared names for final materialization. During evaluation,
// predeclared ModuleExportCell entries read directly from `env`.
self.extract_export_names(inner_decl)
return signal
}
None => ()
}
// export { name1, name2 as alias } [from 'source']
match source {
Some(src) => {
// Re-export from another module. Keep any ModuleExportCell intact so
// namespace objects observe live values while a cycle is evaluating.
let src_exports = match self.module_registry.get(src) {
Some(exports) => exports
None =>
match self.host.module_loader {
Some(ModuleLoader(load)) => {
let exports = load(src)
self.module_registry[src] = exports
exports
}
None =>
raise @errors.SyntaxError(
message="Cannot find module '\{src}' at line \{loc.line}, col \{loc.col}",
)
}
}
for spec in specifiers {
let value = match
module_export_map_get_public(src_exports, spec.local_name) {
Some(v) => v
None =>
raise @errors.SyntaxError(
message="Module '\{src}' does not export '\{spec.local_name}' at line \{loc.line}, col \{loc.col}",
)
}
self.module_exports[spec.exported] = value
}
}
None =>
// Local export: defer final resolution for live bindings.
for spec in specifiers {
self.module_export_bindings.push((spec.exported, spec.local_name))
}
}
Normal(Undefined)
}
///|
/// Execute export * from 'source' or export * as name from 'source'
fn Interpreter::exec_export_all(
self : Interpreter,
ns_alias : String?,
source : String,
loc : @token.Loc,
) -> Signal raise Error {
let src_exports = 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}",
)
}
}
match ns_alias {
Some(name) =>
// export * as name from 'source' - create namespace object
self.module_exports[name] = self.create_module_namespace_object(
src_exports,
)
None =>
// export * from 'source' - re-export all (except default)
src_exports.each(fn(k, v) {
let should_copy = match self.module_exports.get(k) {
Some(Object(data)) if data.class_name == "ModuleTDZ" => true
Some(_) => false
None => true
}
if k != "default" &&
!is_private_module_export_entry(k, v) &&
should_copy {
let export_value = match module_namespace_public_export_value(v) {
Some(public_value) => public_value
None => v
}
self.module_exports[k] = export_value
}
})
}
Normal(Undefined)
}
///|
/// Return the non-`StmtList` statements carried by `stmt` in source order.
/// Semantic wrappers and statement bodies are deliberately left intact.
fn flatten_module_stmt_carriers(stmt : @ast.Stmt) -> Array[@ast.Stmt] {
let flattened : Array[@ast.Stmt] = []
let work = [stmt]
while work.pop() is Some(current) {
match current {
StmtList(stmts, _) =>
for i = stmts.length() - 1; i >= 0; i = i - 1 {
work.push(stmts[i])
}
_ => flattened.push(current)
}
}
flattened
}
///|
/// Record exported names from a declaration for deferred resolution (live bindings)
fn Interpreter::extract_export_names(
self : Interpreter,
decl : @ast.Stmt,
) -> Unit {
for current in flatten_module_stmt_carriers(decl) {
match current {
VarDecl(_, name, _, _) => self.module_export_bindings.push((name, name))
FuncDecl(name, _, _, _, _) =>
self.module_export_bindings.push((name, name))
FuncDeclExt(name, _, _, _, _, _) =>
self.module_export_bindings.push((name, name))
GeneratorDecl(name, _, _, _, _) =>
self.module_export_bindings.push((name, name))
GeneratorDeclExt(name, _, _, _, _, _) =>
self.module_export_bindings.push((name, name))
AsyncFuncDecl(name, _, _, _, _) =>
self.module_export_bindings.push((name, name))
AsyncFuncDeclExt(name, _, _, _, _, _) =>
self.module_export_bindings.push((name, name))
AsyncGeneratorDecl(name, _, _, _, _) =>
self.module_export_bindings.push((name, name))
AsyncGeneratorDeclExt(name, _, _, _, _, _) =>
self.module_export_bindings.push((name, name))
ClassDecl(name, _, _, _, _) =>
self.module_export_bindings.push((name, name))
DestructureDecl(_, pattern, _, _) =>
for name in @static_semantics.bound_names(pattern) {
self.module_export_bindings.push((name, name))
}
_ => ()
}
}
}
///|
/// Register a module's exports in the module registry
pub fn Interpreter::register_module(
self : Interpreter,
specifier : String,
exports : Map[String, Value],
) -> Unit {
self.module_registry[specifier] = exports
}