corewars_core/
load_file.rs

1use std::fmt;
2
3use lazy_static::lazy_static;
4
5mod metadata;
6mod program;
7mod types;
8
9pub use metadata::Metadata;
10pub use program::{Instructions, LabelMap, Program};
11pub use types::{AddressMode, Modifier, Offset, Opcode, PseudoOpcode, UOffset, Value};
12
13lazy_static! {
14    pub static ref DEFAULT_CONSTANTS: LabelMap = {
15        let mut constants = LabelMap::new();
16        constants.insert("CORESIZE".into(), 8000);
17        constants.insert("MAXPROCESSES".into(), 8000);
18        constants.insert("MAXCYCLES".into(), 80_000);
19        constants.insert("MAXLENGTH".into(), 100);
20        constants.insert("MINDISTANCE".into(), 100);
21        constants.insert("ROUNDS".into(), 1);
22
23        // TODO: handle command-line constant redefinition and things like
24        // CURLINE, VERSION, WARRIORS, PSPACESIZE
25        constants
26    };
27}
28
29/// The main public struct used to represent a Redcode warrior
30#[derive(Debug)]
31pub struct Warrior {
32    pub program: Program,
33    pub metadata: Metadata,
34}
35
36impl fmt::Display for Warrior {
37    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
38        write!(formatter, "{}", self.metadata)?;
39        write!(formatter, "{}", self.program)
40    }
41}
42
43#[derive(Clone, Debug, Default, PartialEq)]
44pub struct Field {
45    pub address_mode: AddressMode,
46    pub value: Value,
47}
48
49impl fmt::Display for Field {
50    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
51        f.pad(&format!("{}{}", self.address_mode, self.value))
52    }
53}
54
55impl Field {
56    pub fn direct(value: Offset) -> Self {
57        Self {
58            address_mode: AddressMode::Direct,
59            value: Value::Literal(value),
60        }
61    }
62
63    pub fn direct_label<S: ToString>(label: S) -> Self {
64        Self {
65            address_mode: AddressMode::Direct,
66            value: Value::Label(label.to_string()),
67        }
68    }
69
70    pub fn immediate(value: Offset) -> Self {
71        Self {
72            address_mode: AddressMode::Immediate,
73            value: Value::Literal(value),
74        }
75    }
76}
77
78#[derive(Clone, Debug, Default, PartialEq)]
79pub struct Instruction {
80    pub opcode: Opcode,
81    pub modifier: Modifier,
82    pub field_a: Field,
83    pub field_b: Field,
84}
85
86impl Instruction {
87    pub fn new(opcode: Opcode, field_a: Field, field_b: Field) -> Self {
88        let modifier =
89            Modifier::default_88_to_94(opcode, field_a.address_mode, field_b.address_mode);
90
91        Instruction {
92            opcode,
93            modifier,
94            field_a,
95            field_b,
96        }
97    }
98}
99
100impl fmt::Display for Instruction {
101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102        f.pad(&format!(
103            // Example output:
104            // MOV.AB  $-100,  $1
105            // |----->||----->|
106            "{op:<8}{a:<8}{b}",
107            op = format!("{}.{}", self.opcode, self.modifier),
108            a = format!("{},", self.field_a),
109            b = self.field_b,
110        ))
111    }
112}
113
114#[cfg(test)]
115mod test {
116    use super::*;
117
118    #[test]
119    fn default_instruction() {
120        let expected_instruction = Instruction {
121            opcode: Opcode::Dat,
122            modifier: Modifier::F,
123            field_a: Field {
124                address_mode: AddressMode::Direct,
125                value: Value::Literal(0),
126            },
127            field_b: Field {
128                address_mode: AddressMode::Direct,
129                value: Value::Literal(0),
130            },
131        };
132
133        assert_eq!(Instruction::default(), expected_instruction)
134    }
135}