Skip to content

Commit

Permalink
feat(cli): Allow the generation of output files
Browse files Browse the repository at this point in the history
Also improves structure of input-arguments by using `clap`. To generate
a `.tasm` file with the output of the compiler, you can now call
`tasm-lang [-v] <input-file.rs> <output-file>`. Or, in place of
`tasm-lang` `cargo run --` if you have not installed this binary.
  • Loading branch information
Sword-Smith committed Aug 24, 2024
1 parent 1c8b408 commit 5cb3abb
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 26 deletions.
70 changes: 70 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ edition = "2021"
[dependencies]
anyhow = "1"
chrono = "^0.4.38"
regex = "1.10"
clap = "4.5"
inflections = "1.1"
itertools = "0.12"
num = "0.4"
quote = "1.0"
rand = "0"
regex = "1.10"
strum = { version = "0.26", features = ["derive"] }
syn = { version = "1.0", features = ["full", "extra-traits"] }
tasm-lib = { git = "https://github.com/TritonVM/tasm-lib.git", rev = "9d9ead4455fa1016feed50cef0b2b020ba6e9a46" }
quote = "1.0"

[dev-dependencies]
anyhow = "1"
Expand Down
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ A compiler from a subset of Rust to [Triton VM assembly](https://github.com/Trit

## Restrictions
This compiler only handles a small part of the Rust language.
- There are no `for` loops, use `while` instead
- There are no `for` loops, use `while` instead.
- All functions must end with the `return` keyword and functions may only contain *one* `return`
statement
statement, i.e. early returns are not possible.
- All declarations must use explicit types.

And more ...

## Examples
## How to use
Executing `cargo run <input-file.rs> <output-file> [-v]` will create an assembler file in `output-file.tasm` of the compilation of the
`main` function in `<intput-file.rs>`. If you run `cargo install --path .`, this compiler can be executed as `tasm-lang`.

### Simple arithmetic with `u32` numbers
## Examples
### Arithmetic with `u32` numbers
Solution to [Project Euler Problem 1](https://projecteuler.net/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$.
Expand Down Expand Up @@ -44,7 +47,7 @@ Notice that the result is printed to std-out through helper functions from the [
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.

### Simple use of lists, a naive implementation of Sieve of Eratosthenes
### Lists
Solution to [Project Euler Problem 7](https://projecteuler.net/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?
Expand Down Expand Up @@ -91,7 +94,7 @@ fn main() {
}
```

### Basic object-oriented programming style
### Object-oriented Programming

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
Expand Down
79 changes: 61 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::collections::HashMap;
use std::env;
use std::fs;
use std::fs::File;
use std::io::Read;
use std::io::Write;
use std::process;

use clap::Arg;
use clap::ArgAction;
use clap::Command;
use itertools::Itertools;
use syn::ImplItemMethod;
use syn::Item;
Expand Down Expand Up @@ -41,26 +43,64 @@ pub(crate) mod tasm_code_generator;
pub(crate) mod tests_and_benchmarks;
pub(crate) mod type_checker;

const DEFAULT_ENTRYPOINT_NAME: &str = "main";

pub fn main() {
let mut args = env::args();
let _ = args.next(); // executable name

let filename = match (args.next(), args.next()) {
(Some(filename), None) => filename,
_ => {
eprintln!("Usage: dump-syntax path/to/filename.rs");
process::exit(1);
}
let matches = Command::new("tasm-lang")
.version("0.0")
.about("A limited Rust -> TASM compiler")
.arg(
Arg::new("input")
.help("The input file to process")
.required(true)
.index(1),
)
.arg(
Arg::new("output")
.help("The output file to write to")
.required(true)
.index(2),
)
.arg(
Arg::new("verbose")
.short('v')
.long("verbose")
.help("Verbose: Print generated assembler to standard-out")
.action(ArgAction::SetTrue),
)
.get_matches();

let input_file_name = matches.get_one::<String>("input").unwrap();
let output_file_name = matches.get_one::<String>("output").unwrap();
let verbose = matches.get_flag("verbose");

// Check if the input file has a .rs extension
if !input_file_name.ends_with(".rs") {
eprintln!("Error: The input file must have a .rs extension.");
process::exit(1);
}

// Ensure the output file has a .tasm extension
let output_file_name = if output_file_name.ends_with(".tasm") {
output_file_name.clone()
} else {
format!("{output_file_name}.tasm")
};

let mut file = File::open(&filename).expect("Unable to open file");
let assembler = compile_to_string(input_file_name);

let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
// Write result to file
let mut output_file =
File::create(output_file_name.clone()).expect("Unable to create file {output_file}");
output_file
.write_all(assembler.as_bytes())
.expect("Failed to write to output file {output_file}");

let output = compile_to_string(&filename);
println!("Successfully compiled {input_file_name} to {output_file_name}.",);

println!("{output}");
if verbose {
println!("{assembler}");
}
}

/// Mapping from name of a custom type to its type declaration and associated function and methods.
Expand Down Expand Up @@ -186,7 +226,7 @@ fn unwrap_custom_rust_type(
fn parse_function_and_types(file_path: &str) -> (syn::ItemFn, StructsAndMethodsRustAst) {
let content = fs::read_to_string(file_path).expect("Unable to read file {path}");
let parsed_file: syn::File = syn::parse_str(&content).expect("Unable to parse rust code");
let entrypoint = extract_entrypoint(&parsed_file, "main");
let entrypoint = extract_entrypoint(&parsed_file, DEFAULT_ENTRYPOINT_NAME);
let (custom_types, dependencies) = extract_types_and_function(&parsed_file);

assert!(
Expand Down Expand Up @@ -218,7 +258,10 @@ pub(crate) fn compile_to_instructions(file_path: &str) -> Vec<LabelledInstructio
}

pub(crate) fn compile_to_string(file_path: &str) -> String {
compile_to_instructions(file_path).into_iter().join("\n")
format!(
"{}\n",
compile_to_instructions(file_path).into_iter().join("\n")
)
}

fn extract_entrypoint(parsed_file: &syn::File, entrypoint: &str) -> syn::ItemFn {
Expand Down

0 comments on commit 5cb3abb

Please sign in to comment.