From afdcfa461c68af211146b0d4e822af7b4a7d311f Mon Sep 17 00:00:00 2001 From: Martin Verzilli Date: Wed, 4 Oct 2023 17:55:38 +0200 Subject: [PATCH] Port repl to easy-repl (not compiling) --- Cargo.lock | 178 +++++++++++++++++++++++++- tooling/debugger/Cargo.toml | 1 + tooling/debugger/src/lib.rs | 245 +++++++++++++++++++----------------- 3 files changed, 304 insertions(+), 120 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7e2e8df7c30..c91f3cb158a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -807,6 +807,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" @@ -1342,6 +1353,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" @@ -1395,6 +1421,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" @@ -1463,6 +1495,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" @@ -1509,6 +1551,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" @@ -2223,6 +2274,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" @@ -2273,6 +2333,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" @@ -2405,6 +2474,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" @@ -2422,6 +2513,7 @@ name = "noir_debugger" version = "0.16.0" dependencies = [ "acvm", + "easy-repl", "nargo", "noirc_printable_type", "reedline-repl-rs", @@ -2834,7 +2926,7 @@ dependencies = [ "inferno", "libc", "log", - "nix", + "nix 0.26.2", "once_cell", "parking_lot", "smallvec", @@ -3014,6 +3106,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" @@ -3452,6 +3554,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" @@ -3591,7 +3727,7 @@ dependencies = [ "phf", "serde", "serde-reflection", - "textwrap", + "textwrap 0.13.4", ] [[package]] @@ -3729,6 +3865,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" @@ -3883,6 +4025,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" @@ -4079,6 +4227,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" @@ -4328,6 +4487,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" @@ -4358,6 +4526,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/tooling/debugger/Cargo.toml b/tooling/debugger/Cargo.toml index 319950b526f..f488831609c 100644 --- a/tooling/debugger/Cargo.toml +++ b/tooling/debugger/Cargo.toml @@ -14,3 +14,4 @@ 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 fdb07ae86bd..c8a9430453f 100644 --- a/tooling/debugger/src/lib.rs +++ b/tooling/debugger/src/lib.rs @@ -9,16 +9,15 @@ use nargo::NargoError; use nargo::ops::ForeignCallExecutor; -use std::rc::Rc; -use std::sync::Mutex; - use thiserror::Error; -use reedline_repl_rs::clap::{ - ArgMatches as ReplArgMatches, - Command as ReplCommand, -}; -use reedline_repl_rs::Repl; +use easy_repl::{Repl, CommandStatus, command}; + +// use reedline_repl_rs::clap::{ +// ArgMatches as ReplArgMatches, +// Command as ReplCommand, +// }; +// use reedline_repl_rs::Repl; enum SolveResult { Done, @@ -44,84 +43,78 @@ struct ReplContext<'backend, B: BlackBoxFunctionSolver> { show_output: bool, } -impl<'backend, B> ReplContext<'backend, B> where B: BlackBoxFunctionSolver { - 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 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) - } +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) } - None => ExecutionError::SolvingError(error), - })) - } - ACVMStatus::RequiresForeignCall(foreign_call) => { - let foreign_call_result = self.foreign_call_executor.execute(&foreign_call, self.show_output)?; - acvm.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(); - println!("Stopped at opcode {}: {}", ip, acvm.opcodes()[ip]); - self.show_source_code_location(&OpcodeLocation::Acir(ip)); - } - - fn show_source_code_location(&self, location: &OpcodeLocation) { - let locations = self.debug_artifact.debug_symbols[0].opcode_location(&location); - match locations { - Some(locations) => { - for loc in locations { - let file = &self.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 => {} + 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) } } +} + +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 finalize(&mut self) -> WitnessMap { - self.acvm.take().unwrap().finalize() +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) @@ -145,54 +138,70 @@ pub fn debug_circuit( show_output: bool, ) -> Result { let opcodes = circuit.opcodes.clone(); - let acvm = ACVM::new(blackbox_solver, opcodes, initial_witness); - let foreign_call_executor = ForeignCallExecutor::default(); - - let repl_context = Rc::new(Mutex::new(ReplContext { - acvm: Some(acvm), - debug_artifact, - foreign_call_executor, - circuit, - show_output, - })); - 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 = repl_context.lock().unwrap().finalize(); + let mut acvm = ACVM::new(blackbox_solver, opcodes, initial_witness); + let mut foreign_call_executor = ForeignCallExecutor::default(); + + 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) + } + }) + .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) + } + }) + .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) } -fn step_command(_args: ReplArgMatches, context: &mut Rc>>) -> Result, DebuggingError> { - let mut c = context.lock().unwrap(); - c.show_current_vm_status(); - match c.step_opcode()? { +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())), } } -fn continue_command(_args: ReplArgMatches, context: &mut Rc>>) -> Result, DebuggingError> { - let mut c = context.lock().unwrap(); - c.show_current_vm_status(); +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 c.step_opcode()? { + match step_opcode(acvm, circuit, foreign_call_executor, show_output)? { SolveResult::Done => break, SolveResult::Ok => {}, } @@ -200,7 +209,7 @@ fn continue_command(_args: ReplArgMatches, context: & Ok(Some("Ok".to_string())) } -fn quit_command(_args: ReplArgMatches, context: &mut Rc>>) -> Result, DebuggingError> { - context.lock().unwrap().show_current_vm_status(); +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)) }