Struct Machine

Source
pub struct Machine {
Show 16 fields pub reg_a: u8, pub reg_b: i16, pub reg_L: u16, pub reg_f: f64, pub reg_ch: char, pub reg_ř: [i8; 37], pub reg_ß: ConstantSizeString, pub reg_Ω: Ω, pub num_reg: i32, pub reg_ep: u16, pub reg_dp: u16, pub flag: bool, pub debug_mode: bool, pub halted: bool, pub memory: Box<[u8; 65535]>, pub stack: Stack,
}
Expand description

An esoteric virtual machine.

Create a new machine with [Machine::new] and load machine code and data to it with Machine::load.

§Examples


// initialize a new machine
let mut machine = Machine::default();

// assembly code for the machine
let asm = esoteric_assembly! {
    // initialize dot pointer so that IO operations work

    // push a dot character to stack
    0: pushi b'.';
    // pop to address 28657
    2: pop 28657;

    // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
    5: ldidp 28657;

    // -----------------

    // print hello world
    8: writeline 13;

    // halt machine
    11: Ωtheendisnear;
    12: Ωskiptothechase;

    // hello world text
    13: data b"Hello, world!\n\0";
};

// load machine code
machine.load(&asm, 0);

// run machine until it halts
machine.run();

// return the machine's register A (unused)
machine

Fields§

§reg_a: u8

register a (used as the machine’s exit code)

§reg_b: i16

register b

§reg_L: u16

register L

§reg_f: f64

register f

§reg_ch: char

register ch (ch is one letter in Czech, therefore it’s valid)

§reg_ř: [i8; 37]

register ř

§reg_ß: ConstantSizeString

register ß

§reg_Ω: Ω

register Ω

§num_reg: i32

number register (serves as the return value of the main function and is printed in debug mode if reg_Ω.should_make_infinite_paperclips is true)

§reg_ep: u16

execution pointer

§reg_dp: u16

dot pointer (has to point to a . character. if it doesn’t, then IO operation attempts are cancelled and the flag is set)

§flag: bool

overflow/error flag

§debug_mode: bool

debug mode

§halted: bool

whether the machine is halted (can’t run anymore and is finished)

§memory: Box<[u8; 65535]>

memory (should be 65K)

§stack: Stack

stack memory (default is 4K)

Implementations§

Source§

impl Machine

Source

pub fn fetch_byte(&mut self) -> u8

Fetches a byte at [reg_ep] and increments [reg_ep] by 1.

Source

pub fn fetch_2_bytes(&mut self) -> u16

Fetches 2 bytes at [reg_ep] as a big endian integer and increments [reg_ep] by 2.

Source

pub fn fetch_4_bytes(&mut self) -> u32

Fetches 4 bytes at [reg_ep] as a big endian integer and increments [reg_ep] by 4.

Source

pub fn fetch_8_bytes(&mut self) -> u64

Fetches 8 bytes at [reg_ep] as a big endian integer and increments [reg_ep] by 8.

Source

pub fn fetch_instruction_kind(&mut self) -> Option<InstructionKind>

Fetches a byte and tries to turn it into an InstructionKind.

For more info, read the docs for [fetch_byte].

Source

pub fn num_debug(&self)

Prints [num_reg] with a colon and a space after it if [reg_Ω.should_make_infinite_paperclips] is enabled.

Source

pub fn fetch_instruction(&mut self) -> Option<Instruction>

Fetches an instruction from memory, incrementing [reg_ep] based on the amount of bytes read.

Returns None if the machine is halted.

Source

pub fn execute_instruction(&mut self, instruction: Instruction)

Fetches and executes an instruction.

More info at [fetch_instruction].

Source

pub fn load_instructions( &mut self, instructions: &[Instruction], offset: u16, ) -> u16

Loads instructions into the machine’s memory at the specified offset.

Returns the amount of bytes written

Source

pub fn load(&mut self, data: &[DataOrInstruction<'_>], offset: u16) -> u16

Loads data into the machine’s memory at the specified offset.

Returns the amount of bytes written

Examples found in repository?
examples/helloworld.rs (line 33)
3fn main() -> Machine {
4    // initialize a new machine
5    let mut machine = Machine::default();
6
7    // assembly code for the machine
8    let asm = esoteric_assembly! {
9        // initialize dot pointer so that IO operations work
10
11        // push a dot character to stack
12        0: pushi b'.';
13        // pop to address 28657
14        2: pop 28657;
15
16        // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17        5: ldidp 28657;
18
19        // -----------------
20
21        // print hello world
22        8: writeline 13;
23
24        // halt machine
25        11: Ωtheendisnear;
26        12: Ωskiptothechase;
27
28        // hello world text
29        13: data b"Hello, world!\n\0";
30    };
31
32    // load machine code
33    machine.load(&asm, 0);
34
35    // run machine until it halts
36    machine.run();
37
38    // return the machine's register A (unused)
39    machine
40}
More examples
Hide additional examples
examples/truth_machine.rs (line 78)
3fn main() -> Machine {
4    // initialize a new machine
5    let mut machine = Machine::default();
6
7    // assembly code for the machine
8    let asm = esoteric_assembly! {
9        // initialize dot pointer so that IO operations work
10
11        // push a dot character to stack
12        0: pushi b'.';
13        // pop to address 28657
14        2: pop 28657;
15
16        // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17        4: ldidp 28657;
18
19        // ------------------
20
21        // get a single character to register ch
22        7: getchar;
23
24        // push register ch to stack (4 bytes)
25        8: pushch;
26
27        // pop character to register b
28        9: popb;
29
30        // pop the other 2 bytes
31        10: stackdealloc 2;
32
33        // put 49 (ascii for '1') in register L
34        13: pushi 0;
35        15: pushi 49;
36        17: popl;
37
38        // compare registers L and b
39        18: cmplb;
40
41        // push 30 (input == '1' logic)
42        19: pushi 0;
43        21: pushi 30;
44
45        // pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
46        23: zpopep;
47
48        // empty the stack
49        24: stackdealloc 2;
50
51        // IF INPUT IS '0' (repeat it)
52        // fallback to the input == '1' logic, ran without jumps
53
54        // write the input value ('0')
55        27: writechar;
56
57        // halt machine
58        28: Ωtheendisnear;
59        29: Ωskiptothechase;
60
61        // IF INPUT IS '1' (repeat indefinitely)
62
63        // write the input value ('1')
64        30: writechar;
65
66        // push 30 (input == '1' logic)
67        31: pushi 0;
68        33: pushi 30;
69
70        // pop to execution pointer (jump to value on stack)
71        //
72        // this repeats the input == '1' logic indefinitely
73        35: popep;
74
75    };
76
77    // load machine code
78    machine.load(&asm, 0);
79
80    // run machine until it halts
81    machine.run();
82
83    // return the machine's register A (unused)
84    machine
85}
examples/99_bottles_of_beer.rs (line 128)
3fn main() -> Machine {
4    // initialize a new machine
5    let mut machine = Machine::default();
6
7    // assembly code for the machine
8    let asm = esoteric_assembly! {
9        // initialize dot pointer so that IO operations work
10
11        // push a dot character to stack
12        0: pushi b'.';
13        // pop to address 28657
14        2: pop 28657;
15
16        // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17        5: ldidp 28657;
18
19        // -----------------
20
21
22        // set L to 99
23        8: pushi 0;
24        10: pushi 99;
25        12: popl;
26
27        // set num to 99
28        13: pushi 0;
29        15: pushi 0;
30        17: pushi 0;
31        19: pushi 99;
32        21: popnum;
33
34        // set B to 1
35        22: pushi 0;
36        24: pushi 1;
37        26: popb;
38
39        27: Ωsetpaperclipproduction true;
40
41        // WORK
42            29: writeline 110; // wall
43            33: writeline 140; // bottles
44
45            35: Ωsetpaperclipproduction false;
46
47            37: writeline 158; // take
48
49            40: Ωsetpaperclipproduction true;
50
51            // jump to fin if L == 1
52            42: cmplb;
53            43: pushi 0;
54            45: pushi 71;
55
56            47: zpopep;
57
58            48: stackdealloc 2;
59
60            // set B to 1
61            51: pushi 0;
62            53: pushi 1;
63            55: popb;
64
65            56: subbl; // L -= 1
66
67            // set num to L
68            57: pushi 0;
69            59: pushi 0;
70            61: pushl;
71            62: popnum;
72
73            63: writeline 193; // wall_end
74
75            // jump back to work
76            66: pushi 0;
77            68: pushi 29;
78
79            70: popep;
80
81        // FIN
82            71: Ωsetpaperclipproduction false;
83
84            73: writeline 224; // no_more
85            76: writeline 193; // wall_end
86
87            79: writeline 233; // No_more
88            82: writeline 110; // wall
89            85: writeline 224; // no_more
90            88: writeline 140; // bottles
91
92            91: writeline 242; // store
93
94            // set num to 99
95            94: pushi 0;
96            96: pushi 0;
97            98: pushi 0;
98            100: pushi 99;
99            102: popnum;
100
101            103: Ωsetpaperclipproduction true;
102
103            105: writeline 193; // wall_end
104
105        // halt machine
106        108: Ωtheendisnear;
107        109: Ωskiptothechase;
108
109        // wall (30 bytes)
110        110: data b"bottles of beer on the wall, \0";
111        // bottles (18 bytes)
112        140: data b"bottles of beer.\n\0";
113        // take (35 bytes)
114        158: data b"Take one down and pass it around, \0";
115        // wall end (31 bytes)
116        193: data b"bottles of beer on the wall.\n\n\0";
117
118        // no more (9 bytes)
119        224: data b"no more \0";
120        // No more (9 bytes)
121        233: data b"No more \0";
122
123        // store
124        242: data b"Go to the store and buy some more, \0";
125    };
126
127    // load machine code
128    machine.load(&asm, 0);
129
130    // run machine until it halts
131    machine.run();
132
133    // return the machine's register A (unused)
134    machine
135}
Source

pub fn load_bytes(&mut self, bytes: &[u8], offset: u16) -> Option<u16>

Load bytes into the machine at the specified offset.

Returns the amount of bytes written

Source

pub fn load_instruction(&mut self, instruction: Instruction, offset: &mut u16)

Loads a single instruction into memory at the specified offset, mutating it based on the amount of bytes written.

Source

pub fn run(&mut self) -> u8

Runs the machine until it halts via Ωtheendisnear and Ωskiptothechase.

§Panics

Panics if an invalid opcode (instruction) is stumbled upon with an esoteric message and an explaination for demistification.

Examples found in repository?
examples/helloworld.rs (line 36)
3fn main() -> Machine {
4    // initialize a new machine
5    let mut machine = Machine::default();
6
7    // assembly code for the machine
8    let asm = esoteric_assembly! {
9        // initialize dot pointer so that IO operations work
10
11        // push a dot character to stack
12        0: pushi b'.';
13        // pop to address 28657
14        2: pop 28657;
15
16        // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17        5: ldidp 28657;
18
19        // -----------------
20
21        // print hello world
22        8: writeline 13;
23
24        // halt machine
25        11: Ωtheendisnear;
26        12: Ωskiptothechase;
27
28        // hello world text
29        13: data b"Hello, world!\n\0";
30    };
31
32    // load machine code
33    machine.load(&asm, 0);
34
35    // run machine until it halts
36    machine.run();
37
38    // return the machine's register A (unused)
39    machine
40}
More examples
Hide additional examples
examples/truth_machine.rs (line 81)
3fn main() -> Machine {
4    // initialize a new machine
5    let mut machine = Machine::default();
6
7    // assembly code for the machine
8    let asm = esoteric_assembly! {
9        // initialize dot pointer so that IO operations work
10
11        // push a dot character to stack
12        0: pushi b'.';
13        // pop to address 28657
14        2: pop 28657;
15
16        // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17        4: ldidp 28657;
18
19        // ------------------
20
21        // get a single character to register ch
22        7: getchar;
23
24        // push register ch to stack (4 bytes)
25        8: pushch;
26
27        // pop character to register b
28        9: popb;
29
30        // pop the other 2 bytes
31        10: stackdealloc 2;
32
33        // put 49 (ascii for '1') in register L
34        13: pushi 0;
35        15: pushi 49;
36        17: popl;
37
38        // compare registers L and b
39        18: cmplb;
40
41        // push 30 (input == '1' logic)
42        19: pushi 0;
43        21: pushi 30;
44
45        // pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
46        23: zpopep;
47
48        // empty the stack
49        24: stackdealloc 2;
50
51        // IF INPUT IS '0' (repeat it)
52        // fallback to the input == '1' logic, ran without jumps
53
54        // write the input value ('0')
55        27: writechar;
56
57        // halt machine
58        28: Ωtheendisnear;
59        29: Ωskiptothechase;
60
61        // IF INPUT IS '1' (repeat indefinitely)
62
63        // write the input value ('1')
64        30: writechar;
65
66        // push 30 (input == '1' logic)
67        31: pushi 0;
68        33: pushi 30;
69
70        // pop to execution pointer (jump to value on stack)
71        //
72        // this repeats the input == '1' logic indefinitely
73        35: popep;
74
75    };
76
77    // load machine code
78    machine.load(&asm, 0);
79
80    // run machine until it halts
81    machine.run();
82
83    // return the machine's register A (unused)
84    machine
85}
examples/99_bottles_of_beer.rs (line 131)
3fn main() -> Machine {
4    // initialize a new machine
5    let mut machine = Machine::default();
6
7    // assembly code for the machine
8    let asm = esoteric_assembly! {
9        // initialize dot pointer so that IO operations work
10
11        // push a dot character to stack
12        0: pushi b'.';
13        // pop to address 28657
14        2: pop 28657;
15
16        // set dot pointer to 28657 (has to be a prime or semiprime, which is also a fibonacci number)
17        5: ldidp 28657;
18
19        // -----------------
20
21
22        // set L to 99
23        8: pushi 0;
24        10: pushi 99;
25        12: popl;
26
27        // set num to 99
28        13: pushi 0;
29        15: pushi 0;
30        17: pushi 0;
31        19: pushi 99;
32        21: popnum;
33
34        // set B to 1
35        22: pushi 0;
36        24: pushi 1;
37        26: popb;
38
39        27: Ωsetpaperclipproduction true;
40
41        // WORK
42            29: writeline 110; // wall
43            33: writeline 140; // bottles
44
45            35: Ωsetpaperclipproduction false;
46
47            37: writeline 158; // take
48
49            40: Ωsetpaperclipproduction true;
50
51            // jump to fin if L == 1
52            42: cmplb;
53            43: pushi 0;
54            45: pushi 71;
55
56            47: zpopep;
57
58            48: stackdealloc 2;
59
60            // set B to 1
61            51: pushi 0;
62            53: pushi 1;
63            55: popb;
64
65            56: subbl; // L -= 1
66
67            // set num to L
68            57: pushi 0;
69            59: pushi 0;
70            61: pushl;
71            62: popnum;
72
73            63: writeline 193; // wall_end
74
75            // jump back to work
76            66: pushi 0;
77            68: pushi 29;
78
79            70: popep;
80
81        // FIN
82            71: Ωsetpaperclipproduction false;
83
84            73: writeline 224; // no_more
85            76: writeline 193; // wall_end
86
87            79: writeline 233; // No_more
88            82: writeline 110; // wall
89            85: writeline 224; // no_more
90            88: writeline 140; // bottles
91
92            91: writeline 242; // store
93
94            // set num to 99
95            94: pushi 0;
96            96: pushi 0;
97            98: pushi 0;
98            100: pushi 99;
99            102: popnum;
100
101            103: Ωsetpaperclipproduction true;
102
103            105: writeline 193; // wall_end
104
105        // halt machine
106        108: Ωtheendisnear;
107        109: Ωskiptothechase;
108
109        // wall (30 bytes)
110        110: data b"bottles of beer on the wall, \0";
111        // bottles (18 bytes)
112        140: data b"bottles of beer.\n\0";
113        // take (35 bytes)
114        158: data b"Take one down and pass it around, \0";
115        // wall end (31 bytes)
116        193: data b"bottles of beer on the wall.\n\n\0";
117
118        // no more (9 bytes)
119        224: data b"no more \0";
120        // No more (9 bytes)
121        233: data b"No more \0";
122
123        // store
124        242: data b"Go to the store and buy some more, \0";
125    };
126
127    // load machine code
128    machine.load(&asm, 0);
129
130    // run machine until it halts
131    machine.run();
132
133    // return the machine's register A (unused)
134    machine
135}

Trait Implementations§

Source§

impl Clone for Machine

Source§

fn clone(&self) -> Machine

Returns a copy of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Machine

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Machine

Source§

fn default() -> Self

Returns the “default value” for a type. Read more
Source§

impl Termination for Machine

Source§

fn report(self) -> ExitCode

Is called to get the representation of the value as status code. This status code is returned to the operating system.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.