From fda94c1cb61ec8fa9c804aed1e5446017df7c714 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Fri, 11 Feb 2022 22:43:09 +0800 Subject: [PATCH] Better printing. --- src/bin/rhai-dbg.rs | 903 +++++++++++++++++++++++--------------------- 1 file changed, 477 insertions(+), 426 deletions(-) diff --git a/src/bin/rhai-dbg.rs b/src/bin/rhai-dbg.rs index eb1c419b..c4ee88ca 100644 --- a/src/bin/rhai-dbg.rs +++ b/src/bin/rhai-dbg.rs @@ -10,28 +10,45 @@ use std::{ }; /// Pretty-print source line. -fn print_source(lines: &[String], pos: Position, offset: usize) { - let line_no = if lines.len() > 1 { - if pos.is_none() { - "".to_string() - } else { - format!("{}: ", pos.line().unwrap()) - } - } else { - "".to_string() - }; - - // Print error position +fn print_source(lines: &[String], pos: Position, offset: usize, window: (usize, usize)) { if pos.is_none() { // No position println!(); - } else { - // Specific position - print line text - println!("{}{}", line_no, lines[pos.line().unwrap() - 1]); + return; + } - // Display position marker + let line = pos.line().unwrap() - 1; + let start = if line >= window.0 { line - window.0 } else { 0 }; + let end = usize::min(line + window.1, lines.len() - 1); + let line_no_len = format!("{}", end).len(); + + // Print error position + if start >= end { + println!("{}: {}", start + 1, lines[start]); if let Some(pos) = pos.position() { - println!("{0:>1$}", "^", line_no.len() + pos + offset); + println!("{0:>1$}", "^", pos + offset + line_no_len + 2); + } + } else { + for n in start..=end { + let marker = if n == line { "> " } else { " " }; + + println!( + "{0}{1}{2:>3$}{5}│ {0}{4}{5}", + if n == line { "\x1b[33m" } else { "" }, + marker, + n + 1, + line_no_len, + lines[n], + if n == line { "\x1b[39m" } else { "" }, + ); + + if n == line { + if let Some(pos) = pos.position() { + let shift = offset + line_no_len + marker.len() + 2; + + println!("{0:>1$}{2:>3$}", "│ ", shift, "\x1b[36m^\x1b[39m", pos + 10); + } + } } } } @@ -40,7 +57,8 @@ fn print_current_source( context: &mut rhai::EvalContext, source: Option<&str>, pos: Position, - lines: &Vec, + lines: &[String], + window: (usize, usize), ) { let current_source = &mut *context .global_runtime_state_mut() @@ -58,7 +76,7 @@ fn print_current_source( println!("{} @ {:?}", src, pos); } else { // Print the current source line - print_source(lines, pos, 0); + print_source(lines, pos, 0, window); } } @@ -101,12 +119,13 @@ fn print_debug_help() { println!("quit, q, exit, kill => quit"); println!("scope => print the scope"); println!("print, p => print all variables de-duplicated"); - println!("print/p this => print the `this` pointer"); + println!("print/p this => print the 'this' pointer"); println!("print/p => print the current value of a variable"); #[cfg(not(feature = "no_module"))] println!("imports => print all imported modules"); println!("node => print the current AST node"); println!("list, l => print the current source line"); + println!("list/l => print a source line"); println!("backtrace, bt => print the current call-stack"); println!("info break, i b => print all break-points"); println!("enable/en => enable a break-point"); @@ -123,17 +142,19 @@ fn print_debug_help() { println!( "break/b <#args> => set a new break-point for a function call with #args arguments" ); - println!("throw [message] => throw an exception (message optional)"); + println!("throw => throw a runtime exception"); + println!("throw => throw an exception with string data"); + println!("throw <#> => throw an exception with numeric data"); println!("run, r => restart the script evaluation from beginning"); println!("step, s => go to the next expression, diving into functions"); - println!("over => go to the next expression, skipping oer functions"); + println!("over, o => go to the next expression, skipping oer functions"); println!("next, n, => go to the next statement, skipping over functions"); println!("finish, f => continue until the end of the current function call"); println!("continue, c => continue normal execution"); println!(); } -/// Display the scope. +/// Display the current scope. fn print_scope(scope: &Scope, dedup: bool) { let flattened_clone; let scope = if dedup { @@ -170,6 +191,434 @@ fn print_scope(scope: &Scope, dedup: bool) { } } +// Load script to debug. +fn load_script(engine: &Engine) -> (rhai::AST, String) { + if let Some(filename) = env::args().skip(1).next() { + let mut contents = String::new(); + + let filename = match Path::new(&filename).canonicalize() { + Err(err) => { + eprintln!( + "\x1b[31mError script file path: {}\n{}\x1b[39m", + filename, err + ); + exit(1); + } + Ok(f) => { + match f.strip_prefix(std::env::current_dir().unwrap().canonicalize().unwrap()) { + Ok(f) => f.into(), + _ => f, + } + } + }; + + let mut f = match File::open(&filename) { + Err(err) => { + eprintln!( + "\x1b[31mError reading script file: {}\n{}\x1b[39m", + filename.to_string_lossy(), + err + ); + exit(1); + } + Ok(f) => f, + }; + + if let Err(err) = f.read_to_string(&mut contents) { + println!( + "Error reading script file: {}\n{}", + filename.to_string_lossy(), + err + ); + exit(1); + } + + let script = if contents.starts_with("#!") { + // Skip shebang + &contents[contents.find('\n').unwrap_or(0)..] + } else { + &contents[..] + }; + + let ast = match engine + .compile(script) + .map_err(Into::>::into) + { + Err(err) => { + print_error(script, *err); + exit(1); + } + Ok(ast) => ast, + }; + + println!("Script '{}' loaded.", filename.to_string_lossy()); + + (ast, contents) + } else { + eprintln!("\x1b[31mNo script file specified.\x1b[39m"); + exit(1); + } +} + +// Main callback for debugging. +fn debug_callback( + context: &mut rhai::EvalContext, + event: DebuggerEvent, + node: rhai::ASTNode, + source: Option<&str>, + pos: Position, + lines: &[String], +) -> Result> { + // Check event + match event { + DebuggerEvent::Step => (), + DebuggerEvent::BreakPoint(n) => { + match context.global_runtime_state().debugger.break_points()[n] { + #[cfg(not(feature = "no_position"))] + BreakPoint::AtPosition { .. } => (), + BreakPoint::AtFunctionName { ref name, .. } + | BreakPoint::AtFunctionCall { ref name, .. } => { + println!("! Call to function {}.", name) + } + #[cfg(not(feature = "no_object"))] + BreakPoint::AtProperty { ref name, .. } => { + println!("! Property {} accessed.", name) + } + } + } + DebuggerEvent::FunctionExitWithValue(r) => { + println!( + "! Return from function call '{}' => {:?}", + context + .global_runtime_state() + .debugger + .call_stack() + .last() + .unwrap() + .fn_name, + r + ) + } + DebuggerEvent::FunctionExitWithError(err) => { + println!( + "! Return from function call '{}' with error: {}", + context + .global_runtime_state() + .debugger + .call_stack() + .last() + .unwrap() + .fn_name, + err + ) + } + } + + // Print current source line + print_current_source(context, source, pos, lines, (0, 0)); + + // Read stdin for commands + let mut input = String::new(); + + loop { + print!("rhai-dbg> "); + + stdout().flush().expect("couldn't flush stdout"); + + input.clear(); + + match stdin().read_line(&mut input) { + Ok(0) => break Ok(DebuggerCommand::Continue), + Ok(_) => match input + .trim() + .split_whitespace() + .collect::>() + .as_slice() + { + ["help" | "h"] => print_debug_help(), + ["exit" | "quit" | "q" | "kill", ..] => { + println!("Script terminated. Bye!"); + exit(0); + } + ["node"] => { + if pos.is_none() { + println!("{:?}", node); + } else if let Some(source) = source { + println!("{:?} {} @ {:?}", node, source, pos); + } else { + println!("{:?} @ {:?}", node, pos); + } + println!(); + } + ["list" | "l"] => print_current_source(context, source, pos, &lines, (3, 6)), + ["list" | "l", n] if n.parse::().is_ok() => { + let num = n.parse::().unwrap(); + if num <= 0 || num > lines.len() { + eprintln!("\x1b[31mInvalid line: {}\x1b[39m", num); + } else { + let pos = Position::new(num as u16, 0); + print_current_source(context, source, pos, &lines, (3, 6)); + } + } + ["continue" | "c"] => break Ok(DebuggerCommand::Continue), + ["finish" | "f"] => break Ok(DebuggerCommand::FunctionExit), + [] | ["step" | "s"] => break Ok(DebuggerCommand::StepInto), + ["over" | "o"] => break Ok(DebuggerCommand::StepOver), + ["next" | "n"] => break Ok(DebuggerCommand::Next), + ["scope"] => print_scope(context.scope(), false), + ["print" | "p", "this"] => { + if let Some(value) = context.this_ptr() { + println!("=> {:?}", value); + } else { + println!("'this' pointer is unbound."); + } + } + ["print" | "p", var_name] => { + if let Some(value) = context.scope().get_value::(var_name) { + println!("=> {:?}", value); + } else { + eprintln!("Variable not found: {}", var_name); + } + } + ["print" | "p"] => { + print_scope(context.scope(), true); + if let Some(value) = context.this_ptr() { + println!("this = {:?}", value); + } + } + #[cfg(not(feature = "no_module"))] + ["imports"] => { + for (i, (name, module)) in context + .global_runtime_state() + .scan_imports_raw() + .enumerate() + { + println!( + "[{}] {} = {}", + i + 1, + name, + module.id().unwrap_or("") + ); + } + + println!(); + } + #[cfg(not(feature = "no_function"))] + ["backtrace" | "bt"] => { + for frame in context + .global_runtime_state() + .debugger + .call_stack() + .iter() + .rev() + { + println!("{}", frame) + } + } + ["info" | "i", "break" | "b"] => Iterator::for_each( + context + .global_runtime_state() + .debugger + .break_points() + .iter() + .enumerate(), + |(i, bp)| match bp { + #[cfg(not(feature = "no_position"))] + rhai::debugger::BreakPoint::AtPosition { pos, .. } => { + let line_num = format!("[{}] line ", i + 1); + print!("{}", line_num); + print_source(&lines, *pos, line_num.len(), (0, 0)); + } + _ => println!("[{}] {}", i + 1, bp), + }, + ), + ["enable" | "en", n] => { + if let Ok(n) = n.parse::() { + let range = 1..=context + .global_runtime_state_mut() + .debugger + .break_points() + .len(); + if range.contains(&n) { + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .get_mut(n - 1) + .unwrap() + .enable(true); + println!("Break-point #{} enabled.", n) + } else { + eprintln!("\x1b[31mInvalid break-point: {}\x1b[39m", n); + } + } else { + eprintln!("\x1b[31mInvalid break-point: '{}'\x1b[39m", n); + } + } + ["disable" | "dis", n] => { + if let Ok(n) = n.parse::() { + let range = 1..=context + .global_runtime_state_mut() + .debugger + .break_points() + .len(); + if range.contains(&n) { + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .get_mut(n - 1) + .unwrap() + .enable(false); + println!("Break-point #{} disabled.", n) + } else { + eprintln!("\x1b[31mInvalid break-point: {}\x1b[39m", n); + } + } else { + eprintln!("\x1b[31mInvalid break-point: '{}'\x1b[39m", n); + } + } + ["delete" | "d", n] => { + if let Ok(n) = n.parse::() { + let range = 1..=context + .global_runtime_state_mut() + .debugger + .break_points() + .len(); + if range.contains(&n) { + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .remove(n - 1); + println!("Break-point #{} deleted.", n) + } else { + eprintln!("\x1b[31mInvalid break-point: {}\x1b[39m", n); + } + } else { + eprintln!("\x1b[31mInvalid break-point: '{}'\x1b[39m", n); + } + } + ["delete" | "d"] => { + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .clear(); + println!("All break-points deleted."); + } + ["break" | "b", fn_name, args] => { + if let Ok(args) = args.parse::() { + let bp = rhai::debugger::BreakPoint::AtFunctionCall { + name: fn_name.trim().into(), + args, + enabled: true, + }; + println!("Break-point added for {}", bp); + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .push(bp); + } else { + eprintln!("\x1b[31mInvalid number of arguments: '{}'\x1b[39m", args); + } + } + // Property name + #[cfg(not(feature = "no_object"))] + ["break" | "b", param] if param.starts_with('.') && param.len() > 1 => { + let bp = rhai::debugger::BreakPoint::AtProperty { + name: param[1..].into(), + enabled: true, + }; + println!("Break-point added for {}", bp); + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .push(bp); + } + // Numeric parameter + #[cfg(not(feature = "no_position"))] + ["break" | "b", param] if param.parse::().is_ok() => { + let n = param.parse::().unwrap(); + let range = if source.is_none() { + 1..=lines.len() + } else { + 1..=(u16::MAX as usize) + }; + + if range.contains(&n) { + let bp = rhai::debugger::BreakPoint::AtPosition { + source: source.unwrap_or("").into(), + pos: Position::new(n as u16, 0), + enabled: true, + }; + println!("Break-point added {}", bp); + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .push(bp); + } else { + eprintln!("\x1b[31mInvalid line number: '{}'\x1b[39m", n); + } + } + // Function name parameter + ["break" | "b", param] => { + let bp = rhai::debugger::BreakPoint::AtFunctionName { + name: param.trim().into(), + enabled: true, + }; + println!("Break-point added for {}", bp); + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .push(bp); + } + #[cfg(not(feature = "no_position"))] + ["break" | "b"] => { + let bp = rhai::debugger::BreakPoint::AtPosition { + source: source.unwrap_or("").into(), + pos, + enabled: true, + }; + println!("Break-point added {}", bp); + context + .global_runtime_state_mut() + .debugger + .break_points_mut() + .push(bp); + } + ["throw"] => break Err(EvalAltResult::ErrorRuntime(Dynamic::UNIT, pos).into()), + ["throw", num] if num.trim().parse::().is_ok() => { + let value = num.trim().parse::().unwrap().into(); + break Err(EvalAltResult::ErrorRuntime(value, pos).into()); + } + #[cfg(not(feature = "no_float"))] + ["throw", num] if num.trim().parse::().is_ok() => { + let value = num.trim().parse::().unwrap().into(); + break Err(EvalAltResult::ErrorRuntime(value, pos).into()); + } + ["throw", ..] => { + let msg = input.trim().splitn(2, ' ').skip(1).next().unwrap_or(""); + break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into()); + } + ["run" | "r"] => { + println!("Restarting script..."); + break Err(EvalAltResult::ErrorTerminated(Dynamic::UNIT, pos).into()); + } + _ => eprintln!( + "\x1b[31mInvalid debugger command: '{}'\x1b[39m", + input.trim() + ), + }, + Err(err) => panic!("input error: {}", err), + } + } +} + fn main() { let title = format!("Rhai Debugger (version {})", env!("CARGO_PKG_VERSION")); println!("{}", title); @@ -181,71 +630,7 @@ fn main() { #[cfg(not(feature = "no_optimize"))] engine.set_optimization_level(rhai::OptimizationLevel::None); - let mut script = String::new(); - let main_ast; - - { - // Load init scripts - if let Some(filename) = env::args().skip(1).next() { - let filename = match Path::new(&filename).canonicalize() { - Err(err) => { - eprintln!("Error script file path: {}\n{}", filename, err); - exit(1); - } - Ok(f) => { - match f.strip_prefix(std::env::current_dir().unwrap().canonicalize().unwrap()) { - Ok(f) => f.into(), - _ => f, - } - } - }; - - let mut f = match File::open(&filename) { - Err(err) => { - eprintln!( - "Error reading script file: {}\n{}", - filename.to_string_lossy(), - err - ); - exit(1); - } - Ok(f) => f, - }; - - if let Err(err) = f.read_to_string(&mut script) { - println!( - "Error reading script file: {}\n{}", - filename.to_string_lossy(), - err - ); - exit(1); - } - - let script = if script.starts_with("#!") { - // Skip shebang - &script[script.find('\n').unwrap_or(0)..] - } else { - &script[..] - }; - - main_ast = match engine - .compile(&script) - .map_err(Into::>::into) - { - Err(err) => { - print_error(&script, *err); - exit(1); - } - Ok(ast) => ast, - }; - - println!("Script '{}' loaded.", filename.to_string_lossy()); - println!(); - } else { - eprintln!("No script file specified."); - exit(1); - } - } + let (ast, script) = load_script(&engine); // Hook up debugger let lines: Vec<_> = script.trim().split('\n').map(|s| s.to_string()).collect(); @@ -255,342 +640,7 @@ fn main() { || "".into(), // Main debugging interface move |context, event, node, source, pos| { - match event { - DebuggerEvent::Step => (), - DebuggerEvent::BreakPoint(n) => { - match context.global_runtime_state().debugger.break_points()[n] { - #[cfg(not(feature = "no_position"))] - BreakPoint::AtPosition { .. } => (), - BreakPoint::AtFunctionName { ref name, .. } - | BreakPoint::AtFunctionCall { ref name, .. } => { - println!("! Call to function {}.", name) - } - #[cfg(not(feature = "no_object"))] - BreakPoint::AtProperty { ref name, .. } => { - println!("! Property {} accessed.", name) - } - } - } - DebuggerEvent::FunctionExitWithValue(r) => { - println!( - "! Return from function call '{}' => {:?}", - context - .global_runtime_state() - .debugger - .call_stack() - .last() - .unwrap() - .fn_name, - r - ) - } - DebuggerEvent::FunctionExitWithError(err) => { - println!( - "! Return from function call '{}' with error: {}", - context - .global_runtime_state() - .debugger - .call_stack() - .last() - .unwrap() - .fn_name, - err - ) - } - } - - // Print current source line - print_current_source(context, source, pos, &lines); - - // Read stdin for commands - let mut input = String::new(); - - loop { - print!("rhai-dbg> "); - stdout().flush().expect("couldn't flush stdout"); - - input.clear(); - - match stdin().read_line(&mut input) { - Ok(0) => break Ok(DebuggerCommand::Continue), - Ok(_) => match input - .trim() - .split_whitespace() - .collect::>() - .as_slice() - { - ["help" | "h", ..] => print_debug_help(), - ["exit" | "quit" | "q" | "kill", ..] => { - println!("Script terminated. Bye!"); - exit(0); - } - ["node", ..] => { - if pos.is_none() { - println!("{:?}", node); - } else if let Some(source) = source { - println!("{:?} {} @ {:?}", node, source, pos); - } else { - println!("{:?} @ {:?}", node, pos); - } - println!(); - } - ["list" | "l", ..] => print_current_source(context, source, pos, &lines), - ["continue" | "c", ..] => break Ok(DebuggerCommand::Continue), - ["finish" | "f", ..] => break Ok(DebuggerCommand::FunctionExit), - [] | ["step" | "s", ..] => break Ok(DebuggerCommand::StepInto), - ["over", ..] => break Ok(DebuggerCommand::StepOver), - ["next" | "n", ..] => break Ok(DebuggerCommand::Next), - ["scope", ..] => print_scope(context.scope(), false), - ["print" | "p", "this"] => { - if let Some(value) = context.this_ptr() { - println!("=> {:?}", value); - } else { - println!("`this` pointer is unbound."); - } - } - ["print" | "p", var_name, ..] => { - if let Some(value) = context.scope().get_value::(var_name) { - println!("=> {:?}", value); - } else { - eprintln!("Variable not found: {}", var_name); - } - } - ["print" | "p"] => { - print_scope(context.scope(), true); - if let Some(value) = context.this_ptr() { - println!("this = {:?}", value); - } - } - #[cfg(not(feature = "no_module"))] - ["imports", ..] => { - for (i, (name, module)) in context - .global_runtime_state() - .scan_imports_raw() - .enumerate() - { - println!( - "[{}] {} = {}", - i + 1, - name, - module.id().unwrap_or("") - ); - } - - println!(); - } - #[cfg(not(feature = "no_function"))] - ["backtrace" | "bt", ..] => { - for frame in context - .global_runtime_state() - .debugger - .call_stack() - .iter() - .rev() - { - println!("{}", frame) - } - } - ["info", "break", ..] | ["i", "b", ..] => Iterator::for_each( - context - .global_runtime_state() - .debugger - .break_points() - .iter() - .enumerate(), - |(i, bp)| match bp { - #[cfg(not(feature = "no_position"))] - rhai::debugger::BreakPoint::AtPosition { pos, .. } => { - let line_num = format!("[{}] line ", i + 1); - print!("{}", line_num); - print_source(&lines, *pos, line_num.len()); - } - _ => println!("[{}] {}", i + 1, bp), - }, - ), - ["enable" | "en", n, ..] => { - if let Ok(n) = n.parse::() { - let range = 1..=context - .global_runtime_state_mut() - .debugger - .break_points() - .len(); - if range.contains(&n) { - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .get_mut(n - 1) - .unwrap() - .enable(true); - println!("Break-point #{} enabled.", n) - } else { - eprintln!("Invalid break-point: {}", n); - } - } else { - eprintln!("Invalid break-point: '{}'", n); - } - } - ["disable" | "dis", n, ..] => { - if let Ok(n) = n.parse::() { - let range = 1..=context - .global_runtime_state_mut() - .debugger - .break_points() - .len(); - if range.contains(&n) { - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .get_mut(n - 1) - .unwrap() - .enable(false); - println!("Break-point #{} disabled.", n) - } else { - eprintln!("Invalid break-point: {}", n); - } - } else { - eprintln!("Invalid break-point: '{}'", n); - } - } - ["delete" | "d", n, ..] => { - if let Ok(n) = n.parse::() { - let range = 1..=context - .global_runtime_state_mut() - .debugger - .break_points() - .len(); - if range.contains(&n) { - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .remove(n - 1); - println!("Break-point #{} deleted.", n) - } else { - eprintln!("Invalid break-point: {}", n); - } - } else { - eprintln!("Invalid break-point: '{}'", n); - } - } - ["delete" | "d", ..] => { - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .clear(); - println!("All break-points deleted."); - } - ["break" | "b", fn_name, args, ..] => { - if let Ok(args) = args.parse::() { - let bp = rhai::debugger::BreakPoint::AtFunctionCall { - name: fn_name.trim().into(), - args, - enabled: true, - }; - println!("Break-point added for {}", bp); - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .push(bp); - } else { - eprintln!("Invalid number of arguments: '{}'", args); - } - } - // Property name - #[cfg(not(feature = "no_object"))] - ["break" | "b", param] if param.starts_with('.') && param.len() > 1 => { - let bp = rhai::debugger::BreakPoint::AtProperty { - name: param[1..].into(), - enabled: true, - }; - println!("Break-point added for {}", bp); - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .push(bp); - } - // Numeric parameter - #[cfg(not(feature = "no_position"))] - ["break" | "b", param] if param.parse::().is_ok() => { - let n = param.parse::().unwrap(); - let range = if source.is_none() { - 1..=lines.len() - } else { - 1..=(u16::MAX as usize) - }; - - if range.contains(&n) { - let bp = rhai::debugger::BreakPoint::AtPosition { - source: source.unwrap_or("").into(), - pos: Position::new(n as u16, 0), - enabled: true, - }; - println!("Break-point added {}", bp); - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .push(bp); - } else { - eprintln!("Invalid line number: {}", n); - } - } - // Function name parameter - ["break" | "b", param] => { - let bp = rhai::debugger::BreakPoint::AtFunctionName { - name: param.trim().into(), - enabled: true, - }; - println!("Break-point added for {}", bp); - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .push(bp); - } - #[cfg(not(feature = "no_position"))] - ["break" | "b"] => { - let bp = rhai::debugger::BreakPoint::AtPosition { - source: source.unwrap_or("").into(), - pos, - enabled: true, - }; - println!("Break-point added {}", bp); - context - .global_runtime_state_mut() - .debugger - .break_points_mut() - .push(bp); - } - ["throw"] => { - break Err(EvalAltResult::ErrorRuntime(Dynamic::UNIT, pos).into()) - } - ["throw", num] if num.trim().parse::().is_ok() => { - let value = num.trim().parse::().unwrap().into(); - break Err(EvalAltResult::ErrorRuntime(value, pos).into()); - } - #[cfg(not(feature = "no_float"))] - ["throw", num] if num.trim().parse::().is_ok() => { - let value = num.trim().parse::().unwrap().into(); - break Err(EvalAltResult::ErrorRuntime(value, pos).into()); - } - ["throw", ..] => { - let msg = input.trim().splitn(2, ' ').skip(1).next().unwrap_or(""); - break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into()); - } - ["run" | "r", ..] => { - println!("Restarting script..."); - break Err(EvalAltResult::ErrorTerminated(Dynamic::UNIT, pos).into()); - } - [cmd, ..] => eprintln!("Invalid debugger command: '{}'", cmd), - }, - Err(err) => panic!("input error: {}", err), - } - } + debug_callback(context, event, node, source, pos, &lines) }, ); @@ -603,10 +653,11 @@ fn main() { engine.set_module_resolver(resolver); } - print_debug_help(); + println!("Type 'help' for commands list."); + println!(); // Evaluate - while let Err(err) = engine.run_ast_with_scope(&mut Scope::new(), &main_ast) { + while let Err(err) = engine.run_ast_with_scope(&mut Scope::new(), &ast) { match *err { // Loop back to restart EvalAltResult::ErrorTerminated(..) => (),