summaryrefslogtreecommitdiff
path: root/src/compiler.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler.rs')
-rw-r--r--src/compiler.rs214
1 files changed, 160 insertions, 54 deletions
diff --git a/src/compiler.rs b/src/compiler.rs
index 10f1433..c0caae0 100644
--- a/src/compiler.rs
+++ b/src/compiler.rs
@@ -1,5 +1,9 @@
use crate::*;
+use assembler::*;
+use assembler::DefinitionType::*;
+use assembler::SymbolRole::*;
+
/// Compiles multiple source code files into one.
pub struct Compiler {
@@ -50,82 +54,184 @@ impl Compiler {
self.resolver.error()
}
- pub fn get_compiled_source(&self) -> Result<String, MergeError> {
+ pub fn get_compiled_source(&mut self) -> Result<String, MergeError> {
+ self.resolver.calculate_hierarchy();
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;
- use DefinitionType::*;
- use SymbolRole::*;
- let mut symbols = Vec::new();
- let mut macro_name: Option<String> = None;
- let mut parse_arg_list = false; // true if parsing macro argument list
- let mut after_separator = false; // true if prev token was separator
-
- macro_rules! push {
- ($name:expr, $source:expr, $role:expr) => {
- symbols.push(Symbol {
- name: $name,
- source: $source,
- role: $role,
- namespace: match &macro_name {
- Some(name) => vec![name.to_owned()],
- None => vec![],
- }
- })
+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,
+ };
+ let semantic = match parse_semantic(syntactic) {
+ Ok(semantic) => semantic,
+ Err(_errors) => return None,
+ };
+ Some(SymbolParser::new().parse(&semantic))
+}
+
+
+// Extract symbol definitions from a list of semantic tokens.
+pub struct SymbolParser {
+ pub macro_name: Option<String>,
+ pub symbols: Vec<Symbol>,
+}
+
+impl SymbolParser {
+ pub fn new() -> Self {
+ Self {
+ macro_name: None,
+ symbols: Vec::new(),
}
}
- let syntactic_tokens = SyntacticParser::new(&source_code, path).parse();
- for token in syntactic_tokens {
- match token.variant {
- SynVar::MacroDefinition(name) => {
- push!(name.clone(), token.source, Definition(MustPrecedeReference));
- macro_name = Some(name);
- parse_arg_list = true;
+ fn record_symbol(&mut self, name: &str, source: &SourceSpan, role: SymbolRole) {
+ let name = name.to_string();
+ let namespace = match &self.macro_name {
+ Some(macro_name) => vec![macro_name.to_owned()],
+ None => vec![],
+ };
+ let source = source.to_owned();
+ self.symbols.push(Symbol { name, namespace, source, role });
+
+ }
+
+ pub fn parse(mut self, semantic: &[Tracked<SemanticToken>]) -> Vec<Symbol> {
+ for token in semantic {
+ let source = &token.source;
+ match &token.value {
+ SemanticToken::MacroDefinition(definition) => {
+ // Record macro definition.
+ self.record_symbol(
+ &definition.name,
+ &definition.name.source,
+ Definition(MustPrecedeReference),
+ );
+ self.macro_name = Some(definition.name.to_string());
+
+ for argument in &definition.arguments {
+ self.record_symbol(
+ &argument.name,
+ &argument.source,
+ Definition(MustPrecedeReference),
+ );
+ }
+ match &definition.body {
+ MacroDefinitionBody::Integer(integer) => {
+ self.parse_integer_token(&integer, &integer.source)
+ }
+ MacroDefinitionBody::Invocation(invocation) => {
+ self.parse_invocation(&invocation, &invocation.source)
+ }
+ MacroDefinitionBody::Block(tokens) => {
+ for token in tokens {
+ self.parse_block_token(&token, &token.source);
+ }
+ }
+ }
+ self.macro_name = None;
+ }
+ SemanticToken::BlockToken(token) => {
+ self.parse_block_token(token, &source);
+ }
}
- SynVar::MacroDefinitionTerminator => {
- macro_name = None;
+ }
+ return self.symbols;
+ }
+
+ fn parse_expression(&mut self, expression: &Expression, _source: &SourceSpan) {
+ for token in &expression.tokens {
+ let source = &token.source;
+ match &token.value {
+ ExpressionToken::IntegerToken(integer) => {
+ self.parse_integer_token(integer, source);
+ }
+ ExpressionToken::Invocation(invocation) => {
+ self.parse_invocation(invocation, source);
+ }
+ ExpressionToken::Operator(_) => (),
}
- SynVar::LabelDefinition(name) => {
- push!(name.clone(), token.source, Definition(CanFollowReference));
+ }
+ }
+
+ fn parse_invocation(&mut self, invocation: &Invocation, source: &SourceSpan) {
+ self.record_symbol(
+ &invocation.name,
+ &source,
+ Reference,
+ );
+
+ for argument in &invocation.arguments {
+ let source = &argument.source;
+ match &argument.value {
+ InvocationArgument::IntegerToken(integer) => {
+ self.parse_integer_token(integer, &source);
+ }
+ InvocationArgument::BlockToken(block) => {
+ self.parse_block_token(block, &source);
+ }
+ InvocationArgument::Invocation(invocation) => {
+ self.parse_invocation(invocation, &source);
+ }
+ InvocationArgument::String(_) => (),
}
- SynVar::Symbol(name) => if parse_arg_list && after_separator {
- push!(name, token.source, Definition(MustPrecedeReference));
- } else {
- parse_arg_list = false;
- push!(name, token.source, Reference);
+ }
+ }
+
+ fn parse_block_token(&mut self, token: &BlockToken, source: &SourceSpan) {
+ match token {
+ BlockToken::LabelDefinition(name) => {
+ self.record_symbol(
+ &name,
+ &source,
+ Definition(CanFollowReference),
+ );
}
- SynVar::Separator => {
- after_separator = true;
- continue;
+ BlockToken::PinnedAddress(integer) => {
+ self.parse_integer_token(integer, &integer.source);
}
- SynVar::BlockOpen | SynVar::BlockClose => {
- continue;
+ BlockToken::ConditionalBlock(condition) => {
+ self.parse_integer_token(&condition.predicate, &condition.predicate.source);
+ self.parse_block_token(&condition.body, &condition.body.source);
}
- SynVar::PackedBinaryLiteral(pbl) => {
- for field in pbl.fields {
- push!(field.name.to_string(), field.source, Reference)
+ BlockToken::WordTemplate(word_template) => {
+ for field in &word_template.fields {
+ self.record_symbol(
+ &field.name.to_string(),
+ &field.source,
+ Reference,
+ );
}
}
- SynVar::Expression(expr) => {
- for token in expr.tokens {
- if let ExpressionTokenVariant::Invocation(name) = token.variant {
- push!(name, token.source, Reference);
- }
+ BlockToken::Block(tokens) => {
+ for token in tokens {
+ self.parse_block_token(token, &token.source);
}
}
- _ => ()
- };
- after_separator = false;
+ BlockToken::Invocation(invocation) => {
+ self.parse_invocation(invocation, source);
+ }
+ }
+ }
+
+ fn parse_integer_token(&mut self, token: &IntegerToken, source: &SourceSpan) {
+ match &token {
+ IntegerToken::Expression(expression) => {
+ self.parse_expression(&expression, source)
+ }
+ IntegerToken::Invocation(invocation) => {
+ self.parse_invocation(&invocation, source)
+ }
+ IntegerToken::IntegerLiteral(_) => (),
+ }
}
- return symbols;
}
+
/// Push source code to a source compilation string.
fn push_source_code(compilation: &mut String, source_file: &SourceFile) {
// Skip blank files.