Implementation of the UM-32 "Universal Machine" as described by the Cult of the Bound Variable
1// Copyright (C) 2025 Thom Hayward.
2//
3// This program is free software: you can redistribute it and/or modify it under
4// the terms of the GNU General Public License as published by the Free Software
5// Foundation, version 3.
6//
7// This program is distributed in the hope that it will be useful, but WITHOUT
8// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
9// FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
10// details.
11//
12// You should have received a copy of the GNU General Public License along with
13// this program. If not, see <https://www.gnu.org/licenses/>.
14//
15
16#[cfg(feature = "asm")]
17mod asm;
18
19mod conv;
20mod ops;
21mod reg;
22mod universal_machine;
23
24use std::{path::Path, time::Instant};
25
26use universal_machine::Um;
27
28fn main() {
29 let mut program = Vec::new();
30 let mut time = false;
31
32 for arg in std::env::args().skip(1) {
33 if arg == "--time" {
34 time = true;
35 continue;
36 }
37
38 let path = Path::new(&arg);
39 program.extend_from_slice(&match load_program(path) {
40 Ok(p) => p,
41 Err(error) => {
42 eprintln!("{error}");
43 std::process::exit(1);
44 }
45 });
46 }
47
48 let start = Instant::now();
49 Um::new(program)
50 .stdout(&mut std::io::stdout())
51 .stdin(&mut std::io::stdin())
52 .run();
53
54 if time {
55 eprintln!("{:?}", start.elapsed());
56 }
57}
58
59#[cfg(feature = "asm")]
60fn load_program(path: &Path) -> std::io::Result<Vec<u32>> {
61 match path.extension().map(|ext| ext.as_encoded_bytes()) {
62 // In an ideal world we would just add `#[cfg(feature = "asm")]` here.
63 // Unfortunately this leads some wierd code generation fuckery which
64 // makes the version without the 'asm' feature ~1-2 seconds slower
65 // when running the sandmark program.
66 Some(b"uasm" | b"asm") => {
67 let source = std::fs::read_to_string(path)?;
68 Ok(asm::assemble(&source))
69 }
70 _ => {
71 let program = std::fs::read(path)?;
72 Ok(conv::bytes_to_program(&program).unwrap())
73 }
74 }
75}
76
77#[cfg(not(feature = "asm"))]
78fn load_program(path: &Path) -> std::io::Result<Vec<u32>> {
79 let program = std::fs::read(path)?;
80 Ok(conv::bytes_to_program(&program).unwrap())
81}