From 281c696da61c64b42b9525b8756ffc195f70d775 Mon Sep 17 00:00:00 2001 From: Martin Verzilli Date: Fri, 13 Oct 2023 16:32:06 +0200 Subject: [PATCH] feat: Add experimental REPL-based debugger (#2995) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gustavo Giráldez Co-authored-by: synthia Co-authored-by: kevaundray Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- Cargo.lock | 200 ++++++++++++++++++++++++- Cargo.toml | 2 + tooling/debugger/Cargo.toml | 16 ++ tooling/debugger/src/lib.rs | 178 ++++++++++++++++++++++ tooling/nargo/src/ops/foreign_calls.rs | 4 +- tooling/nargo/src/ops/mod.rs | 1 + tooling/nargo_cli/Cargo.toml | 1 + tooling/nargo_cli/src/cli/debug_cmd.rs | 129 ++++++++++++++++ tooling/nargo_cli/src/cli/mod.rs | 4 + 9 files changed, 531 insertions(+), 4 deletions(-) create mode 100644 tooling/debugger/Cargo.toml create mode 100644 tooling/debugger/src/lib.rs create mode 100644 tooling/nargo_cli/src/cli/debug_cmd.rs diff --git a/Cargo.lock b/Cargo.lock index c0c3079f36b..86df9e1a13b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -819,6 +819,17 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +[[package]] +name = "clipboard-win" +version = "4.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7191c27c2357d9b7ef96baac1773290d4ca63b24205b82a3fd8a0637afcf0362" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + [[package]] name = "codespan" version = "0.11.1" @@ -1340,6 +1351,21 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" +[[package]] +name = "easy-repl" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d0001ed25c451c57f8d6724d448a6546a5d78bbac77a63a22e32c735b7ea16" +dependencies = [ + "anyhow", + "rustyline", + "rustyline-derive", + "shell-words", + "textwrap 0.15.2", + "thiserror", + "trie-rs", +] + [[package]] name = "ecdsa" version = "0.14.8" @@ -1399,6 +1425,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "enum-iterator" version = "0.7.0" @@ -1467,6 +1499,16 @@ dependencies = [ "libc", ] +[[package]] +name = "error-code" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21" +dependencies = [ + "libc", + "str-buf", +] + [[package]] name = "eyre" version = "0.6.8" @@ -1492,6 +1534,17 @@ dependencies = [ "instant", ] +[[package]] +name = "fd-lock" +version = "3.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef033ed5e9bad94e55838ca0ca906db0e043f517adda0c8b79c7a8c66c93c1b5" +dependencies = [ + "cfg-if", + "rustix 0.38.4", + "windows-sys 0.48.0", +] + [[package]] name = "ff" version = "0.12.1" @@ -1502,6 +1555,15 @@ dependencies = [ "subtle", ] +[[package]] +name = "fid-rs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28658c0c3420305705adde833a0d2d614207507d013a5f25707553fb2ae2cd" +dependencies = [ + "rayon", +] + [[package]] name = "filetime" version = "0.2.22" @@ -2216,6 +2278,15 @@ version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +[[package]] +name = "louds-rs" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16a91fb20f74b6d9a758a0103a2884af525a2fa34fbfe19f4b3c5482a4a54e9" +dependencies = [ + "fid-rs", +] + [[package]] name = "lsp-types" version = "0.88.0" @@ -2266,6 +2337,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.8.0" @@ -2360,6 +2440,7 @@ dependencies = [ "nargo", "nargo_fmt", "nargo_toml", + "noir_debugger", "noir_lsp", "noirc_abi", "noirc_driver", @@ -2409,6 +2490,28 @@ dependencies = [ "url", ] +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" +dependencies = [ + "bitflags 1.3.2", + "cc", + "cfg-if", + "libc", + "memoffset 0.6.5", +] + [[package]] name = "nix" version = "0.26.2" @@ -2421,6 +2524,17 @@ dependencies = [ "static_assertions", ] +[[package]] +name = "noir_debugger" +version = "0.16.0" +dependencies = [ + "acvm", + "easy-repl", + "nargo", + "noirc_printable_type", + "thiserror", +] + [[package]] name = "noir_lsp" version = "0.16.0" @@ -2820,7 +2934,7 @@ dependencies = [ "inferno", "libc", "log", - "nix", + "nix 0.26.2", "once_cell", "parking_lot", "smallvec", @@ -3000,6 +3114,16 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "rand" version = "0.8.5" @@ -3409,6 +3533,40 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "rustyline" +version = "9.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7826789c0e25614b03e5a54a0717a86f9ff6e6e5247f92b369472869320039" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "clipboard-win", + "dirs-next", + "fd-lock", + "libc", + "log", + "memchr", + "nix 0.23.2", + "radix_trie", + "scopeguard", + "smallvec", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + +[[package]] +name = "rustyline-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb35a55ab810b5c0fe31606fe9b47d1354e4dc519bec0a102655f78ea2b38057" +dependencies = [ + "quote", + "syn 1.0.109", +] + [[package]] name = "ryu" version = "1.0.15" @@ -3548,7 +3706,7 @@ dependencies = [ "phf", "serde", "serde-reflection", - "textwrap", + "textwrap 0.13.4", ] [[package]] @@ -3686,6 +3844,12 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + [[package]] name = "shellexpand" version = "2.1.2" @@ -3830,6 +3994,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "str-buf" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" + [[package]] name = "str_stack" version = "0.1.0" @@ -3998,6 +4168,17 @@ dependencies = [ "unicode-width", ] +[[package]] +name = "textwrap" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" +dependencies = [ + "smawk", + "unicode-linebreak", + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.43" @@ -4247,6 +4428,15 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "trie-rs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5096c019d49566aff57593a06e401c7f588da84e9a575d0ed2ac0913f51928c0" +dependencies = [ + "louds-rs", +] + [[package]] name = "try-lock" version = "0.2.4" @@ -4277,6 +4467,12 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + [[package]] name = "unicode-normalization" version = "0.1.22" diff --git a/Cargo.toml b/Cargo.toml index e57c53afcc4..b0bb24ddb03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ members = [ "tooling/backend_interface", "tooling/bb_abstraction_leaks", "tooling/lsp", + "tooling/debugger", "tooling/nargo", "tooling/nargo_fmt", "tooling/nargo_cli", @@ -54,6 +55,7 @@ nargo_fmt = { path = "tooling/nargo_fmt" } nargo_cli = { path = "tooling/nargo_cli" } nargo_toml = { path = "tooling/nargo_toml" } noir_lsp = { path = "tooling/lsp" } +noir_debugger = { path = "tooling/debugger" } noirc_abi = { path = "tooling/noirc_abi" } bb_abstraction_leaks = { path = "tooling/bb_abstraction_leaks" } noirc_driver = { path = "compiler/noirc_driver" } diff --git a/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml new file mode 100644 index 00000000000..5b8248345a0 --- /dev/null +++ b/tooling/debugger/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "noir_debugger" +description = "Debugger for Noir" +version.workspace = true +authors.workspace = true +edition.workspace = true +license.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +acvm.workspace = true +nargo.workspace = true +noirc_printable_type.workspace = true +thiserror.workspace = true +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 new file mode 100644 index 00000000000..ed9fe08ca97 --- /dev/null +++ b/tooling/debugger/src/lib.rs @@ -0,0 +1,178 @@ +use acvm::acir::circuit::OpcodeLocation; +use acvm::pwg::{ACVMStatus, ErrorLocation, OpcodeResolutionError, ACVM}; +use acvm::BlackBoxFunctionSolver; +use acvm::{acir::circuit::Circuit, acir::native_types::WitnessMap}; + +use nargo::artifacts::debug::DebugArtifact; +use nargo::errors::ExecutionError; +use nargo::NargoError; + +use nargo::ops::ForeignCallExecutor; + +use easy_repl::{command, CommandStatus, Critical, Repl}; +use std::cell::{Cell, RefCell}; + +enum SolveResult { + Done, + Ok, +} + +struct DebugContext<'backend, B: BlackBoxFunctionSolver> { + acvm: Option>, + debug_artifact: DebugArtifact, + foreign_call_executor: ForeignCallExecutor, + circuit: Circuit, + show_output: bool, +} + +impl<'backend, B: BlackBoxFunctionSolver> DebugContext<'backend, B> { + fn step_opcode(&mut self) -> Result { + 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, + }; + + Err(NargoError::ExecutionError(match call_stack { + Some(call_stack) => { + if let Some(assert_message) = self.circuit.get_assert_message( + *call_stack.last().expect("Call stacks should not be empty"), + ) { + ExecutionError::AssertionFailed(assert_message.to_owned(), 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(&self) { + let acvm = self.acvm.as_ref().unwrap(); + let ip = acvm.instruction_pointer(); + let opcodes = acvm.opcodes(); + if ip >= opcodes.len() { + println!("Finished execution"); + } else { + println!("Stopped at opcode {}: {}", ip, 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); + if let Some(locations) = 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 {}.nr:{start}-{end}", file.path.as_path().display()); + println!("\n{}\n", &source[start..end]); + } + } + } + + fn cont(&mut self) -> Result { + loop { + match self.step_opcode()? { + SolveResult::Done => break, + SolveResult::Ok => {} + } + } + Ok(SolveResult::Done) + } + + fn finalize(&mut self) -> WitnessMap { + self.acvm.take().unwrap().finalize() + } +} + +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, + debug_artifact: DebugArtifact, + initial_witness: WitnessMap, + show_output: bool, +) -> Result, NargoError> { + let opcodes = circuit.opcodes.clone(); + + 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 = Cell::new(false); + + context.borrow().show_current_vm_status(); + + let handle_result = |result| { + solved.set(matches!(result, SolveResult::Done)); + Ok(map_command_status(result)) + }; + + let mut repl = Repl::builder() + .add( + "s", + command! { + "step to the next opcode", + () => || { + 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", + () => || { + println!("(Continuing execution...)"); + let result = ref_cont.borrow_mut().cont().into_critical()?; + handle_result(result) + } + }, + ) + .build() + .expect("Failed to initialize debugger repl"); + + repl.run().expect("Debugger error"); + + if solved.get() { + let solved_witness = context.borrow_mut().finalize(); + Ok(Some(solved_witness)) + } else { + Ok(None) + } +} diff --git a/tooling/nargo/src/ops/foreign_calls.rs b/tooling/nargo/src/ops/foreign_calls.rs index e44ab1732c9..4d20a0bd4f0 100644 --- a/tooling/nargo/src/ops/foreign_calls.rs +++ b/tooling/nargo/src/ops/foreign_calls.rs @@ -89,7 +89,7 @@ impl MockedCall { } #[derive(Debug, Default)] -pub(crate) struct ForeignCallExecutor { +pub struct ForeignCallExecutor { /// Mocks have unique ids used to identify them in Noir, allowing to update or remove them. last_mock_id: usize, /// The registered mocks @@ -97,7 +97,7 @@ pub(crate) struct ForeignCallExecutor { } impl ForeignCallExecutor { - pub(crate) fn execute( + pub fn execute( &mut self, foreign_call: &ForeignCallWaitInfo, show_output: bool, diff --git a/tooling/nargo/src/ops/mod.rs b/tooling/nargo/src/ops/mod.rs index f789455577c..491320482cf 100644 --- a/tooling/nargo/src/ops/mod.rs +++ b/tooling/nargo/src/ops/mod.rs @@ -1,4 +1,5 @@ pub use self::execute::execute_circuit; +pub use self::foreign_calls::ForeignCallExecutor; pub use self::optimize::{optimize_contract, optimize_program}; pub use self::test::{run_test, TestStatus}; diff --git a/tooling/nargo_cli/Cargo.toml b/tooling/nargo_cli/Cargo.toml index d90aa0ca2ab..cb824b41428 100644 --- a/tooling/nargo_cli/Cargo.toml +++ b/tooling/nargo_cli/Cargo.toml @@ -26,6 +26,7 @@ nargo.workspace = true nargo_fmt.workspace = true nargo_toml.workspace = true noir_lsp.workspace = true +noir_debugger.workspace = true noirc_driver.workspace = true noirc_frontend.workspace = true noirc_abi.workspace = true diff --git a/tooling/nargo_cli/src/cli/debug_cmd.rs b/tooling/nargo_cli/src/cli/debug_cmd.rs new file mode 100644 index 00000000000..5dcb2c7bdec --- /dev/null +++ b/tooling/nargo_cli/src/cli/debug_cmd.rs @@ -0,0 +1,129 @@ +use acvm::acir::native_types::WitnessMap; +use clap::Args; + +use nargo::artifacts::debug::DebugArtifact; +use nargo::constants::PROVER_INPUT_FILE; +use nargo::package::Package; +use nargo_toml::{get_package_manifest, resolve_workspace_from_toml, PackageSelection}; +use noirc_abi::input_parser::{Format, InputValue}; +use noirc_abi::InputMap; +use noirc_driver::{CompileOptions, CompiledProgram}; +use noirc_frontend::graph::CrateName; + +use super::compile_cmd::compile_bin_package; +use super::fs::{inputs::read_inputs_from_file, witness::save_witness_to_dir}; +use super::NargoConfig; +use crate::backends::Backend; +use crate::errors::CliError; + +/// Executes a circuit in debug mode +#[derive(Debug, Clone, Args)] +pub(crate) struct DebugCommand { + /// Write the execution witness to named file + witness_name: Option, + + /// The name of the toml file which contains the inputs for the prover + #[clap(long, short, default_value = PROVER_INPUT_FILE)] + prover_name: String, + + /// The name of the package to execute + #[clap(long)] + package: Option, + + #[clap(flatten)] + compile_options: CompileOptions, +} + +pub(crate) fn run( + backend: &Backend, + args: DebugCommand, + config: NargoConfig, +) -> Result<(), CliError> { + let toml_path = get_package_manifest(&config.program_dir)?; + let selection = args.package.map_or(PackageSelection::DefaultOrAll, PackageSelection::Selected); + let workspace = resolve_workspace_from_toml(&toml_path, selection)?; + let target_dir = &workspace.target_directory_path(); + let (np_language, opcode_support) = backend.get_backend_info()?; + + let Some(package) = workspace.into_iter().find(|p| p.is_binary()) else { + println!( + "No matching binary packages found in workspace. Only binary packages can be debugged." + ); + return Ok(()); + }; + + let compiled_program = compile_bin_package( + &workspace, + package, + &args.compile_options, + true, + np_language, + &|opcode| opcode_support.is_opcode_supported(opcode), + )?; + + println!("[{}] Starting debugger", package.name); + let (return_value, solved_witness) = + debug_program_and_decode(compiled_program, package, &args.prover_name)?; + + if let Some(solved_witness) = solved_witness { + println!("[{}] Circuit witness successfully solved", package.name); + + if let Some(return_value) = return_value { + println!("[{}] Circuit output: {return_value:?}", package.name); + } + + if let Some(witness_name) = &args.witness_name { + let witness_path = save_witness_to_dir(solved_witness, witness_name, target_dir)?; + + println!("[{}] Witness saved to {}", package.name, witness_path.display()); + } + } else { + println!("Debugger execution halted."); + } + + Ok(()) +} + +fn debug_program_and_decode( + program: CompiledProgram, + package: &Package, + prover_name: &str, +) -> Result<(Option, Option), CliError> { + // Parse the initial witness values from Prover.toml + let (inputs_map, _) = + read_inputs_from_file(&package.root_dir, prover_name, Format::Toml, &program.abi)?; + let solved_witness = debug_program(&program, &inputs_map)?; + let public_abi = program.abi.public_abi(); + + match solved_witness { + Some(witness) => { + let (_, return_value) = public_abi.decode(&witness)?; + Ok((return_value, Some(witness))) + } + None => Ok((None, None)), + } +} + +pub(crate) fn debug_program( + compiled_program: &CompiledProgram, + inputs_map: &InputMap, +) -> Result, CliError> { + #[allow(deprecated)] + let blackbox_solver = barretenberg_blackbox_solver::BarretenbergSolver::new(); + + let initial_witness = compiled_program.abi.encode(inputs_map, None)?; + + let debug_artifact = DebugArtifact { + debug_symbols: vec![compiled_program.debug.clone()], + file_map: compiled_program.file_map.clone(), + }; + + noir_debugger::debug_circuit( + &blackbox_solver, + compiled_program.circuit.clone(), + debug_artifact, + initial_witness, + true, + ) + .map_err(CliError::from) +} diff --git a/tooling/nargo_cli/src/cli/mod.rs b/tooling/nargo_cli/src/cli/mod.rs index 9e832317331..a0ef778e1a5 100644 --- a/tooling/nargo_cli/src/cli/mod.rs +++ b/tooling/nargo_cli/src/cli/mod.rs @@ -13,6 +13,7 @@ mod backend_cmd; mod check_cmd; mod codegen_verifier_cmd; mod compile_cmd; +mod debug_cmd; mod execute_cmd; mod fmt_cmd; mod info_cmd; @@ -61,6 +62,8 @@ enum NargoCommand { New(new_cmd::NewCommand), Init(init_cmd::InitCommand), Execute(execute_cmd::ExecuteCommand), + #[command(hide = true)] // Hidden while the feature is being built out + Debug(debug_cmd::DebugCommand), Prove(prove_cmd::ProveCommand), Verify(verify_cmd::VerifyCommand), Test(test_cmd::TestCommand), @@ -95,6 +98,7 @@ pub(crate) fn start_cli() -> eyre::Result<()> { NargoCommand::Init(args) => init_cmd::run(&backend, args, config), NargoCommand::Check(args) => check_cmd::run(&backend, args, config), NargoCommand::Compile(args) => compile_cmd::run(&backend, args, config), + NargoCommand::Debug(args) => debug_cmd::run(&backend, args, config), NargoCommand::Execute(args) => execute_cmd::run(&backend, args, config), NargoCommand::Prove(args) => prove_cmd::run(&backend, args, config), NargoCommand::Verify(args) => verify_cmd::run(&backend, args, config),