use std::cell::Cell; use std::cmp::Ordering; use std::collections::HashMap; use std::ops::{Add, AddAssign}; use std::vec::Vec; pub type Var = String; pub type Atom = String; pub enum PredicateClause { Fact(Term), Rule(Rule) } impl PredicateClause { pub fn name(&self) -> &Atom { match self { &PredicateClause::Fact(ref t) => t.name().unwrap(), &PredicateClause::Rule(ref rule) => rule.head.0.name().unwrap() } } pub fn arity(&self) -> usize { match self { &PredicateClause::Fact(ref t) => t.arity(), &PredicateClause::Rule(ref rule) => rule.head.0.arity() } } } pub enum TopLevel { Fact(Term), Predicate(Vec), Query(Term), Rule(Rule) } #[derive(Clone, Copy)] pub enum Level { Deep, Shallow } #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub enum RegType { Perm(usize), Temp(usize) } impl Default for RegType { fn default() -> Self { RegType::Temp(0) } } impl RegType { pub fn reg_num(self) -> usize { match self { RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num } } pub fn is_perm(self) -> bool { match self { RegType::Perm(_) => true, _ => false } } } #[derive(Clone, Copy)] pub enum VarReg { ArgAndNorm(RegType, usize), Norm(RegType) } impl VarReg { pub fn norm(self) -> RegType { match self { VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg } } pub fn is_temp(self) -> bool { !self.norm().is_perm() } pub fn root_register(self) -> usize { match self { VarReg::ArgAndNorm(_, root) => root, VarReg::Norm(root) => root.reg_num() } } } impl Default for VarReg { fn default() -> Self { VarReg::Norm(RegType::default()) } } #[derive(Clone, PartialEq)] pub enum Constant { Atom(Atom), EmptyList } pub enum Term { AnonVar, Clause(Cell, Atom, Vec>), Cons(Cell, Box, Box), Constant(Cell, Constant), Var(Cell, Var) } pub struct Rule { pub head: (Term, Term), pub clauses: Vec } impl Rule { pub fn last_clause(&self) -> &Term { match self.clauses.last() { None => &self.head.1, Some(clause) => clause } } } pub enum TermRef<'a> { AnonVar(Level), Cons(Level, &'a Cell, &'a Term, &'a Term), Constant(Level, &'a Cell, &'a Constant), Clause(Level, &'a Cell, &'a Atom, &'a Vec>), Var(Level, &'a Cell, &'a Var) } pub enum FactInstruction { GetConstant(Level, Constant, RegType), GetList(Level, RegType), GetStructure(Level, Atom, usize, RegType), GetValue(RegType, usize), GetVariable(RegType, usize), UnifyConstant(Constant), UnifyLocalValue(RegType), UnifyVariable(RegType), UnifyValue(RegType), UnifyVoid(usize) } pub enum QueryInstruction { PutConstant(Level, Constant, RegType), PutList(Level, RegType), PutStructure(Level, Atom, usize, RegType), PutUnsafeValue(usize, usize), PutValue(RegType, usize), PutVariable(RegType, usize), SetConstant(Constant), SetLocalValue(RegType), SetVariable(RegType), SetValue(RegType), SetVoid(usize) } pub enum ChoiceInstruction { RetryMeElse(usize), TrustMe, TryMeElse(usize) } pub enum ControlInstruction { Allocate(usize), Call(Atom, usize, usize), Deallocate, Execute(Atom, usize), Proceed } pub type CompiledFact = Vec; pub type CompiledQuery = Vec; pub enum Line { Choice(ChoiceInstruction), Control(ControlInstruction), Fact(CompiledFact), Query(CompiledQuery) } pub enum LineOrCodeOffset<'a> { Instruction(&'a Line), Offset(usize) } impl<'a> From<&'a Line> for LineOrCodeOffset<'a> { fn from(line: &'a Line) -> Self { LineOrCodeOffset::Instruction(line) } } pub type Code = Vec; #[derive(Clone, PartialEq)] pub enum Addr { Con(Constant), Lis(usize), HeapCell(usize), StackCell(usize, usize), Str(usize) } impl Addr { pub fn is_ref(&self) -> bool { match self { &Addr::HeapCell(_) | &Addr::StackCell(_, _) => true, _ => false } } pub fn as_ref(&self) -> Option { match self { &Addr::HeapCell(hc) => Some(Ref::HeapCell(hc)), &Addr::StackCell(fr, sc) => Some(Ref::StackCell(fr, sc)), _ => None } } pub fn is_protected(&self, e: usize) -> bool { match self { &Addr::StackCell(fr, _) if fr > e => false, _ => true } } } impl From for Addr { fn from(r: Ref) -> Self { match r { Ref::HeapCell(hc) => Addr::HeapCell(hc), Ref::StackCell(fr, sc) => Addr::StackCell(fr, sc) } } } #[derive(Clone, Copy, PartialEq)] pub enum Ref { HeapCell(usize), StackCell(usize, usize) } #[derive(Clone, PartialEq)] pub enum HeapCellValue { Con(Constant), Lis(usize), NamedStr(usize, Atom), Ref(Ref), Str(usize) } impl From for HeapCellValue { fn from(addr: Addr) -> HeapCellValue { match addr { Addr::Con(constant) => HeapCellValue::Con(constant), Addr::HeapCell(hc) => HeapCellValue::Ref(Ref::HeapCell(hc)), Addr::Lis(a) => HeapCellValue::Lis(a), Addr::StackCell(fr, sc) => HeapCellValue::Ref(Ref::StackCell(fr, sc)), Addr::Str(hc) => HeapCellValue::Str(hc) } } } impl HeapCellValue { pub fn as_addr(&self, focus: usize) -> Addr { match self { &HeapCellValue::Con(ref c) => Addr::Con(c.clone()), &HeapCellValue::Lis(a) => Addr::Lis(a), &HeapCellValue::Ref(r) => Addr::from(r), &HeapCellValue::Str(s) => Addr::Str(s), &HeapCellValue::NamedStr(_, _) => Addr::Str(focus) } } } impl PartialOrd for Ref { fn partial_cmp(&self, other: &Self) -> Option { match (*self, *other) { (Ref::HeapCell(hc1), Ref::HeapCell(hc2)) => Some(hc1.cmp(&hc2)), (Ref::HeapCell(_), _) => Some(Ordering::Less), (Ref::StackCell(fr1, sc1), Ref::StackCell(fr2, sc2)) => if fr1 < fr2 { Some(Ordering::Less) } else if fr1 == fr2 { Some(sc1.cmp(&sc2)) } else { Some(Ordering::Greater) }, _ => Some(Ordering::Greater) } } } #[derive(Clone, Copy)] pub enum CodePtr { DirEntry(usize), TopLevel } impl Default for CodePtr { fn default() -> Self { CodePtr::TopLevel } } impl Add for CodePtr { type Output = CodePtr; fn add(self, rhs: usize) -> Self::Output { match self { CodePtr::DirEntry(p) => CodePtr::DirEntry(p + rhs), CodePtr::TopLevel => CodePtr::TopLevel } } } impl AddAssign for CodePtr { fn add_assign(&mut self, rhs: usize) { match self { &mut CodePtr::DirEntry(ref mut p) => *p += rhs, _ => {} } } } pub type Heap = Vec; pub type Registers = Vec; impl Term { pub fn is_clause(&self) -> bool { if let &Term::Clause(_, _, _) = self { true } else { false } } pub fn subterms(&self) -> usize { match self { &Term::Clause(_, _, ref terms) => terms.len(), _ => 1 } } pub fn name(&self) -> Option<&Atom> { match self { &Term::Constant(_, Constant::Atom(ref atom)) | &Term::Clause(_, ref atom, _) => Some(atom), _ => None } } pub fn arity(&self) -> usize { match self { &Term::Clause(_, _, ref child_terms) => child_terms.len(), _ => 0 } } } pub type HeapVarDict = HashMap; pub enum EvalResult { EntryFailure, EntrySuccess, InitialQuerySuccess(HeapVarDict), QueryFailure, SubsequentQuerySuccess, } impl EvalResult { #[allow(dead_code)] pub fn failed_query(&self) -> bool { if let &EvalResult::QueryFailure = self { true } else { false } } }