init
This commit is contained in:
commit
0de67fd423
13 changed files with 1263 additions and 0 deletions
226
iagorithms/src/lib.rs
Normal file
226
iagorithms/src/lib.rs
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
use neorusticus::{PrologEngine, quick_query};
|
||||
use std::error::Error;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn init() -> Result<(), Box<dyn Error>> {
|
||||
println!("=== Neorusticus Prolog Engine Demo ===\n");
|
||||
|
||||
// Create engine with conservative limits for safety
|
||||
let mut engine = PrologEngine::with_limits(50);
|
||||
|
||||
// Test basic parsing with error handling
|
||||
println!("=== Testing Basic Operations ===");
|
||||
|
||||
// Test successful 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);
|
||||
}
|
||||
}
|
||||
|
||||
// Test error cases
|
||||
println!("\n=== Testing Error Handling ===");
|
||||
|
||||
// Test syntax errors
|
||||
println!("Testing syntax errors:");
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom bob).") {
|
||||
// Missing comma
|
||||
println!("✓ Caught syntax error: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom, bob") {
|
||||
// Missing closing paren
|
||||
println!("✓ Caught delimiter error: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom, bob)") {
|
||||
// Missing dot
|
||||
println!("✓ Caught missing dot error: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_and_add("parent(tom, 999999999999999999999).") {
|
||||
// Number too large
|
||||
println!("✓ Caught number overflow error: {}", e);
|
||||
}
|
||||
|
||||
// Test arithmetic operations with error handling
|
||||
println!("\n=== Testing Arithmetic Error Handling ===");
|
||||
|
||||
engine.parse_and_add("test_arith :- X is 5 + 3.")?;
|
||||
|
||||
// Test division by zero
|
||||
if let Err(e) = engine.parse_query("X is 5 // 0.") {
|
||||
println!("✓ Caught division by zero: {}", e);
|
||||
}
|
||||
|
||||
// Test uninstantiated variable in arithmetic
|
||||
if let Err(e) = engine.parse_query("X is Y + 1.") {
|
||||
println!("✓ Caught uninstantiated variable: {}", e);
|
||||
}
|
||||
|
||||
// Test type mismatch
|
||||
if let Err(e) = engine.parse_query("X is atom + 1.") {
|
||||
println!("✓ Caught type mismatch: {}", e);
|
||||
}
|
||||
|
||||
// Test successful arithmetic
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Test list operations with error handling
|
||||
println!("\n=== Testing List Error Handling ===");
|
||||
|
||||
// Test invalid list structure
|
||||
if let Err(e) = engine.parse_query("member(X, not_a_list).") {
|
||||
println!("✓ Caught invalid list structure: {}", e);
|
||||
}
|
||||
|
||||
// Test uninstantiated list
|
||||
if let Err(e) = engine.parse_query("length(L, 3).") {
|
||||
println!("✓ Caught uninstantiated list: {}", e);
|
||||
}
|
||||
|
||||
// Test successful list operations
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Test predicate suggestions
|
||||
println!("\n=== Testing Predicate Suggestions ===");
|
||||
|
||||
if let Err(e) = engine.parse_query("lentgh([1, 2, 3], X).") {
|
||||
// Typo in "length"
|
||||
println!("✓ Predicate suggestion: {}", e);
|
||||
}
|
||||
|
||||
if let Err(e) = engine.parse_query("appendd([1], [2], X).") {
|
||||
// Typo in "append"
|
||||
println!("✓ Predicate suggestion: {}", e);
|
||||
}
|
||||
|
||||
// Test stack overflow protection with a safer approach
|
||||
println!("\n=== Testing Stack Overflow Protection ===");
|
||||
|
||||
// Use a very conservative engine for this test
|
||||
let mut test_engine = PrologEngine::with_limits(5);
|
||||
|
||||
// Add the infinite recursion rule to the test engine only
|
||||
match test_engine.parse_and_add("infinite(X) :- infinite(X).") {
|
||||
Ok(_) => {
|
||||
// Now test the query with the dangerous rule
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Test cut operations
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Display engine statistics
|
||||
println!("\n=== Engine Statistics ===");
|
||||
println!("{}", engine.get_stats());
|
||||
|
||||
// Test complex query with multiple error possibilities
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Test recovery from errors
|
||||
println!("\n=== Testing Error Recovery ===");
|
||||
|
||||
// Even after errors, the engine should continue to work
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// Demonstrate the quick_query convenience function
|
||||
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 ===");
|
||||
panic!();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue