A Rust compiler with ownership checking, written in PHP
PHP
360
74 commits
updated Mar 8, 2026
A Rust compiler written in PHP that emits x86-64 Linux ELF binaries directly (no LLVM, no assembler, no linker). Implements ownership checking, borrow checking, type checking, move semantics, generics, traits, closures, and iterators. Useful if you need to compile Rust on a shared hosting server from 2008 where the only installed runtime is PHP.
In order to execute Rust code you of course first need to install PHP. You can do this easily on Windows 11 by running:
winget install PHP.PHP.8.4
This compiler outputs valid machine code for Linux, so the most practical approach if you're on Windows is to use WSL. Start by installing Ubuntu (if you haven't already):
wsl --install
After the install completes, reboot your machine and then open Ubuntu from the Start menu to finish the initial setup.
Compile a .rs file by running:
php rustc.php main.rs -o main
Then execute the compiled binary through WSL:
wsl ./main
To see the exit code of the program:
wsl ./main; echo $?
Types
i32, bool, u8, u16, u32, u64, u128, usizeString (heap string, move semantics)&str and string slice indexing (s[0])&T, &mut T references with borrow checking*const T and *mut Tmatch() in expressions, return types, and generic argumentsimpl blocksOption<T> and Result<T, E> with Some/None, Ok/Err (no source definitions required)Box<T> (Box::new, deref)alloc::Vec<T> (monomorphized: Vec<i32>, Vec<u8>, etc.; Vec::new(), push, indexing v[i] and v[i] = x; uses size_of::<T>() in alloc crate). Legacy alloc::VecI32 also supported.Control flow
if / else (including as expressions)if let and while letwhile, loop, break, continue (including break level)for x in start..end (range iteration)match with enum arms, int literals, and wildcard _returnHeap and allocation
alloc crate: alloc(), dealloc(), realloc() (only callable from inside the alloc crate)alloc::Vec<T> as aboveFunctions and closures
const fn (accepted and treated as a regular function)impl blocks with self, &self, &mut selfimpl Trait for Type|x: i32| x + captured_var)Ownership and borrowing
Copy typesCopy inference for i32, bool, &T, and all-copy structs/enums+=, -=, *=, /=) for variables, derefs, and fieldsModules and syntax
mod name; declarations with file-based module resolutionpub visibility on functions, structs, and fieldsuse paths for cross-module importsconst and static items#[...] and #![...] (parsed and skipped)Output
println!("{}", expr) — print a single valueexit(code) — explicit exit with status codeRun the full test suite:
php tests/run.php
Test cases live in tests/cases/ organized into fundamentals/valid/, fundamentals/invalid/, modules/, and programs/. Each .rs file declares its expected output in comments at the top:
// exit: 42
// stdout: hello
// error: Use of moved value
Roughly in order of impact:
alloc() outside the alloc crate (heap and alloc::Vec<T> are supported)f32 / f64 floating point? operator (Result is supported; ? is not)fn apply(f: impl Fn(i32) -> i32))|| expr)println! (only "{}" with one argument is supported)i8, i16, i64, i128)74 commits
PHP
84.9%
Rust
15.1%
A Rust compiler with ownership checking, written in PHP
PHP
360
74 commits
updated Mar 8, 2026
A Rust compiler written in PHP that emits x86-64 Linux ELF binaries directly (no LLVM, no assembler, no linker). Implements ownership checking, borrow checking, type checking, move semantics, generics, traits, closures, and iterators. Useful if you need to compile Rust on a shared hosting server from 2008 where the only installed runtime is PHP.
In order to execute Rust code you of course first need to install PHP. You can do this easily on Windows 11 by running:
winget install PHP.PHP.8.4
This compiler outputs valid machine code for Linux, so the most practical approach if you're on Windows is to use WSL. Start by installing Ubuntu (if you haven't already):
wsl --install
After the install completes, reboot your machine and then open Ubuntu from the Start menu to finish the initial setup.
Compile a .rs file by running:
php rustc.php main.rs -o main
Then execute the compiled binary through WSL:
wsl ./main
To see the exit code of the program:
wsl ./main; echo $?
Types
i32, bool, u8, u16, u32, u64, u128, usizeString (heap string, move semantics)&str and string slice indexing (s[0])&T, &mut T references with borrow checking*const T and *mut Tmatch() in expressions, return types, and generic argumentsimpl blocksOption<T> and Result<T, E> with Some/None, Ok/Err (no source definitions required)Box<T> (Box::new, deref)alloc::Vec<T> (monomorphized: Vec<i32>, Vec<u8>, etc.; Vec::new(), push, indexing v[i] and v[i] = x; uses size_of::<T>() in alloc crate). Legacy alloc::VecI32 also supported.Control flow
if / else (including as expressions)if let and while letwhile, loop, break, continue (including break level)for x in start..end (range iteration)match with enum arms, int literals, and wildcard _returnHeap and allocation
alloc crate: alloc(), dealloc(), realloc() (only callable from inside the alloc crate)alloc::Vec<T> as aboveFunctions and closures
const fn (accepted and treated as a regular function)impl blocks with self, &self, &mut selfimpl Trait for Type|x: i32| x + captured_var)Ownership and borrowing
Copy typesCopy inference for i32, bool, &T, and all-copy structs/enums+=, -=, *=, /=) for variables, derefs, and fieldsModules and syntax
mod name; declarations with file-based module resolutionpub visibility on functions, structs, and fieldsuse paths for cross-module importsconst and static items#[...] and #![...] (parsed and skipped)Output
println!("{}", expr) — print a single valueexit(code) — explicit exit with status codeRun the full test suite:
php tests/run.php
Test cases live in tests/cases/ organized into fundamentals/valid/, fundamentals/invalid/, modules/, and programs/. Each .rs file declares its expected output in comments at the top:
// exit: 42
// stdout: hello
// error: Use of moved value
Roughly in order of impact:
alloc() outside the alloc crate (heap and alloc::Vec<T> are supported)f32 / f64 floating point? operator (Result is supported; ? is not)fn apply(f: impl Fn(i32) -> i32))|| expr)println! (only "{}" with one argument is supported)i8, i16, i64, i128)74 commits
PHP
84.9%
Rust
15.1%