From 7047fea8f48c3f2f39bed6a9cab4ad924e0a1faa Mon Sep 17 00:00:00 2001 From: pluveto Date: Fri, 15 Dec 2023 10:59:55 +0800 Subject: [PATCH] chore: remove residule --- rulog-core/src/types/ast.rs | 73 ------- rulog-vm/src/environment.rs | 33 --- rulog-vm/src/interpreter.rs | 192 ----------------- rulog-vm/src/lib.rs | 58 ------ rulog-vm/src/resolver.rs | 403 ------------------------------------ rulog-vm/src/types.rs | 6 - 6 files changed, 765 deletions(-) delete mode 100644 rulog-core/src/types/ast.rs delete mode 100644 rulog-vm/src/environment.rs delete mode 100644 rulog-vm/src/interpreter.rs delete mode 100644 rulog-vm/src/lib.rs delete mode 100644 rulog-vm/src/resolver.rs delete mode 100644 rulog-vm/src/types.rs diff --git a/rulog-core/src/types/ast.rs b/rulog-core/src/types/ast.rs deleted file mode 100644 index 8d5f538..0000000 --- a/rulog-core/src/types/ast.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::hash::Hasher; - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Directive { - Predicate(Predicate), - OperatorDefinition(OperatorDefinition), -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct OperatorDefinition { - pub priority: i64, - pub operator_type: String, - pub atom: String, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct Query { - pub predicates: Vec, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Term { - Atom(String), - Variable(String), - Integer(i64), - Float(Float), - String(String), - List(Vec), - Structure(String, Vec), -} - -#[derive(Debug, PartialEq, Clone)] -pub struct Float(pub f64); - -impl std::hash::Hash for Float { - fn hash(&self, state: &mut H) { - if self.0.is_nan() { - // You can use a constant or a custom value to represent NaN - u64::MAX.hash(state); - } else { - self.0.to_bits().hash(state); - } - } -} - -impl From for Float { - fn from(f: f64) -> Self { - Float(f) - } -} - -impl Eq for Float {} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct Predicate { - pub name: String, - pub terms: Vec, -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub enum Clause { - /// A directive, such as `:- use_module(library(lists)).` - Directive(Directive), - /// A query, such as `?- parent(X, a).` - Query(Query), - /// A fact, such as `parent(a, b).` - Fact(Predicate), - /// A rule, such as `parent(X, Y) :- father(X, Y).` - Rule(Predicate, Vec), -} - -#[derive(Debug, PartialEq, Eq, Hash, Clone)] -pub struct Program(pub Vec); diff --git a/rulog-vm/src/environment.rs b/rulog-vm/src/environment.rs deleted file mode 100644 index 0110360..0000000 --- a/rulog-vm/src/environment.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::collections::HashMap; - -use rulog_core::types::ast::Term; -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct Environment { - pub bindings: HashMap, -} - -impl Environment { - pub fn new() -> Self { - Environment { - bindings: HashMap::new(), - } - } - - pub fn bind(&mut self, var: String, term: Term) { - self.bindings.insert(var, term); - } - - pub fn lookup(&self, var: &String) -> Option<&Term> { - self.bindings.get(var) - } -} - -impl FromIterator<(std::string::String, Term)> for Environment { - fn from_iter>(iter: T) -> Self { - let mut env = Environment::new(); - for (var, term) in iter { - env.bind(var, term); - } - env - } -} diff --git a/rulog-vm/src/interpreter.rs b/rulog-vm/src/interpreter.rs deleted file mode 100644 index 317b833..0000000 --- a/rulog-vm/src/interpreter.rs +++ /dev/null @@ -1,192 +0,0 @@ -use rulog_core::{ - parser::parse, - types::ast::{Clause, Directive, OperatorDefinition, Predicate, Query}, -}; - -use std::collections::HashMap; - -use crate::{ - resolver::{QuerySolution, QuerySolver}, - types::InterpretingError, -}; - -pub struct Interpreter { - clauses: Vec<(Predicate, Vec)>, - operator_definitions: HashMap, - - on_solution: Option bool>>, -} - -impl Interpreter { - pub fn new() -> Self { - Interpreter { - clauses: Vec::new(), - operator_definitions: HashMap::new(), - on_solution: None, - } - } - - pub fn on_solution(&mut self, f: F) - where - F: Fn(&QuerySolution) -> bool + 'static, - { - self.on_solution = Some(Box::new(f)); - } - - pub fn eval(&mut self, input: &str) -> Result<(), InterpretingError> { - let program = parse(input).map_err(InterpretingError::ParseError)?; - for clause in program.0 { - let ret = match clause { - Clause::Directive(directive) => self.handle_directive(directive), - Clause::Query(query) => self.handle_query(query), - Clause::Fact(fact) => self.handle_fact(fact), - Clause::Rule(rule_head, rule_body) => self.handle_rule(rule_head, rule_body), - }; - - if let Err(e) = ret { - return Err(e); - } - } - - Ok(()) - } - - fn handle_directive(&mut self, directive: Directive) -> Result<(), InterpretingError> { - log::trace!("handle directive: {:?}", directive); - match directive { - Directive::OperatorDefinition(op_def) => { - self.operator_definitions - .insert(op_def.atom.clone(), op_def); - } - Directive::Predicate(pred) => { - self.clauses.push((pred, Vec::new())); - } - } - Ok(()) - } - - fn handle_query(&mut self, query: Query) -> Result<(), InterpretingError> { - log::trace!("handle query resolved: {:?}", query); - let mut query_solver = QuerySolver::new(self.clauses.clone(), query); - if let Some(ref on_solution) = self.on_solution { - while let Some(solution) = query_solver.next() { - if !on_solution(&solution) { - break; - } - } - } else { - for solution in query_solver { - println!("solution: {:?}", solution); - } - } - - Ok(()) - } - - fn handle_fact(&mut self, fact: Predicate) -> Result<(), InterpretingError> { - log::trace!("handle fact: {:?}", fact); - self.clauses.push((fact, Vec::new())); - Ok(()) - } - - fn handle_rule( - &mut self, - rule_head: Predicate, - rule_body: Vec, - ) -> Result<(), InterpretingError> { - log::trace!("handle rule: {:?} :- {:?}", rule_head, rule_body); - self.clauses.push((rule_head, rule_body)); - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use std::io::Write; - - fn setup_logger() { - use log::LevelFilter; - let _ = env_logger::builder() - .is_test(true) - .format(|buf, record| { - writeln!( - buf, - "{}:{} \t[{}] - {}", - record.file().unwrap_or("unknown"), - record.line().unwrap_or(0), - record.level(), - record.args() - ) - }) - .filter_level(LevelFilter::Trace) - .try_init(); - } - - #[test] - fn test_parent_true() { - setup_logger(); - let mut vm = Interpreter::new(); - let ret = vm.eval( - r#" - parent(tom, liz). - ?- parent(tom, liz). - "#, - ); - assert!(ret.is_ok(), "{:?}", ret); - } - - #[test] - fn test_parent_false() { - setup_logger(); - let mut vm = Interpreter::new(); - let ret = vm.eval( - r#" - parent(tom, liz). - ?- parent(liz, tom). - "#, - ); - assert!(ret.is_ok(), "{:?}", ret); - } - - #[test] - fn test_parent_var() { - setup_logger(); - let mut vm = Interpreter::new(); - let ret = vm.eval( - r#" - parent(tom, liz). - ?- parent(X, liz). - "#, - ); - assert!(ret.is_ok(), "{:?}", ret); - } - - #[test] - fn test_parent_var_multiple() { - setup_logger(); - let mut vm = Interpreter::new(); - let ret = vm.eval( - r#" - parent(tom, liz). - parent(tom, bob). - ?- parent(X, liz). - "#, - ); - assert!(ret.is_ok(), "{:?}", ret); - } - - #[test] - fn test_parent_var_multiple_children() { - setup_logger(); - let mut vm = Interpreter::new(); - let ret = vm.eval( - r#" - parent(tom, liz). - parent(tom, bob). - ?- parent(tom, X). - "#, - ); - assert!(ret.is_ok(), "{:?}", ret); - } -} diff --git a/rulog-vm/src/lib.rs b/rulog-vm/src/lib.rs deleted file mode 100644 index 1f43ba5..0000000 --- a/rulog-vm/src/lib.rs +++ /dev/null @@ -1,58 +0,0 @@ -pub mod environment; -pub mod interpreter; -pub mod resolver; -pub mod types; - -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - fn setup_logger() { - use log::LevelFilter; - let _ = env_logger::builder() - .is_test(true) - .filter_level(LevelFilter::Trace) - .try_init(); - } - - fn load_specs() -> std::io::Result> { - use std::fs; - use std::path::Path; - - let mut specs = Vec::new(); - - let entries = fs::read_dir("spec/")?; - - for entry in entries { - let entry = entry?; - if let Some(file_name) = entry.file_name().to_str() { - if !file_name.ends_with(".ans") { - continue; - } - let spec_name = file_name.trim_end_matches(".ans"); - if !Path::new(&format!("spec/{}", spec_name)).exists() { - log::warn!("skip spec/{}", spec_name); - continue; - } - specs.push(spec_name.to_string()); - } - } - - Ok(specs) - } - - #[test] - fn test_all_specs() { - setup_logger(); - let specs = load_specs().unwrap(); - for spec in specs { - log::info!("test spec/{}", spec); - let result = add(2, 2); - assert_eq!(result, 4); - } - } -} diff --git a/rulog-vm/src/resolver.rs b/rulog-vm/src/resolver.rs deleted file mode 100644 index 9632b88..0000000 --- a/rulog-vm/src/resolver.rs +++ /dev/null @@ -1,403 +0,0 @@ -use rulog_core::types::ast::{Predicate, Query, Term}; - -use crate::environment::Environment; - -#[derive(Debug, PartialEq, Eq, Clone)] -pub struct QuerySolution { - pub env: Environment, -} - -pub struct QuerySolver { - pub query: Query, - pub clauses: Vec<(Predicate, Vec)>, - state: Vec<(Predicate, Environment)>, - index: usize, -} - -impl QuerySolver { - pub fn new(rules: Vec<(Predicate, Vec)>, query: Query) -> QuerySolver { - let initial_state = query - .predicates - .iter() - .map(|predicate| (predicate.clone(), Environment::new())) - .collect(); - - QuerySolver { - clauses: rules, - query, - index: 0, - state: initial_state, - } - } -} - -impl Iterator for QuerySolver { - type Item = QuerySolution; - - fn next(&mut self) -> Option { - while !self.state.is_empty() { - if self.index >= self.clauses.len() { - self.index = 0; - self.state.pop(); - continue; - } - - let (goal, env) = self.state.last().unwrap().clone(); - let clause = self.clauses[self.index].clone(); - self.index += 1; - - if let Some(new_env) = self.try_unify_and_expand(&goal, &env, &clause) { - if self.state.last().unwrap().1 == new_env { - self.state.pop(); - } - return Some(QuerySolution { env: new_env }); - } - } - - None - } -} - -impl QuerySolver { - fn try_unify_and_expand( - &mut self, - goal: &Predicate, - env: &Environment, - clause: &(Predicate, Vec), - ) -> Option { - // First, check if the goal can be unified with the head of the clause. - if goal.name != clause.0.name { - return None; - } - - // Attempt unification of the terms of the goal and the clause. - if let Some(new_env) = unify_terms(&goal.terms, &clause.0.terms) { - // Compose the new environment with the existing one. - let new_env = compose(&env, &new_env); - - // If the clause has a body, we need to expand the state with the new sub-goals. - if !clause.1.is_empty() { - let new_goals = clause.1.iter().map(|predicate| { - ( - Predicate { - name: predicate.name.clone(), - terms: apply_env_terms(&predicate.terms, &new_env), - }, - new_env.clone(), - ) - }); - - // Extend the state with the new goals in reverse order. - self.state.extend(new_goals.rev()); - } - - // If the clause is a fact (no body), or after adding new goals for a rule, - // return the new environment. - return Some(new_env); - } - - None - } -} - -#[test] -fn test_query_solver_no_var() { - let rules = vec![( - Predicate { - name: "parent".to_string(), - terms: vec![Term::Atom("a".to_string())], - }, - vec![], - )]; - let query = Query { - predicates: vec![Predicate { - name: "parent".to_string(), - terms: vec![Term::Atom("a".to_string())], - }], - }; - - let mut query_solver = QuerySolver::new(rules, query); - let next_solution = query_solver.next(); - assert_eq!( - next_solution, - Some(QuerySolution { - env: Environment::new() - }) - ); - assert_eq!(query_solver.next(), None); -} - -#[test] -fn test_query_solver_with_var() { - /* - f(a). - ?- f(X). % expect X = a - */ - let rules = vec![( - Predicate { - name: "f".to_string(), - terms: vec![Term::Atom("a".to_string())], - }, - vec![], - )]; - let query = Query { - predicates: vec![Predicate { - name: "f".to_string(), - terms: vec![Term::Variable("X".to_string())], - }], - }; - - let mut query_solver = QuerySolver::new(rules, query); - let next_solution = query_solver.next(); - assert_eq!( - next_solution, - Some(QuerySolution { - env: [("X".to_string(), Term::Atom("a".to_string()))] - .iter() - .cloned() - .collect() - }) - ); - assert_eq!(query_solver.next(), None); -} - -#[test] -fn test_query_solver() { - /* - parent(tom, liz). - parent(tom, bob). - ?- parent(tom, X). - */ - let rules = vec![ - ( - Predicate { - name: "parent".to_string(), - terms: vec![Term::Atom("tom".to_string()), Term::Atom("liz".to_string())], - }, - vec![], - ), - ( - Predicate { - name: "parent".to_string(), - terms: vec![Term::Atom("tom".to_string()), Term::Atom("bob".to_string())], - }, - vec![], - ), - ]; - - let query = Query { - predicates: vec![Predicate { - name: "parent".to_string(), - terms: vec![ - Term::Atom("tom".to_string()), - Term::Variable("X".to_string()), - ], - }], - }; - - let mut query_solver = QuerySolver::new(rules, query); - let next_solution = query_solver.next(); - assert_eq!( - next_solution, - Some(QuerySolution { - env: [("X".to_string(), Term::Atom("liz".to_string()))] - .iter() - .cloned() - .collect() - }) - ); - let next_solution = query_solver.next(); - assert_eq!( - next_solution, - Some(QuerySolution { - env: [("X".to_string(), Term::Atom("bob".to_string()))] - .iter() - .cloned() - .collect() - }) - ); -} - -/// Composes two environments. -fn compose(env1: &Environment, env2: &Environment) -> Environment { - let mut env = Environment::new(); - for (var, term) in env1.bindings.iter() { - env.bind(var.clone(), apply_env(term, env2)); - } - for (var, term) in env2.bindings.iter() { - env.bind(var.clone(), apply_env(term, env1)); - } - env -} - -#[test] -fn test_compose() { - let mut env1 = Environment::new(); - env1.bind("X".to_string(), Term::Integer(1)); - env1.bind("Y".to_string(), Term::Integer(2)); - env1.bind("Z".to_string(), Term::Integer(3)); - let mut env2 = Environment::new(); - env2.bind("X".to_string(), Term::Integer(4)); - env2.bind("Y".to_string(), Term::Integer(5)); - env2.bind("W".to_string(), Term::Integer(6)); - let env = compose(&env1, &env2); - assert_eq!( - env.bindings, - [ - ("X".to_string(), Term::Integer(4)), - ("Y".to_string(), Term::Integer(5)), - ("Z".to_string(), Term::Integer(3)), - ("W".to_string(), Term::Integer(6)) - ] - .iter() - .cloned() - .collect() - ); -} - -/// Applies an environment to a term. -fn apply_env(term: &Term, env: &Environment) -> Term { - match term { - Term::Variable(var) => { - if let Some(binding) = env.lookup(var) { - apply_env(binding, env) - } else { - term.clone() - } - } - Term::List(terms) => Term::List(terms.iter().map(|t| apply_env(t, env)).collect()), - Term::Structure(name, terms) => Term::Structure( - name.clone(), - terms.iter().map(|t| apply_env(t, env)).collect(), - ), - _ => term.clone(), - } -} - -#[test] -fn test_apply_env() { - let mut env = Environment::new(); - env.bind("X".to_string(), Term::Integer(1)); - env.bind("Y".to_string(), Term::Integer(2)); - env.bind("Z".to_string(), Term::Integer(3)); - assert_eq!( - apply_env( - &Term::Structure( - "foo".to_string(), - vec![ - Term::Variable("X".to_string()), - Term::Variable("Y".to_string()), - Term::Variable("Z".to_string()) - ] - ), - &env - ), - Term::Structure( - "foo".to_string(), - vec![Term::Integer(1), Term::Integer(2), Term::Integer(3)] - ) - ); -} - -fn apply_env_terms(terms: &[Term], env: &Environment) -> Vec { - terms.iter().map(|t| apply_env(t, env)).collect() -} - -fn unify(term1: &Term, term2: &Term) -> Option { - let mut env = Environment::new(); - if unify_helper(term1, term2, &mut env) { - Some(env) - } else { - None - } -} - -fn unify_terms(terms1: &[Term], terms2: &[Term]) -> Option { - let mut env = Environment::new(); - if terms1.len() != terms2.len() { - return None; - } - for (term1, term2) in terms1.iter().zip(terms2.iter()) { - if !unify_helper(term1, term2, &mut env) { - return None; - } - } - Some(env) -} - -fn unify_helper(term1: &Term, term2: &Term, env: &mut Environment) -> bool { - match (term1, term2) { - // simple case: the terms are equal - (Term::Atom(a1), Term::Atom(a2)) if a1 == a2 => true, - (Term::Integer(i1), Term::Integer(i2)) if i1 == i2 => true, - (Term::Float(f1), Term::Float(f2)) if f1 == f2 => true, - (Term::String(s1), Term::String(s2)) if s1 == s2 => true, - // if one of the terms is a variable, bind it to the other term - (Term::Variable(v), t) | (t, Term::Variable(v)) => { - // if the variable is already bound, unify the bound term with the other term - if let Some(binding) = env.lookup(v) { - let binding = binding.clone(); - return unify_helper(&binding, t, env); - } else { - env.bind(v.clone(), t.clone()); - return true; - } - } - // if both terms are lists and have the same length, unify the pairs of items - (Term::List(l1), Term::List(l2)) if l1.len() == l2.len() => { - for (item1, item2) in l1.iter().zip(l2.iter()) { - if !unify_helper(item1, item2, env) { - return false; - } - } - true - } - // if both terms are list structures and have the same name and arity, unify the pairs of items - (Term::Structure(name1, terms1), Term::Structure(name2, terms2)) - if name1 == name2 && terms1.len() == terms2.len() => - { - for (item1, item2) in terms1.iter().zip(terms2.iter()) { - if !unify_helper(item1, item2, env) { - return false; - } - } - true - } - // otherwise, the terms cannot be unified - _ => false, - } -} - -#[test] -fn test_unify_helper() { - let mut env = Environment::new(); - assert_eq!( - unify_helper( - &Term::Structure( - "foo".to_string(), - vec![ - Term::Variable("X".to_string()), - Term::Variable("Y".to_string()), - Term::Variable("Z".to_string()) - ] - ), - &Term::Structure( - "foo".to_string(), - vec![Term::Integer(1), Term::Integer(2), Term::Integer(3)] - ), - &mut env - ), - true - ); - assert_eq!( - env.bindings, - [ - ("X".to_string(), Term::Integer(1)), - ("Y".to_string(), Term::Integer(2)), - ("Z".to_string(), Term::Integer(3)) - ] - .iter() - .cloned() - .collect() - ); -} diff --git a/rulog-vm/src/types.rs b/rulog-vm/src/types.rs deleted file mode 100644 index 34cd693..0000000 --- a/rulog-vm/src/types.rs +++ /dev/null @@ -1,6 +0,0 @@ -#[derive(Debug)] -pub enum InterpretingError { - ParseError(rulog_core::types::error::ParsingError), - UnsupportedDirective, - QueryFailed, -}