summaryrefslogblamecommitdiff
path: root/src/tokens/assembler.rs
blob: 04ecd38d43096ca570277101d1e3f977ef9f2257 (plain) (tree)










































































































































                                                                               
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);
            }
        }
    }
}