scryer-prolog 0.8.102

A modern Prolog implementation written mostly in Rust.
use std::cell::Cell;
use std::fmt;
use std::ops::{Add, AddAssign};
use std::vec::Vec;

pub type Var = String;

pub type Atom = String;

pub enum TopLevel {
    Fact(Term),
    Rule(Rule),
    Query(Term)
}

#[derive(Clone, Copy)]
pub enum Level {
    Shallow, Deep
}

impl fmt::Display for Level {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Level::Shallow => write!(f, "A"),
            &Level::Deep => write!(f, "X")
        }
    }
}

#[derive(Clone, Copy)]
pub enum RegType {
    Perm(usize),
    Temp(usize)
}

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
        }
    }
}

impl fmt::Display for VarReg {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg),
            &VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg),
            &VarReg::ArgAndNorm(RegType::Perm(reg), arg) =>
                write!(f, "Y{} A{}", reg, arg),
            &VarReg::ArgAndNorm(RegType::Temp(reg), arg) =>
                write!(f, "X{} A{}", reg, arg)
        }
    }
}

impl From<RegType> for Addr {
    fn from(reg: RegType) -> Addr {
        match reg {
            RegType::Perm(reg) => Addr::StackCell(reg),
            RegType::Temp(reg) => Addr::RegNum(reg)
        }
    }
}

impl fmt::Display for RegType {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &RegType::Perm(val) => write!(f, "Y{}", val),
            &RegType::Temp(val) => write!(f, "X{}", val)
        }
    }
}

#[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 root_register(self) -> usize {
        match self {
            VarReg::ArgAndNorm(_, root) => root,
            VarReg::Norm(root) => root.reg_num()
        }
    }
}

pub enum Term {
    Atom(Cell<RegType>, Atom),
    Clause(Cell<RegType>, Atom, Vec<Box<Term>>),
    Var(Cell<VarReg>, Var)
}

pub struct Rule {
    pub head: (Term, Term),
    pub clauses: Vec<Term>
}

pub enum TermRef<'a> {
    Atom(Level, &'a Cell<RegType>, &'a Atom),
    Clause(Level, &'a Cell<RegType>, &'a Atom, &'a Vec<Box<Term>>),
    Var(Level, &'a Cell<VarReg>, &'a Var)
}

pub enum FactInstruction {
    GetStructure(Level, Atom, usize, RegType),
    GetValue(RegType, usize),
    GetVariable(RegType, usize),
    UnifyVariable(RegType),
    UnifyValue(RegType)
}

pub enum QueryInstruction {
    PutStructure(Level, Atom, usize, RegType),
    PutValue(RegType, usize),
    PutVariable(RegType, usize),
    SetVariable(RegType),
    SetValue(RegType)
}

pub enum ControlInstruction {
    Allocate(usize),
    Call(Atom, usize),
    Deallocate,
    Proceed
}

pub type CompiledFact = Vec<FactInstruction>;

pub type CompiledQuery = Vec<QueryInstruction>;

pub enum Line {
    Control(ControlInstruction),    
    Fact(CompiledFact),
    Query(CompiledQuery)
}

pub type Code = Vec<Line>;

#[derive(Clone, Copy, PartialEq)]
pub enum Addr {
    HeapCell(usize),
    RegNum(usize),
    StackCell(usize),
}

#[derive(Clone, PartialEq)]
pub enum HeapCellValue {
    NamedStr(usize, Atom),
    Ref(usize),
    Str(usize)
}

impl HeapCellValue {
    pub fn as_ref(&self, focus: usize) -> HeapCellRef {
        match self {
            &HeapCellValue::Ref(r) => HeapCellRef::Ref(r),
            &HeapCellValue::Str(s) => HeapCellRef::Str(s),
            &HeapCellValue::NamedStr(_, _) => HeapCellRef::Str(focus)
        }
    }
}

#[derive(Copy, Clone)]
pub enum HeapCellRef {
    Ref(usize),
    Str(usize)
}

impl HeapCellRef {
    pub fn heap_offset(&self) -> usize {
        match self {
            &HeapCellRef::Ref(r) | &HeapCellRef::Str(r) => r
        }
    }        
}

impl From<HeapCellRef> for HeapCellValue {
    fn from(hcr: HeapCellRef) -> HeapCellValue {
        match hcr {
            HeapCellRef::Ref(r) => HeapCellValue::Ref(r),
            HeapCellRef::Str(s) => HeapCellValue::Str(s)
        }
    }
}

#[derive(Clone, Copy)]
pub enum CodePtr {
    DirEntry(usize),
    TopLevel
}

impl Add<usize> 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<usize> for CodePtr {
    fn add_assign(&mut self, rhs: usize) {
        match self {
            &mut CodePtr::DirEntry(ref mut p) => *p += rhs,
            _ => {}
        }
    }
}

pub type Heap = Vec<HeapCellValue>;

pub type Registers = Vec<HeapCellRef>;

impl Term {
    pub fn subterms(&self) -> usize {
        match self {
            &Term::Clause(_, _, ref terms) => terms.len(),
            _ => 1
        }
    }

    pub fn name(&self) -> &Atom {
        match self {
            &Term::Atom(_, ref atom)
            | &Term::Var(_, ref atom)
            | &Term::Clause(_, ref atom, _) => atom
        }
    }

    pub fn arity(&self) -> usize {
        match self {
            &Term::Atom(_, _) | &Term::Var(_, _) => 0,
            &Term::Clause(_, _, ref child_terms) => child_terms.len()
        }
    }
}