Implement export star

This commit is contained in:
Andrew Morris
2023-07-26 15:29:49 +10:00
parent 960e5ef879
commit b683e47bc5
20 changed files with 204 additions and 25 deletions

View File

@@ -78,6 +78,7 @@ where
};
let mut compiler_output = compile_module(&file_contents);
// println!("{}: {}", dependency.path, compiler_output.module);
gm.diagnostics
.entry(dependency.path.clone())

View File

@@ -6,6 +6,7 @@ pub struct ImportPattern {
pub kind: ImportKind,
}
#[derive(PartialEq, Eq)]
pub enum ImportKind {
Default,
Star,

View File

@@ -1,6 +1,9 @@
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap, HashSet};
use std::mem::swap;
use crate::asm::{Definition, DefinitionContent, ExportStar, FnLine, Instruction, Pointer, Value};
use crate::asm::{
Definition, DefinitionContent, ExportStar, FnLine, Instruction, Object, Pointer, Value,
};
use crate::gather_modules::PathAndModule;
use crate::import_pattern::{ImportKind, ImportPattern};
use crate::name_allocator::NameAllocator;
@@ -174,7 +177,14 @@ fn link_import_patterns(
included_modules: &HashMap<ResolvedPath, (Value, ExportStar)>,
diagnostics: &mut Vec<Diagnostic>,
) {
for definition in &mut module.definitions {
module.export_star = ExportStar {
includes: vec![],
local: flatten_export_star(&module.export_star, &*module, included_modules, diagnostics),
};
let mut new_definitions = HashMap::<Pointer, Definition>::new();
for definition in &module.definitions {
let import_pattern = match ImportPattern::decode(definition) {
Some(import_pattern) => import_pattern,
None => continue,
@@ -185,24 +195,21 @@ fn link_import_patterns(
path: import_pattern.path.clone(),
};
let (default, namespace) = match included_modules.get(&resolved_path) {
let (default, export_star) = match included_modules.get(&resolved_path) {
Some(el) => el,
None => continue,
};
let export_star = flatten_export_star(export_star, module, included_modules, diagnostics);
let new_definition = Definition {
pointer: import_pattern.pointer,
pointer: import_pattern.pointer.clone(),
content: match import_pattern.kind {
ImportKind::Default => DefinitionContent::Value(default.clone()),
ImportKind::Star => {
// TODO: namespace.includes
DefinitionContent::Value(Value::Object(Box::new(namespace.local.clone())))
}
ImportKind::Name(name) => match namespace.local.try_resolve_key(&name) {
ImportKind::Star => DefinitionContent::Value(Value::Object(Box::new(export_star.clone()))),
ImportKind::Name(name) => match export_star.try_resolve_key(&name) {
Some(value) => DefinitionContent::Value(value.clone()),
None => {
// TODO: namespace.includes
diagnostics.push(Diagnostic {
level: DiagnosticLevel::Error,
message: format!(
@@ -218,6 +225,124 @@ fn link_import_patterns(
},
};
*definition = new_definition;
new_definitions.insert(import_pattern.pointer, new_definition);
}
for definition in &mut module.definitions {
if let Some(new_definition) = new_definitions.get_mut(&definition.pointer) {
swap(definition, new_definition);
}
}
}
fn flatten_export_star(
export_star: &ExportStar,
module: &Module,
included_modules: &HashMap<ResolvedPath, (Value, ExportStar)>,
diagnostics: &mut Vec<Diagnostic>,
) -> Object {
let mut include_pointers_to_process = export_star.includes.clone();
let mut include_map = BTreeMap::<String, Value>::new();
let mut processed_includes = HashSet::<ResolvedPath>::new();
let mut i = 0;
while i < include_pointers_to_process.len() {
let include_p = include_pointers_to_process[i].clone();
i += 1;
let mut matched = false;
for defn in &module.definitions {
if defn.pointer == include_p {
matched = true;
let ip = match ImportPattern::decode(defn) {
Some(ip) => ip,
None => {
diagnostics.push(Diagnostic::internal_error(
swc_common::DUMMY_SP,
"Expected import pattern",
));
break;
}
};
if ip.kind != ImportKind::Star {
diagnostics.push(Diagnostic::internal_error(
swc_common::DUMMY_SP,
"Expected import star pattern",
));
break;
}
let path = ResolvedPath::from(ip.path);
let inserted = processed_includes.insert(path.clone());
if !inserted {
break;
}
let matched_export_star = match included_modules.get(&path) {
Some((_, es)) => es,
None => {
diagnostics.push(Diagnostic::internal_error(
swc_common::DUMMY_SP,
"Missing module",
));
break;
}
};
for (k, v) in &matched_export_star.local.properties {
let k_string = match k {
Value::String(k_string) => k_string.clone(),
_ => {
diagnostics.push(Diagnostic::internal_error(
swc_common::DUMMY_SP,
"Expected exported name to be a string",
));
continue;
}
};
let old_value = include_map.insert(k_string.clone(), v.clone());
if old_value.is_some() {
diagnostics.push(Diagnostic::error(
swc_common::DUMMY_SP,
&format!("Conflicting export {}", k_string),
));
}
}
include_pointers_to_process.append(&mut matched_export_star.includes.clone());
break;
}
}
if !matched {
diagnostics.push(Diagnostic::internal_error(
swc_common::DUMMY_SP,
"Failed to match export* pointer",
));
}
}
let mut obj = Object::default();
for (key, value) in include_map {
obj.properties.push((Value::String(key), value));
}
obj
.properties
.append(&mut export_star.local.properties.clone());
obj
}

View File

@@ -176,7 +176,7 @@ impl ModuleCompiler {
ExportNamed(en) => self.compile_named_export(en),
ExportDefaultDecl(edd) => self.compile_export_default_decl(edd),
ExportDefaultExpr(ede) => self.module.export_default = self.static_ec().expr(&ede.expr),
ExportAll(_) => self.todo(module_decl.span(), "ExportAll declaration"),
ExportAll(ea) => self.compile_export_all(ea),
TsImportEquals(_) => self.not_supported(module_decl.span(), "TsImportEquals declaration"),
TsExportAssignment(_) => {
self.not_supported(module_decl.span(), "TsExportAssignment declaration")
@@ -559,6 +559,22 @@ impl ModuleCompiler {
}
}
fn compile_export_all(&mut self, ea: &swc_ecma_ast::ExportAll) {
let defn = self.allocate_defn(&format!("{}_export_star", ident_from_str(&ea.src.value)));
self.module.definitions.push(Definition {
pointer: defn.clone(),
content: DefinitionContent::Lazy(Lazy {
body: vec![FnLine::Instruction(Instruction::ImportStar(
Value::String(ea.src.value.to_string()),
Register::return_(),
))],
}),
});
self.module.export_star.includes.push(defn);
}
fn compile_import(&mut self, import: &swc_ecma_ast::ImportDecl) {
if import.type_only {
return;