1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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: Option<&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: Option<&str>) {
let libraries = gather_from_path(path, 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: Option<&str>) {
let libraries = gather_from_path_variable(name, 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;
}
|