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
|
use crate::*;
/// Compiles multiple source code files into one.
pub struct Compiler {
pub source_path: PathBuf,
pub resolver: Resolver,
}
impl Compiler {
pub fn from_string<P: AsRef<Path>>(source_code: String, path: P) -> Self {
let source_unit = SourceUnit::from_string(source_code, &path, parse_symbols);
Self {
source_path: path.as_ref().to_path_buf(),
resolver: Resolver::new(source_unit)
}
}
pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, FileError> {
let source_unit = SourceUnit::from_path(&path, None, parse_symbols)?;
Ok(Self {
source_path: path.as_ref().to_path_buf(),
resolver: Resolver::new(source_unit)
})
}
/// Find library files descending from the parent directory.
pub fn include_libs_from_parent(&mut self, ext: &str) {
if let Some(parent_path) = self.source_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), 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), parse_symbols);
self.resolver.add_library_source_units(libraries);
self.resolver.resolve();
}
pub fn error(&self) -> Option<ResolverError> {
self.resolver.error()
}
pub fn get_compiled_source(&self) -> Result<String, MergeError> {
self.resolver.get_merged_source_code(push_source_code)
}
}
/// Parse all symbols from a source code string.
fn parse_symbols(source_code: &str, path: Option<&Path>) -> Vec<Symbol> {
use SyntacticTokenVariant as SynVar;
let mut symbols = Vec::new();
for token in SyntacticParser::from_source_code(&source_code, path) {
let source = token.source;
let (name, role) = match token.variant {
SynVar::LabelDefinition(name) =>
(name, SymbolRole::Definition(DefinitionType::CanFollowReference)),
SynVar::MacroDefinition(name) =>
(name, SymbolRole::Definition(DefinitionType::MustPrecedeReference)),
SynVar::Symbol(name) =>
(name, SymbolRole::Reference),
_ => continue,
};
symbols.push(Symbol { name, source, role });
}
return symbols;
}
/// Push source code to a source compilation string.
fn push_source_code(compilation: &mut String, source_file: &SourceFile) {
// Skip blank files.
let source_code = &source_file.source_code;
if source_code.chars().all(|c| c.is_whitespace()) { return; }
// Ensure that the previous section is followed by two newline characters.
if !compilation.is_empty() {
if !compilation.ends_with('\n') { compilation.push('\n'); }
if !compilation.ends_with("\n\n") { compilation.push('\n'); }
}
// Push a path comment and the source code.
let path_str = source_file.path.as_os_str().to_string_lossy();
let path_comment = format!("(: {path_str} )\n");
compilation.push_str(&path_comment);
compilation.push_str(&source_code);
}
|