diff options
Diffstat (limited to 'src/compiler.rs')
-rw-r--r-- | src/compiler.rs | 214 |
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 ¯o_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. |