diff --git a/Cargo.toml b/Cargo.toml index 1cbe295..3b3125d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] - +resolver = "2" members = [ "rulog_core", "rulog_cli", diff --git a/rulog_core/src/types/ast.rs b/rulog_core/src/types/ast.rs index 8d5f538..af1a1b6 100644 --- a/rulog_core/src/types/ast.rs +++ b/rulog_core/src/types/ast.rs @@ -29,6 +29,38 @@ pub enum Term { Structure(String, Vec), } +impl std::fmt::Display for Term { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Term::Atom(s) => write!(f, "{}", s), + Term::Variable(s) => write!(f, "{}", s), + Term::Integer(i) => write!(f, "{}", i), + Term::Float(Float(val)) => write!(f, "{}", val), + Term::String(s) => write!(f, "\"{}\"", s), + Term::List(terms) => { + write!(f, "[")?; + for (i, term) in terms.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", term)?; + } + write!(f, "]") + } + Term::Structure(name, terms) => { + write!(f, "{}(", name)?; + for (i, term) in terms.iter().enumerate() { + if i > 0 { + write!(f, ", ")?; + } + write!(f, "{}", term)?; + } + write!(f, ")") + } + } + } +} + #[derive(Debug, PartialEq, Clone)] pub struct Float(pub f64); diff --git a/rulog_vm/src/environment.rs b/rulog_vm/src/environment.rs index e143478..5b53397 100644 --- a/rulog_vm/src/environment.rs +++ b/rulog_vm/src/environment.rs @@ -19,6 +19,14 @@ impl Environment { self.bind(var, term); self } + + pub fn is_empty(&self) -> bool { + self.bindings.is_empty() + } + + pub fn iter(&self) -> std::collections::hash_map::Iter { + self.bindings.iter() + } } impl FromIterator<(std::string::String, Term)> for Environment { diff --git a/rulog_vm/src/interpreter.rs b/rulog_vm/src/interpreter.rs index 6cb8acb..00e03d0 100644 --- a/rulog_vm/src/interpreter.rs +++ b/rulog_vm/src/interpreter.rs @@ -3,9 +3,11 @@ use rulog_core::{ types::ast::{Clause, Directive, OperatorDefinition, Predicate, Query}, }; -use std::collections::HashMap; +use std::io::{self, Write}; +use std::{cell::RefCell, collections::HashMap}; use crate::{ + environment::Environment, resolver::{QuerySolution, QuerySolver}, types::InterpretingError, }; @@ -60,7 +62,7 @@ impl Interpreter { handler: Option<&dyn SolutionHandler>, ) -> Result<(), InterpretingError> { log::trace!("handle query: {:?}", query); - let handler = handler.unwrap_or(&PrintSolutionHandler); + let handler = handler.unwrap_or(&ConsoleSolutionHandler); let query_solver = QuerySolver::new(self.clauses.clone(), query); let mut has_solution = false; @@ -94,13 +96,54 @@ impl Interpreter { Ok(()) } } +pub struct WriteSolutionHandler<'a, W: Write> { + writer: RefCell<&'a mut W>, +} + +impl<'a, W: Write> WriteSolutionHandler<'a, W> { + pub fn new(writer: &'a mut W) -> Self { + WriteSolutionHandler { + writer: RefCell::new(writer), + } + } + + fn print_solution(&self, solution: Option<&QuerySolution>) -> io::Result<()> { + let mut writer = self.writer.borrow_mut(); + if let Some(solution) = solution { + if solution.env.is_empty() { + writeln!(writer, "true.")?; + } else { + self.print_env(&mut writer, &solution.env)?; + } + } else { + writeln!(writer, "false.")?; + } + Ok(()) + } + + fn print_env(&self, writer: &mut W, env: &Environment) -> io::Result<()> { + let mut env_str = String::new(); + for (var, term) in env.iter() { + env_str.push_str(&format!("{} = {}, ", var, term)); + } + writeln!(writer, "{{{}}}.", env_str.trim_end_matches(", "))?; + Ok(()) + } +} + +impl<'a, W: Write> SolutionHandler for WriteSolutionHandler<'a, W> { + fn handle_solution(&self, solution: Option<&QuerySolution>) -> bool { + self.print_solution(solution).is_ok() + } +} -pub struct PrintSolutionHandler; +pub struct ConsoleSolutionHandler; -impl SolutionHandler for PrintSolutionHandler { +impl SolutionHandler for ConsoleSolutionHandler { fn handle_solution(&self, solution: Option<&QuerySolution>) -> bool { - println!("solution: {:?}", solution); - true // Continue processing + let mut writer = io::stdout(); + let handler = WriteSolutionHandler::new(&mut writer); + handler.handle_solution(solution) } }