mirror of
https://github.com/voltrevo/ValueScript.git
synced 2026-04-18 03:00:27 -04:00
wip gather and link
This commit is contained in:
@@ -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>,
|
||||
}
|
||||
|
||||
150
valuescript_compiler/src/gather_modules.rs
Normal file
150
valuescript_compiler/src/gather_modules.rs
Normal 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
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
33
valuescript_compiler/src/link_module.rs
Normal file
33
valuescript_compiler/src/link_module.rs
Normal 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
|
||||
}
|
||||
@@ -3,7 +3,8 @@ use std::io::Write;
|
||||
use std::process::exit;
|
||||
|
||||
use super::handle_diagnostics_cli::handle_diagnostics_cli;
|
||||
use valuescript_compiler::compile;
|
||||
use valuescript_compiler::gather_modules;
|
||||
use valuescript_compiler::link_module;
|
||||
|
||||
pub fn compile_command(args: &Vec<String>) {
|
||||
if args.len() != 3 {
|
||||
@@ -12,19 +13,36 @@ pub fn compile_command(args: &Vec<String>) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
let source = std::fs::read_to_string(&args[2]).expect("Failed to read file");
|
||||
let compiler_output = compile(&source);
|
||||
let entry_path = &args[2];
|
||||
|
||||
handle_diagnostics_cli(&args[2], &compiler_output.diagnostics);
|
||||
let abs_entry_path = std::fs::canonicalize(entry_path)
|
||||
.expect("Failed to get absolute path")
|
||||
.to_str()
|
||||
.expect("Failed to convert to str")
|
||||
.to_string();
|
||||
|
||||
let gm = gather_modules(abs_entry_path, |path| {
|
||||
std::fs::read_to_string(path).map_err(|err| err.to_string())
|
||||
});
|
||||
|
||||
for (path, diagnostics) in gm.diagnostics.iter() {
|
||||
handle_diagnostics_cli(path, diagnostics);
|
||||
}
|
||||
|
||||
let link_module_result = link_module(&gm.entry_point, &gm.modules);
|
||||
|
||||
// FIXME: Diagnostics from link_module should have paths associated
|
||||
handle_diagnostics_cli(&gm.entry_point, &link_module_result.diagnostics);
|
||||
|
||||
let module = link_module_result
|
||||
.module
|
||||
.expect("Should have exited if module is None");
|
||||
|
||||
let mut file = File::create("out.vsm").expect("Couldn't create out.vsm");
|
||||
|
||||
for line in compiler_output.module.as_lines() {
|
||||
file
|
||||
.write_all(line.as_bytes())
|
||||
.expect("Failed to write line");
|
||||
file.write_all(b"\n").expect("Failed to write line");
|
||||
}
|
||||
file
|
||||
.write(module.to_string().as_bytes())
|
||||
.expect("Failed to write out.vsm");
|
||||
}
|
||||
|
||||
fn show_help() {
|
||||
|
||||
Reference in New Issue
Block a user