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