use neorusticus::{PrologEngine, quick_query};
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
println!("=== Neorusticus Prolog Engine Demo ===\n");
let mut engine = PrologEngine::with_limits(50);
println!("=== Testing Basic Operations ===");
match engine.parse_and_add("parent(tom, bob).") {
Ok(()) => println!("✓ Successfully added: parent(tom, bob)."),
Err(e) => {
println!("✗ Failed to add clause:");
engine.print_error(&e);
}
}
match engine.parse_and_add("parent(bob, ann).") {
Ok(()) => println!("✓ Successfully added: parent(bob, ann)."),
Err(e) => {
println!("✗ Failed to add clause:");
engine.print_error(&e);
}
}
println!("\n=== Testing Error Handling ===");
println!("Testing syntax errors:");
if let Err(e) = engine.parse_and_add("parent(tom bob).") { println!("✓ Caught syntax error: {}", e);
}
if let Err(e) = engine.parse_and_add("parent(tom, bob") { println!("✓ Caught delimiter error: {}", e);
}
if let Err(e) = engine.parse_and_add("parent(tom, bob)") { println!("✓ Caught missing dot error: {}", e);
}
if let Err(e) = engine.parse_and_add("parent(tom, 999999999999999999999).") { println!("✓ Caught number overflow error: {}", e);
}
println!("\n=== Testing Arithmetic Error Handling ===");
engine.parse_and_add("test_arith :- X is 5 + 3.")?;
if let Err(e) = engine.parse_query("X is 5 // 0.") {
println!("✓ Caught division by zero: {}", e);
}
if let Err(e) = engine.parse_query("X is Y + 1.") {
println!("✓ Caught uninstantiated variable: {}", e);
}
if let Err(e) = engine.parse_query("X is atom + 1.") {
println!("✓ Caught type mismatch: {}", e);
}
match engine.parse_query("X is 2 + 3 * 4.") {
Ok(solutions) => {
println!("✓ Arithmetic success:");
engine.print_solutions(&solutions, &["X".to_string()]);
}
Err(e) => {
println!("✗ Unexpected arithmetic error:");
engine.print_boxed_error(&e);
}
}
println!("\n=== Testing List Error Handling ===");
if let Err(e) = engine.parse_query("member(X, not_a_list).") {
println!("✓ Caught invalid list structure: {}", e);
}
if let Err(e) = engine.parse_query("length(L, 3).") {
println!("✓ Caught uninstantiated list: {}", e);
}
match engine.parse_query("append([1, 2], [3, 4], X).") {
Ok(solutions) => {
println!("✓ List append success:");
engine.print_solutions(&solutions, &["X".to_string()]);
}
Err(e) => {
println!("✗ Unexpected list error:");
engine.print_boxed_error(&e);
}
}
println!("\n=== Testing Predicate Suggestions ===");
if let Err(e) = engine.parse_query("lentgh([1, 2, 3], X).") { println!("✓ Predicate suggestion: {}", e);
}
if let Err(e) = engine.parse_query("appendd([1], [2], X).") { println!("✓ Predicate suggestion: {}", e);
}
println!("\n=== Testing Stack Overflow Protection ===");
let mut test_engine = PrologEngine::with_limits(5);
match test_engine.parse_and_add("infinite(X) :- infinite(X).") {
Ok(_) => {
match test_engine.parse_query("infinite(test).") {
Ok(_) => println!("✗ Failed to catch infinite recursion"),
Err(e) => println!("✓ Caught infinite recursion: {}", e),
}
}
Err(e) => {
println!("✗ Failed to add infinite rule: {}", e);
}
}
println!("\n=== Testing Cut Operations ===");
engine.parse_and_add("max(X, Y, X) :- X >= Y, !.")?;
engine.parse_and_add("max(X, Y, Y).")?;
match engine.parse_query("max(5, 3, Z).") {
Ok(solutions) => {
println!("✓ Cut operation success:");
engine.print_solutions(&solutions, &["Z".to_string()]);
}
Err(e) => {
println!("✗ Unexpected cut error:");
engine.print_boxed_error(&e);
}
}
println!("\n=== Engine Statistics ===");
println!("{}", engine.get_stats());
println!("\n=== Testing Complex Query ===");
engine.parse_and_add("complex(X, Y) :- X > 0, Y is X * 2, Y < 20.")?;
match engine.parse_query("complex(5, Z).") {
Ok(solutions) => {
println!("✓ Complex query success:");
engine.print_solutions(&solutions, &["Z".to_string()]);
}
Err(e) => {
println!("✗ Complex query error:");
engine.print_boxed_error(&e);
}
}
println!("\n=== Testing Error Recovery ===");
match engine.parse_query("parent(tom, X).") {
Ok(solutions) => {
println!("✓ Engine recovered, normal operation:");
engine.print_solutions(&solutions, &["X".to_string()]);
}
Err(e) => {
println!("✗ Engine failed to recover:");
engine.print_boxed_error(&e);
}
}
println!("\n=== Testing Quick Query Function ===");
let clauses = &[
"ancestor(X, Y) :- parent(X, Y).",
"ancestor(X, Z) :- parent(X, Y), ancestor(Y, Z).",
"parent(alice, bob).",
"parent(bob, charlie).",
"parent(charlie, diana).",
];
match quick_query(clauses, "ancestor(alice, diana).") {
Ok(solutions) => {
println!("✓ Quick query found {} solutions", solutions.len());
}
Err(e) => {
println!("✗ Quick query failed: {}", e);
}
}
println!("\n=== All tests completed ===");
Ok(())
}