From 0ee230efe03a308daec02ded1e8d134052ce6534 Mon Sep 17 00:00:00 2001 From: arthurfiorette Date: Thu, 24 Feb 2022 12:16:12 -0300 Subject: [PATCH] feat: transpile cli and subcommands --- Cargo.lock | 20 +++++++++++++ Cargo.toml | 7 +++-- src/args.rs | 18 ------------ src/cli.rs | 21 ++++++++++++++ src/main.rs | 52 ++++++++++------------------------ src/reader.rs | 15 ---------- src/run.rs | 70 ++++++++++++++++++++++++++++++++++++++++++++++ src/transpile.rs | 66 +++++++++++++++++++++++++++++++++++++++++++ src/util.rs | 15 ---------- src/util/logger.rs | 11 ++++++++ src/util/mod.rs | 5 ++++ src/util/reader.rs | 27 ++++++++++++++++++ 12 files changed, 240 insertions(+), 87 deletions(-) delete mode 100644 src/args.rs create mode 100644 src/cli.rs delete mode 100644 src/reader.rs create mode 100644 src/run.rs create mode 100644 src/transpile.rs delete mode 100644 src/util.rs create mode 100644 src/util/logger.rs create mode 100644 src/util/mod.rs create mode 100644 src/util/reader.rs diff --git a/Cargo.lock b/Cargo.lock index f505fd4..325702f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -40,7 +40,9 @@ version = "1.0.3" dependencies = [ "brainease_lexer", "brainease_runtime", + "brainease_transpiler", "clap", + "clap-verbosity-flag", "env_logger", "log", ] @@ -61,6 +63,14 @@ dependencies = [ "log", ] +[[package]] +name = "brainease_transpiler" +version = "1.0.3" +dependencies = [ + "brainease_lexer", + "log", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -84,6 +94,16 @@ dependencies = [ "textwrap", ] +[[package]] +name = "clap-verbosity-flag" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17e437250f23cdd03daf3de763093aa27873a026ef9a156800da9ddd617c51d4" +dependencies = [ + "clap", + "log", +] + [[package]] name = "clap_derive" version = "3.1.0" diff --git a/Cargo.toml b/Cargo.toml index 9b235eb..5a2e3a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["brainease_lexer", "brainease_runtime"] +members = ["brainease_lexer", "brainease_runtime", "brainease_transpiler"] [package] name = "brainease" @@ -15,7 +15,10 @@ readme = "./README.md" [dependencies] brainease_runtime = { path = "brainease_runtime", version = "^1" } brainease_lexer = { path = "brainease_lexer", version = "^1" } +brainease_transpiler = { path = "brainease_transpiler", version = "^1" } clap = { version = "^3.1", features = ["derive"] } + +clap-verbosity-flag = "^1" env_logger = "^0.9" -log = "^0.4" +log = "^0.4" \ No newline at end of file diff --git a/src/args.rs b/src/args.rs deleted file mode 100644 index 8c007bc..0000000 --- a/src/args.rs +++ /dev/null @@ -1,18 +0,0 @@ -use clap::Parser; - -/// Brainease command line interface. -#[derive(Parser, Debug)] -#[clap(author, version, about)] -pub struct Args { - /// The main brainease file to run - #[clap(short = 'f', long = "file")] - pub main: String, - - /// The length to initialize the memory array - #[clap(short = 'm', long = "memory", default_value = "3000")] - pub memory: usize, - - /// The compiler log level to use - #[clap(long = "log", default_value = "info")] - pub log_level: String, -} diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..bf9e14f --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,21 @@ +use clap::{Parser, Subcommand}; +use clap_verbosity_flag::Verbosity; + +use crate::{run::RunOpts, transpile::TranspileOpts}; + +#[derive(Parser, Debug)] +#[clap(name = "Brainease")] +#[clap(about = "A brainf*ck-style programming language, but readable")] +pub struct Cli { + #[clap(subcommand)] + pub command: Commands, + + #[clap(flatten)] + pub verbose: Verbosity, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + Transpile(TranspileOpts), + Run(RunOpts), +} diff --git a/src/main.rs b/src/main.rs index e8fadfe..717d338 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,44 +1,22 @@ -use brainease_lexer::parser; -use brainease_runtime::{io_handler::DefaultIoHandler, runtime::Runtime}; +mod cli; +mod run; +mod transpile; +mod util; + use clap::Parser; -use std::{ - io::{stdout, Result, Write}, - path::Path, - process, -}; +use cli::{Cli, Commands}; -pub mod args; -pub mod reader; -pub mod util; +fn main() { + let args = Cli::parse(); -fn main() -> Result<()> { - let args = args::Args::parse(); - util::fallback_rust_log(&args.log_level); + util::setup_logger(&args.verbose); - log::trace!("Cli args: {:?}", args); + let result = match &args.command { + Commands::Transpile(opts) => transpile::run(opts), + Commands::Run(opts) => run::run(opts), + }; - if !args.main.ends_with(".brain") { - log::error!("{} does not end with .brain", args.main); - process::exit(1); + if let Err(err) = result { + log::trace!("{:#?}", err) } - - let path = Path::new(&args.main); - - let main_file = reader::read_file(path); - let instructions = parser::parse_file(&main_file); - - log::trace!("Instructions: {:?}", instructions); - - let mut runtime = Runtime::new(instructions, args.memory, DefaultIoHandler {}); - - log::debug!("Starting runtime"); - - // A little space between stdout - let elapsed_time = runtime.run()?; - - stdout().write_all(b"\n").unwrap(); - - log::debug!("Elapsed time: {}s.", elapsed_time.as_secs_f64()); - - Ok(()) } diff --git a/src/reader.rs b/src/reader.rs deleted file mode 100644 index ae7cbd7..0000000 --- a/src/reader.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::{fs, path::Path, process}; - -pub fn read_file(path: &Path) -> String { - log::trace!("Reading {}", path.display()); - - let content = fs::read_to_string(path); - - if let Err(err) = content { - log::error!("Could not find file {}", path.display()); - log::trace!("{}", err); - process::exit(1); - } - - content.unwrap() -} diff --git a/src/run.rs b/src/run.rs new file mode 100644 index 0000000..16c99f2 --- /dev/null +++ b/src/run.rs @@ -0,0 +1,70 @@ +use std::{ + io::{self, stdout, Write}, + path::Path, +}; + +use brainease_lexer::parser; +use brainease_runtime::{ + io_handler::{DefaultIoHandler, IoHandler}, + runtime::Runtime, +}; +use clap::Parser; + +use crate::util; + +#[derive(Parser, Debug)] +#[clap(name = "run", about = "Run Brainease source code")] +pub struct RunOpts { + /// The main brainease file to run + #[clap(short = 'f', long = "file")] + main: String, + + /// The length to initialize the memory array + #[clap(short = 'm', long = "memory", default_value = "3000")] + memory_length: usize, +} + +pub fn run(opts: &RunOpts) -> io::Result<()> { + let main = Path::new(&opts.main); + + // Checks for .main file format + if !opts.main.ends_with(".brain") { + log::error!( + "{:?} has an unknown file format of {:?}", + main.file_name().unwrap(), + main.extension().unwrap() + ); + + return Ok(()); + } + + let main_content = util::read_file(main)?; + + log::trace!("Parsing {}", main.display()); + + let instructions = parser::parse_file(&main_content); + + log::trace!("{:#?}", instructions); + + let mut runtime = Runtime::new(instructions, opts.memory_length, DefaultIoHandler {}); + + start_runtime(&mut runtime)?; + + Ok(()) +} + +pub fn start_runtime(runtime: &mut Runtime) -> Result<(), I::Err> +where + I: IoHandler, +{ + log::debug!("Starting runtime"); + + let elapsed_time = runtime.run()?; + + // Prints suffix + stdout().write_all(b"\n").unwrap(); + + log::debug!("Elapsed time: {}s.", elapsed_time.as_secs_f64()); + + Ok(()) +} diff --git a/src/transpile.rs b/src/transpile.rs new file mode 100644 index 0000000..d59c7fd --- /dev/null +++ b/src/transpile.rs @@ -0,0 +1,66 @@ +use std::{io, path::Path}; + +use brainease_runtime::io_handler::DefaultIoHandler; +use brainease_runtime::runtime::Runtime; +use brainease_transpiler::as_string::AsString; +use brainease_transpiler::parser; +use clap::Parser; + +use crate::run::start_runtime; +use crate::util; + +#[derive(Parser, Debug)] +#[clap( + name = "transpile", + about = "Transpile Brainease source code to Brainfuck" +)] +pub struct TranspileOpts { + /// The bf source file to transpile + #[clap(short = 'f', long = "file")] + main: String, + + /// The output file to write + #[clap(short = 'o', long = "output")] + output: Option, + + #[clap(short = 'r', long = "run", help = "Run the transpiled code")] + run_after: bool, + + #[clap( + long = "memory", + help = "The memory length when -r is used", + default_value = "3000" + )] + memory_length: usize, +} + +pub fn run(opts: &TranspileOpts) -> io::Result<()> { + let main = Path::new(&opts.main); + let main_content = util::read_file(main)?; + + log::trace!("Transpiling {}", main.display()); + + let transpiled = parser::parse_bf(&main_content); + + log::trace!("{:#?}", transpiled); + + let output_name = &opts.output.clone().unwrap_or_else(|| { + if opts.main.ends_with(".bf") { + opts.main.replace(".bf", ".brain") + } else { + format!("{}.brain", opts.main) + } + }); + + let string_lines = AsString::all(&transpiled, 0); + + util::write_file(Path::new(output_name), string_lines)?; + + if opts.run_after { + let mut runtime = Runtime::new(transpiled, opts.memory_length, DefaultIoHandler {}); + + start_runtime(&mut runtime)?; + } + + Ok(()) +} diff --git a/src/util.rs b/src/util.rs deleted file mode 100644 index 72224e4..0000000 --- a/src/util.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::env; - -pub fn fallback_rust_log(def: &str) { - let log_env = env::var("RUST_LOG"); - if log_env.is_err() || log_env.unwrap().is_empty() { - env::set_var("RUST_LOG", def); - } - - env_logger::builder() - .format_indent(None) - .format_module_path(false) - .format_target(false) - .format_timestamp(None) - .init(); -} diff --git a/src/util/logger.rs b/src/util/logger.rs new file mode 100644 index 0000000..779baf5 --- /dev/null +++ b/src/util/logger.rs @@ -0,0 +1,11 @@ +use clap_verbosity_flag::Verbosity; + +pub fn setup_logger(verbose: &Verbosity) { + env_logger::builder() + .filter_level(verbose.log_level_filter()) + .format_indent(None) + .format_module_path(false) + .format_target(false) + .format_timestamp(None) + .init(); +} diff --git a/src/util/mod.rs b/src/util/mod.rs new file mode 100644 index 0000000..1a53e4c --- /dev/null +++ b/src/util/mod.rs @@ -0,0 +1,5 @@ +mod logger; +mod reader; + +pub use logger::*; +pub use reader::*; diff --git a/src/util/reader.rs b/src/util/reader.rs new file mode 100644 index 0000000..832deb9 --- /dev/null +++ b/src/util/reader.rs @@ -0,0 +1,27 @@ +use std::{fs, io, path::Path}; + +pub fn read_file(path: &Path) -> io::Result { + log::trace!("Reading {}", path.display()); + + let content = fs::read_to_string(path); + + if let Err(err) = &content { + log::error!("Could not find {}", path.display()); + log::trace!("{:#?}", err); + } + + content +} + +pub fn write_file(path: &Path, contents: Vec) -> io::Result<()> { + log::trace!("Writing {}", path.display()); + + let result = fs::write(path, contents.join("\n")); + + if let Err(err) = &result { + log::error!("Could not write to {}", path.display()); + log::trace!("{:#?}", err); + } + + result +}