diff options
-rw-r--r-- | src/errors/merge_error.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 17 | ||||
-rw-r--r-- | src/locators/source.rs | 12 | ||||
-rw-r--r-- | src/processors/compiler.rs | 134 | ||||
-rw-r--r-- | src/processors/mod.rs | 7 | ||||
-rw-r--r-- | src/processors/resolver.rs (renamed from src/resolver.rs) | 10 | ||||
-rw-r--r-- | src/processors/tokeniser.rs (renamed from src/tokeniser.rs) | 0 | ||||
-rw-r--r-- | src/reports/resolver_error.rs | 14 | ||||
-rw-r--r-- | src/types/context.rs (renamed from src/context.rs) | 0 | ||||
-rw-r--r-- | src/types/mod.rs | 5 | ||||
-rw-r--r-- | src/types/source_unit.rs (renamed from src/source_unit.rs) | 63 |
11 files changed, 174 insertions, 90 deletions
diff --git a/src/errors/merge_error.rs b/src/errors/merge_error.rs index 3ff60d2..d830d96 100644 --- a/src/errors/merge_error.rs +++ b/src/errors/merge_error.rs @@ -12,7 +12,7 @@ pub struct MergeError<'a> { impl MergeError<'_> { pub fn report(&self) { - error!("A cyclic dependency was found between the following libraries:"); + error!("A cyclic dependency was found between the following files:"); for id in &self.cyclic_unit_ids { let unit = &self.resolver.source_units[*id]; let path = &unit.source_unit.path(); @@ -1,17 +1,14 @@ -#![feature(io_error_more)] - -mod context; mod errors; mod locators; -mod resolver; +mod processors; mod reports; -mod source_unit; -mod tokeniser; +mod types; -pub use context::*; pub use errors::*; pub use locators::*; -pub use resolver::*; +pub use processors::*; pub use reports::*; -pub use source_unit::*; -pub use tokeniser::*; +pub use types::*; + +pub type ParseFn = fn(&str, Option<&Path>) -> Option<Vec<Symbol>>; +pub type PushFn = fn(&mut String, &SourceFile); diff --git a/src/locators/source.rs b/src/locators/source.rs index 7e5abd2..15a0809 100644 --- a/src/locators/source.rs +++ b/src/locators/source.rs @@ -19,8 +19,16 @@ impl SourceSpan { } /// Wrap this source span around a child source span. - pub fn wrap(mut self, source: SourceSpan) -> Self { - self.child = Some(Box::new(source)); self + pub fn wrap(&self, child: impl Into<SourceSpan>) -> Self { + let mut new = self.clone(); + new.child = Some(Box::new(child.into())); + return new; + } +} + +impl From<&SourceSpan> for SourceSpan { + fn from(source: &SourceSpan) -> Self { + source.clone() } } 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; +} diff --git a/src/processors/mod.rs b/src/processors/mod.rs new file mode 100644 index 0000000..a0ce56f --- /dev/null +++ b/src/processors/mod.rs @@ -0,0 +1,7 @@ +mod compiler; +mod resolver; +mod tokeniser; + +pub use compiler::*; +pub use resolver::*; +pub use tokeniser::*; diff --git a/src/resolver.rs b/src/processors/resolver.rs index 1f6e0a2..6c1d0f1 100644 --- a/src/resolver.rs +++ b/src/processors/resolver.rs @@ -4,8 +4,6 @@ use log::{info, error}; use std::collections::HashSet; -type PushFn = fn(&mut String, &SourceFile); - /// Resolve undeclared symbols in a source unit with definitions from other units. pub struct Resolver { @@ -27,8 +25,8 @@ pub struct Resolver { impl Resolver { - pub fn new(source_unit: SourceUnit) -> Self { - let mut new = Self { + pub fn new() -> Self { + Self { definitions: Vec::new(), resolved: Vec::new(), unresolved: Vec::new(), @@ -36,9 +34,7 @@ impl Resolver { source_units: Vec::new(), root_unit_ids: Vec::new(), library_source_units: Vec::new(), - }; - new.include_source_unit(source_unit, None); - return new; + } } pub fn include_source_unit(&mut self, mut source_unit: SourceUnit, parent_id: Option<usize>) { diff --git a/src/tokeniser.rs b/src/processors/tokeniser.rs index 0350afe..0350afe 100644 --- a/src/tokeniser.rs +++ b/src/processors/tokeniser.rs diff --git a/src/reports/resolver_error.rs b/src/reports/resolver_error.rs index 1aa3e37..0fce3c4 100644 --- a/src/reports/resolver_error.rs +++ b/src/reports/resolver_error.rs @@ -8,20 +8,18 @@ pub struct ResolverError<'a> { impl<'a> ResolverError<'a> { pub fn report(&self) { for reference in &self.resolver.unresolved { - let message = format!( - "Undefined symbol, no label or macro has been defined with the name {:?}", - &reference.symbol.name, - ); + let message = format!("Undefined symbol '{}'", reference.symbol.name); let context = reference.context(&self.resolver); report_source_issue(LogLevel::Error, &context, &message); } for redefinition in &self.resolver.redefinitions { let definition = &self.resolver.definitions[redefinition.definition]; - let message = format!( - "Redefined symbol, first defined at {}", - &definition.tracked.symbol.source.in_merged, - ); + let message = format!("Redefined symbol '{}'", definition.tracked.symbol.name); let context = redefinition.tracked.context(&self.resolver); + let context = Context { + source_code: context.source_code, + source: &context.source.wrap(&definition.tracked.symbol.source) + }; report_source_issue(LogLevel::Error, &context, &message); } } diff --git a/src/context.rs b/src/types/context.rs index c015c7e..c015c7e 100644 --- a/src/context.rs +++ b/src/types/context.rs diff --git a/src/types/mod.rs b/src/types/mod.rs new file mode 100644 index 0000000..df23058 --- /dev/null +++ b/src/types/mod.rs @@ -0,0 +1,5 @@ +mod context; +mod source_unit; + +pub use context::*; +pub use source_unit::*; diff --git a/src/source_unit.rs b/src/types/source_unit.rs index 28cc854..2fbbc61 100644 --- a/src/source_unit.rs +++ b/src/types/source_unit.rs @@ -1,67 +1,5 @@ use crate::*; -use log::{info, warn}; -use vagabond::*; - - -type ParseFn = fn(&str, Option<&Path>) -> Option<Vec<Symbol>>; - - -/// 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; -} - pub struct SourceUnit { pub main: SourceFile, @@ -136,6 +74,7 @@ pub struct SourceFile { pub symbols: Option<Vec<Symbol>>, } + pub struct Symbol { pub name: String, pub namespace: Vec<String>, |