From 1ecee352f5844b0809d7ae66df52e34f42b44c8e Mon Sep 17 00:00:00 2001
From: Ben Bridle <ben@derelict.engineering>
Date: Thu, 6 Mar 2025 20:33:27 +1300
Subject: Rewrite entire assembler

The language is now more general, the code is better structured, error
reporting is more detailed, and many new language features have
been implemented:
- conditional blocks
- first-class strings
- more expression operators
- binary literals
- negative values
- invocations in constant expressions
---
 src/compiler.rs | 214 ++++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 160 insertions(+), 54 deletions(-)

(limited to 'src/compiler.rs')

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.
-- 
cgit v1.2.3-70-g09d2