diff options
Diffstat (limited to 'src/processors/compiler.rs')
-rw-r--r-- | src/processors/compiler.rs | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/src/processors/compiler.rs b/src/processors/compiler.rs new file mode 100644 index 0000000..626dfd3 --- /dev/null +++ b/src/processors/compiler.rs @@ -0,0 +1,134 @@ +use crate::*; + +use log::{info, warn}; +use vagabond::*; + + +/// Compiles multiple source code files into one. +pub struct Compiler { + pub source_path: Option<PathBuf>, + pub resolver: Resolver, + pub parse_symbols: ParseFn, + pub push_code: PushFn, +} + +impl Compiler { + pub fn new(parse_symbols: ParseFn, push_code: PushFn) -> Self { + let resolver = Resolver::new(); + Self { source_path: None, resolver, parse_symbols, push_code } + } + + pub fn root_from_string<P: AsRef<Path>>(&mut self, source_code: String, path: P) { + let source_unit = SourceUnit::from_string(source_code, &path, self.parse_symbols); + self.source_path = Some(path.as_ref().to_path_buf()); + self.resolver.include_source_unit(source_unit, None); + } + + pub fn root_from_path<P: AsRef<Path>>(&mut self, path: P) -> Result<(), FileError> { + let source_unit = SourceUnit::from_path(&path, None, self.parse_symbols)?; + self.source_path = Some(path.as_ref().to_path_buf()); + self.resolver.include_source_unit(source_unit, None); + return Ok(()); + } + + /// Find library files descending from the parent directory. + pub fn include_libs_from_parent(&mut self, ext: &str) { + if let Some(path) = &self.source_path { + if let Some(parent_path) = path.parent() { + let parent_path = parent_path.to_owned(); + self.include_libs_from_path(&parent_path, ext); + } + } + } + + /// Find library files at or descending from a path. + pub fn include_libs_from_path(&mut self, path: &Path, ext: &str) { + let libraries = gather_from_path(path, Some(ext), self.parse_symbols); + self.resolver.add_library_source_units(libraries); + self.resolver.resolve(); + } + + /// Find library files from a PATH-style environment variable. + pub fn include_libs_from_path_variable(&mut self, name: &str, ext: &str) { + let libraries = gather_from_path_variable(name, Some(ext), self.parse_symbols); + self.resolver.add_library_source_units(libraries); + self.resolver.resolve(); + } + + pub fn error(&self) -> Option<ResolverError> { + self.resolver.error() + } + + pub fn hierarchy(&self) -> SourceHierarchy { + self.resolver.hierarchy() + } + + pub fn symbols(&self) -> SourceSymbols { + self.resolver.symbols() + } + + pub fn unused(&self) -> UnusedSymbols { + self.resolver.unused() + } + + pub fn get_compiled_source(&mut self) -> Result<String, MergeError> { + self.resolver.calculate_hierarchy(); + self.resolver.get_merged_source_code(self.push_code) + } +} + + +/// Gather all source units with a given extension using a PATH-style environment variable. +pub fn gather_from_path_variable(variable: &str, extension: Option<&str>, parse: ParseFn) -> Vec<SourceUnit> { + let mut source_units = Vec::new(); + if let Ok(string) = std::env::var(variable) { + for path in string.split(":").map(PathBuf::from) { + info!("Found path {path:?} in environment variable {variable:?}"); + source_units.extend(gather_from_path(&path, extension, parse)); + } + }; + return source_units; +} + +/// Gather source units with a given extension at or descending from a path. +pub fn gather_from_path(path: &Path, extension: Option<&str>, parse: ParseFn) -> Vec<SourceUnit> { + let mut source_units = Vec::new(); + let check_optional_file = |file: &Option<SourceFile>| -> bool { + match file { + Some(file) => match file.symbols { + Some(_) => { info!("Found source file at {:?}", file.path); true } + None => { warn!("Could not parse source file at {:?}", file.path); false } + } + None => true, + } + }; + let mut gather_source_unit = |path: &Path| { + if let Ok(unit) = SourceUnit::from_path(&path, extension, parse) { + if unit.main.symbols.is_some() { + info!("Found source file at {:?}", unit.main.path); + let head_good = check_optional_file(&unit.head); + let tail_good = check_optional_file(&unit.tail); + if head_good && tail_good { + source_units.push(unit); + } + } else { + warn!("Could not parse source file at {path:?}"); + check_optional_file(&unit.head); + check_optional_file(&unit.tail); + } + } + }; + if let Ok(entry) = Entry::from_path(path) { + if EntryType::File == entry.entry_type { + gather_source_unit(&entry.path) + } else if EntryType::Directory == entry.entry_type { + info!("Traversing directory {path:?} for source files"); + if let Ok(entries) = traverse_directory(entry.path) { + for entry in entries { + gather_source_unit(&entry.path) + } + } + } + }; + return source_units; +} |