summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/errors/merge_error.rs2
-rw-r--r--src/lib.rs17
-rw-r--r--src/locators/source.rs12
-rw-r--r--src/processors/compiler.rs134
-rw-r--r--src/processors/mod.rs7
-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.rs14
-rw-r--r--src/types/context.rs (renamed from src/context.rs)0
-rw-r--r--src/types/mod.rs5
-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();
diff --git a/src/lib.rs b/src/lib.rs
index 3c9c28e..6c076d5 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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>,