1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
use std::fmt;

use lazy_static::lazy_static;

mod metadata;
mod program;
mod types;

pub use metadata::Metadata;
pub use program::{Instructions, LabelMap, Program};
pub use types::{AddressMode, Modifier, Offset, Opcode, PseudoOpcode, UOffset, Value};

lazy_static! {
    pub static ref DEFAULT_CONSTANTS: LabelMap = {
        let mut constants = LabelMap::new();
        constants.insert("CORESIZE".into(), 8000);
        constants.insert("MAXPROCESSES".into(), 8000);
        constants.insert("MAXCYCLES".into(), 80_000);
        constants.insert("MAXLENGTH".into(), 100);
        constants.insert("MINDISTANCE".into(), 100);
        constants.insert("ROUNDS".into(), 1);

        // TODO: handle command-line constant redefinition and things like
        // CURLINE, VERSION, WARRIORS, PSPACESIZE
        constants
    };
}

/// The main public struct used to represent a Redcode warrior
#[derive(Debug)]
pub struct Warrior {
    pub program: Program,
    pub metadata: Metadata,
}

impl fmt::Display for Warrior {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(formatter, "{}", self.metadata)?;
        write!(formatter, "{}", self.program)
    }
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct Field {
    pub address_mode: AddressMode,
    pub value: Value,
}

impl fmt::Display for Field {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(&format!("{}{}", self.address_mode, self.value))
    }
}

impl Field {
    pub fn direct(value: Offset) -> Self {
        Self {
            address_mode: AddressMode::Direct,
            value: Value::Literal(value),
        }
    }

    pub fn direct_label<S: ToString>(label: S) -> Self {
        Self {
            address_mode: AddressMode::Direct,
            value: Value::Label(label.to_string()),
        }
    }

    pub fn immediate(value: Offset) -> Self {
        Self {
            address_mode: AddressMode::Immediate,
            value: Value::Literal(value),
        }
    }
}

#[derive(Clone, Debug, Default, PartialEq)]
pub struct Instruction {
    pub opcode: Opcode,
    pub modifier: Modifier,
    pub field_a: Field,
    pub field_b: Field,
}

impl Instruction {
    pub fn new(opcode: Opcode, field_a: Field, field_b: Field) -> Self {
        let modifier =
            Modifier::default_88_to_94(opcode, field_a.address_mode, field_b.address_mode);

        Instruction {
            opcode,
            modifier,
            field_a,
            field_b,
        }
    }
}

impl fmt::Display for Instruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.pad(&format!(
            // Example output:
            // MOV.AB  $-100,  $1
            // |----->||----->|
            "{op:<8}{a:<8}{b}",
            op = format!("{}.{}", self.opcode, self.modifier),
            a = format!("{},", self.field_a),
            b = self.field_b,
        ))
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn default_instruction() {
        let expected_instruction = Instruction {
            opcode: Opcode::Dat,
            modifier: Modifier::F,
            field_a: Field {
                address_mode: AddressMode::Direct,
                value: Value::Literal(0),
            },
            field_b: Field {
                address_mode: AddressMode::Direct,
                value: Value::Literal(0),
            },
        };

        assert_eq!(Instruction::default(), expected_instruction)
    }
}