diff --git a/Cargo.lock b/Cargo.lock index 96ab6106e0f..1612acddce9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,8 +15,8 @@ dependencies = [ "serde-generate", "serde-reflection", "serde_json", - "strum 0.24.1", - "strum_macros 0.24.3", + "strum", + "strum_macros", "thiserror", ] @@ -350,12 +350,6 @@ dependencies = [ "rand", ] -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "arrayvec" version = "0.7.4" @@ -977,7 +971,7 @@ version = "0.91.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98b022ed2a5913a38839dfbafe6cf135342661293b08049843362df4301261dc" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "bumpalo", "cranelift-bforest", "cranelift-codegen-meta", @@ -1133,32 +1127,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "crossterm" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a84cda67535339806297f1b331d6dd6320470d2a0fe65381e79ee9e156dd3d13" -dependencies = [ - "bitflags 1.3.2", - "crossterm_winapi", - "libc", - "mio", - "parking_lot", - "serde", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - [[package]] name = "crypto-bigint" version = "0.4.9" @@ -2382,7 +2350,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.48.0", ] @@ -2516,7 +2483,6 @@ dependencies = [ "easy-repl", "nargo", "noirc_printable_type", - "reedline-repl-rs", "thiserror", ] @@ -2575,8 +2541,8 @@ dependencies = [ "num-traits", "serde", "serde_json", - "strum 0.24.1", - "strum_macros 0.24.3", + "strum", + "strum_macros", "thiserror", "toml", ] @@ -2658,8 +2624,8 @@ dependencies = [ "serde_json", "small-ord-set", "smol_str", - "strum 0.24.1", - "strum_macros 0.24.3", + "strum", + "strum_macros", "thiserror", ] @@ -2681,15 +2647,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" -[[package]] -name = "nu-ansi-term" -version = "0.49.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c073d3c1930d0751774acf49e66653acecb416c3a54c6ec095a9b11caddb5a68" -dependencies = [ - "windows-sys 0.48.0", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -2707,7 +2664,7 @@ version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" dependencies = [ - "arrayvec 0.7.4", + "arrayvec", "itoa", ] @@ -3216,41 +3173,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "reedline" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2fde955d11817fdcb79d703932fb6b473192cb36b6a92ba21f7f4ac0513374e" -dependencies = [ - "chrono", - "crossterm", - "fd-lock", - "itertools", - "nu-ansi-term", - "serde", - "strip-ansi-escapes", - "strum 0.25.0", - "strum_macros 0.25.2", - "thiserror", - "unicode-segmentation", - "unicode-width", -] - -[[package]] -name = "reedline-repl-rs" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda59601d3b0c3ed9de96d342ca40f95cca2409e8497249139a6c723b211ee33" -dependencies = [ - "clap", - "crossterm", - "nu-ansi-term", - "reedline", - "regex", - "winapi-util", - "yansi", -] - [[package]] name = "regalloc2" version = "0.5.1" @@ -3881,36 +3803,6 @@ dependencies = [ "dirs", ] -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - [[package]] name = "signature" version = "1.6.4" @@ -4038,15 +3930,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" -[[package]] -name = "strip-ansi-escapes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" -dependencies = [ - "vte", -] - [[package]] name = "strsim" version = "0.10.0" @@ -4059,12 +3942,6 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -[[package]] -name = "strum" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" - [[package]] name = "strum_macros" version = "0.24.3" @@ -4078,19 +3955,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "strum_macros" -version = "0.25.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.26", -] - [[package]] name = "subtle" version = "2.5.0" @@ -4602,27 +4466,6 @@ version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" -[[package]] -name = "vte" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" -dependencies = [ - "arrayvec 0.5.2", - "utf8parse", - "vte_generate_state_changes", -] - -[[package]] -name = "vte_generate_state_changes" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" -dependencies = [ - "proc-macro2", - "quote", -] - [[package]] name = "wait-timeout" version = "0.2.0" @@ -5168,12 +5011,6 @@ dependencies = [ "libc", ] -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - [[package]] name = "zeroize" version = "1.6.0" diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index f488831609c..5b8248345a0 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -13,5 +13,4 @@ acvm.workspace = true nargo.workspace = true noirc_printable_type.workspace = true thiserror.workspace = true -reedline-repl-rs = "1.0.7" easy-repl = "0.2.1" \ No newline at end of file diff --git a/tooling/debugger/src/lib.rs b/tooling/debugger/src/lib.rs index c8a9430453f..5534861a463 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -11,13 +11,8 @@ use nargo::ops::ForeignCallExecutor; use thiserror::Error; -use easy_repl::{Repl, CommandStatus, command}; - -// use reedline_repl_rs::clap::{ -// ArgMatches as ReplArgMatches, -// Command as ReplCommand, -// }; -// use reedline_repl_rs::Repl; +use easy_repl::{Repl, CommandStatus, command, Critical}; +use std::cell::RefCell; enum SolveResult { Done, @@ -35,7 +30,7 @@ enum DebuggingError { ForeignCallError(#[from] noirc_printable_type::ForeignCallError), } -struct ReplContext<'backend, B: BlackBoxFunctionSolver> { +struct DebugContext<'backend, B: BlackBoxFunctionSolver> { acvm: Option>, debug_artifact: DebugArtifact, foreign_call_executor: ForeignCallExecutor, @@ -43,81 +38,85 @@ struct ReplContext<'backend, B: BlackBoxFunctionSolver> { show_output: bool, } -fn step_opcode<'backend, B: BlackBoxFunctionSolver>(acvm: &mut ACVM<'backend, B>, circuit: Circuit, foreign_call_executor: &mut ForeignCallExecutor, show_output: bool) -> Result { - // Assert messages are not a map due to https://github.com/noir-lang/acvm/issues/522 - let assert_messages = circuit.assert_messages; - let get_assert_message = |opcode_location| { - assert_messages - .iter() - .find(|(loc, _)| loc == opcode_location) - .map(|(_, message)| message.clone()) - }; - - // let acvm = self.acvm.as_mut().unwrap(); - let solver_status = acvm.solve_opcode(); - - match solver_status { - ACVMStatus::Solved => Ok(SolveResult::Done), - ACVMStatus::InProgress => Ok(SolveResult::Ok), - ACVMStatus::Failure(error) => { - let call_stack = match &error { - OpcodeResolutionError::UnsatisfiedConstrain { - opcode_location: ErrorLocation::Resolved(opcode_location), - } => Some(vec![*opcode_location]), - OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } => { - Some(call_stack.clone()) - } - _ => None, - }; - - Err(DebuggingError::ExecutionError(match call_stack { - Some(call_stack) => { - if let Some(assert_message) = get_assert_message( - call_stack.last().expect("Call stacks should not be empty"), - ) { - ExecutionError::AssertionFailed(assert_message, call_stack) - } else { - ExecutionError::SolvingError(error) +impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { + fn step_opcode(&mut self) -> Result { + // Assert messages are not a map due to https://github.com/noir-lang/acvm/issues/522 + let assert_messages = &self.circuit.assert_messages; + let get_assert_message = |opcode_location| { + assert_messages + .iter() + .find(|(loc, _)| loc == opcode_location) + .map(|(_, message)| message.clone()) + }; + + let solver_status = self.acvm.as_mut().unwrap().solve_opcode(); + + match solver_status { + ACVMStatus::Solved => Ok(SolveResult::Done), + ACVMStatus::InProgress => Ok(SolveResult::Ok), + ACVMStatus::Failure(error) => { + let call_stack = match &error { + OpcodeResolutionError::UnsatisfiedConstrain { + opcode_location: ErrorLocation::Resolved(opcode_location), + } => Some(vec![*opcode_location]), + OpcodeResolutionError::BrilligFunctionFailed { call_stack, .. } => { + Some(call_stack.clone()) } - } - None => ExecutionError::SolvingError(error), - })) - } - ACVMStatus::RequiresForeignCall(foreign_call) => { - let foreign_call_result = foreign_call_executor.execute(&foreign_call, show_output)?; - acvm.resolve_pending_foreign_call(foreign_call_result); - Ok(SolveResult::Ok) + _ => None, + }; + + Err(DebuggingError::ExecutionError(match call_stack { + Some(call_stack) => { + if let Some(assert_message) = get_assert_message( + call_stack.last().expect("Call stacks should not be empty"), + ) { + ExecutionError::AssertionFailed(assert_message, call_stack) + } else { + ExecutionError::SolvingError(error) + } + } + None => ExecutionError::SolvingError(error), + })) + } + ACVMStatus::RequiresForeignCall(foreign_call) => { + let foreign_call_result = self.foreign_call_executor.execute(&foreign_call, self.show_output)?; + self.acvm.as_mut().unwrap().resolve_pending_foreign_call(foreign_call_result); + Ok(SolveResult::Ok) + } } } -} - -fn show_current_vm_status<'backend, B: BlackBoxFunctionSolver>(acvm: &mut ACVM<'backend, B>, debug_artifact: DebugArtifact) { - let ip = acvm.instruction_pointer(); - println!("Stopped at opcode {}: {}", ip, acvm.opcodes()[ip]); - show_source_code_location(&OpcodeLocation::Acir(ip), debug_artifact); -} -fn show_source_code_location(location: &OpcodeLocation, debug_artifact: DebugArtifact) { - let locations = debug_artifact.debug_symbols[0].opcode_location(&location); - match locations { - Some(locations) => { - for loc in locations { - let file = &debug_artifact.file_map[&loc.file]; - let source = &file.source.as_str(); - let start = loc.span.start() as usize; - let end = loc.span.end() as usize; - println!("At {}:{start}-{end}", file.path.as_path().display()); - println!("\n{}\n", &source[start..end]); - } - }, - None => {} + fn show_current_vm_status(&self) { + let ip = self.acvm.as_ref().unwrap().instruction_pointer(); + println!("Stopped at opcode {}: {}", ip, self.acvm.as_ref().unwrap().opcodes()[ip]); + Self::show_source_code_location(&OpcodeLocation::Acir(ip), &self.debug_artifact); } -} + fn show_source_code_location(location: &OpcodeLocation, debug_artifact: &DebugArtifact) { + let locations = debug_artifact.debug_symbols[0].opcode_location(&location); + match locations { + Some(locations) => { + for loc in locations { + let file = &debug_artifact.file_map[&loc.file]; + let source = &file.source.as_str(); + let start = loc.span.start() as usize; + let end = loc.span.end() as usize; + println!("At {}:{start}-{end}", file.path.as_path().display()); + println!("\n{}\n", &source[start..end]); + } + }, + None => {} + } + } -impl From for DebuggingError { - fn from(_e: reedline_repl_rs::Error) -> Self { - DebuggingError::ExecutionError(ExecutionError::Halted) + fn cont(&mut self) -> Result { + loop { + match self.step_opcode()? { + SolveResult::Done => break, + SolveResult::Ok => {}, + } + } + Ok(SolveResult::Done) } } @@ -130,6 +129,13 @@ impl From for DebuggingError { } } +fn map_command_status(result: SolveResult) -> CommandStatus { + match result { + SolveResult::Ok => CommandStatus::Done, + SolveResult::Done => CommandStatus::Quit + } +} + pub fn debug_circuit( blackbox_solver: &B, circuit: Circuit, @@ -138,78 +144,56 @@ pub fn debug_circuit( show_output: bool, ) -> Result { let opcodes = circuit.opcodes.clone(); - let mut acvm = ACVM::new(blackbox_solver, opcodes, initial_witness); - let mut foreign_call_executor = ForeignCallExecutor::default(); + + let context = RefCell::new(DebugContext { + acvm: Some(ACVM::new(blackbox_solver, opcodes, initial_witness)), + foreign_call_executor: ForeignCallExecutor::default(), + circuit, + debug_artifact, + show_output, + }); + let ref_step = &context; + let ref_cont = &context; + + let solved = RefCell::new(false); + + context.borrow().show_current_vm_status(); + + let handle_result = |result| { + solved.replace(match result { + SolveResult::Done => true, + _ => false, + }); + Ok(map_command_status(result)) + }; let mut repl = Repl::builder() .add("s", command! { "step to the next opcode", () => || { - step_command(&mut acvm, debug_artifact, circuit, &mut foreign_call_executor, show_output); - Ok(CommandStatus::Done) - } + let result = ref_step.borrow_mut().step_opcode().into_critical()?; + ref_step.borrow().show_current_vm_status(); + handle_result(result) + } }) .add("c", command! { "continue execution until the end of the program", () => || { - continue_command(&mut acvm, debug_artifact, circuit, &mut foreign_call_executor, show_output); - Ok(CommandStatus::Quit) + println!("(Continuing execution...)"); + let result = ref_cont.borrow_mut().cont().into_critical()?; + handle_result(result) } }) - .add("q", command! { - "quit the debugger", - () => || { - quit_command(&mut acvm, debug_artifact); - Ok(CommandStatus::Quit) - } - }).build().expect("Failed to initialize debugger repl"); - repl.run().expect("Critical debugger error"); - - // // let mut repl = Repl::new(repl_context.clone()) - // // .with_name("debug") - // // .with_version(env!["CARGO_PKG_VERSION"]) - // // .with_command( - // // ReplCommand::new("s") - // // .about("step to the next opcode"), - // // step_command, - // // ) - // // .with_command( - // // ReplCommand::new("c") - // // .about("continue execution until the end of the program"), - // // continue_command, - // // ) - // // .with_command( - // // ReplCommand::new("q") - // // .about("quit the debugger"), - // // quit_command, - // // ); - // // repl.run().unwrap(); - - let solved_witness = acvm.finalize(); - Ok(solved_witness) -} + .build() + .expect("Failed to initialize debugger repl"); -fn step_command<'backend, B: BlackBoxFunctionSolver>(acvm: &mut ACVM<'backend, B>, debug_artifact: DebugArtifact, circuit: Circuit, foreign_call_executor: &mut ForeignCallExecutor, show_output: bool) -> Result, DebuggingError> { - show_current_vm_status(acvm, debug_artifact); - match step_opcode(acvm, circuit, foreign_call_executor, show_output)? { - SolveResult::Done => Ok(Some("Done".to_string())), - SolveResult::Ok => Ok(Some("Ok".to_string())), - } -} + repl.run().expect("Debugger error"); -fn continue_command<'backend, B: BlackBoxFunctionSolver>(acvm: &mut ACVM<'backend, B>, debug_artifact: DebugArtifact, circuit: Circuit, foreign_call_executor: &mut ForeignCallExecutor, show_output: bool) -> Result, DebuggingError> { - show_current_vm_status(acvm, debug_artifact); - println!("(Continuing execution...)"); - loop { - match step_opcode(acvm, circuit, foreign_call_executor, show_output)? { - SolveResult::Done => break, - SolveResult::Ok => {}, - } + let acvm = context.borrow_mut().acvm.take().unwrap(); + if *solved.borrow() { + let solved_witness = acvm.finalize(); + Ok(solved_witness) + } else { + Err(NargoError::ExecutionError(ExecutionError::Halted)) } - Ok(Some("Ok".to_string())) -} - -fn quit_command<'backend, B: BlackBoxFunctionSolver>(acvm: &mut ACVM<'backend, B>, debug_artifact: DebugArtifact) -> Result, DebuggingError> { - show_current_vm_status(acvm, debug_artifact); - Err(DebuggingError::ExecutionError(ExecutionError::Halted)) }