wip gather and link

This commit is contained in:
Andrew Morris
2023-03-08 22:29:58 +11:00
parent 452a2c5e06
commit 5e95be162e
5 changed files with 221 additions and 16 deletions

View File

@@ -1,4 +1,4 @@
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Module {
pub export_default: Value,
pub export_star: Object,
@@ -47,7 +47,7 @@ impl std::fmt::Display for Module {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Definition {
pub pointer: Pointer,
pub content: DefinitionContent,
@@ -59,7 +59,7 @@ impl std::fmt::Display for Definition {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum DefinitionContent {
Function(Function),
Class(Class),
@@ -97,7 +97,7 @@ impl std::fmt::Display for Pointer {
}
}
#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Function {
pub parameters: Vec<Register>,
pub body: Vec<InstructionOrLabel>,
@@ -127,7 +127,7 @@ impl std::fmt::Display for Function {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Class {
pub constructor: Value,
pub methods: Value,
@@ -513,7 +513,7 @@ impl std::fmt::Display for Value {
}
}
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Lazy {
pub body: Vec<InstructionOrLabel>,
}

View File

@@ -0,0 +1,150 @@
use std::{
collections::{HashMap, HashSet},
path::{Path, PathBuf},
};
use queues::{IsQueue, Queue};
use crate::{
asm::{DefinitionContent, Instruction, InstructionOrLabel, Module, Value},
compile, Diagnostic, DiagnosticLevel,
};
#[derive(Clone, Debug)]
enum DependencyReason {
EntryPoint,
ImportedBy(String),
}
#[derive(Clone)]
struct Dependency {
path: String,
reason: DependencyReason,
}
pub struct GatheredModules {
pub entry_point: String,
pub modules: HashMap<String, Module>,
pub diagnostics: HashMap<String, Vec<Diagnostic>>,
}
pub fn gather_modules<ReadFile>(entry_point: String, read_file: ReadFile) -> GatheredModules
where
ReadFile: Fn(&str) -> Result<String, String>,
{
let mut gm = GatheredModules {
entry_point,
modules: HashMap::new(),
diagnostics: HashMap::new(),
};
let mut dependencies = Queue::<Dependency>::new();
dependencies
.add(Dependency {
path: gm.entry_point.clone(),
reason: DependencyReason::EntryPoint,
})
.expect("Failed to add to queue");
loop {
let dependency = match dependencies.remove() {
Ok(dependency) => dependency,
Err(_) => break,
};
let file_contents = match read_file(&dependency.path) {
Ok(file_contents) => file_contents,
Err(err) => {
gm.diagnostics
.entry(dependency.path.clone())
.or_insert(vec![])
.push(Diagnostic {
level: DiagnosticLevel::Error,
message: match dependency.reason {
DependencyReason::EntryPoint => format!("File read failed: {}", err),
DependencyReason::ImportedBy(importer) => {
format!("Error reading file imported by {}: {}", importer, err)
}
},
span: swc_common::DUMMY_SP,
});
continue;
}
};
let mut compiler_output = compile(&file_contents);
gm.diagnostics
.entry(dependency.path.clone())
.or_insert(vec![])
.append(&mut compiler_output.diagnostics);
for imported_path in get_imported_paths(
&compiler_output.module,
&DependencyReason::ImportedBy(dependency.path.clone()),
) {
if gm.modules.contains_key(&imported_path) {
continue;
}
dependencies
.add(Dependency {
path: imported_path,
reason: DependencyReason::ImportedBy(dependency.path.clone()),
})
.expect("Failed to add to queue");
}
gm.modules.insert(dependency.path, compiler_output.module);
}
gm
}
fn get_imported_paths(module: &Module, reason: &DependencyReason) -> HashSet<String> {
let mut imported_paths = HashSet::<String>::new();
for definition in &module.definitions {
let lazy = match &definition.content {
DefinitionContent::Lazy(lazy) => lazy,
_ => continue,
};
match lazy.body.first() {
Some(InstructionOrLabel::Instruction(instruction)) => {
match instruction {
Instruction::Import(import_path, _) | Instruction::ImportStar(import_path, _) => {
match import_path {
Value::String(import_path) => {
let resolved_path = match reason {
DependencyReason::EntryPoint => import_path.clone(),
DependencyReason::ImportedBy(importer) => {
let importer_path = PathBuf::from(importer);
let parent = importer_path.parent().unwrap_or_else(|| Path::new("/"));
parent
.join(import_path)
.canonicalize()
.expect("Failed to canonicalize path")
.to_str()
.expect("Failed to convert path to string")
.to_string()
}
};
imported_paths.insert(resolved_path);
}
_ => {}
}
}
_ => {}
};
}
_ => {}
}
}
imported_paths
}

View File

@@ -5,6 +5,8 @@ mod capture_finder;
mod diagnostic;
mod expression_compiler;
mod function_compiler;
mod gather_modules;
mod link_module;
mod module_compiler;
mod name_allocator;
mod scope;
@@ -14,5 +16,7 @@ pub use assembler::assemble;
pub use assembly_parser::parse_module;
pub use diagnostic::Diagnostic;
pub use diagnostic::DiagnosticLevel;
pub use gather_modules::gather_modules;
pub use link_module::link_module;
pub use module_compiler::compile;
pub use module_compiler::CompilerOutput;

View File

@@ -0,0 +1,33 @@
use std::collections::HashMap;
use crate::DiagnosticLevel;
use crate::{asm::Module, Diagnostic};
pub struct LinkModuleResult {
pub module: Option<Module>,
pub diagnostics: Vec<Diagnostic>,
}
pub fn link_module(entry_point: &String, modules: &HashMap<String, Module>) -> LinkModuleResult {
let mut result = LinkModuleResult {
module: None,
diagnostics: vec![],
};
result.module = Some(match modules.get(&entry_point.clone()) {
Some(module) => module.clone(),
None => {
result.diagnostics.push(Diagnostic {
level: DiagnosticLevel::Error,
message: format!("Module not found: {}", entry_point),
span: swc_common::DUMMY_SP,
});
return result;
}
});
// TODO
result
}