167 lines
4.7 KiB
Rust
167 lines
4.7 KiB
Rust
use std::{collections::HashMap, fs, rc::Rc};
|
|
|
|
use compiler::compile;
|
|
use parser::parse;
|
|
use semantics::{check, Error, Semantics};
|
|
use vm::{eval, Context};
|
|
|
|
pub mod compiler;
|
|
pub mod parser;
|
|
pub mod semantics;
|
|
pub mod tokens;
|
|
pub mod vm;
|
|
|
|
pub enum ModuleSource {
|
|
SourceText(String),
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub enum ModuleLoadError {
|
|
IO(std::io::Error),
|
|
}
|
|
|
|
pub trait ModuleLoader {
|
|
fn normalize_module_name(&self, name: String) -> String;
|
|
fn load_module(&self, name: &String) -> Result<ModuleSource, ModuleLoadError>;
|
|
}
|
|
|
|
pub struct StandardModuleLoader {}
|
|
|
|
impl ModuleLoader for StandardModuleLoader {
|
|
fn normalize_module_name(&self, name: String) -> String {
|
|
match std::fs::canonicalize(&name) {
|
|
Ok(p) => match p.into_os_string().into_string() {
|
|
Ok(s) => s,
|
|
Err(_) => name,
|
|
},
|
|
Err(_) => name,
|
|
}
|
|
}
|
|
|
|
fn load_module(&self, name: &String) -> Result<ModuleSource, ModuleLoadError> {
|
|
match fs::read_to_string(name) {
|
|
Ok(c) => Ok(ModuleSource::SourceText(c)),
|
|
Err(e) => Err(ModuleLoadError::IO(e)),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub struct Module {
|
|
module: Rc<compiler::Module>,
|
|
semantics: Rc<Semantics>,
|
|
}
|
|
|
|
impl Module {
|
|
pub fn semantics(&self) -> Rc<Semantics> {
|
|
self.semantics.clone()
|
|
}
|
|
|
|
pub fn compiled(&self) -> Rc<compiler::Module> {
|
|
self.module.clone()
|
|
}
|
|
}
|
|
|
|
pub struct Runtime {
|
|
modules: HashMap<String, Rc<Module>>,
|
|
loader: Box<dyn ModuleLoader>,
|
|
}
|
|
|
|
impl Runtime {
|
|
pub fn new(loader: Box<dyn ModuleLoader>) -> Self {
|
|
Runtime {
|
|
modules: HashMap::new(),
|
|
loader,
|
|
}
|
|
}
|
|
|
|
pub fn load_module(&mut self, name: &str) -> Result<(Vec<Error>, Rc<Module>), ModuleLoadError> {
|
|
let mut init_pending = HashMap::new();
|
|
let mut names = Vec::new();
|
|
let name = self.loader.normalize_module_name(name.to_string());
|
|
names.push(name.clone());
|
|
|
|
while let Some(name) = names.pop() {
|
|
if self.modules.contains_key(&name) {
|
|
continue;
|
|
}
|
|
if !init_pending.contains_key(&name) {
|
|
let loaded = self.loader.load_module(&name)?;
|
|
match loaded {
|
|
ModuleSource::SourceText(source) => {
|
|
let source: Rc<str> = source.into();
|
|
let (tree, lines) = parse(&source);
|
|
let semantics = Rc::new(Semantics::new(source, tree, lines));
|
|
|
|
let mut normalized = Vec::new();
|
|
for import in semantics.imports() {
|
|
let import = self.loader.normalize_module_name(import);
|
|
names.push(import.clone());
|
|
normalized.push(import);
|
|
}
|
|
|
|
init_pending.insert(name, (normalized, semantics));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (_, (imports, semantics)) in init_pending.iter() {
|
|
let mut import_table = HashMap::new();
|
|
for import in imports.iter() {
|
|
let target = if let Some(module) = self.modules.get(&*import) {
|
|
Rc::downgrade(&module.semantics)
|
|
} else {
|
|
Rc::downgrade(&init_pending.get(&*import).unwrap().1)
|
|
};
|
|
import_table.insert(import.clone(), target);
|
|
}
|
|
semantics.set_imports(import_table);
|
|
}
|
|
|
|
let mut errors = Vec::new();
|
|
for (name, (_, semantics)) in init_pending.into_iter() {
|
|
check(&semantics);
|
|
errors.append(&mut semantics.snapshot_errors());
|
|
let module = compile(&semantics);
|
|
self.modules
|
|
.insert(name, Rc::new(Module { semantics, module }));
|
|
}
|
|
|
|
let result = self.modules.get(&name).unwrap().clone();
|
|
Ok((errors, result))
|
|
}
|
|
}
|
|
|
|
pub fn process_file(file: &str) {
|
|
let mut runtime = Runtime::new(Box::new(StandardModuleLoader {}));
|
|
|
|
let (errors, module) = match runtime.load_module(file) {
|
|
Ok(r) => r,
|
|
Err(_) => {
|
|
eprintln!("Error loading module");
|
|
return;
|
|
}
|
|
};
|
|
|
|
// OK now there might be errors.
|
|
if errors.len() > 0 {
|
|
for e in errors {
|
|
eprintln!("{file}: {}:{}: {}", e.start.0, e.start.1, e.message);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// shrug
|
|
let module = module.module.clone();
|
|
let main_function = module.functions[module.init].clone();
|
|
|
|
let mut context = Context::new(module.clone());
|
|
match eval(&mut context, main_function, vec![]) {
|
|
Ok(v) => {
|
|
println!("{:?}", v);
|
|
}
|
|
Err(e) => {
|
|
eprintln!("{:?}", e);
|
|
}
|
|
}
|
|
}
|