add beginnings of simple CLI

This commit is contained in:
Jacob Lifshay 2024-07-21 20:47:52 -07:00
parent 8080cc7b5c
commit 23a77368b3
Signed by: programmerjake
SSH key fingerprint: SHA256:B1iRVvUJkvd7upMIiMqn6OyxvD2SgJkAH3ZnUOj6z+c
4 changed files with 257 additions and 1 deletions

View file

@ -21,6 +21,8 @@ num-traits = { workspace = true }
fayalite-proc-macros = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
clap = { version = "4.5.9", features = ["derive"] }
eyre = "0.6.12"
[dev-dependencies]
trybuild = { workspace = true }
@ -32,4 +34,4 @@ fayalite-visit-gen = { workspace = true }
unstable-doc = []
[package.metadata.docs.rs]
features = ["unstable-doc"]
features = ["unstable-doc"]

116
crates/fayalite/src/cli.rs Normal file
View file

@ -0,0 +1,116 @@
use crate::{
bundle::{BundleType, BundleValue, DynBundle},
firrtl,
intern::Interned,
module::Module,
};
use clap::{Parser, Subcommand, ValueHint};
use std::{path::PathBuf, process::exit};
#[derive(Subcommand)]
enum CliCommand {
/// Generate FIRRTL
Firrtl {
/// the directory to put the generated FIRRTL and associated files in
#[arg(short, long, value_hint = ValueHint::DirPath)]
output: PathBuf,
/// the stem of the generated .fir file, e.g. to get foo.fir, pass --file-stem=foo
#[arg(long)]
file_stem: Option<String>,
},
}
/// a simple CLI
///
/// Use like:
///
/// ```no_run
/// # use fayalite::{hdl_module, cli::Cli};
/// # #[hdl_module]
/// # fn my_module() {}
/// fn main() {
/// Cli::parse().run(my_module());
/// }
/// ```
///
/// You can also use it with a larger [`clap`]-based CLI like so:
///
/// ```no_run
/// # use fayalite::{hdl_module};
/// # #[hdl_module]
/// # fn my_module() {}
///
/// #[derive(clap::Subcommand)]
/// pub enum Subcommand {
/// #[command(flatten)]
/// Fayalite(fayalite::cli::Cli),
/// MySpecialCommand {
/// #[arg]
/// foo: bool,
/// },
/// }
///
/// #[derive(clap::Parser)]
/// pub struct Cli {
/// #[command(subcommand)]
/// subcommand: Subcommand, // or just use fayalite::cli::Cli directly
/// }
/// fn main() {
/// match Cli::parse().subcommand {
/// Subcommand::Fayalite(v) => v.run(my_module()),
/// Subcommand::MySpecialCommand { foo } => println!("special: foo={foo}"),
/// }
/// }
/// ```
#[derive(Parser)]
// clear things that would be crate-specific
#[command(name = "Fayalite Simple CLI", about = None, long_about = None)]
pub struct Cli {
#[command(subcommand)]
subcommand: CliCommand,
}
impl clap::Subcommand for Cli {
fn augment_subcommands(cmd: clap::Command) -> clap::Command {
CliCommand::augment_subcommands(cmd)
}
fn augment_subcommands_for_update(cmd: clap::Command) -> clap::Command {
CliCommand::augment_subcommands_for_update(cmd)
}
fn has_subcommand(name: &str) -> bool {
CliCommand::has_subcommand(name)
}
}
impl Cli {
/// forwards to [`clap::Parser::parse()`] so you don't have to import [`clap::Parser`]
pub fn parse() -> Self {
clap::Parser::parse()
}
fn run_impl(self, top_module: Module<DynBundle>) -> ! {
match self.subcommand {
CliCommand::Firrtl { output, file_stem } => {
let result = firrtl::export(
firrtl::FileBackend {
dir_path: output,
top_fir_file_stem: file_stem,
},
&top_module,
);
if let Err(e) = result {
eprintln!("Error: {:?}", eyre::Report::new(e));
exit(1);
}
}
}
exit(0)
}
pub fn run<T: BundleValue>(self, top_module: Interned<Module<T>>) -> !
where
T::Type: BundleType<Value = T>,
{
self.run_impl(top_module.canonical())
}
}

View file

@ -27,6 +27,7 @@ pub mod _docs;
pub mod annotations;
pub mod array;
pub mod bundle;
pub mod cli;
pub mod clock;
pub mod enum_;
pub mod expr;