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)
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
fn main() -> Machine {
    // 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
}
More examples
Hide additional examples
examples/truth_machine.rs (line 78)
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
fn main() -> Machine {
    // 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)
        4: ldidp 28657;

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

        // get a single character to register ch
        7: getchar;

        // push register ch to stack (4 bytes)
        8: pushch;

        // pop character to register b
        9: popb;

        // pop the other 2 bytes
        10: stackdealloc 2;

        // put 49 (ascii for '1') in register L
        13: pushi 0;
        15: pushi 49;
        17: popl;

        // compare registers L and b
        18: cmplb;

        // push 30 (input == '1' logic)
        19: pushi 0;
        21: pushi 30;

        // pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
        23: zpopep;

        // empty the stack
        24: stackdealloc 2;

        // IF INPUT IS '0' (repeat it)
        // fallback to the input == '1' logic, ran without jumps

        // write the input value ('0')
        27: writechar;

        // halt machine
        28: Ωtheendisnear;
        29: Ωskiptothechase;

        // IF INPUT IS '1' (repeat indefinitely)

        // write the input value ('1')
        30: writechar;

        // push 30 (input == '1' logic)
        31: pushi 0;
        33: pushi 30;

        // pop to execution pointer (jump to value on stack)
        //
        // this repeats the input == '1' logic indefinitely
        35: popep;

    };

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

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

    // return the machine's register A (unused)
    machine
}
examples/99_bottles_of_beer.rs (line 128)
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
fn main() -> Machine {
    // 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;

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


        // set L to 99
        8: pushi 0;
        10: pushi 99;
        12: popl;

        // set num to 99
        13: pushi 0;
        15: pushi 0;
        17: pushi 0;
        19: pushi 99;
        21: popnum;

        // set B to 1
        22: pushi 0;
        24: pushi 1;
        26: popb;

        27: Ωsetpaperclipproduction true;

        // WORK
            29: writeline 110; // wall
            33: writeline 140; // bottles

            35: Ωsetpaperclipproduction false;

            37: writeline 158; // take

            40: Ωsetpaperclipproduction true;

            // jump to fin if L == 1
            42: cmplb;
            43: pushi 0;
            45: pushi 71;

            47: zpopep;

            48: stackdealloc 2;

            // set B to 1
            51: pushi 0;
            53: pushi 1;
            55: popb;

            56: subbl; // L -= 1

            // set num to L
            57: pushi 0;
            59: pushi 0;
            61: pushl;
            62: popnum;

            63: writeline 193; // wall_end

            // jump back to work
            66: pushi 0;
            68: pushi 29;

            70: popep;

        // FIN
            71: Ωsetpaperclipproduction false;

            73: writeline 224; // no_more
            76: writeline 193; // wall_end

            79: writeline 233; // No_more
            82: writeline 110; // wall
            85: writeline 224; // no_more
            88: writeline 140; // bottles

            91: writeline 242; // store

            // set num to 99
            94: pushi 0;
            96: pushi 0;
            98: pushi 0;
            100: pushi 99;
            102: popnum;

            103: Ωsetpaperclipproduction true;

            105: writeline 193; // wall_end

        // halt machine
        108: Ωtheendisnear;
        109: Ωskiptothechase;

        // wall (30 bytes)
        110: data b"bottles of beer on the wall, \0";
        // bottles (18 bytes)
        140: data b"bottles of beer.\n\0";
        // take (35 bytes)
        158: data b"Take one down and pass it around, \0";
        // wall end (31 bytes)
        193: data b"bottles of beer on the wall.\n\n\0";

        // no more (9 bytes)
        224: data b"no more \0";
        // No more (9 bytes)
        233: data b"No more \0";

        // store
        242: data b"Go to the store and buy some more, \0";
    };

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

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

    // return the machine's register A (unused)
    machine
}
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)
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
fn main() -> Machine {
    // 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
}
More examples
Hide additional examples
examples/truth_machine.rs (line 81)
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
fn main() -> Machine {
    // 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)
        4: ldidp 28657;

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

        // get a single character to register ch
        7: getchar;

        // push register ch to stack (4 bytes)
        8: pushch;

        // pop character to register b
        9: popb;

        // pop the other 2 bytes
        10: stackdealloc 2;

        // put 49 (ascii for '1') in register L
        13: pushi 0;
        15: pushi 49;
        17: popl;

        // compare registers L and b
        18: cmplb;

        // push 30 (input == '1' logic)
        19: pushi 0;
        21: pushi 30;

        // pop to execution pointer (jump to value on stack) if b is 0 (input is '1')
        23: zpopep;

        // empty the stack
        24: stackdealloc 2;

        // IF INPUT IS '0' (repeat it)
        // fallback to the input == '1' logic, ran without jumps

        // write the input value ('0')
        27: writechar;

        // halt machine
        28: Ωtheendisnear;
        29: Ωskiptothechase;

        // IF INPUT IS '1' (repeat indefinitely)

        // write the input value ('1')
        30: writechar;

        // push 30 (input == '1' logic)
        31: pushi 0;
        33: pushi 30;

        // pop to execution pointer (jump to value on stack)
        //
        // this repeats the input == '1' logic indefinitely
        35: popep;

    };

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

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

    // return the machine's register A (unused)
    machine
}
examples/99_bottles_of_beer.rs (line 131)
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
fn main() -> Machine {
    // 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;

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


        // set L to 99
        8: pushi 0;
        10: pushi 99;
        12: popl;

        // set num to 99
        13: pushi 0;
        15: pushi 0;
        17: pushi 0;
        19: pushi 99;
        21: popnum;

        // set B to 1
        22: pushi 0;
        24: pushi 1;
        26: popb;

        27: Ωsetpaperclipproduction true;

        // WORK
            29: writeline 110; // wall
            33: writeline 140; // bottles

            35: Ωsetpaperclipproduction false;

            37: writeline 158; // take

            40: Ωsetpaperclipproduction true;

            // jump to fin if L == 1
            42: cmplb;
            43: pushi 0;
            45: pushi 71;

            47: zpopep;

            48: stackdealloc 2;

            // set B to 1
            51: pushi 0;
            53: pushi 1;
            55: popb;

            56: subbl; // L -= 1

            // set num to L
            57: pushi 0;
            59: pushi 0;
            61: pushl;
            62: popnum;

            63: writeline 193; // wall_end

            // jump back to work
            66: pushi 0;
            68: pushi 29;

            70: popep;

        // FIN
            71: Ωsetpaperclipproduction false;

            73: writeline 224; // no_more
            76: writeline 193; // wall_end

            79: writeline 233; // No_more
            82: writeline 110; // wall
            85: writeline 224; // no_more
            88: writeline 140; // bottles

            91: writeline 242; // store

            // set num to 99
            94: pushi 0;
            96: pushi 0;
            98: pushi 0;
            100: pushi 99;
            102: popnum;

            103: Ωsetpaperclipproduction true;

            105: writeline 193; // wall_end

        // halt machine
        108: Ωtheendisnear;
        109: Ωskiptothechase;

        // wall (30 bytes)
        110: data b"bottles of beer on the wall, \0";
        // bottles (18 bytes)
        140: data b"bottles of beer.\n\0";
        // take (35 bytes)
        158: data b"Take one down and pass it around, \0";
        // wall end (31 bytes)
        193: data b"bottles of beer on the wall.\n\n\0";

        // no more (9 bytes)
        224: data b"no more \0";
        // No more (9 bytes)
        233: data b"No more \0";

        // store
        242: data b"Go to the store and buy some more, \0";
    };

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

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

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

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, dst: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dst. 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.