summaryrefslogtreecommitdiff
path: root/src/processors/compiler.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/processors/compiler.rs')
-rw-r--r--src/processors/compiler.rs134
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;
+}