From b927892b3b2ac620a2a2dca48fd8a444af610a10 Mon Sep 17 00:00:00 2001 From: pluveto Date: Fri, 22 Nov 2024 10:17:42 +0800 Subject: [PATCH 1/4] feat: implement Display trait for Term enum to format output various variants. --- rulog_core/src/types/ast.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) 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); From 80dcb9c3d70f44f0400794a5bee1ecd86a939122 Mon Sep 17 00:00:00 2001 From: pluveto Date: Fri, 22 Nov 2024 10:17:59 +0800 Subject: [PATCH 2/4] chore: update Cargo.toml to set the resolver to version 2. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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", From 226420e4e7b744a8c3ea389b0fb4bc5c080a7a75 Mon Sep 17 00:00:00 2001 From: pluveto Date: Fri, 22 Nov 2024 10:18:10 +0800 Subject: [PATCH 3/4] chore: add `is_empty` and `iter` methods to the ` struct for improved functionality. --- rulog_vm/src/environment.rs | 8 ++++++++ 1 file changed, 8 insertions(+) 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 { From f1ee236b15bb876bd59c955d150a1386ede5cf2d Mon Sep 17 00:00:00 2001 From: pluveto Date: Fri, 22 Nov 2024 10:18:37 +0800 Subject: [PATCH 4/4] refactor: in the interpreter module, SolutionHandler output. Updated ConsoleSolutionHandler to use the new handler for printing solutions. --- rulog_vm/src/interpreter.rs | 55 +++++++++++++++++++++++++++++++++---- 1 file changed, 49 insertions(+), 6 deletions(-) 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) } }