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
|
use crate::*;
use assembler::SymbolRole::*;
use assembler::DefinitionType::*;
pub fn new_compiler() -> Compiler {
Compiler::new(parse_symbols, push_code)
}
/// Parse all symbols from a source code string.
pub fn parse_symbols(source_code: &str, path: Option<&Path>) -> Option<Vec<Symbol>> {
let syntactic = match parse_syntactic(source_code, path) {
Ok(syntactic) => syntactic,
Err(_errors) => return None,
};
Some(SymbolParser::new().parse(&syntactic))
}
/// Push source code to a source compilation string.
pub fn push_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);
}
// Extract symbol definitions from a list of syntactic tokens.
pub struct SymbolParser {
pub symbols: Vec<Symbol>,
}
impl SymbolParser {
pub fn new() -> Self {
Self {
symbols: Vec::new(),
}
}
fn record_symbol(&mut self, name: &str, source: &SourceSpan, role: SymbolRole) {
let name = name.to_string();
let namespace = Vec::new();
let source = source.to_owned();
self.symbols.push(Symbol { name, namespace, source, role });
}
pub fn parse(mut self, syntactic: &[Tracked<SyntacticToken>]) -> Vec<Symbol> {
for token in syntactic {
match &token.value {
SyntacticToken::MacroDefinition(definition) => {
self.record_symbol(
&definition.name,
&definition.name.source,
Definition(MustPrecedeReference),
);
for token in &definition.body {
if let SyntacticToken::Invocation(name) = &token.value {
self.record_symbol(&name, &token.source, Reference);
}
}
}
SyntacticToken::LabelDefinition(name) => {
self.record_symbol(&name, &token.source, Definition(CanFollowReference));
}
SyntacticToken::Invocation(name) => {
self.record_symbol(&name, &token.source, Reference);
}
_ => (),
}
}
return self.symbols;
}
}
|