From 67470aea034fd46f4bbcfe815c51ad3451043188 Mon Sep 17 00:00:00 2001
From: Ben Bridle <ben@derelict.engineering>
Date: Thu, 27 Feb 2025 14:53:21 +1300
Subject: Finish first working version of Torque

This is a huge and messy commit, worked on piecemeal while traveling
and while the language was still being designed.
---
 src/tokens/assembler.rs | 140 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 140 insertions(+)
 create mode 100644 src/tokens/assembler.rs

(limited to 'src/tokens/assembler.rs')

diff --git a/src/tokens/assembler.rs b/src/tokens/assembler.rs
new file mode 100644
index 0000000..04ecd38
--- /dev/null
+++ b/src/tokens/assembler.rs
@@ -0,0 +1,140 @@
+use crate::*;
+
+
+#[derive(Clone)]
+pub enum AssembledToken {
+    Word(AssembledWord),
+    LabelDefinition(LabelDefinition),
+    PinnedAddress(PinnedAddress),
+    Error(AssemblerError),
+}
+
+#[derive(Clone)]
+pub struct AssembledWord {
+    pub source: SourceSpan,
+    pub value: usize,
+    pub bits: usize,
+    pub fields: Vec<AssembledField>,
+    pub errors: Vec<AssemblerError>,
+}
+
+#[derive(Clone)]
+pub struct AssembledField {
+    pub source: SourceSpan,
+    pub value: IntegerArgument,
+    /// Length of field in bits
+    pub bits: usize,
+    /// Distance to left-shift field in value
+    pub shift: usize,
+}
+
+#[derive(Clone)]
+pub struct AssembledExpression {
+    pub source: SourceSpan,
+    pub tokens: Vec<AssembledExpressionToken>,
+}
+
+#[derive(Clone)]
+pub enum AssembledExpressionToken {
+    Integer(TrackedInteger),
+    LabelReference(Tracked<String>),
+    Operator(Operator),
+    Expression(Box<AssembledExpression>),
+}
+
+#[derive(Clone)]
+pub enum Argument {
+    Integer(IntegerArgument),
+    Block(Vec<AssembledToken>),
+}
+
+#[derive(Clone)]
+pub enum IntegerArgument {
+    LabelReference(Tracked<String>),
+    Integer(TrackedInteger),
+    Expression(AssembledExpression),
+}
+
+#[derive(Clone)]
+pub struct AssemblerError {
+    pub source: SourceSpan,
+    pub variant: AssemblerErrorVariant,
+}
+
+#[derive(Clone, Debug)]
+pub enum AssemblerErrorVariant {
+    DefinitionNotFound(String),
+    NotAnInteger,
+    NotABlock,
+    IntegerInBlock,
+    /// expected, received
+    IncorrectArgumentCount(usize, usize),
+    /// expected, received, index
+    IncorrectArgumentType(ArgumentVariant, ArgumentVariant),
+}
+
+// ------------------------------------------------------------------------ //
+
+macro_rules! indent {
+    ($indent:expr => $($tokens:tt)*) => {{
+        for _ in 0..$indent { print!("  "); }
+        println!($($tokens)*);
+    }};
+}
+
+pub fn print_assembled_tokens(tokens: &[AssembledToken]) {
+    println!();
+    println!("--------------------------------------------------------------");
+    println!();
+    for token in tokens {
+        match token {
+            AssembledToken::LabelDefinition(definition) => {
+                println!("LABEL {}", definition.name)
+            }
+            AssembledToken::PinnedAddress(address) => {
+                println!("PINNED {}", address.address)
+            }
+            AssembledToken::Word(word) => {
+                println!("WORD {:b}", word.value);
+                for field in &word.fields {
+                    print!("  FIELD ({} << {}) ", field.bits, field.shift);
+                    match &field.value {
+                        IntegerArgument::LabelReference(name) => {
+                            println!("LABEL '{name}'");
+                        }
+                        IntegerArgument::Integer(integer) => {
+                            println!("INTEGER '{}'", integer.value);
+                        }
+                        IntegerArgument::Expression(expr) => {
+                            println!("EXPRESSION");
+                            print_assembled_expression(2, expr);
+                        }
+                    }
+                }
+            }
+            AssembledToken::Error(error) => {
+                println!("ERROR {:?}", error.variant)
+            }
+        }
+    }
+}
+
+fn print_assembled_expression(indent: usize, expr: &AssembledExpression) {
+    for token in &expr.tokens {
+        match token {
+            AssembledExpressionToken::Integer(integer) => {
+                indent!(indent => "INTEGER {}", integer.value)
+            }
+            AssembledExpressionToken::LabelReference(name) => {
+                indent!(indent => "LABEL '{name}'")
+            }
+            AssembledExpressionToken::Operator(operator) => {
+                indent!(indent => "OPERATOR {operator:?}")
+            }
+            AssembledExpressionToken::Expression(expr) => {
+                indent!(indent => "EXPRESSION");
+                print_assembled_expression(indent+1, expr);
+            }
+        }
+    }
+}
-- 
cgit v1.2.3-70-g09d2