Skip to main content

spydecy_debugger/
repl.rs

1//! Interactive REPL for stepping through transpilation
2//!
3//! Provides a command-line interface for debugging.
4
5use crate::commands::{parse_command, Command};
6use crate::stepper::Stepper;
7use anyhow::Result;
8use colored::Colorize;
9use std::io::{self, Write};
10
11/// Run interactive REPL session
12///
13/// # Errors
14///
15/// Returns error if I/O fails
16pub fn run_repl(mut stepper: Stepper) -> Result<()> {
17    print_header();
18    print_help_hint();
19
20    loop {
21        print!("\n{} ", "(spydecy-debug)".blue().bold());
22        io::stdout().flush()?;
23
24        let mut input = String::new();
25        io::stdin().read_line(&mut input)?;
26
27        let command = match parse_command(&input) {
28            Ok(cmd) => cmd,
29            Err(e) => {
30                eprintln!("{} {}", "Error:".red().bold(), e);
31                continue;
32            }
33        };
34
35        match handle_command(command, &mut stepper) {
36            Ok(true) => break, // Quit
37            Ok(false) => {}
38            Err(e) => {
39                eprintln!("{} {e:#}", "Error:".red().bold());
40            }
41        }
42    }
43
44    println!("\n{}", "Exiting debugger.".dimmed());
45    Ok(())
46}
47
48fn handle_command(command: Command, stepper: &mut Stepper) -> Result<bool> {
49    match command {
50        Command::Step => {
51            let phase = stepper.step()?;
52            println!(
53                "\n{}",
54                format!("═══ Step {} ═══", stepper.state().step_count)
55                    .cyan()
56                    .bold()
57            );
58            println!("{} {}", "Phase:".green(), phase.name());
59            print_current_state(stepper);
60        }
61        Command::Continue => {
62            stepper.continue_execution()?;
63            println!("{}", "Execution continued.".green());
64            print_current_state(stepper);
65        }
66        Command::Visualize => {
67            visualize_state(stepper);
68        }
69        Command::Inspect(target) => {
70            inspect_target(&target, stepper);
71        }
72        Command::Break(bp) => {
73            stepper.add_breakpoint(bp.clone());
74            println!("{} {bp}", "Breakpoint added:".green().bold());
75        }
76        Command::ListBreakpoints => {
77            list_breakpoints(stepper);
78        }
79        Command::ClearBreakpoint(idx) => {
80            if stepper.clear_breakpoint(idx) {
81                println!("{} {idx}", "Cleared breakpoint:".green().bold());
82            } else {
83                eprintln!("{} {idx}", "Invalid breakpoint:".red().bold());
84            }
85        }
86        Command::Help => {
87            print_help();
88        }
89        Command::Quit => {
90            return Ok(true);
91        }
92    }
93    Ok(false)
94}
95
96fn print_header() {
97    println!(
98        "{}",
99        "═══════════════════════════════════════".cyan().bold()
100    );
101    println!("{}", "   Spydecy Interactive Debugger".cyan().bold());
102    println!(
103        "{}",
104        "═══════════════════════════════════════".cyan().bold()
105    );
106}
107
108fn print_help_hint() {
109    println!(
110        "\nType {} for help, {} to step, {} to quit",
111        "'help'".yellow(),
112        "'step'".yellow(),
113        "'quit'".yellow()
114    );
115}
116
117fn print_help() {
118    println!("\n{}", "Available Commands:".green().bold());
119    println!(
120        "  {} {}     Step to next phase",
121        "step, s".yellow(),
122        " ".repeat(7)
123    );
124    println!(
125        "  {} {}  Continue until breakpoint",
126        "continue, c".yellow(),
127        " ".repeat(2)
128    );
129    println!("  {}  Visualize current state", "visualize, v".yellow());
130    println!(
131        "  {}  Inspect target (python_hir, c_hir, etc.)",
132        "inspect <target>".yellow()
133    );
134    println!("  {}    Add breakpoint", "break <type>".yellow());
135    println!(
136        "  {} {}     List breakpoints",
137        "list, l".yellow(),
138        " ".repeat(7)
139    );
140    println!(
141        "  {} {}  Clear breakpoint",
142        "clear <num>".yellow(),
143        " ".repeat(3)
144    );
145    println!(
146        "  {} {}    Show this help",
147        "help, h, ?".yellow(),
148        " ".repeat(4)
149    );
150    println!("  {} {}  Exit debugger", "quit, q".yellow(), " ".repeat(7));
151}
152
153fn print_current_state(stepper: &Stepper) {
154    let state = stepper.state();
155    println!("  {} {}", "Step:".dimmed(), state.step_count);
156    println!("  {} {}", "Phase:".dimmed(), state.phase.name());
157}
158
159fn visualize_state(stepper: &Stepper) {
160    let state = stepper.state();
161    println!(
162        "\n{}",
163        format!("═══ State at Step {} ═══", state.step_count)
164            .cyan()
165            .bold()
166    );
167
168    if let Some(ref hir) = state.python_hir {
169        println!("\n{}", "📄 Python HIR:".green().bold());
170        println!("{hir:#?}");
171    }
172
173    if let Some(ref hir) = state.c_hir {
174        println!("\n{}", "🔧 C HIR:".green().bold());
175        println!("{hir:#?}");
176    }
177
178    if let Some(ref hir) = state.unified_hir {
179        println!("\n{}", "🔗 Unified HIR:".green().bold());
180        println!("{hir:#?}");
181    }
182
183    if let Some(ref code) = state.rust_code {
184        println!("\n{}", "🦀 Rust Code:".green().bold());
185        println!("{code}");
186    }
187}
188
189fn inspect_target(target: &str, stepper: &Stepper) {
190    let state = stepper.state();
191
192    match target {
193        "python" | "python_hir" => {
194            if let Some(ref hir) = state.python_hir {
195                println!("{hir:#?}");
196            } else {
197                println!("{}", "Python HIR not yet available".dimmed());
198            }
199        }
200        "c" | "c_hir" => {
201            if let Some(ref hir) = state.c_hir {
202                println!("{hir:#?}");
203            } else {
204                println!("{}", "C HIR not yet available".dimmed());
205            }
206        }
207        "unified" => {
208            if let Some(ref hir) = state.unified_hir {
209                println!("{hir:#?}");
210            } else {
211                println!("{}", "Unified HIR not yet available".dimmed());
212            }
213        }
214        "rust" => {
215            if let Some(ref code) = state.rust_code {
216                println!("{code}");
217            } else {
218                println!("{}", "Rust code not yet generated".dimmed());
219            }
220        }
221        _ => {
222            eprintln!("{} {target}", "Unknown target:".red().bold());
223        }
224    }
225}
226
227fn list_breakpoints(stepper: &Stepper) {
228    let breakpoints = stepper.breakpoints();
229
230    if breakpoints.is_empty() {
231        println!("{}", "No breakpoints set.".dimmed());
232    } else {
233        println!("\n{}", "Breakpoints:".green().bold());
234        for (i, bp) in breakpoints.iter().enumerate() {
235            println!("  {}: {bp}", format!("[{i}]").yellow());
236        }
237    }
238}