use anyhow::Result;
pub fn handle_eval_command(expr: &str, verbose: bool, format: &str, trace: bool) -> Result<()> {
if trace {
std::env::set_var("RUCHY_TRACE", "1");
} else {
std::env::remove_var("RUCHY_TRACE");
}
if verbose {
eprintln!("Parsing expression: {expr}");
}
let mut repl = super::create_repl()?;
let expr_to_eval = if expr.contains("fun main(") {
format!("{expr}\nmain()")
} else {
expr.to_string()
};
match repl.eval(&expr_to_eval) {
Ok(result) => {
if verbose {
eprintln!("Evaluation successful");
}
if result != "nil" && !result.is_empty() {
println!("{result}");
use std::io::Write;
let _ = std::io::stdout().flush();
}
Ok(())
}
Err(e) => {
if verbose {
eprintln!("Evaluation failed: {e}");
}
print_eval_error(&e, format);
Err(e)
}
}
}
#[allow(dead_code)]
pub fn print_eval_success(result: &str, format: &str) {
if format == "json" {
let result_str = result.replace('"', "\\\"");
println!("{{\"success\":true,\"result\":\"{result_str}\"}}");
} else {
println!("{result}");
}
}
pub fn print_eval_error(e: &anyhow::Error, format: &str) {
if format == "json" {
println!(
"{}",
serde_json::json!({
"success": false,
"error": e.to_string()
})
);
} else {
eprintln!("Error: {e}");
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_print_eval_success_json() {
let result = "42";
let format = "json";
if format == "json" {
let result_str = result.replace('"', "\\\"");
let output = format!("{{\"success\":true,\"result\":\"{result_str}\"}}");
assert!(output.contains("success"));
assert!(output.contains("true"));
assert!(output.contains("42"));
}
}
#[test]
fn test_print_eval_success_text() {
let result = "42";
let format = "text";
if format != "json" {
assert_eq!(result, "42");
}
}
#[test]
fn test_expr_with_main_detection() {
let expr = "fun main() { 42 }";
assert!(expr.contains("fun main("));
}
#[test]
fn test_expr_without_main() {
let expr = "2 + 2";
assert!(!expr.contains("fun main("));
}
#[test]
fn test_nil_result_not_printed() {
let result = "nil";
assert!(result == "nil" || result.is_empty());
}
#[test]
fn test_empty_result_not_printed() {
let result = "";
assert!(result == "nil" || result.is_empty());
}
#[test]
fn test_print_eval_error_text_format() {
let error = anyhow::anyhow!("Test error message");
print_eval_error(&error, "text");
}
#[test]
fn test_print_eval_error_json_format() {
let error = anyhow::anyhow!("Parse error");
print_eval_error(&error, "json");
}
#[test]
fn test_print_eval_success_formats() {
print_eval_success("42", "text");
print_eval_success("42", "json");
print_eval_success("hello world", "text");
print_eval_success("hello world", "json");
}
#[test]
fn test_main_function_detection_patterns() {
let patterns = [
("fun main() { }", true),
("fun main(args) { }", true),
("fun foo() { }", false),
("let main = 42", false),
("// fun main()", false),
];
for (expr, should_have_main) in &patterns {
assert_eq!(expr.contains("fun main("), *should_have_main);
}
}
#[test]
fn test_result_filtering_logic() {
let results = ["nil", "", "42", "hello", "true"];
for result in &results {
let should_print = *result != "nil" && !result.is_empty();
if *result == "42" || *result == "hello" || *result == "true" {
assert!(should_print);
} else {
assert!(!should_print);
}
}
}
#[test]
fn test_json_escaping_in_success() {
let result = "hello \"world\"";
let escaped = result.replace('"', "\\\"");
assert_eq!(escaped, "hello \\\"world\\\"");
}
#[test]
fn test_handle_eval_command_simple_expr() {
let result = handle_eval_command("2 + 2", false, "text", false);
assert!(result.is_ok());
}
#[test]
fn test_handle_eval_command_with_trace() {
let result = handle_eval_command("42", false, "text", true);
std::env::remove_var("RUCHY_TRACE");
assert!(result.is_ok());
}
#[test]
fn test_handle_eval_command_verbose() {
let result = handle_eval_command("1 + 1", true, "text", false);
assert!(result.is_ok());
}
#[test]
fn test_handle_eval_command_json_format() {
let result = handle_eval_command("42", false, "json", false);
assert!(result.is_ok());
}
#[test]
fn test_handle_eval_command_invalid_syntax() {
let result = handle_eval_command("let x = {", false, "text", false);
assert!(result.is_err());
}
#[test]
fn test_trace_env_var_setting() {
std::env::set_var("RUCHY_TRACE", "1");
assert_eq!(std::env::var("RUCHY_TRACE").unwrap(), "1");
std::env::remove_var("RUCHY_TRACE");
assert!(std::env::var("RUCHY_TRACE").is_err());
}
}