diff --git a/crates/llvm-context/src/debug_config/ir_type.rs b/crates/llvm-context/src/debug_config/ir_type.rs index e479392d..2ea88f96 100644 --- a/crates/llvm-context/src/debug_config/ir_type.rs +++ b/crates/llvm-context/src/debug_config/ir_type.rs @@ -15,6 +15,9 @@ pub enum IRType { LLVM, /// Whether to dump the assembly code. Assembly, + /// Whether to jump JSON + #[cfg(debug_assertions)] + JSON, } impl IRType { @@ -26,6 +29,8 @@ impl IRType { Self::EVMLA => revive_common::EXTENSION_EVMLA, Self::LLVM => revive_common::EXTENSION_LLVM_SOURCE, Self::Assembly => revive_common::EXTENSION_POLKAVM_ASSEMBLY, + #[cfg(debug_assertions)] + Self::JSON => revive_common::EXTENSION_JSON, } } } diff --git a/crates/llvm-context/src/debug_config/mod.rs b/crates/llvm-context/src/debug_config/mod.rs index bcd6b2c1..49c31ac0 100644 --- a/crates/llvm-context/src/debug_config/mod.rs +++ b/crates/llvm-context/src/debug_config/mod.rs @@ -94,6 +94,22 @@ impl DebugConfig { Ok(()) } + /// Dumps the stage output as a json file suitable for use with --recursive-process + #[cfg(debug_assertions)] + pub fn dump_stage_output( + &self, + contract_path: &str, + contract_suffix: Option<&str>, + stage_json: &Vec, + ) -> anyhow::Result<()> { + let mut file_path = self.output_directory.to_owned(); + let full_file_name = Self::full_file_name(contract_path, contract_suffix, IRType::JSON); + file_path.push(full_file_name); + std::fs::write(file_path, stage_json)?; + + Ok(()) + } + /// Creates a full file name, given the contract full path, suffix, and extension. fn full_file_name(contract_path: &str, suffix: Option<&str>, ir_type: IRType) -> String { let mut full_file_name = contract_path.replace('/', "_").replace(':', "."); diff --git a/crates/solidity/src/process/input.rs b/crates/solidity/src/process/input.rs index 94923185..be105358 100644 --- a/crates/solidity/src/process/input.rs +++ b/crates/solidity/src/process/input.rs @@ -4,6 +4,8 @@ use serde::Deserialize; use serde::Serialize; +#[cfg(debug_assertions)] +use crate::project::contract::ir::IR; use crate::project::contract::Contract; use crate::project::Project; diff --git a/crates/solidity/src/process/mod.rs b/crates/solidity/src/process/mod.rs index b4c461ef..9752cb90 100644 --- a/crates/solidity/src/process/mod.rs +++ b/crates/solidity/src/process/mod.rs @@ -17,13 +17,32 @@ use self::output::Output; pub static EXECUTABLE: OnceCell = OnceCell::new(); /// Read input from `stdin`, compile a contract, and write the output to `stdout`. -pub fn run() -> anyhow::Result<()> { +pub fn run(input_file: Option<&mut std::fs::File>) -> anyhow::Result<()> { let mut stdin = std::io::stdin(); let mut stdout = std::io::stdout(); let mut stderr = std::io::stderr(); let mut buffer = Vec::with_capacity(16384); - stdin.read_to_end(&mut buffer).expect("Stdin reading error"); + match input_file { + Some(ins) => { + let _ = ins + .read_to_end(&mut buffer) + .map_err(|error| -> anyhow::Result<()> { + anyhow::bail!("Failed to read recursive process input file: {:?}", error); + }); + () + } + None => { + let _ = stdin + .read_to_end(&mut buffer) + .map_err(|error| -> anyhow::Result<()> { + anyhow::bail!( + "Failed to read recursive process input from stdin: {:?}", + error + ); + }); + } + } let input: Input = revive_common::deserialize_from_slice(buffer.as_slice())?; if input.enable_test_encoding { @@ -74,6 +93,19 @@ pub fn call(input: Input) -> anyhow::Result { anyhow::anyhow!("{:?} subprocess spawning error: {:?}", executable, error) })?; + #[cfg(debug_assertions)] + if let Some(dbg_config) = &input.debug_config { + let _ = dbg_config + .dump_stage_output(&input.contract.path, Some("stage"), &input_json) + .map_err(|error| -> anyhow::Result { + anyhow::bail!( + "{:?} failed to log the recursive process output: {:?}", + executable, + error, + ) + }); + } + process .stdin .as_ref() diff --git a/crates/solidity/src/resolc/arguments.rs b/crates/solidity/src/resolc/arguments.rs index aba46a14..be6938f8 100644 --- a/crates/solidity/src/resolc/arguments.rs +++ b/crates/solidity/src/resolc/arguments.rs @@ -164,6 +164,12 @@ pub struct Arguments { /// Only for usage from within the compiler. #[structopt(long = "recursive-process")] pub recursive_process: bool, + + /// Specify the input file to use instead of stdin when --recursive-process is given. + /// This is only intended for use when developing the compiler. + #[cfg(debug_assertions)] + #[structopt(long = "recursive-process-input")] + pub recursive_process_input: Option, } impl Default for Arguments { @@ -185,6 +191,20 @@ impl Arguments { anyhow::bail!("No other options are allowed while getting the compiler version."); } + #[cfg(debug_assertions)] + if self.recursive_process_input != None && !self.recursive_process { + anyhow::bail!("--process-input can be only used when --recursive-process is given"); + } + + #[cfg(debug_assertions)] + if self.recursive_process + && ((self.recursive_process_input == None && std::env::args().count() > 2) + || (self.recursive_process_input != None && std::env::args().count() > 4)) + { + anyhow::bail!("No other options are allowed in recursive mode."); + } + + #[cfg(not(debug_assertions))] if self.recursive_process && std::env::args().count() > 2 { anyhow::bail!("No other options are allowed in recursive mode."); } diff --git a/crates/solidity/src/resolc/main.rs b/crates/solidity/src/resolc/main.rs index cc444b38..30641df2 100644 --- a/crates/solidity/src/resolc/main.rs +++ b/crates/solidity/src/resolc/main.rs @@ -47,7 +47,13 @@ fn main_inner() -> anyhow::Result<()> { revive_llvm_context::initialize_target(revive_llvm_context::Target::PVM); // TODO: pass from CLI if arguments.recursive_process { - return revive_solidity::run_process(); + #[cfg(debug_assertions)] + if let Some(fname) = arguments.recursive_process_input { + let mut infile = std::fs::File::open(fname)?; + return revive_solidity::run_process(Some(&mut infile)); + } + + return revive_solidity::run_process(None); } let debug_config = match arguments.debug_output_directory {