use std::collections::{HashSet, HashMap};
use std::path::PathBuf;
use std::rc::Rc;
+use std::include_str;
use anyhow::{Result, bail};
text: Vec<IR>,
imports: Vec<Rc<IRModule>>,
exports: Vec<String>,
- source_file: PathBuf,
+ // TODO these next two should form an enum, not two options
+ source_file: Option<PathBuf>,
+ std_specifier: Option<String>,
number: usize,
}
struct ImportTree {
data: Vec<IR>,
text: Vec<IR>,
- all_modules: HashMap<PathBuf, Rc<IRModule>>,
+ all_modules: HashMap<String, Rc<IRModule>>,
all_exports: HashSet<String>,
entrypoint: Rc<IRModule>,
module_count: usize,
- collapse_seen: HashSet<PathBuf>,
+ collapse_seen: HashSet<String>,
+}
+
+fn std_import(specifier: &str) -> Result<&str> {
+ match specifier {
+ "std:mem" => Ok(include_str!("../../stdlib/mem.rel")),
+ "std:out" => Ok(include_str!("../../stdlib/out.rel")),
+ _ => bail!("{} is not a standard library module", specifier),
+ }
}
impl ImportTree {
fn import(&mut self, importer_dir: &PathBuf, specifier: &str, is_entrypoint: bool) -> Result<Rc<IRModule>> {
- let mut path = PathBuf::from(specifier);
- if path.is_relative() {
- let mut new_path = importer_dir.clone();
- new_path.push(path);
- path = new_path.canonicalize()?;
- }
- if self.all_modules.contains_key(&path) {
- let module = self.all_modules.get(&path).unwrap().clone();
- return Ok(module);
- }
+ Ok(if specifier.starts_with("std:") {
+ let contents = std_import(specifier)?;
+ let parsed = &Module::parse(tokenize(&contents)?, is_entrypoint)?;
+ let module = self.generate_internal(None, Some(specifier.to_string()), parsed);
+ let module = Rc::new(module);
+ self.all_modules.insert(specifier.to_string(), module.clone());
+ module
+ } else {
+ let mut path = PathBuf::from(specifier);
+ if path.is_relative() {
+ let mut new_path = importer_dir.clone();
+ new_path.push(path);
+ path = new_path.canonicalize()?;
+ }
+ let path_key = path.to_string_lossy().to_string();
+ if self.all_modules.contains_key(&path_key) {
+ let module = self.all_modules.get(&path_key).unwrap().clone();
+ return Ok(module);
+ }
- let contents = std::fs::read_to_string(&path)?;
+ let contents = &std::fs::read_to_string(&path)?;
+ let module = self.generate_internal(Some(path), None, &Module::parse(tokenize(&contents)?, is_entrypoint)?);
+ let module = Rc::new(module);
+ self.all_modules.insert(path_key, module.clone());
+ if is_entrypoint {
+ self.entrypoint = module.clone();
+ }
+ module
+ })
- let module = self.generate_internal(path, &Module::parse(tokenize(&contents)?, is_entrypoint)?);
- let module = Rc::new(module);
- self.all_modules.insert(module.source_file.clone(), module.clone());
- if is_entrypoint {
- self.entrypoint = module.clone();
- }
- Ok(module)
}
- fn generate_internal(&mut self, path: PathBuf, module: &Module) -> IRModule {
+ fn generate_internal(&mut self, path: Option<PathBuf>, std_specifier: Option<String>, module: &Module) -> IRModule {
// Eventually these will end up being sections in assembly
let mut text = vec![];
let mut data = vec![];
let mut imports = vec![];
- module.imports.iter().for_each(|imported| {
- if let Some(parent_path) = path.parent() {
- match self.import(&parent_path.to_path_buf(), imported, false) {
+ if let Some(ref path) = path {
+ module.imports.iter().for_each(|imported| {
+ if let Some(parent_path) = path.parent() {
+ match self.import(&parent_path.to_path_buf(), imported, false) {
+ Ok(module) => {
+ imports.push(module);
+ },
+ Err(msg) => {
+ eprintln!("{}", msg);
+ }
+ }
+ } else {
+ }
+ });
+ } else {
+ // We're in a stdlib module, which can only import other stdlib
+ // modules.
+ module.imports.iter().for_each(|imported| {
+ match self.import(&PathBuf::new(), imported, false) {
Ok(module) => {
imports.push(module);
},
eprintln!("{}", msg);
}
}
- } else {
- }
- });
+ });
+ }
let exports: Vec<_> = module.exports.iter().map(|s| {
self.all_exports.insert(s.to_string());
imports,
exports,
source_file: path,
+ std_specifier,
number,
}
}
fn collapse(&mut self, module: Rc<IRModule>) -> Result<()> {
- if self.collapse_seen.contains(&module.source_file) {
+ let seen_key = if let Some(source_file) = &module.source_file {
+ source_file.to_string_lossy().to_string()
+ } else {
+ module.std_specifier.clone().unwrap()
+ };
+ if self.collapse_seen.contains(&seen_key) {
return Ok(())
}
self.text.push(new_instruction);
}
+ self.collapse_seen.insert(seen_key);
+
Ok(())
}
}