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//
15use std::{
16 ffi::OsStr,
17 io,
18 path::{Path, PathBuf},
19};
20
21fn main() -> io::Result<()> {
22 let mut output = PathBuf::from("./a.um");
23
24 let mut program = Vec::new();
25 let mut args = std::env::args().skip(1);
26 while let Some(arg) = args.next() {
27 match arg.as_str() {
28 "-o" | "--out" => {
29 output = PathBuf::from(args.next().expect("expected output path"));
30 }
31 _ => {
32 let path = Path::new(&arg);
33 program.extend_from_slice(&load_program(path)?);
34 }
35 }
36 }
37
38 // Convert the program to bytes.
39 let bytes: Vec<_> = program.into_iter().flat_map(u32::to_be_bytes).collect();
40 std::fs::write(&output, bytes)
41}
42
43fn load_program(path: &Path) -> io::Result<Vec<u32>> {
44 if let Some(b"uasm" | b"asm") = path.extension().map(OsStr::as_encoded_bytes) {
45 let source = std::fs::read_to_string(path)?;
46 let program = um::asm::assemble(&source);
47 Ok(program)
48 } else {
49 let program = std::fs::read(path)?;
50 Ok(um::conv::bytes_to_program(&program).unwrap())
51 }
52}