diff --git a/rust2/Cargo.lock b/rust2/Cargo.lock index f77761b..50792a7 100644 --- a/rust2/Cargo.lock +++ b/rust2/Cargo.lock @@ -30,6 +30,7 @@ name = "brainfuck" version = "0.1.0" dependencies = [ "bumpalo", + "clap 3.1.9", "criterion", "insta", "owo-colors", @@ -75,10 +76,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "bitflags", - "textwrap", + "textwrap 0.11.0", "unicode-width", ] +[[package]] +name = "clap" +version = "3.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aad2534fad53df1cc12519c5cda696dd3e20e6118a027e24054aea14a0bdcbe" +dependencies = [ + "atty", + "bitflags", + "clap_derive", + "clap_lex", + "indexmap", + "lazy_static", + "strsim", + "termcolor", + "textwrap 0.15.0", +] + +[[package]] +name = "clap_derive" +version = "3.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d716edb7c26222b1b21de6e6d505b274f9f3db9e7bc2e06baf389d57ae842df8" +dependencies = [ + "os_str_bytes", +] + [[package]] name = "console" version = "0.15.0" @@ -100,7 +140,7 @@ checksum = "1604dafd25fba2fe2d5895a9da139f8dc9b319a5fe5354ca137cbbce4e178d10" dependencies = [ "atty", "cast", - "clap", + "clap 2.34.0", "criterion-plot", "csv", "itertools", @@ -219,6 +259,12 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +[[package]] +name = "heck" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -355,6 +401,15 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "os_str_bytes" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" +dependencies = [ + "memchr", +] + [[package]] name = "owo-colors" version = "3.3.0" @@ -389,6 +444,30 @@ dependencies = [ "plotters-backend", ] +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.37" @@ -548,6 +627,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + [[package]] name = "syn" version = "1.0.91" @@ -559,6 +644,15 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "termcolor" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +dependencies = [ + "winapi-util", +] + [[package]] name = "terminal_size" version = "0.1.17" @@ -578,6 +672,12 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" + [[package]] name = "tinytemplate" version = "1.2.1" @@ -600,6 +700,12 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.3.2" diff --git a/rust2/Cargo.toml b/rust2/Cargo.toml index e5b3977..79ce315 100644 --- a/rust2/Cargo.toml +++ b/rust2/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" [dependencies] bumpalo = { version = "3.9.1", features = ["allocator_api"] } +clap = { version = "3.1.9", features = ["derive"] } owo-colors = "3.3.0" [dev-dependencies] diff --git a/rust2/src/codegen.rs b/rust2/src/codegen.rs index 01316d1..68d573f 100644 --- a/rust2/src/codegen.rs +++ b/rust2/src/codegen.rs @@ -21,6 +21,7 @@ use crate::opts::{Ir, Stmt as IrStmt, StmtKind}; use crate::parse::Span; use crate::BumpVec; use bumpalo::Bump; +use std::fmt::{Debug, Formatter}; #[derive(Debug, Clone, Copy)] pub enum Stmt { @@ -39,12 +40,18 @@ pub enum Stmt { const _: [(); 8] = [(); std::mem::size_of::()]; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Code<'c> { stmts: BumpVec<'c, Stmt>, debug: BumpVec<'c, Span>, } +impl Debug for Code<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.stmts.fmt(f) + } +} + impl Code<'_> { pub fn stmts(&self) -> &[Stmt] { &self.stmts diff --git a/rust2/src/lib.rs b/rust2/src/lib.rs index f216805..9a059fd 100644 --- a/rust2/src/lib.rs +++ b/rust2/src/lib.rs @@ -7,12 +7,43 @@ use bumpalo::Bump; use owo_colors::OwoColorize; use std::fmt::Display; use std::io::{Read, Write}; +use std::path::PathBuf; +use std::str::FromStr; pub mod codegen; pub mod codegen_interpreter; pub mod opts; pub mod parse; +#[derive(clap::Parser, Default)] +#[clap(author, about)] +pub struct Args { + #[clap(short, long)] + pub profile: bool, + #[clap(long)] + pub dump: Option, + pub file: PathBuf, +} + +pub enum DumpKind { + Ast, + Ir, + Code, +} + +impl FromStr for DumpKind { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "ast" => Ok(Self::Ast), + "ir" => Ok(Self::Ir), + "code" => Ok(Self::Code), + other => Err(format!("Invalid IR level: '{other}'")), + } + } +} + type BumpVec<'a, T> = Vec; pub enum UseProfile { @@ -20,7 +51,7 @@ pub enum UseProfile { No, } -pub fn run(src: &str, stdout: W, stdin: R, use_profile: UseProfile) -> Result<(), ParseError> +pub fn run(src: &str, stdout: W, stdin: R, config: &Args) -> Result<(), ParseError> where W: Write, R: Read, @@ -29,10 +60,20 @@ where let parsed = parse::parse(&ast_alloc, src.bytes().enumerate())?; + if let Some(DumpKind::Ast) = config.dump { + println!("{parsed:#?}"); + return Ok(()); + } + let ir_alloc = Bump::new(); let optimized_ir = opts::optimize(&ir_alloc, &parsed); + if let Some(DumpKind::Ir) = config.dump { + println!("{optimized_ir:#?}"); + return Ok(()); + } + drop(parsed); drop(ast_alloc); @@ -40,11 +81,16 @@ where let code = codegen::generate(&cg_alloc, &optimized_ir); + if let Some(DumpKind::Code) = config.dump { + println!("{code:#?}"); + return Ok(()); + } + drop(optimized_ir); drop(ir_alloc); - match use_profile { - UseProfile::Yes => { + match config.profile { + true => { let mut code_profile_count = vec![0; code.debug().len()]; codegen_interpreter::run(&code, stdout, stdin, |ip| unsafe { @@ -65,7 +111,7 @@ where print!("{}", color_by_profile(char as char, value, max)); } } - UseProfile::No => { + false => { codegen_interpreter::run(&code, stdout, stdin, |_| {}); } } @@ -90,7 +136,7 @@ fn color_by_profile(char: char, value: u64, max: u64) -> impl Display { #[cfg(test)] mod tests { - use crate::UseProfile; + use crate::Args; #[test] fn fizzbuzz() { @@ -98,7 +144,7 @@ mod tests { let mut stdout = Vec::new(); let stdin = []; - super::run(str, &mut stdout, stdin.as_slice(), UseProfile::No).unwrap(); + super::run(str, &mut stdout, stdin.as_slice(), &Args::default()).unwrap(); insta::assert_debug_snapshot!(String::from_utf8(stdout)); } diff --git a/rust2/src/main.rs b/rust2/src/main.rs index 03e5969..ba90936 100644 --- a/rust2/src/main.rs +++ b/rust2/src/main.rs @@ -1,31 +1,24 @@ #![feature(allocator_api, let_else)] #![warn(rust_2018_idioms)] -use brainfuck::UseProfile; -use std::{env, fs, io, process}; +use brainfuck::Args; +use clap::Parser; +use std::{fs, io, process}; fn main() { - let Some(path) = env::args().nth(1) else { - eprintln!("error: Provide a path as input."); - process::exit(1); - }; - - let file = fs::read_to_string(path).unwrap_or_else(|err| { - eprintln!("error: Failed to read file: {err}"); - process::exit(1); - }); - let stdout = io::stdout(); let stdout = stdout.lock(); let stdin = io::stdin(); let stdin = stdin.lock(); - let profile = env::args() - .any(|a| a == "--profile") - .then(|| UseProfile::Yes) - .unwrap_or(UseProfile::No); + let args = Args::parse(); - brainfuck::run(&file, stdout, stdin, profile).unwrap_or_else(|_| { + let src = fs::read_to_string(&args.file).unwrap_or_else(|err| { + eprintln!("error: Failed to read file: {err}"); + process::exit(1); + }); + + brainfuck::run(&src, stdout, stdin, &args).unwrap_or_else(|_| { eprintln!("error: Failed to parse brainfuck code"); process::exit(1); }); diff --git a/rust2/src/opts.rs b/rust2/src/opts.rs index 58c635b..1aad54c 100644 --- a/rust2/src/opts.rs +++ b/rust2/src/opts.rs @@ -1,13 +1,14 @@ use crate::parse::{Instr, Span}; use crate::BumpVec; use bumpalo::Bump; +use std::fmt::{Debug, Formatter}; #[derive(Debug, Clone)] pub struct Ir<'ir> { pub stmts: BumpVec<'ir, Stmt<'ir>>, } -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct Stmt<'ir> { pub kind: StmtKind<'ir>, pub span: Span, @@ -23,6 +24,12 @@ impl<'ir> Stmt<'ir> { } } +impl Debug for Stmt<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_tuple("Stmt").field(&self.kind).finish() + } +} + #[derive(Debug, Clone)] pub enum StmtKind<'ir> { Add(u8), diff --git a/rust2/src/parse.rs b/rust2/src/parse.rs index 9e0c64d..895952f 100644 --- a/rust2/src/parse.rs +++ b/rust2/src/parse.rs @@ -1,5 +1,6 @@ use bumpalo::Bump; use std::cmp; +use std::fmt::Debug; #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct Span { diff --git a/rust2/test.bf b/rust2/test.bf index 44f7661..8fa0f72 100644 --- a/rust2/test.bf +++ b/rust2/test.bf @@ -1,5 +1 @@ - Benchmark brainf*ck program ->++[<+++++++++++++>-]<[[>+>+<<-]>[<+>-]++++++++ -[>++++++++<-]>.[-]<<>++++++++++[>++++++++++[>++ -++++++++[>++++++++++[>++++++++++[>++++++++++[>+ -+++++++++[-]<-]<-]<-]<-]<-]<-]<-]++++++++++. \ No newline at end of file +++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.