From 8480721b7a17af52cf7c394fe246a473255caceb Mon Sep 17 00:00:00 2001 From: Manyfestation <240733973+Manyfestation@users.noreply.github.com> Date: Wed, 18 Mar 2026 19:13:27 +0200 Subject: [PATCH] minor cleanup --- debugger/cli/src/main.rs | 25 ++-- debugger/session/src/lib.rs | 2 +- debugger/session/src/session.rs | 139 +++++++----------- debugger/session/tests/debug_session_tests.rs | 72 +++++---- 4 files changed, 97 insertions(+), 141 deletions(-) diff --git a/debugger/cli/src/main.rs b/debugger/cli/src/main.rs index 774c2b64..bee99dac 100644 --- a/debugger/cli/src/main.rs +++ b/debugger/cli/src/main.rs @@ -5,12 +5,12 @@ use std::path::{Path, PathBuf}; use clap::Parser; use debugger_session::args::{parse_call_args, parse_ctor_args, parse_hex_bytes}; -use debugger_session::format_failure_report; use debugger_session::session::{DebugEngine, DebugSession, ShadowTxContext, Variable, VariableOrigin}; use debugger_session::test_runner::{ TestExpectation, TestTxInputScenarioResolved, TestTxOutputScenarioResolved, TestTxScenarioResolved, discover_sidecar_path, resolve_contract_test, }; +use debugger_session::{format_failure_report, format_value}; use kaspa_consensus_core::Hash; use kaspa_consensus_core::hashing::sighash::SigHashReusedValuesUnsync; use kaspa_consensus_core::tx::{ @@ -127,30 +127,25 @@ fn show_vars(session: &DebugSession<'_, '_>) { if variables.is_empty() { println!("No variables in scope."); } else { - print_variable_section(session, "Contract Constants", &variables, |origin| { + print_variable_section("Contract Constants", &variables, |origin| { matches!(origin, VariableOrigin::ConstructorArg | VariableOrigin::Constant) }); - print_variable_section(session, "Entrypoint Parameters", &variables, |origin| origin == VariableOrigin::Param); - print_variable_section(session, "Locals", &variables, |origin| origin == VariableOrigin::Local); + print_variable_section("Entrypoint Parameters", &variables, |origin| origin == VariableOrigin::Param); + print_variable_section("Locals", &variables, |origin| origin == VariableOrigin::Local); } } Err(err) => println!("ERROR: {err}"), } } -fn print_variable_section( - session: &DebugSession<'_, '_>, - title: &str, - variables: &[Variable], - matches_origin: impl Fn(VariableOrigin) -> bool, -) { +fn print_variable_section(title: &str, variables: &[Variable], matches_origin: impl Fn(VariableOrigin) -> bool) { let section_vars: Vec<_> = variables.iter().filter(|var| matches_origin(var.origin)).collect(); if section_vars.is_empty() { return; } println!("{title}:"); for var in section_vars { - println!(" {} ({}) = {}", var.name, var.type_name, session.format_value(&var.type_name, &var.value)); + println!(" {} ({}) = {}", var.name, var.type_name, format_value(&var.type_name, &var.value)); } } @@ -161,7 +156,7 @@ fn show_step_view(session: &DebugSession<'_, '_>) { fn print_failure(session: &DebugSession<'_, '_>, err: kaspa_txscript_errors::TxScriptError) { let report = session.build_failure_report(&err); - let formatted = format_failure_report(&report, &|type_name, value| session.format_value(type_name, value)); + let formatted = format_failure_report(&report, &format_value); eprintln!("{formatted}"); } @@ -269,8 +264,8 @@ fn run_repl(session: &mut DebugSession<'_, '_>) -> Result<(), Box"); } else { match session.evaluate_expression(rest) { - Ok(result) => { - println!("{rest} = ({}) {}", result.type_name, session.format_value(&result.type_name, &result.value)); + Ok((type_name, value)) => { + println!("{rest} = ({type_name}) {}", format_value(&type_name, &value)); } Err(err) => println!("ERROR: {err}"), } @@ -280,7 +275,7 @@ fn run_repl(session: &mut DebugSession<'_, '_>) -> Result<(), Box { - println!("{} ({}) = {}", var.name, var.type_name, session.format_value(&var.type_name, &var.value)); + println!("{} ({}) = {}", var.name, var.type_name, format_value(&var.type_name, &var.value)); } Err(err) => println!("ERROR: {err}"), } diff --git a/debugger/session/src/lib.rs b/debugger/session/src/lib.rs index a97f3ea6..a7d4923f 100644 --- a/debugger/session/src/lib.rs +++ b/debugger/session/src/lib.rs @@ -4,5 +4,5 @@ pub mod session; pub mod test_runner; pub mod util; -pub use presentation::format_failure_report; +pub use presentation::{format_failure_report, format_value}; pub use session::{CallStackEntry, FailureFrame, FailureReport}; diff --git a/debugger/session/src/session.rs b/debugger/session/src/session.rs index cf140405..f7be1fd5 100644 --- a/debugger/session/src/session.rs +++ b/debugger/session/src/session.rs @@ -14,8 +14,8 @@ use silverscript_lang::debug_info::{ DebugFunctionRange, DebugInfo, DebugNamedValue, DebugStep, DebugVariableUpdate, RuntimeBinding, SourceSpan, StepId, StepKind, }; +use crate::presentation::build_source_context; pub use crate::presentation::{SourceContext, SourceContextLine}; -use crate::presentation::{build_source_context, format_value as format_debug_value}; use crate::util::{decode_i64, encode_hex}; pub type DebugTx<'a> = PopulatedTransaction<'a>; @@ -68,7 +68,6 @@ pub struct Variable { pub name: String, pub type_name: String, pub value: DebugValue, - pub is_constant: bool, pub origin: VariableOrigin, } @@ -108,12 +107,6 @@ pub struct FailureReport { pub source_text: String, } -#[derive(Debug, Clone)] -pub struct EvaluatedExpression { - pub type_name: String, - pub value: DebugValue, -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StackSnapshot { pub dstack: Vec, @@ -173,7 +166,6 @@ struct ScopeBinding<'i> { type_name: String, source: ScopeValueSource<'i>, origin: VariableOrigin, - is_constant: bool, hidden: bool, } @@ -291,7 +283,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { loop { let Some(target_index) = self.next_steppable_step_index(search_from, |step| predicate(step.call_depth, current_depth)) else { - while self.step_opcode()?.is_some() {} + self.run_until_end()?; return Ok(None); }; @@ -305,6 +297,11 @@ impl<'a, 'i> DebugSession<'a, 'i> { } } + fn run_until_end(&mut self) -> Result<(), kaspa_txscript_errors::TxScriptError> { + while self.step_opcode()?.is_some() {} + Ok(()) + } + fn advance_to_step(&mut self, target_index: usize) -> Result { let Some(target) = self.step_at_order(target_index) else { return Ok(false); @@ -355,7 +352,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { /// Continues execution until a breakpoint is hit or script completes. pub fn continue_to_breakpoint(&mut self) -> Result>, kaspa_txscript_errors::TxScriptError> { if self.breakpoints.is_empty() { - while self.step_opcode()?.is_some() {} + self.run_until_end()?; return Ok(None); } loop { @@ -453,7 +450,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { /// Returns all variables in scope at current execution point. /// Includes locals, params, constructor args, and contract constants. pub fn list_variables(&self) -> Result, String> { - self.collect_variables(self.active_scope_step_id()) + self.collect_variables(self.current_scope_step_id()) } pub fn list_variables_at_sequence(&self, sequence: u32, frame_id: u32) -> Result, String> { @@ -462,20 +459,20 @@ impl<'a, 'i> DebugSession<'a, 'i> { fn collect_variables(&self, step_id: StepId) -> Result, String> { let scope_state = self.scope_state(step_id)?; - let mut variables = self.collect_variables_map(&scope_state)?.into_values().collect::>(); + let mut variables = self.collect_variables_map(&scope_state).into_values().collect::>(); variables.sort_by(|a, b| a.name.cmp(&b.name)); Ok(variables) } /// Returns a specific variable by name, or error if not in scope. pub fn variable_by_name(&self, name: &str) -> Result { - let scope_state = self.scope_state(self.active_scope_step_id())?; - let variables = self.collect_variables_map(&scope_state)?; + let scope_state = self.current_scope_state()?; + let variables = self.collect_variables_map(&scope_state); variables.get(name).cloned().ok_or_else(|| format!("unknown variable '{name}'")) } - pub fn evaluate_expression(&self, expr_src: &str) -> Result { - let scope_state = self.scope_state(self.active_scope_step_id())?; + pub fn evaluate_expression(&self, expr_src: &str) -> Result<(String, DebugValue), String> { + let scope_state = self.current_scope_state()?; let expr = parse_expression_ast(expr_src).map_err(|err| format!("parse error: {err}"))?; let (shadow_bindings, env, stack_bindings, eval_types) = self.scope_state_eval_context(&scope_state)?; let (bytecode, type_name) = compile_debug_expr(&expr, &env, &stack_bindings, &eval_types) @@ -483,13 +480,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { let script = self.build_shadow_script(&shadow_bindings, &bytecode)?; let bytes = self.execute_shadow_script(&script)?; let value = decode_value_by_type(&type_name, bytes)?; - Ok(EvaluatedExpression { type_name, value }) - } - - // --- DebugValue formatting --- - /// Formats a debug value for display based on its type. - pub fn format_value(&self, type_name: &str, value: &DebugValue) -> String { - format_debug_value(type_name, value) + Ok((type_name, value)) } /// Returns the debug step for the current bytecode position. @@ -509,13 +500,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { pub fn call_stack(&self) -> Vec { let mut stack = Vec::new(); - let Some(current) = self.current_step_index else { - return stack; - }; - for order_index in 0..=current { - let Some(step) = self.step_at_order(order_index) else { - continue; - }; + for step in self.active_steps() { match &step.kind { StepKind::InlineCallEnter { callee } => stack.push(callee.clone()), StepKind::InlineCallExit { .. } => { @@ -530,13 +515,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { /// Returns the active inline call stack with source spans and frame identity. pub fn call_stack_with_spans(&self) -> Vec { let mut stack = Vec::new(); - let Some(current) = self.current_step_index else { - return stack; - }; - for order_index in 0..=current { - let Some(step) = self.step_at_order(order_index) else { - continue; - }; + for step in self.active_steps() { match &step.kind { StepKind::InlineCallEnter { callee } => stack.push(CallStackEntry { callee_name: callee.clone(), @@ -588,14 +567,9 @@ impl<'a, 'i> DebugSession<'a, 'i> { }) } - fn visible_scope(&self, step_id: StepId) -> Result, String> { - let context = self.current_variable_context(step_id)?; - let updates = self.current_variable_updates(&context); - Ok(VisibleScope { context, updates }) - } - fn scope_state(&self, step_id: StepId) -> Result, String> { - let scope = self.visible_scope(step_id)?; + let context = self.current_variable_context(step_id)?; + let scope = VisibleScope { updates: self.current_variable_updates(&context), context }; Ok(self.scope_state_from_visible(&scope)) } @@ -607,13 +581,12 @@ impl<'a, 'i> DebugSession<'a, 'i> { type_name: param.type_name.clone(), source: ScopeValueSource::RuntimeSlot { from_top: param.stack_index }, origin: VariableOrigin::Param, - is_constant: false, hidden: false, }); } - record_debug_named_values(&mut bindings, &self.debug_info.constructor_args, VariableOrigin::ConstructorArg, false); - record_debug_named_values(&mut bindings, &self.debug_info.constants, VariableOrigin::Constant, true); + record_debug_named_values(&mut bindings, &self.debug_info.constructor_args, VariableOrigin::ConstructorArg); + record_debug_named_values(&mut bindings, &self.debug_info.constants, VariableOrigin::Constant); for (name, update) in &scope.updates { let source = match update.runtime_binding.as_ref() { @@ -631,7 +604,6 @@ impl<'a, 'i> DebugSession<'a, 'i> { type_name: update.type_name.clone(), source, origin: VariableOrigin::Local, - is_constant: false, hidden: is_inline_synthetic_name(name), }); } @@ -639,7 +611,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { bindings } - fn collect_variables_map(&self, scope_state: &ScopeState<'i>) -> Result, String> { + fn collect_variables_map(&self, scope_state: &ScopeState<'i>) -> HashMap { let mut variables: HashMap = HashMap::new(); for (name, binding) in scope_state { @@ -649,17 +621,11 @@ impl<'a, 'i> DebugSession<'a, 'i> { let value = self.resolve_scope_binding(scope_state, binding).unwrap_or_else(DebugValue::Unknown); variables.insert( name.clone(), - Variable { - name: name.clone(), - type_name: binding.type_name.clone(), - value, - is_constant: binding.is_constant, - origin: binding.origin, - }, + Variable { name: name.clone(), type_name: binding.type_name.clone(), value, origin: binding.origin }, ); } - Ok(variables) + variables } fn step_updates_are_visible(&self, step: &DebugStep<'i>, context: &VariableContext<'_>) -> bool { @@ -681,7 +647,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { let mut best: Option<&DebugStep<'i>> = None; let mut best_len = usize::MAX; for step in &self.debug_info.steps { - if step_matches_offset(step, offset) { + if range_matches_offset(step.bytecode_start, step.bytecode_end, offset) { let len = step.bytecode_end.saturating_sub(step.bytecode_start); if len < best_len { best = Some(step); @@ -701,16 +667,12 @@ impl<'a, 'i> DebugSession<'a, 'i> { self.current_step_index.and_then(|index| self.step_at_order(index)) } - fn current_step_id(&self) -> StepId { - self.current_timeline_step().map(DebugStep::id).unwrap_or(StepId::ROOT) - } - - fn active_scope_step_id(&self) -> StepId { + fn current_scope_step_id(&self) -> StepId { let Some(current_index) = self.current_step_index else { - return self.current_step_id(); + return self.current_timeline_step().map(DebugStep::id).unwrap_or(StepId::ROOT); }; let Some(current_step) = self.current_timeline_step() else { - return self.current_step_id(); + return StepId::ROOT; }; if !matches!(current_step.kind, StepKind::InlineCallEnter { .. }) { return current_step.id(); @@ -723,6 +685,15 @@ impl<'a, 'i> DebugSession<'a, 'i> { current_step.id() } + fn current_scope_state(&self) -> Result, String> { + self.scope_state(self.current_scope_step_id()) + } + + fn active_steps(&self) -> impl Iterator> + '_ { + let end = self.current_step_index.map(|index| index + 1).unwrap_or(0); + self.step_order[..end].iter().filter_map(|&step_index| self.debug_info.steps.get(step_index)) + } + fn mark_step_executed(&mut self, step_index: usize) { if let Some(step) = self.step_at_order(step_index) { self.executed_steps.insert(step.id()); @@ -776,7 +747,8 @@ impl<'a, 'i> DebugSession<'a, 'i> { } self.find_steppable_step_index(|step| { - step_matches_offset(step, offset) && min_sequence.is_none_or(|min_sequence| step.sequence >= min_sequence) + range_matches_offset(step.bytecode_start, step.bytecode_end, offset) + && min_sequence.is_none_or(|min_sequence| step.sequence >= min_sequence) }) } @@ -916,7 +888,8 @@ impl<'a, 'i> DebugSession<'a, 'i> { let failure_span = self.current_span(); let call_stack = self.call_stack_with_spans(); let innermost_function = self.current_function_name().unwrap_or("").to_string(); - let innermost_vars: Vec = self.list_variables().unwrap_or_default().into_iter().filter(|v| !v.is_constant).collect(); + let innermost_vars: Vec = + self.list_variables().unwrap_or_default().into_iter().filter(|v| v.origin != VariableOrigin::Constant).collect(); let mut frames = vec![FailureFrame { function_name: innermost_function.clone(), span: failure_span, variables: innermost_vars }]; @@ -928,7 +901,7 @@ impl<'a, 'i> DebugSession<'a, 'i> { .list_variables_at_sequence(entry.sequence, entry.frame_id) .unwrap_or_default() .into_iter() - .filter(|v| !v.is_constant) + .filter(|v| v.origin != VariableOrigin::Constant) .collect(); let caller_name = if idx == 0 { entry_name.clone() } else { call_stack[idx - 1].callee_name.clone() }; frames.push(FailureFrame { function_name: caller_name, span: entry.call_site_span, variables: caller_vars }); @@ -1142,26 +1115,16 @@ fn range_matches_offset(bytecode_start: usize, bytecode_end: usize, offset: usiz if bytecode_start == bytecode_end { offset == bytecode_start } else { offset >= bytecode_start && offset < bytecode_end } } -fn step_matches_offset(step: &DebugStep<'_>, offset: usize) -> bool { - range_matches_offset(step.bytecode_start, step.bytecode_end, offset) -} - fn is_inline_synthetic_name(name: &str) -> bool { name.starts_with("__arg_") } -fn record_debug_named_values<'i>( - bindings: &mut ScopeState<'i>, - values: &[DebugNamedValue<'i>], - origin: VariableOrigin, - is_constant: bool, -) { +fn record_debug_named_values<'i>(bindings: &mut ScopeState<'i>, values: &[DebugNamedValue<'i>], origin: VariableOrigin) { for value in values { bindings.entry(value.name.clone()).or_insert_with(|| ScopeBinding { type_name: value.type_name.clone(), source: ScopeValueSource::Expr(value.value.clone()), origin, - is_constant, hidden: false, }); } @@ -1357,7 +1320,7 @@ mod tests { }; let session = DebugSession::full(&[], &[], "", Some(debug_info), engine).unwrap(); let scope_state = session.scope_state(StepId::ROOT).unwrap(); - let vars = session.collect_variables_map(&scope_state).unwrap(); + let vars = session.collect_variables_map(&scope_state); let pair = vars.get("DEFAULT_PAIR").expect("DEFAULT_PAIR variable"); match &pair.value { DebugValue::Object(fields) => { @@ -1469,7 +1432,7 @@ mod tests { session.current_step_index = Some(1); let x = session.variable_by_name("x").unwrap(); - assert_eq!(session.format_value(&x.type_name, &x.value), "5"); + assert_eq!(crate::presentation::format_value(&x.type_name, &x.value), "5"); } #[test] @@ -1516,16 +1479,16 @@ mod tests { session.current_step_index = Some(1); let literal = session.evaluate_expression("1 + 2").unwrap(); - assert_eq!(literal.type_name, "int"); - assert!(matches!(literal.value, DebugValue::Int(3))); + assert_eq!(literal.0, "int"); + assert!(matches!(literal.1, DebugValue::Int(3))); let scoped = session.evaluate_expression("x + 1").unwrap(); - assert_eq!(scoped.type_name, "int"); - assert!(matches!(scoped.value, DebugValue::Int(6))); + assert_eq!(scoped.0, "int"); + assert!(matches!(scoped.1, DebugValue::Int(6))); let constant = session.evaluate_expression("K + 1").unwrap(); - assert_eq!(constant.type_name, "int"); - assert!(matches!(constant.value, DebugValue::Int(8))); + assert_eq!(constant.0, "int"); + assert!(matches!(constant.1, DebugValue::Int(8))); let parse_err = session.evaluate_expression("1 +").unwrap_err(); assert!(parse_err.contains("parse error")); diff --git a/debugger/session/tests/debug_session_tests.rs b/debugger/session/tests/debug_session_tests.rs index 7a62eae5..3a1c36f9 100644 --- a/debugger/session/tests/debug_session_tests.rs +++ b/debugger/session/tests/debug_session_tests.rs @@ -12,7 +12,10 @@ use kaspa_txscript::covenants::CovenantsContext; use kaspa_txscript::opcodes::codes::OpTrue; use kaspa_txscript::{EngineCtx, EngineFlags}; -use debugger_session::session::{DebugSession, DebugValue, ShadowTxContext}; +use debugger_session::{ + format_value, + session::{DebugSession, DebugValue, ShadowTxContext}, +}; use silverscript_lang::ast::{Expr, ExprKind, parse_contract_ast}; use silverscript_lang::compiler::{CompileOptions, compile_contract}; use silverscript_lang::debug_info::StepKind; @@ -187,8 +190,8 @@ contract Shadow(int x) { assert_eq!(x_count, 1, "expected a single visible x variable"); let x = session.variable_by_name("x")?; - assert!(!x.is_constant, "function parameter should shadow constructor constant"); - assert_eq!(session.format_value(&x.type_name, &x.value), "3"); + assert_eq!(x.origin.label(), "arg", "function parameter should shadow constructor constant"); + assert_eq!(format_value(&x.type_name, &x.value), "3"); Ok(()) }) } @@ -211,15 +214,15 @@ contract ShadowMath(int fee) { session.step_over()?; let local_after_init = session.variable_by_name("local")?; - assert_eq!(session.format_value(&local_after_init.type_name, &local_after_init.value), "4"); + assert_eq!(format_value(&local_after_init.type_name, &local_after_init.value), "4"); session.step_over()?; let local_after_update = session.variable_by_name("local")?; - assert_eq!(session.format_value(&local_after_update.type_name, &local_after_update.value), "7"); + assert_eq!(format_value(&local_after_update.type_name, &local_after_update.value), "7"); let fee = session.variable_by_name("fee")?; - assert!(!fee.is_constant); - assert_eq!(session.format_value(&fee.type_name, &fee.value), "3"); + assert_eq!(fee.origin.label(), "arg"); + assert_eq!(format_value(&fee.type_name, &fee.value), "3"); Ok(()) }) } @@ -241,10 +244,10 @@ contract FieldOffset(int c) { session.run_to_first_executed_statement()?; let a = session.variable_by_name("a")?; - assert_eq!(session.format_value(&a.type_name, &a.value), "5"); + assert_eq!(format_value(&a.type_name, &a.value), "5"); let x = session.variable_by_name("x")?; - assert_eq!(session.format_value(&x.type_name, &x.value), "7"); + assert_eq!(format_value(&x.type_name, &x.value), "7"); Ok(()) }) } @@ -268,7 +271,7 @@ contract FieldMath(int c) { for _ in 0..4 { if let Ok(z) = session.variable_by_name("z") { - assert_eq!(session.format_value(&z.type_name, &z.value), "14"); + assert_eq!(format_value(&z.type_name, &z.value), "14"); return Ok(()); } if session.step_over()?.is_none() { @@ -336,7 +339,7 @@ contract OpcodeCursor() { assert_ne!(after_si.line, start.line, "si should refresh statement cursor"); let x = session.variable_by_name("x")?; - assert_eq!(session.format_value(&x.type_name, &x.value), "1"); + assert_eq!(format_value(&x.type_name, &x.value), "1"); Ok(()) }) } @@ -384,11 +387,11 @@ contract LocalVars() { session.step_over()?; let x_after_init = session.variable_by_name("x")?; - assert_eq!(session.format_value(&x_after_init.type_name, &x_after_init.value), "4"); + assert_eq!(format_value(&x_after_init.type_name, &x_after_init.value), "4"); session.step_over()?; let x_after_assign = session.variable_by_name("x")?; - assert_eq!(session.format_value(&x_after_assign.type_name, &x_after_assign.value), "6"); + assert_eq!(format_value(&x_after_assign.type_name, &x_after_assign.value), "6"); Ok(()) }) } @@ -440,7 +443,7 @@ contract InlineCalls() { } assert_eq!(after_over.line, 11, "step_over should eventually move past inline call"); let b = session.variable_by_name("b")?; - assert_eq!(session.format_value(&b.type_name, &b.value), "4", "inline return should resolve against caller params"); + assert_eq!(format_value(&b.type_name, &b.value), "4", "inline return should resolve against caller params"); Ok(()) })?; @@ -648,7 +651,7 @@ contract InlineParams() { let in_callee = session.call_stack().iter().any(|name| name == "add1"); if in_callee { if let Ok(x) = session.variable_by_name("x") { - let rendered = session.format_value(&x.type_name, &x.value); + let rendered = format_value(&x.type_name, &x.value); assert_eq!(rendered, "4", "inline param x should reflect caller-provided value"); saw_inline_param = true; break; @@ -700,12 +703,9 @@ contract InlineEval() { _ => return Err("expected inline callee bindings x and y to be ints".into()), }; - let evaluated = session.evaluate_expression("((y * 2) + (x - 1)) - (y - x)")?; - assert_eq!(evaluated.type_name, "int"); - assert_eq!( - session.format_value(&evaluated.type_name, &evaluated.value), - ((y_value * 2) + (x_value - 1) - (y_value - x_value)).to_string() - ); + let (type_name, value) = session.evaluate_expression("((y * 2) + (x - 1)) - (y - x)")?; + assert_eq!(type_name, "int"); + assert_eq!(format_value(&type_name, &value), ((y_value * 2) + (x_value - 1) - (y_value - x_value)).to_string()); Ok(()) }) } @@ -730,15 +730,13 @@ contract ScopeKinds(int init_amount) { let vars = session.list_variables()?; let init_amount = vars.iter().find(|var| var.name == "init_amount").ok_or("missing ctor arg")?; assert_eq!(init_amount.origin.label(), "ctor"); - assert!(!init_amount.is_constant); let bonus = vars.iter().find(|var| var.name == "BONUS").ok_or("missing contract constant")?; assert_eq!(bonus.origin.label(), "const"); - assert!(bonus.is_constant); - let evaluated = session.evaluate_expression("init_amount + BONUS + delta")?; - assert_eq!(evaluated.type_name, "int"); - assert_eq!(session.format_value(&evaluated.type_name, &evaluated.value), "12"); + let (type_name, value) = session.evaluate_expression("init_amount + BONUS + delta")?; + assert_eq!(type_name, "int"); + assert_eq!(format_value(&type_name, &value), "12"); Ok(()) }) } @@ -777,7 +775,7 @@ contract StepVisibility(int init_amount) { session.current_span().ok_or("missing span after step")?; let base = session.variable_by_name("base")?; - assert_eq!(session.format_value(&base.type_name, &base.value), "11"); + assert_eq!(format_value(&base.type_name, &base.value), "11"); Ok(()) }, ) @@ -830,19 +828,19 @@ contract ShiftedBindings() { assert!(current_line > call_line, "expected to step past inline call"); let amount = session.variable_by_name("amount")?; - assert_eq!(session.format_value(&amount.type_name, &amount.value), "11"); + assert_eq!(format_value(&amount.type_name, &amount.value), "11"); let delta = session.variable_by_name("delta")?; - assert_eq!(session.format_value(&delta.type_name, &delta.value), "3"); + assert_eq!(format_value(&delta.type_name, &delta.value), "3"); let values = session.variable_by_name("values")?; - assert_eq!(session.format_value(&values.type_name, &values.value), "[4, 5]"); + assert_eq!(format_value(&values.type_name, &values.value), "[4, 5]"); let base = session.variable_by_name("base")?; - assert_eq!(session.format_value(&base.type_name, &base.value), "15"); + assert_eq!(format_value(&base.type_name, &base.value), "15"); let after = session.variable_by_name("after")?; - assert_eq!(session.format_value(&after.type_name, &after.value), "20"); + assert_eq!(format_value(&after.type_name, &after.value), "20"); Ok(()) }, @@ -908,7 +906,7 @@ contract LoopIndex() { for _ in 0..12 { if let Ok(i) = session.variable_by_name("i") { - assert_eq!(session.format_value(&i.type_name, &i.value), "0"); + assert_eq!(format_value(&i.type_name, &i.value), "0"); saw_loop_index = true; break; } @@ -976,7 +974,7 @@ contract CovLocal() { for _ in 0..4 { if let Ok(covid) = session.variable_by_name("covid") { - let rendered = session.format_value(&covid.type_name, &covid.value); + let rendered = format_value(&covid.type_name, &covid.value); assert_eq!(rendered, format!("0x{}", "11".repeat(32))); return Ok(()); } @@ -1039,8 +1037,8 @@ contract CovEval() { let mut session = DebugSession::full(&sigscript, &compiled.script, source, debug_info, engine)?.with_shadow_tx_context(shadow_ctx); session.run_to_first_executed_statement()?; - let evaluated = session.evaluate_expression("OpInputCovenantId(this.activeInputIndex)")?; - assert_eq!(evaluated.type_name, "byte[32]"); - assert_eq!(session.format_value(&evaluated.type_name, &evaluated.value), format!("0x{}", "22".repeat(32))); + let (type_name, value) = session.evaluate_expression("OpInputCovenantId(this.activeInputIndex)")?; + assert_eq!(type_name, "byte[32]"); + assert_eq!(format_value(&type_name, &value), format!("0x{}", "22".repeat(32))); Ok(()) }