Skip to content

Commit 9062765

Browse files
authored
Merge pull request #596 from os-checker/subcommand/pretty-print
feat: add pretty-print subcommand
2 parents 4fd5cf6 + 7a0f7ea commit 9062765

File tree

5 files changed

+118
-5
lines changed

5 files changed

+118
-5
lines changed

charon/src/bin/charon-driver/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ fn main() {
9090
use clap::Parser;
9191
let mut charon_args = compiler_args.split_off(i);
9292
charon_args[0] = origin_args[0].clone(); // Replace `--` with the name of the binary
93-
options::CliOpts::parse_from(charon_args)
93+
options::OldCliOpts::parse_from(charon_args).opts
9494
} else {
9595
Default::default()
9696
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use charon_lib::options::CliOpts;
2+
use clap::{Args, Parser, Subcommand};
3+
use std::path::PathBuf;
4+
5+
#[derive(Debug, Parser)]
6+
#[clap(name = "Charon")]
7+
pub struct Cli {
8+
// Makes CliOpts parsable.
9+
// This should be removed once subcommands are fully implemented.
10+
#[command(flatten)]
11+
pub opts: CliOpts,
12+
13+
#[command(subcommand)]
14+
pub command: Option<Charon>,
15+
}
16+
17+
#[derive(Debug, Subcommand)]
18+
pub enum Charon {
19+
PrettyPrint(PrettyPrintArgs),
20+
}
21+
22+
/// Read a llbc or ullbc file and pretty print it.
23+
#[derive(Args, Debug)]
24+
pub struct PrettyPrintArgs {
25+
/// Single file path to llbc or ullbc
26+
pub file: PathBuf,
27+
}

charon/src/bin/charon/main.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
use anyhow::bail;
3737
use clap::Parser;
38-
use options::{CliOpts, CHARON_ARGS};
38+
use options::CHARON_ARGS;
3939
use serde::Deserialize;
4040
use std::env;
4141
use std::ffi::OsStr;
@@ -47,6 +47,8 @@ use charon_lib::logger;
4747
use charon_lib::options;
4848
use charon_lib::trace;
4949

50+
/// Rename this module once subcommand migration finishes.
51+
mod cli_rework;
5052
mod toml_config;
5153

5254
// Store the toolchain details directly in the binary.
@@ -158,8 +160,21 @@ pub fn main() -> anyhow::Result<()> {
158160
// Initialize the logger
159161
logger::initialize_logger();
160162

163+
let cli = cli_rework::Cli::parse();
164+
165+
match cli.command {
166+
Some(cli_rework::Charon::PrettyPrint(pretty_print)) => {
167+
let krate = charon_lib::deserialize_llbc(&pretty_print.file)?;
168+
println!("{krate}");
169+
return Ok(());
170+
}
171+
_ => (),
172+
}
173+
174+
// ******* Old cli args parsing *******
175+
161176
// Parse the command-line
162-
let mut options = CliOpts::parse();
177+
let mut options = cli.opts;
163178
trace!("Arguments: {:?}", std::env::args());
164179
options.validate();
165180

charon/src/options.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
//! The options that control charon behavior.
2-
use clap::Parser;
32
use indoc::indoc;
43
use serde::{Deserialize, Serialize};
54
use std::path::PathBuf;
@@ -10,6 +9,15 @@ use crate::{ast::*, errors::ErrorCtx, name_matcher::NamePattern, raise_error, re
109
/// when calling charon-driver from cargo-charon.
1110
pub const CHARON_ARGS: &str = "CHARON_ARGS";
1211

12+
// Makes CliOpts parsable. This should be removed once subcommands are fully implemented.
13+
#[derive(Debug, clap::Parser)]
14+
#[clap(name = "Charon")]
15+
#[charon::rename("cli_options")]
16+
pub struct OldCliOpts {
17+
#[command(flatten)]
18+
pub opts: CliOpts,
19+
}
20+
1321
// This structure is used to store the command-line instructions.
1422
// We automatically derive a command-line parser based on this structure.
1523
// Note that the doc comments are used to generate the help message when using
@@ -18,7 +26,7 @@ pub const CHARON_ARGS: &str = "CHARON_ARGS";
1826
// Note that because we need to transmit the options to the charon driver,
1927
// we store them in a file before calling this driver (hence the `Serialize`,
2028
// `Deserialize` options).
21-
#[derive(Debug, Default, Clone, Parser, Serialize, Deserialize)]
29+
#[derive(Debug, Default, Clone, clap::Args, Serialize, Deserialize)]
2230
#[clap(name = "Charon")]
2331
#[charon::rename("cli_options")]
2432
pub struct CliOpts {

charon/tests/cli.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
use anyhow::{ensure, Context, Result};
2+
use assert_cmd::prelude::CommandCargoExt;
3+
use itertools::Itertools;
4+
use std::process::Command;
5+
6+
fn charon<T>(args: &[&str], f: impl FnOnce(String) -> Result<T>) -> Result<T> {
7+
let cmd_str = || {
8+
std::iter::once("charon")
9+
.chain(args.iter().copied())
10+
.join(" ")
11+
};
12+
13+
let mut cmd = Command::cargo_bin("charon")?;
14+
let output = cmd.args(args).output()?;
15+
let stdout = String::from_utf8(output.stdout).with_context(|| {
16+
format!(
17+
"`{}`:\nthe content of stdout is not UTF8 encoded.",
18+
cmd_str()
19+
)
20+
})?;
21+
let stderr = String::from_utf8(output.stderr).with_context(|| {
22+
format!(
23+
"`{}`:\nthe content of stderr is not UTF8 encoded.",
24+
cmd_str()
25+
)
26+
})?;
27+
28+
let status = output.status;
29+
ensure!(
30+
status.success(),
31+
"Error when executing `{}`:\nstderr={stderr:?}\nstdout={stdout:?}",
32+
cmd_str()
33+
);
34+
35+
f(stdout)
36+
}
37+
38+
#[test]
39+
fn charon_pretty_print() -> Result<()> {
40+
// charon --rustc-flag=--crate-type=rlib --no-cargo --input tests/ui/arrays.rs
41+
charon(
42+
&[
43+
"--rustc-flag=--crate-type=rlib",
44+
"--no-cargo",
45+
"--input",
46+
"tests/ui/arrays.rs",
47+
],
48+
|_| {
49+
// arrays.llbc is generated
50+
let llbc = "arrays.llbc";
51+
ensure!(std::fs::exists(llbc)?, "{llbc} doesn't exist!");
52+
53+
charon(&["pretty-print", llbc], |stdout| {
54+
let search = "pub fn arrays::";
55+
ensure!(
56+
stdout.contains(search),
57+
"Output of pretty-printing {llbc} is:\n{stdout:?}\nIt doesn't contain {search:?}."
58+
);
59+
Ok(())
60+
})
61+
},
62+
)
63+
}

0 commit comments

Comments
 (0)