A compiler from a subset of Rust to Triton VM assembly.
This compiler only handles a small part of the Rust language.
- There are no
for
loops, usewhile
instead. - All functions must end with the
return
keyword and functions may only contain onereturn
statement, i.e. early returns are not possible. - All declarations must use explicit types.
And more ...
- Clone this repo
cd tasm-lang
cargo install --path .
Executing tasm-lang <input-file.rs> <output-file>
will create an assembler file in <output-file>.tasm
of the compilation of the
main
function in <intput-file.rs>
.
The compiled assembler code can be executed through Triton VM's run
function, or through triton-tui,
the debugger for Triton VM. triton-tui allows you to step through the assember one instruction at a time and see the state of the virtual
machine before each instruction. If you've installed triton-tui, you can execute your compiled assembler:
triton-tui <output-file.tasm>
See the examples in triton-tui to see how to set initial conditions (like input streams) on Triton VM executions.
Solution to Project Euler Problem 1
If we list all the natural numbers below
$10$ that are multiples of$3$ or$5$ , we get$3, 5, 6$ and$9$ . The sum of these multiples is$23$ . Find the sum of all the multiples of$3$ or$5$ below$1000$ .
fn main() {
let mut i: u32 = 1;
let mut acc: u32 = 0;
while i < 1000 {
if i % 3 == 0 || i % 5 == 0 {
acc += i;
}
i += 1;
}
tasm::tasmlib_io_write_to_stdout___u32(acc);
return;
}
Notice that the result is printed to std-out through helper functions from the tasm-lib
library.
Also notice that the above code is valid Rust code that will run on both Triton VM and your host-machine, provided that the host-machine
implementation of tasmlib_io_write_to_stdout___u32
is available.
Solution to Project Euler Problem 7
By listing the first six prime numbers:
$2, 3, 5, 7, 11$ , and$13$ , we can see that the$6^{th}$ prime is$13$ . What is the$10,001^{st}$ prime number?
fn main() {
// Execute with `10001` in standard input to find the 10,001th prime
let index_of_prime_to_find: u32 = tasm::tasmlib_io_read_stdin___u32();
let log2_of_desired_index: u32 = index_of_prime_to_find.ilog2();
let sieve_size: u32 = index_of_prime_to_find * log2_of_desired_index;
let mut primes: Vec<bool> = Vec::<bool>::default();
// 0 and 1 are not primes
primes.push(false);
primes.push(false);
// Initialize all cells to `true`
let mut tmp_vec_initializer: u32 = 2;
while tmp_vec_initializer < sieve_size {
primes.push(true);
tmp_vec_initializer += 1;
}
let mut num_primes_found: u32 = 1;
let mut prime_candidate: u32 = 3;
let mut last_prime_found: u32 = prime_candidate;
while num_primes_found < index_of_prime_to_find {
if primes[prime_candidate as usize] {
num_primes_found += 1;
last_prime_found = prime_candidate;
let mut multiples_of_found_prime: u32 = 2 * prime_candidate;
while multiples_of_found_prime < sieve_size {
primes[multiples_of_found_prime as usize] = false;
multiples_of_found_prime += prime_candidate;
}
}
prime_candidate += 2;
}
tasm::tasmlib_io_write_to_stdout___u32(last_prime_found);
return;
}
Notice that there is full support for types native to Triton VM like BFieldElement
, XFieldElement
, and Digest
.
And support for an object-oriented programming style and the initialization of memory at program execution start. In this
example, the program must be initialized with an encoded structure TestStructure
at position 0
in memory.
#[derive(TasmObject, BFieldCodec)]
struct TestStruct {
a: BFieldElement,
b: BFieldElement,
c: u32,
d: u64,
}
impl TestStruct {
fn ab_sum(&self) -> BFieldElement {
return self.a + self.b;
}
fn cd_sum(&self, other_value: u64) -> u128 {
return self.c as u128 + self.d as u128 + other_value as u128;
}
}
fn main() {
let test_struct: Box<TestStruct> =
TestStruct::decode(&tasm::load_from_memory(BFieldElement::new(0))).unwrap();
let other_value: u64 = 2023;
tasm::tasmlib_io_write_to_stdout___bfe(test_struct.ab_sum());
tasm::tasmlib_io_write_to_stdout___u128(test_struct.cd_sum(other_value));
return;
}
For many more code examples, see programs.