DynamicProperty,
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
AbolishClause,
- #[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))]
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
Asserta,
- #[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))]
+ #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
Assertz,
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
Retract,
}
}
+ pub fn name(&self) -> Atom {
+ match self {
+ #(
+ #clause_type_name_arms,
+ )*
+ }
+ }
+
pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
matches!((name, arity),
#(#is_inbuilt_arms)|*
use crate::forms::*;
use crate::instructions::*;
-use crate::machine::heap::Heap;
use crate::targets::*;
+use std::cell::Cell;
+
pub(crate) trait Allocator {
fn new() -> Self;
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
- heap_loc: usize,
context: GenContext,
+ cell: &'a Cell<RegType>,
code: &mut CodeDeque,
- ) -> RegType;
+ );
#[allow(clippy::too_many_arguments)]
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
- context: GenContext,
+ cell: &Cell<VarReg>,
+ term_loc: GenContext,
code: &mut CodeDeque,
r: RegType,
is_new_var: bool,
- ) -> RegType;
+ );
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
&mut self,
var_num: usize,
lvl: Level,
+ cell: &Cell<VarReg>,
context: GenContext,
code: &mut CodeDeque,
- ) -> RegType;
+ );
fn reset(&mut self);
fn reset_arg(&mut self, arg_num: usize);
- fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize);
+ fn reset_at_head(&mut self, args: &[Term]);
fn reset_contents(&mut self);
fn advance_arg(&mut self);
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
-use crate::machine::disjuncts::*;
-use crate::machine::stack::Stack;
use crate::targets::QueryInstruction;
use crate::types::*;
use num_order::NumOrd;
use ordered_float::{Float, OrderedFloat};
+use std::cell::Cell;
use std::cmp::{max, min, Ordering};
use std::convert::TryFrom;
use std::f64;
}
}
+#[derive(Debug)]
+pub(crate) struct ArithInstructionIterator<'a> {
+ state_stack: Vec<TermIterState<'a>>,
+}
+
pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>);
+impl<'a> ArithInstructionIterator<'a> {
+ fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
+ self.state_stack
+ .push(TermIterState::subterm_to_state(lvl, term));
+ }
+
+ fn from(term: &'a Term) -> Result<Self, ArithmeticError> {
+ let state = match term {
+ Term::AnonVar => return Err(ArithmeticError::UninstantiatedVar),
+ Term::Clause(cell, name, terms) => {
+ TermIterState::Clause(Level::Shallow, 0, cell, *name, terms)
+ }
+ Term::Literal(cell, cons) => TermIterState::Literal(Level::Shallow, cell, cons),
+ Term::Cons(..) | Term::PartialString(..) | Term::CompleteString(..) => {
+ return Err(ArithmeticError::NonEvaluableFunctor(
+ Literal::Atom(atom!(".")),
+ 2,
+ ))
+ }
+ Term::Var(cell, var_ptr) => TermIterState::Var(Level::Shallow, cell, var_ptr.clone()),
+ };
+
+ Ok(ArithInstructionIterator {
+ state_stack: vec![state],
+ })
+ }
+}
+
+#[derive(Debug)]
+pub(crate) enum ArithTermRef<'a> {
+ Literal(Literal),
+ Op(Atom, usize), // name, arity.
+ Var(Level, &'a Cell<VarReg>, VarPtr),
+}
+
+impl<'a> Iterator for ArithInstructionIterator<'a> {
+ type Item = Result<ArithTermRef<'a>, ArithmeticError>;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some(iter_state) = self.state_stack.pop() {
+ match iter_state {
+ TermIterState::AnonVar(_) => return Some(Err(ArithmeticError::UninstantiatedVar)),
+ TermIterState::Clause(lvl, child_num, cell, name, subterms) => {
+ let arity = subterms.len();
+
+ if child_num == arity {
+ return Some(Ok(ArithTermRef::Op(name, arity)));
+ } else {
+ self.state_stack.push(TermIterState::Clause(
+ lvl,
+ child_num + 1,
+ cell,
+ name,
+ subterms,
+ ));
+
+ self.push_subterm(lvl.child_level(), &subterms[child_num]);
+ }
+ }
+ TermIterState::Literal(_, _, c) => return Some(Ok(ArithTermRef::Literal(*c))),
+ TermIterState::Var(lvl, cell, var_ptr) => {
+ return Some(Ok(ArithTermRef::Var(lvl, cell, var_ptr)));
+ }
+ _ => {
+ return Some(Err(ArithmeticError::NonEvaluableFunctor(
+ Literal::Atom(atom!(".")),
+ 2,
+ )));
+ }
+ };
+ }
+
+ None
+ }
+}
+
#[derive(Debug)]
pub(crate) struct ArithmeticEvaluator<'a> {
marker: &'a mut DebrayAllocator,
interm_c: usize,
}
-fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: HeapCellValue) -> Result<(), ArithmeticError> {
- let c = unmark_cell_bits!(c);
+pub(crate) trait ArithmeticTermIter<'a> {
+ type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
- read_heap_cell!(c,
- (HeapCellValueTag::Fixnum, n) => {
- interm.push(ArithmeticTerm::Number(Number::Fixnum(n)))
- }
- (HeapCellValueTag::Cons, cons_ptr) => {
- match_untyped_arena_ptr!(cons_ptr,
- (ArenaHeaderTag::Integer, n) => {
- interm.push(ArithmeticTerm::Number(Number::Integer(n)));
- }
- (ArenaHeaderTag::Rational, n) => {
- interm.push(ArithmeticTerm::Number(Number::Rational(n)));
- }
- _ => return Err(ArithmeticError::NonEvaluableFunctor(c, 0)),
- );
- }
- (HeapCellValueTag::Atom, (name, arity)) => {
- debug_assert_eq!(arity, 0);
-
- match name {
- atom!("pi") => interm.push(ArithmeticTerm::Number(
- Number::Float(OrderedFloat(std::f64::consts::PI)),
- )),
- atom!("epsilon") => interm.push(ArithmeticTerm::Number(
- Number::Float(OrderedFloat(std::f64::EPSILON)),
- )),
- atom!("e") => interm.push(ArithmeticTerm::Number(
- Number::Float(OrderedFloat(std::f64::consts::E)),
- )),
- _ => unreachable!(),
- }
- }
- (HeapCellValueTag::F64, n) => {
- interm.push(ArithmeticTerm::Number(Number::Float(*n)));
- }
- _ => {
- return Err(ArithmeticError::NonEvaluableFunctor(c, 0));
- }
- );
+ fn iter(self) -> Result<Self::Iter, ArithmeticError>;
+}
+
+impl<'a> ArithmeticTermIter<'a> for &'a Term {
+ type Iter = ArithInstructionIterator<'a>;
+
+ fn iter(self) -> Result<Self::Iter, ArithmeticError> {
+ ArithInstructionIterator::from(self)
+ }
+}
+
+fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: &Literal) -> Result<(), ArithmeticError> {
+ match c {
+ Literal::Fixnum(n) => interm.push(ArithmeticTerm::Number(Number::Fixnum(*n))),
+ Literal::Integer(n) => interm.push(ArithmeticTerm::Number(Number::Integer(*n))),
+ Literal::Float(n) => interm.push(ArithmeticTerm::Number(Number::Float(*n.as_ptr()))),
+ Literal::Rational(n) => interm.push(ArithmeticTerm::Number(Number::Rational(*n))),
+ Literal::Atom(name) if name == &atom!("e") => interm.push(ArithmeticTerm::Number(
+ Number::Float(OrderedFloat(std::f64::consts::E)),
+ )),
+ Literal::Atom(name) if name == &atom!("pi") => interm.push(ArithmeticTerm::Number(
+ Number::Float(OrderedFloat(std::f64::consts::PI)),
+ )),
+ Literal::Atom(name) if name == &atom!("epsilon") => interm.push(ArithmeticTerm::Number(
+ Number::Float(OrderedFloat(f64::EPSILON)),
+ )),
+ _ => return Err(ArithmeticError::NonEvaluableFunctor(*c, 0)),
+ }
Ok(())
}
atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)),
atom!("sign") => Ok(Instruction::Sign(a1, t)),
atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
- _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 1)),
+ _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
}
}
atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
atom!("atan2") => Ok(Instruction::ATan2(a1, a2, t)),
- _ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 2)),
+ _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 2)),
}
}
self.get_binary_instr(name, a1, a2, ninterm)
}
_ => Err(ArithmeticError::NonEvaluableFunctor(
- atom_as_cell!(name),
+ Literal::Atom(name),
arity,
)),
}
pub(crate) fn compile_is(
&mut self,
- src: &mut FocusedHeapRefMut,
- term_loc: usize,
- context: GenContext,
+ src: &'a Term,
+ term_loc: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> {
let mut code = CodeDeque::new();
- let mut stack = Stack::uninitialized();
- let mut iter = query_iterator::<false>(&mut src.heap, &mut stack, term_loc);
-
- let chunk_num = context.chunk_num();
-
- while let Some(term) = iter.next() {
- read_heap_cell!(term,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
- let lvl = iter.level();
-
- let r = match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) {
- VarPtr::Numbered(var_num) => {
- let old_r = self.marker.get_var_binding(var_num);
-
- if lvl == Level::Root {
- self.marker.mark_non_callable(var_num, arg, context, &mut code)
- } else if context.is_last() || old_r.reg_num() == 0 {
- let r = old_r;
-
- if r.reg_num() == 0 {
- self.marker.mark_var::<QueryInstruction>(
- var_num, lvl, context, &mut code,
- )
- } else {
- self.marker.increment_running_count(var_num);
- r
- }
- } else {
- self.marker.increment_running_count(var_num);
- old_r
- }
- }
- VarPtr::Anon => {
- self.marker.mark_anon_var::<QueryInstruction>(lvl, context, &mut code)
+
+ for term_ref in src.iter()? {
+ match term_ref? {
+ ArithTermRef::Literal(c) => push_literal(&mut self.interm, &c)?,
+ ArithTermRef::Var(lvl, cell, name) => {
+ let var_num = name.to_var_num().unwrap();
+
+ let r = if lvl == Level::Shallow {
+ self.marker
+ .mark_non_callable(var_num, arg, term_loc, cell, &mut code)
+ } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
+ let r = self.marker.get_binding(var_num);
+
+ if r.reg_num() == 0 {
+ self.marker.mark_var::<QueryInstruction>(
+ var_num, lvl, cell, term_loc, &mut code,
+ );
+ cell.get().norm()
+ } else {
+ self.marker.increment_running_count(var_num);
+ r
}
+ } else {
+ self.marker.increment_running_count(var_num);
+ cell.get().norm()
};
self.interm.push(ArithmeticTerm::Reg(r));
}
- (HeapCellValueTag::Atom, (name, arity)) => {
- if arity == 0 {
- push_literal(&mut self.interm, atom_as_cell!(name))?;
- } else {
- code.push_back(self.instr_from_clause(name, arity)?);
- }
- }
- _ => {
- push_literal(&mut self.interm, term)?;
+ ArithTermRef::Op(name, arity) => {
+ code.push_back(self.instr_from_clause(name, arity)?);
}
- );
+ }
}
Ok((code, self.interm.pop()))
Dynamic(AtomTableRef<str>),
}
-fn inlined_to_str<'a>(bytes: &'a [u8; 8]) -> &'a str {
+fn inlined_to_str(bytes: &[u8; 8]) -> &str {
// allow the '\0\' atom to be represented as the 0-valued inlined atom
let slice_len = if bytes[0] == 0 {
1
unsafe impl Send for AtomTable {}
unsafe impl Sync for AtomTable {}
-
-/*
-#[bitfield]
-#[repr(u64)]
-#[derive(Copy, Clone, Debug)]
-pub struct AtomCell {
- name: B48,
- arity: B10,
- #[allow(unused)]
- f: bool,
- #[allow(unused)]
- m: bool,
- #[allow(unused)]
- inlined: bool,
- #[allow(unused)]
- tag: B3,
-}
-
-impl AtomCell {
- #[inline]
- pub fn build_with(name: u64, arity: u16, tag: HeapCellValueTag) -> Self {
- if arity > 0 {
- debug_assert!(arity as usize <= MAX_ARITY);
-
- AtomCell::new()
- .with_name(name)
- .with_arity(arity)
- .with_f(false)
- .with_tag(tag as u8)
- } else {
- AtomCell::new()
- .with_name(name)
- .with_f(false)
- .with_tag(tag as u8)
- }
- }
-
- #[inline]
- pub fn get_index(self) -> usize {
- self.name() as usize
- }
-
- #[inline]
- pub fn get_name(self) -> Atom {
- Atom::from((self.get_index() as u64) << 3)
- }
-
- #[inline]
- pub fn get_arity(self) -> usize {
- self.arity() as usize
- }
-
- #[inline]
- pub fn get_name_and_arity(self) -> (Atom, usize) {
- (Atom::from((self.get_index() as u64) << 3), self.get_arity())
- }
-}
-*/
use crate::allocator::*;
-use crate::arena::ArenaHeaderTag;
use crate::arithmetic::*;
use crate::atom_table::*;
use crate::debray_allocator::*;
use crate::indexing::*;
use crate::instructions::*;
use crate::iterators::*;
-use crate::machine::heap::*;
use crate::parser::ast::*;
use crate::targets::*;
use crate::types::*;
use crate::machine::disjuncts::*;
use crate::machine::machine_errors::*;
-use crate::machine::machine_indices::CodeIndex;
-use crate::machine::stack::Stack;
use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
use indexmap::IndexSet;
+use std::cell::Cell;
use std::collections::VecDeque;
-use std::rc::Rc;
#[derive(Debug)]
pub struct BranchCodeStack {
}
impl DebrayAllocator {
+ fn mark_var_in_non_callable(
+ &mut self,
+ var_num: usize,
+ term_loc: GenContext,
+ vr: &Cell<VarReg>,
+ code: &mut CodeDeque,
+ ) -> RegType {
+ self.mark_var::<QueryInstruction>(var_num, Level::Shallow, vr, term_loc, code);
+ vr.get().norm()
+ }
+
pub(crate) fn mark_non_callable(
&mut self,
var_num: usize,
arg: usize,
- context: GenContext,
+ term_loc: GenContext,
+ vr: &Cell<VarReg>,
code: &mut CodeDeque,
) -> RegType {
- match self.get_var_binding(var_num) {
+ match self.get_binding(var_num) {
RegType::Temp(t) if t != 0 => RegType::Temp(t),
RegType::Perm(p) if p != 0 => {
- if let GenContext::Last(_) = context {
- self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code);
+ if let GenContext::Last(_) = term_loc {
+ self.mark_var_in_non_callable(var_num, term_loc, vr, code);
temp_v!(arg)
} else {
- if let VarAlloc::Perm {
- allocation: PermVarAllocation::Pending,
- ..
- } = &self.var_data.records[var_num].allocation
+ if let VarAlloc::Perm(_, PermVarAllocation::Pending) =
+ &self.var_data.records[var_num].allocation
{
- self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code);
+ self.mark_var_in_non_callable(var_num, term_loc, vr, code);
} else {
self.increment_running_count(var_num);
}
RegType::Perm(p)
}
}
- _ => self.mark_var::<QueryInstruction>(var_num, Level::Shallow, context, code),
+ _ => self.mark_var_in_non_callable(var_num, term_loc, vr, code),
}
}
}
trait AddToFreeList<'a, Target: CompilationTarget<'a>> {
fn add_term_to_free_list(&mut self, r: RegType);
- fn add_subterm_to_free_list(&mut self, r: RegType);
+ fn add_subterm_to_free_list(&mut self, term: &Term);
}
impl<'a> AddToFreeList<'a, FactInstruction> for CodeGenerator {
self.marker.add_reg_to_free_list(r);
}
- fn add_subterm_to_free_list(&mut self, _r: RegType) {}
+ fn add_subterm_to_free_list(&mut self, _term: &Term) {}
}
impl<'a> AddToFreeList<'a, QueryInstruction> for CodeGenerator {
fn add_term_to_free_list(&mut self, _r: RegType) {}
#[inline(always)]
- fn add_subterm_to_free_list(&mut self, r: RegType) {
- self.marker.add_reg_to_free_list(r);
+ fn add_subterm_to_free_list(&mut self, term: &Term) {
+ if let Some(cell) = structure_cell(term) {
+ self.marker.add_reg_to_free_list(cell.get());
+ }
}
}
-fn add_index_ptr<'a, Target: crate::targets::CompilationTarget<'a>>(
- index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
- heap: &Heap,
- heap_loc: usize,
-) -> Option<Instruction> {
- if let Some(index_ptr) = index_ptrs.get(&heap_loc) {
- let subterm = HeapCellValue::from(*index_ptr);
- return Some(Target::constant_subterm(subterm));
- } else if !heap[heap_loc.saturating_sub(1)].get_mark_bit() {
- if let Some(index_ptr) = fetch_index_ptr(heap, heap_loc) {
- let subterm = HeapCellValue::from(index_ptr);
- return Some(Target::constant_subterm(subterm));
- }
+fn structure_cell(term: &Term) -> Option<&Cell<RegType>> {
+ match term {
+ &Term::Cons(ref cell, ..)
+ | &Term::Clause(ref cell, ..)
+ | Term::PartialString(ref cell, ..)
+ | Term::CompleteString(ref cell, ..) => Some(cell),
+ _ => None,
}
-
- None
}
impl CodeGenerator {
fn deep_var_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
&mut self,
+ cell: &'a Cell<VarReg>,
var_num: usize,
- context: GenContext,
+ term_loc: GenContext,
target: &mut CodeDeque,
) {
if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker
- .mark_var::<Target>(var_num, Level::Deep, context, target);
+ .mark_var::<Target>(var_num, Level::Deep, cell, term_loc, target);
} else {
Self::add_or_increment_void_instr::<Target>(target);
}
fn subterm_to_instr<'a, Target: crate::targets::CompilationTarget<'a>>(
&mut self,
- subterm: HeapCellValue,
- heap_loc: usize,
- context: GenContext,
- index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
+ subterm: &'a Term,
+ term_loc: GenContext,
target: &mut CodeDeque,
- ) -> Option<RegType> {
- let subterm = unmark_cell_bits!(subterm);
- let chunk_num = context.chunk_num();
-
- read_heap_cell!(subterm,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
- match self.marker.var_data.var_locs_to_nums.get(VarPtrIndex { chunk_num, term_loc }) {
- VarPtr::Numbered(var_num) => {
- self.deep_var_instr::<Target>(
- var_num,
- context,
- target,
- );
- }
- VarPtr::Anon => {
- Self::add_or_increment_void_instr::<Target>(target);
- }
- }
-
- None
+ ) {
+ match subterm {
+ &Term::AnonVar => {
+ Self::add_or_increment_void_instr::<Target>(target);
}
- (HeapCellValueTag::Atom, (name, _arity)) => {
- if index_ptrs.contains_key(&heap_loc) {
- let r = self.marker.mark_non_var::<Target>(Level::Deep, heap_loc, context, target);
- target.push_back(Target::clause_arg_to_instr(r));
- return Some(r);
- } else {
- target.push_back(Target::constant_subterm(atom_as_cell!(name)));
- }
-
- None
+ &Term::Cons(ref cell, ..)
+ | &Term::Clause(ref cell, ..)
+ | Term::PartialString(ref cell, ..)
+ | Term::CompleteString(ref cell, ..) => {
+ self.marker
+ .mark_non_var::<Target>(Level::Deep, term_loc, cell, target);
+ target.push_back(Target::clause_arg_to_instr(cell.get()));
}
- (HeapCellValueTag::Str
- | HeapCellValueTag::Lis
- | HeapCellValueTag::PStrLoc) => {
- let r = self.marker.mark_non_var::<Target>(Level::Deep, heap_loc, context, target);
- target.push_back(Target::clause_arg_to_instr(r));
- return Some(r);
+ Term::Literal(_, ref constant) => {
+ target.push_back(Target::constant_subterm(*constant));
}
- _ => {
- target.push_back(Target::constant_subterm(subterm));
- None
+ Term::Var(ref cell, ref var_ptr) => {
+ self.deep_var_instr::<Target>(
+ cell,
+ var_ptr.to_var_num().unwrap(),
+ term_loc,
+ target,
+ );
}
- )
+ };
}
- fn compile_target<'a, Target, Iter>(
- &mut self,
- mut iter: Iter,
- index_ptrs: &IndexMap<usize, CodeIndex, FxBuildHasher>,
- context: GenContext,
- ) -> CodeDeque
+ fn compile_target<'a, Target, Iter>(&mut self, iter: Iter, context: GenContext) -> CodeDeque
where
Target: crate::targets::CompilationTarget<'a>,
- Iter: TermIterator,
+ Iter: Iterator<Item = TermRef<'a>>,
CodeGenerator: AddToFreeList<'a, Target>,
{
let mut target = CodeDeque::new();
- let chunk_num = context.chunk_num();
-
- while let Some(term) = iter.next() {
- let lvl = iter.level();
- let term = unmark_cell_bits!(term);
-
- read_heap_cell!(term,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
- if lvl == Level::Shallow {
- match self.marker.var_data.var_locs_to_nums.get(
- VarPtrIndex { chunk_num, term_loc }
- ) {
- VarPtr::Numbered(var_num) => {
- self.marker.mark_var::<Target>(
- var_num,
- lvl,
- context,
- &mut target,
- );
- }
- VarPtr::Anon => {
- if let GenContext::Head = context {
- self.marker.advance_arg();
- } else {
- self.marker.mark_anon_var::<Target>(lvl, context, &mut target);
- }
- }
- }
+
+ for term in iter {
+ match term {
+ TermRef::AnonVar(lvl @ Level::Shallow) => {
+ if let GenContext::Head = context {
+ self.marker.advance_arg();
+ } else {
+ self.marker
+ .mark_anon_var::<Target>(lvl, context, &mut target);
}
}
- (HeapCellValueTag::Atom, (name, arity)) => {
- let heap_loc = iter.focus().value() as usize;
- let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
-
- if arity == 0 {
- if let Some(instr) = add_index_ptr::<Target>(index_ptrs, &iter, heap_loc) {
- let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- target.push_back(instr);
- target.push_back(Target::to_structure(lvl, name, 0, r));
- } else if lvl == Level::Shallow {
- let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- target.push_back(Target::to_constant(lvl, atom_as_cell!(name), r));
- }
- } else {
- let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-
- <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
- self,
- r,
- );
-
- if let Some(instr) = add_index_ptr::<Target>(index_ptrs, &iter, heap_loc) {
- target.push_back(instr);
- }
+ TermRef::Clause(lvl, cell, name, terms) => {
+ let terms_range =
+ if let Some(subterm @ Term::Literal(_, Literal::CodeIndex(_))) =
+ terms.last()
+ {
+ self.subterm_to_instr::<Target>(subterm, context, &mut target);
+ 0..terms.len() - 1
+ } else {
+ 0..terms.len()
+ };
- target.push_back(Target::to_structure(lvl, name, arity, r));
+ self.marker
+ .mark_non_var::<Target>(lvl, context, cell, &mut target);
+ target.push_back(Target::to_structure(lvl, name, terms_range.end, cell.get()));
- let free_list_regs: Vec<_> = (heap_loc + 1 ..= heap_loc + arity)
- .map(|subterm_loc| {
- let (subterm_loc, subterm) = subterm_index(iter.deref(), subterm_loc);
+ <CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
+ self,
+ cell.get(),
+ );
- self.subterm_to_instr::<Target>(
- subterm, subterm_loc, context, index_ptrs, &mut target,
- )
- })
- .collect();
+ for subterm in &terms[terms_range.clone()] {
+ self.subterm_to_instr::<Target>(subterm, context, &mut target);
+ }
- for r_opt in free_list_regs {
- if let Some(r) = r_opt {
- <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
- self, r,
- );
- }
- }
+ for subterm in &terms[terms_range] {
+ <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+ self, subterm,
+ );
}
}
- (HeapCellValueTag::Lis, l) => {
- let heap_loc = iter.focus().value() as usize;
- let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
-
- let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
-
- target.push_back(Target::to_list(lvl, r));
+ TermRef::Cons(lvl, cell, head, tail) => {
+ self.marker
+ .mark_non_var::<Target>(lvl, context, cell, &mut target);
+ target.push_back(Target::to_list(lvl, cell.get()));
<CodeGenerator as AddToFreeList<'a, Target>>::add_term_to_free_list(
self,
- r,
+ cell.get(),
);
- let (head_loc, head) = subterm_index(iter.deref(), l);
- let (tail_loc, tail) = subterm_index(iter.deref(), l+1);
+ self.subterm_to_instr::<Target>(head, context, &mut target);
+ self.subterm_to_instr::<Target>(tail, context, &mut target);
- let head_r_opt = self.subterm_to_instr::<Target>(
- head,
- head_loc,
- context,
- index_ptrs,
- &mut target,
+ <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+ self, head,
);
-
- let tail_r_opt = self.subterm_to_instr::<Target>(
- tail,
- tail_loc,
- context,
- index_ptrs,
- &mut target,
+ <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
+ self, tail,
);
-
- if let Some(r) = head_r_opt {
- <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
- self, r,
- );
- }
-
- if let Some(r) = tail_r_opt {
- <CodeGenerator as AddToFreeList<'a, Target>>::add_subterm_to_free_list(
- self, r,
- );
- }
}
- (HeapCellValueTag::PStrLoc, pstr_loc) => {
- let heap_loc = iter.focus().value() as usize;
- let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
- let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- let HeapStringScan { string, tail_idx } = iter.scan_slice_to_str(pstr_loc);
+ TermRef::Literal(lvl @ Level::Shallow, cell, constant) => {
+ self.marker
+ .mark_non_var::<Target>(lvl, context, cell, &mut target);
+ target.push_back(Target::to_constant(lvl, *constant, cell.get()));
+ }
+ TermRef::PartialString(lvl, cell, string, tail) => {
+ self.marker
+ .mark_non_var::<Target>(lvl, context, cell, &mut target);
- target.push_back(Target::to_pstr(lvl, Rc::new(string.to_owned()), r));
+ target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
+ self.subterm_to_instr::<Target>(tail, context, &mut target);
+ }
+ TermRef::CompleteString(lvl, cell, string) => {
+ self.marker
+ .mark_non_var::<Target>(lvl, context, cell, &mut target);
- let (tail_loc, tail) = subterm_index(iter.deref(), tail_idx);
- self.subterm_to_instr::<Target>(
- tail, tail_loc, context, index_ptrs, &mut target,
- );
+ target.push_back(Target::to_pstr(lvl, string.clone(), cell.get()));
+ target.push_back(Target::constant_subterm(Literal::Atom(atom!("[]"))));
}
- _ if lvl == Level::Shallow => {
- if term.is_constant() {
- let heap_loc = iter.focus().value() as usize;
- let (heap_loc, _) = subterm_index(iter.deref(), heap_loc);
- let r = self.marker.mark_non_var::<Target>(lvl, heap_loc, context, &mut target);
- target.push_back(Target::to_constant(lvl, term, r));
- }
+ TermRef::Var(lvl @ Level::Shallow, cell, var) => {
+ self.marker.mark_var::<Target>(
+ var.to_var_num().unwrap(),
+ lvl,
+ cell,
+ context,
+ &mut target,
+ );
}
_ => {}
- );
+ };
}
target
fn compile_inlined(
&mut self,
ct: &InlinedClauseType,
- terms: &mut FocusedHeapRefMut,
- term_loc: usize,
- context: GenContext,
+ terms: &'_ [Term],
+ term_loc: GenContext,
code: &mut CodeDeque,
) -> Result<(), CompilationError> {
- let first_arg_loc = terms.nth_arg(term_loc, 1).unwrap();
- let first_arg = terms.deref_loc(first_arg_loc);
-
- let chunk_num = context.chunk_num();
- let mut variable_marker = |marker: &mut DebrayAllocator| {
- read_heap_cell!(first_arg,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, first_arg_loc) => {
- match marker.var_data.var_locs_to_nums.get(
- VarPtrIndex { chunk_num, term_loc: first_arg_loc },
- ) {
- VarPtr::Numbered(var_num) => {
- Some(marker.mark_non_callable(
- var_num,
- 1,
- context,
- code,
- ))
- }
- VarPtr::Anon => {
- Some(marker.mark_anon_var::<QueryInstruction>(
- Level::Shallow,
- context,
- code,
- ))
- }
- }
- }
- _ => {
- marker.advance_arg();
- None
- }
- )
- };
-
let call_instr = match ct {
&InlinedClauseType::CompareNumber(mut cmp) => {
self.marker.reset_arg(2);
- let (mut lcode, at_1) = if let Some(r) = variable_marker(&mut self.marker) {
- (CodeDeque::default(), Some(ArithmeticTerm::Reg(r)))
- } else {
- self.compile_arith_expr(terms, first_arg_loc, 1, context, 1)?
- };
+ let (mut lcode, at_1) = self.compile_arith_expr(&terms[0], 1, term_loc, 1)?;
- let (mut rcode, at_2) =
- self.compile_arith_expr(terms, first_arg_loc + 1, 2, context, 2)?;
+ if !matches!(terms[0], Term::Var(..)) {
+ self.marker.advance_arg();
+ }
+
+ let (mut rcode, at_2) = self.compile_arith_expr(&terms[1], 2, term_loc, 2)?;
code.append(&mut lcode);
code.append(&mut rcode);
compare_number_instr!(cmp, at_1, at_2)
}
- InlinedClauseType::IsAtom(..) => {
- self.marker.reset_arg(1);
+ InlinedClauseType::IsAtom(..) => match &terms[0] {
+ Term::Literal(_, Literal::Atom(..)) => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("atom", r)
- } else {
- read_heap_cell!(first_arg,
- (HeapCellValueTag::Atom, (_name, arity)) => {
- if arity == 0 {
- instr!("$succeed")
- } else {
- instr!("$fail")
- }
- }
- _ => {
- instr!("$fail")
- }
- )
}
- }
- InlinedClauseType::IsAtomic(..) => {
- self.marker.reset_arg(1);
+ _ => {
+ instr!("$fail")
+ }
+ },
+ InlinedClauseType::IsAtomic(..) => match &terms[0] {
+ Term::AnonVar
+ | Term::Clause(..)
+ | Term::Cons(..)
+ | Term::PartialString(..)
+ | Term::CompleteString(..) => {
+ instr!("$fail")
+ }
+ Term::Literal(..) => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("atomic", r)
- } else {
- read_heap_cell!(first_arg,
- (HeapCellValueTag::Fixnum |
- HeapCellValueTag::F64) => {
- instr!("$succeed")
- }
- (HeapCellValueTag::Cons, cons_ptr) => {
- match cons_ptr.get_tag() {
- ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
- instr!("$succeed")
- }
- _ => {
- instr!("$fail")
- }
- }
- }
- (HeapCellValueTag::Atom, (_name, arity)) => {
- if arity == 0 {
- instr!("$succeed")
- } else {
- instr!("$fail")
- }
- }
- (HeapCellValueTag::Lis
- | HeapCellValueTag::Str
- | HeapCellValueTag::PStrLoc) => {
- instr!("$fail")
- }
- _ => {
- if first_arg.is_constant() {
- instr!("$succeed")
- } else {
- instr!("$fail")
- }
- }
- )
}
- }
- InlinedClauseType::IsCompound(..) => {
- self.marker.reset_arg(1);
+ },
+ InlinedClauseType::IsCompound(..) => match &terms[0] {
+ Term::Clause(..)
+ | Term::Cons(..)
+ | Term::PartialString(..)
+ | Term::CompleteString(..) => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("compound", r)
- } else {
- read_heap_cell!(first_arg,
- (HeapCellValueTag::Atom, (_, arity)) => {
- if arity > 0 {
- instr!("$succeed")
- } else {
- instr!("$fail")
- }
- }
- (HeapCellValueTag::Lis
- | HeapCellValueTag::Str
- | HeapCellValueTag::PStrLoc) => {
- instr!("$succeed")
- }
- _ => {
- instr!("$fail")
- }
- )
}
- }
- InlinedClauseType::IsRational(..) => {
- self.marker.reset_arg(1);
-
- if let Some(r) = variable_marker(&mut self.marker) {
+ _ => {
+ instr!("$fail")
+ }
+ },
+ InlinedClauseType::IsRational(..) => match terms[0] {
+ Term::Literal(_, Literal::Rational(_)) => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
instr!("rational", r)
- } else {
- read_heap_cell!(first_arg,
- (HeapCellValueTag::Cons, cons_ptr) => {
- match cons_ptr.get_tag() {
- ArenaHeaderTag::Integer | ArenaHeaderTag::Rational => {
- instr!("$succeed")
- }
- _ => {
- instr!("$fail")
- }
- }
- }
- (HeapCellValueTag::Fixnum) => {
- instr!("$succeed")
- }
- _ => {
- instr!("$fail")
- }
- )
}
- }
- InlinedClauseType::IsFloat(..) => {
- self.marker.reset_arg(1);
+ _ => {
+ instr!("$fail")
+ }
+ },
+ InlinedClauseType::IsFloat(..) => match terms[0] {
+ Term::Literal(_, Literal::Float(_)) => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("float", r)
- } else {
- read_heap_cell!(first_arg,
- (HeapCellValueTag::F64) => {
- instr!("$succeed")
- }
- _ => {
- instr!("$fail")
- }
- )
}
- }
- InlinedClauseType::IsNumber(..) => {
- self.marker.reset_arg(1);
- if let Some(r) = variable_marker(&mut self.marker) {
- instr!("number", r)
- } else if Number::try_from(first_arg).is_ok() {
+ _ => {
+ instr!("$fail")
+ }
+ },
+ InlinedClauseType::IsNumber(..) => match terms[0] {
+ Term::Literal(_, Literal::Float(_))
+ | Term::Literal(_, Literal::Rational(_))
+ | Term::Literal(_, Literal::Integer(_))
+ | Term::Literal(_, Literal::Fixnum(_)) => {
instr!("$succeed")
- } else {
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
+
+ instr!("number", r)
+ }
+ _ => {
instr!("$fail")
}
- }
- InlinedClauseType::IsNonVar(..) => {
- self.marker.reset_arg(1);
+ },
+ InlinedClauseType::IsNonVar(..) => match terms[0] {
+ Term::AnonVar => {
+ instr!("$fail")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("nonvar", r)
- } else if first_arg.is_var() {
- instr!("$fail")
- } else {
+ }
+ _ => {
instr!("$succeed")
}
- }
- InlinedClauseType::IsInteger(..) => {
- self.marker.reset_arg(1);
+ },
+ InlinedClauseType::IsInteger(..) => match &terms[0] {
+ Term::Literal(_, Literal::Integer(_)) | Term::Literal(_, Literal::Fixnum(_)) => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("integer", r)
- } else {
- match Number::try_from(first_arg) {
- Ok(Number::Integer(_) | Number::Fixnum(_)) => {
- instr!("$succeed")
- }
- _ => {
- instr!("$fail")
- }
- }
}
- }
- InlinedClauseType::IsVar(..) => {
- self.marker.reset_arg(1);
+ _ => {
+ instr!("$fail")
+ }
+ },
+ InlinedClauseType::IsVar(..) => match terms[0] {
+ Term::Literal(..)
+ | Term::Clause(..)
+ | Term::Cons(..)
+ | Term::PartialString(..)
+ | Term::CompleteString(..) => {
+ instr!("$fail")
+ }
+ Term::AnonVar => {
+ instr!("$succeed")
+ }
+ Term::Var(ref vr, ref name) => {
+ self.marker.reset_arg(1);
+
+ let r = self.marker.mark_non_callable(
+ name.to_var_num().unwrap(),
+ 1,
+ term_loc,
+ vr,
+ code,
+ );
- if let Some(r) = variable_marker(&mut self.marker) {
instr!("var", r)
- } else if first_arg.is_var() {
- instr!("$succeed")
- } else {
- instr!("$fail")
}
- }
+ },
};
// inlined predicates are never counted, so this overrides nothing.
fn compile_arith_expr(
&mut self,
- terms: &mut FocusedHeapRefMut,
- term_loc: usize,
+ term: &Term,
target_int: usize,
- context: GenContext,
+ term_loc: GenContext,
arg: usize,
) -> Result<ArithCont, ArithmeticError> {
let mut evaluator = ArithmeticEvaluator::new(&mut self.marker, target_int);
- evaluator.compile_is(terms, term_loc, context, arg)
+ evaluator.compile_is(term, term_loc, arg)
}
fn compile_is_call(
&mut self,
- terms: &mut FocusedHeapRefMut,
- term_loc: usize,
+ terms: &[Term],
code: &mut CodeDeque,
- context: GenContext,
+ term_loc: GenContext,
call_policy: CallPolicy,
) -> Result<(), CompilationError> {
macro_rules! compile_expr {
- ($self:expr, $terms:expr, $context:expr, $code:expr) => {{
- let (acode, at) = $self.compile_arith_expr($terms, term_loc + 2, 1, $context, 2)?;
+ ($self:expr, $terms:expr, $term_loc:expr, $code:expr) => {{
+ let (acode, at) = $self.compile_arith_expr($terms, 1, $term_loc, 2)?;
$code.extend(acode.into_iter());
at
}};
self.marker.reset_arg(2);
- let var = heap_bound_store(
- terms.heap,
- heap_bound_deref(terms.heap, heap_loc_as_cell!(term_loc + 1)),
- );
+ let at = match terms[0] {
+ Term::Var(ref vr, ref name) => {
+ let var_num = name.to_var_num().unwrap();
+
+ if self.marker.var_data.records[var_num].num_occurrences > 1 {
+ self.marker.mark_var::<QueryInstruction>(
+ var_num,
+ Level::Shallow,
+ vr,
+ term_loc,
+ code,
+ );
+
+ self.marker.mark_safe_var_unconditionally(var_num);
+ compile_expr!(self, &terms[1], term_loc, code)
+ } else {
+ self.marker
+ .mark_anon_var::<QueryInstruction>(Level::Shallow, term_loc, code);
- let at = read_heap_cell!(var,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => {
- let chunk_num = context.chunk_num();
+ if let Term::Var(ref vr, ref var) = &terms[1] {
+ let var_num = var.to_var_num().unwrap();
- match self.marker.var_data.var_locs_to_nums.get(
- VarPtrIndex { chunk_num, term_loc },
- ) {
- VarPtr::Numbered(var_num) => {
+ // if var is an anonymous variable, insert
+ // is/2 call so that an instantiation error is
+ // thrown when the predicate is run.
if self.marker.var_data.records[var_num].num_occurrences > 1 {
self.marker.mark_var::<QueryInstruction>(
var_num,
Level::Shallow,
- context,
+ vr,
+ term_loc,
code,
);
self.marker.mark_safe_var_unconditionally(var_num);
+
+ let at = ArithmeticTerm::Reg(vr.get().norm());
+ self.add_call(code, instr!("$get_number", at), call_policy);
+
+ return Ok(());
}
}
- VarPtr::Anon => {}
- };
- compile_expr!(self, terms, context, code)
+ compile_expr!(self, &terms[1], term_loc, code)
+ }
+ }
+ Term::Literal(
+ _,
+ c @ Literal::Integer(_)
+ | c @ Literal::Float(_)
+ | c @ Literal::Rational(_)
+ | c @ Literal::Fixnum(_),
+ ) => {
+ let v = HeapCellValue::from(c);
+ code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
+
+ self.marker.advance_arg();
+ compile_expr!(self, &terms[1], term_loc, code)
}
_ => {
- if Number::try_from(var).is_ok() {
- let v = HeapCellValue::from(var);
- code.push_back(instr!("put_constant", Level::Shallow, v, temp_v!(1)));
-
- self.marker.advance_arg();
- compile_expr!(self, terms, context, code)
- } else {
- code.push_back(instr!("$fail"));
- return Ok(());
- }
+ code.push_back(instr!("$fail"));
+ return Ok(());
}
- );
+ };
let at = at.unwrap_or(interm!(1));
self.add_call(code, instr!("is", temp_v!(1), at), call_policy);
fn compile_seq(
&mut self,
- mut focused_heap: FocusedHeapRefMut,
clauses: &ChunkedTermVec,
code: &mut CodeDeque,
) -> Result<(), CompilationError> {
+ let mut chunk_num = 0;
let mut branch_code_stack = BranchCodeStack::new();
let mut clause_iter = ClauseIterator::new(clauses);
while let Some(clause_item) = clause_iter.next() {
match clause_item {
- ClauseItem::Chunk { chunk_num, terms } => {
+ ClauseItem::Chunk { terms } => {
for (idx, term) in terms.iter().enumerate() {
- let context = if idx + 1 < terms.len() {
+ let term_loc = if idx + 1 < terms.len() {
GenContext::Mid(chunk_num)
} else {
self.marker.in_tail_position = clause_iter.in_tail_position();
if chunk_num == 0 {
code.push_back(instr!("neck_cut"));
} else {
- let r = self.marker.get_var_binding(var_num);
+ let r = self.marker.get_binding(var_num);
code.push_back(instr!("cut", r));
}
}
&QueryTerm::LocalCut { var_num, cut_prev } => {
let code = branch_code_stack.code(code);
- let r = self.marker.get_var_binding(var_num);
+ let r = self.marker.get_binding(var_num);
code.push_back(if cut_prev {
instr!("cut_prev", r)
}
}
&QueryTerm::Clause(
- ref clause @ QueryClause {
- ct: ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
- call_policy,
- ..
- },
+ _,
+ ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
+ ref terms,
+ call_policy,
) => self.compile_is_call(
- &mut focused_heap,
- clause.term_loc(),
+ terms,
branch_code_stack.code(code),
- context,
+ term_loc,
call_policy,
)?,
- &QueryTerm::Clause(
- ref clause @ QueryClause {
- ct: ClauseType::Inlined(ref ct),
- ..
- },
- ) => self.compile_inlined(
- ct,
- &mut focused_heap,
- clause.term_loc(),
- context,
- branch_code_stack.code(code),
- )?,
+ &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
+ self.compile_inlined(
+ ct,
+ terms,
+ term_loc,
+ branch_code_stack.code(code),
+ )?
+ }
&QueryTerm::Fail => {
branch_code_stack.code(code).push_back(instr!("$fail"));
}
- &QueryTerm::Succeed => {
- let code = branch_code_stack.code(code);
-
- if self.marker.in_tail_position && self.marker.var_data.allocates {
- code.push_back(instr!("deallocate"));
- }
-
- code.push_back(if self.marker.in_tail_position {
- instr!("$succeed").into_execute()
- } else {
- instr!("$succeed")
- });
- }
- QueryTerm::Clause(clause) => {
+ term @ &QueryTerm::Clause(..) => {
self.compile_query_line(
- &mut focused_heap,
- clause,
- context,
+ term,
+ term_loc,
branch_code_stack.code(code),
);
}
}
+ chunk_num += 1;
self.marker.in_tail_position = false;
self.marker.reset_contents();
}
pub(crate) fn compile_rule(
&mut self,
- heap: &mut Heap,
- rule: &mut Rule,
+ rule: &Rule,
var_data: VarData,
) -> Result<Code, CompilationError> {
- let Rule { term_loc, clauses } = rule;
-
+ let Rule {
+ head: (_, args),
+ clauses,
+ } = rule;
self.marker.var_data = var_data;
-
- let term = FocusedHeapRefMut {
- heap,
- focus: *term_loc,
- };
let mut code = VecDeque::new();
- let head_loc = term.nth_arg(term.focus, 1).unwrap();
+ self.marker.reset_at_head(args);
- self.marker.reset_at_head(term.heap, head_loc);
-
- let mut stack = Stack::uninitialized();
- let iter = fact_iterator::<true>(term.heap, &mut stack, head_loc);
-
- let fact = self.compile_target::<FactInstruction, _>(
- iter,
- &IndexMap::with_hasher(FxBuildHasher::default()),
- GenContext::Head,
- );
+ let iter = FactIterator::from_rule_head_clause(args);
+ let fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
if self.marker.max_reg_allocated() > MAX_ARITY {
return Err(CompilationError::ExceededMaxArity);
self.marker.reset_free_list();
code.extend(fact);
- self.compile_seq(term, &clauses, &mut code)?;
+ self.compile_seq(clauses, &mut code)?;
Ok(Vec::from(code))
}
pub(crate) fn compile_fact(
&mut self,
- heap: &mut Heap,
- fact: &mut Fact,
+ fact: &Fact,
var_data: VarData,
) -> Result<Code, CompilationError> {
let mut code = Vec::new();
-
- let mut stack = Stack::uninitialized();
-
self.marker.var_data = var_data;
- self.marker.reset_at_head(heap, fact.term_loc);
- let iter = fact_iterator::<true>(heap, &mut stack, fact.term_loc);
+ if let Term::Clause(_, _, args) = &fact.head {
+ self.marker.reset_at_head(args);
- let compiled_fact = self.compile_target::<FactInstruction, _>(
- iter,
- &IndexMap::with_hasher(FxBuildHasher::default()),
- GenContext::Head,
- );
+ let iter = FactInstruction::iter(&fact.head);
+ let compiled_fact = self.compile_target::<FactInstruction, _>(iter, GenContext::Head);
- if self.marker.max_reg_allocated() > MAX_ARITY {
- return Err(CompilationError::ExceededMaxArity);
+ if self.marker.max_reg_allocated() > MAX_ARITY {
+ return Err(CompilationError::ExceededMaxArity);
+ }
+
+ code.extend(compiled_fact);
}
- code.extend(compiled_fact);
code.push(instr!("proceed"));
-
Ok(code)
}
- fn compile_query_line(
- &mut self,
- term: &mut FocusedHeapRefMut,
- clause: &QueryClause,
- context: GenContext,
- code: &mut CodeDeque,
- ) {
- self.marker.reset_arg(term.arity(clause.term_loc()));
-
- let mut stack = Stack::uninitialized();
- let iter = query_iterator::<true>(&mut term.heap, &mut stack, clause.term_loc());
+ fn compile_query_line(&mut self, term: &QueryTerm, term_loc: GenContext, code: &mut CodeDeque) {
+ self.marker.reset_arg(term.arity());
- let query = self.compile_target::<QueryInstruction, _>(iter, &clause.code_indices, context);
+ let iter = QueryIterator::new(term);
+ let query = self.compile_target::<QueryInstruction, _>(iter, term_loc);
code.extend(query);
- self.add_call(code, clause.ct.to_instr(), clause.call_policy);
+
+ match term {
+ &QueryTerm::Clause(_, ref ct, _, call_policy) => {
+ self.add_call(code, ct.to_instr(), call_policy);
+ }
+ _ => unreachable!(),
+ };
}
- fn split_predicate(heap: &mut Heap, clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
+ fn split_predicate(clauses: &[PredicateClause]) -> Vec<ClauseSpan> {
let mut subseqs = Vec::new();
let mut left = 0;
let mut optimal_index = 0;
'outer: for (right, clause) in clauses.iter().enumerate() {
- if let Some(args) = clause.args(heap) {
- for (instantiated_arg_index, arg_idx) in args.enumerate() {
- let arg = heap[arg_idx];
- let arg = heap_bound_store(heap, heap_bound_deref(heap, arg));
-
- if !arg.is_var() {
+ if let Some(args) = clause.args() {
+ for (instantiated_arg_index, arg) in args.iter().enumerate() {
+ if !matches!(arg, Term::Var(..) | Term::AnonVar) {
if optimal_index != instantiated_arg_index {
if left >= right {
optimal_index = instantiated_arg_index;
fn compile_pred_subseq<I: Indexer>(
&mut self,
- heap: &mut Heap,
clauses: &mut [PredicateClause],
optimal_index: usize,
) -> Result<Code, CompilationError> {
let clause_code = match clause {
PredicateClause::Fact(fact, var_data) => {
let var_data = std::mem::take(var_data);
- self.compile_fact(heap, fact, var_data)?
+ self.compile_fact(fact, var_data)?
}
PredicateClause::Rule(rule, var_data) => {
let var_data = std::mem::take(var_data);
- self.compile_rule(heap, rule, var_data)?
+ self.compile_rule(rule, var_data)?
}
};
skip_stub_try_me_else = !self.settings.is_dynamic();
}
- let arg = clause.args(heap).map(|r| heap[r.start() + optimal_index]);
+ let arg = clause.args().and_then(|args| args.get(optimal_index));
if let Some(arg) = arg {
let index = code.len();
if clauses_len > 1 || self.settings.is_extensible {
- let arg = heap_bound_store(heap, heap_bound_deref(heap, arg));
- code_offsets.index_term(heap, arg, index, &mut clause_index_info);
+ code_offsets.index_term(arg, index, &mut clause_index_info);
}
}
pub(crate) fn compile_predicate(
&mut self,
- heap: &mut Heap,
mut clauses: Vec<PredicateClause>,
) -> Result<Code, CompilationError> {
let mut code = Code::new();
- let split_pred = Self::split_predicate(heap, &clauses);
+ let split_pred = Self::split_predicate(&clauses);
let multi_seq = split_pred.len() > 1;
for ClauseSpan {
let skel_lower_bound = self.skeleton.clauses.len();
let code_segment = if self.settings.is_dynamic() {
self.compile_pred_subseq::<DynamicCodeIndices>(
- heap,
&mut clauses[left..right],
instantiated_arg_index,
)?
} else {
self.compile_pred_subseq::<StaticCodeIndices>(
- heap,
&mut clauses[left..right],
instantiated_arg_index,
)?
use crate::allocator::*;
-use crate::atom_table::*;
use crate::codegen::SubsumedBranchHits;
use crate::forms::{GenContext, Level};
use crate::instructions::*;
-use crate::machine::disjuncts::*;
-use crate::machine::heap::*;
+use crate::machine::disjuncts::VarData;
use crate::parser::ast::*;
use crate::targets::*;
-use crate::types::*;
use crate::variable_records::*;
use bit_set::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
+use std::cell::Cell;
use std::collections::VecDeque;
use std::ops::{Deref, DerefMut};
in_use: BitSet<usize>, // deep and non-var allocations
temp_free_list: Vec<usize>,
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num
- non_var_registers: IndexMap<usize, usize, FxBuildHasher>,
- non_var_register_heap_locs: IndexMap<usize, usize, FxBuildHasher>,
}
impl DebrayAllocator {
for var_num in subsumed_hits {
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm {
- ref mut allocation, ..
- } => {
+ VarAlloc::Perm(_, ref mut allocation) => {
if let PermVarAllocation::Done {
shallow_safety,
deep_safety,
let num_occurrences = self.var_data.records[var_num].num_occurrences;
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm { allocation, .. } => {
+ VarAlloc::Perm(_, allocation) => {
let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num),
branch_designator,
&mut self,
chunk_num: usize,
code: &mut CodeDeque,
- ) -> Option<RegType> {
+ ) {
if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
let k = self.arg_c;
.allocation
.set_register(r.reg_num());
self.in_use.insert(r.reg_num());
-
- return Some(r);
}
};
-
- None
}
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
}
self.temp_lb = final_index + 1;
-
final_index
}
p
};
- self.var_data.records[var_num].allocation = VarAlloc::Perm {
- reg: p,
- allocation: PermVarAllocation::done(),
- };
-
+ self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
p
}
}
#[inline(always)]
- pub fn get_var_binding(&self, var_num: usize) -> RegType {
+ pub fn get_binding(&self, var_num: usize) -> RegType {
self.var_data.records[var_num].allocation.as_reg_type()
}
- #[inline(always)]
- pub fn get_non_var_binding(&self, heap_loc: usize) -> RegType {
- RegType::Temp(self.non_var_registers.get(&heap_loc).cloned().unwrap_or(0))
- }
-
pub fn num_perm_vars(&self) -> usize {
self.perm_lb - 1
}
}
fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) {
- if let VarAlloc::Perm { .. } = &self.var_data.records[var_num].allocation {
+ if let VarAlloc::Perm(..) = &self.var_data.records[var_num].allocation {
self.perm_free_list.push_back((chunk_num, var_num));
}
}
self.perm_free_list.pop_front();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm {
- reg: p,
- allocation: PermVarAllocation::Pending,
- } if *p > 0 => {
+ VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
return Some(std::mem::replace(p, 0));
}
_ => {}
}
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
- match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm { allocation, .. } => {
- *allocation = PermVarAllocation::Pending;
- self.add_perm_to_free_list(chunk_num, var_num);
- }
- _ => {}
+ if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
+ *allocation = PermVarAllocation::Pending;
+ self.add_perm_to_free_list(chunk_num, var_num);
}
}
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm {
- allocation:
- PermVarAllocation::Done {
- deep_safety,
- shallow_safety,
- ..
- },
- ..
- } => {
+ VarAlloc::Perm(
+ _,
+ PermVarAllocation::Done {
+ deep_safety,
+ shallow_safety,
+ ..
+ },
+ ) => {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator);
}
*safety = VarSafetyStatus::unneeded(branch_designator);
}
_ => {
- // the (permanent) variable might have been freed by
- // this point, in which case we do nothing.
+ unreachable!()
}
}
}
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm {
- allocation:
- PermVarAllocation::Done {
- deep_safety,
- shallow_safety,
- ..
- },
- ..
- } => {
+ VarAlloc::Perm(
+ _,
+ PermVarAllocation::Done {
+ deep_safety,
+ shallow_safety,
+ ..
+ },
+ ) => {
// GetVariable in head chunk is considered safe.
if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::unneeded(branch_designator);
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm {
- allocation:
- PermVarAllocation::Done {
- ref mut shallow_safety,
- ..
- },
- ..
- } => {
+ VarAlloc::Perm(
+ _,
+ PermVarAllocation::Done {
+ ref mut shallow_safety,
+ ..
+ },
+ ) => {
if !self.in_tail_position
|| self
.branch_stack
let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm {
- allocation:
- PermVarAllocation::Done {
- ref mut deep_safety,
- ..
- },
- ..
- } => {
+ VarAlloc::Perm(
+ _,
+ PermVarAllocation::Done {
+ ref mut deep_safety,
+ ..
+ },
+ ) => {
if self
.branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator)
temp_free_list: vec![],
perm_free_list: VecDeque::new(),
branch_stack: BranchStack { stack: vec![] },
- non_var_registers: IndexMap::with_hasher(FxBuildHasher::default()),
- non_var_register_heap_locs: IndexMap::with_hasher(FxBuildHasher::default()),
}
}
fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
- context: GenContext,
+ term_loc: GenContext,
code: &mut CodeDeque,
) -> RegType {
let r = RegType::Temp(self.alloc_reg_to_non_var());
Level::Root | Level::Shallow => {
let k = self.arg_c;
- if let GenContext::Last(chunk_num) = context {
+ if let GenContext::Last(chunk_num) = term_loc {
self.evacuate_arg::<Target>(chunk_num, code);
}
fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self,
lvl: Level,
- heap_loc: usize,
- context: GenContext,
+ term_loc: GenContext,
+ cell: &'a Cell<RegType>,
code: &mut CodeDeque,
- ) -> RegType {
- let r = self.get_non_var_binding(heap_loc);
+ ) {
+ let r = cell.get();
let r = match lvl {
Level::Shallow => {
let k = self.arg_c;
- if let GenContext::Last(chunk_num) = context {
- if let Some(new_r) = self.evacuate_arg::<Target>(chunk_num, code) {
- self.non_var_register_heap_locs
- .swap_remove(&k)
- .map(|old_heap_loc| {
- self.non_var_registers.insert(old_heap_loc, new_r.reg_num());
- self.non_var_register_heap_locs
- .insert(new_r.reg_num(), old_heap_loc);
- });
-
- self.non_var_registers.insert(heap_loc, k);
- self.non_var_register_heap_locs.insert(k, heap_loc);
- }
+ if let GenContext::Last(chunk_num) = term_loc {
+ self.evacuate_arg::<Target>(chunk_num, code);
}
self.arg_c += 1;
RegType::Temp(k)
}
- _ if r.reg_num() == 0 => {
- let r = RegType::Temp(self.alloc_reg_to_non_var());
- self.non_var_registers.insert(heap_loc, r.reg_num());
- self.non_var_register_heap_locs
- .insert(r.reg_num(), heap_loc);
- r
- }
+ _ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
_ => {
self.in_use.insert(r.reg_num());
r
}
};
- r
+ cell.set(r);
}
fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
- context: GenContext,
+ cell: &Cell<VarReg>,
+ term_loc: GenContext,
code: &mut CodeDeque,
- ) -> RegType {
- let (r, is_new_var) = match self.get_var_binding(var_num) {
+ ) {
+ let (r, is_new_var) = match self.get_binding(var_num) {
RegType::Temp(0) => {
- let o = self.alloc_reg_to_var::<Target>(var_num, lvl, context, code);
+ let o = self.alloc_reg_to_var::<Target>(var_num, lvl, term_loc, code);
+ cell.set(VarReg::Norm(RegType::Temp(o)));
(RegType::Temp(o), true)
}
RegType::Perm(0) => {
- let p = self.alloc_perm_var(var_num, context.chunk_num());
+ let p = self.alloc_perm_var(var_num, term_loc.chunk_num());
+ cell.set(VarReg::Norm(RegType::Perm(p)));
(RegType::Perm(p), true)
}
r @ RegType::Perm(_) => {
let is_new_var = match &mut self.var_data.records[var_num].allocation {
- VarAlloc::Perm { allocation, .. } => {
+ VarAlloc::Perm(_, allocation) => {
if allocation.pending() {
*allocation = PermVarAllocation::done();
true
r => (r, false),
};
- self.mark_reserved_var::<Target>(var_num, lvl, context, code, r, is_new_var)
+ self.mark_reserved_var::<Target>(var_num, lvl, cell, term_loc, code, r, is_new_var);
}
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self,
var_num: usize,
lvl: Level,
- context: GenContext,
+ cell: &Cell<VarReg>,
+ term_loc: GenContext,
code: &mut CodeDeque,
r: RegType,
is_new_var: bool,
- ) -> RegType {
+ ) {
match lvl {
Level::Root | Level::Shallow => {
let k = self.arg_c;
if self.is_curr_arg_distinct_from(var_num) {
- self.evacuate_arg::<Target>(context.chunk_num(), code);
+ self.evacuate_arg::<Target>(term_loc.chunk_num(), code);
}
- if !self.in_place(var_num, context, r, k) {
+ cell.set(VarReg::ArgAndNorm(r, k));
+
+ if !self.in_place(var_num, term_loc, r, k) {
if is_new_var {
- self.mark_safe_var(var_num, lvl, context);
+ self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::argument_to_variable(r, k));
} else {
code.push_back(self.argument_to_value::<Target>(var_num, r, k));
self.arg_c += 1;
}
Level::Deep if is_new_var => {
- if let GenContext::Head = context {
+ if let GenContext::Head = term_loc {
if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
code.push_back(self.subterm_to_value::<Target>(var_num, r));
} else {
- self.mark_safe_var(var_num, lvl, context);
+ self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::subterm_to_variable(r));
}
} else {
- self.mark_safe_var(var_num, lvl, context);
+ self.mark_safe_var(var_num, lvl, term_loc);
code.push_back(Target::subterm_to_variable(r));
}
}
if record.running_count < record.num_occurrences {
record.running_count += 1;
} else {
- self.free_var(context.chunk_num(), var_num);
+ self.free_var(term_loc.chunk_num(), var_num);
}
self.in_use.insert(o);
- r
}
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType {
- match self.get_var_binding(var_num) {
+ match self.get_binding(var_num) {
RegType::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
RegType::Temp(0) => {
let t = self.alloc_reg_to_non_var();
fn reset(&mut self) {
self.perm_lb = 1;
self.shallow_temp_mappings.clear();
- self.non_var_registers.clear();
- self.non_var_register_heap_locs.clear();
self.in_use.clear();
self.temp_free_list.clear();
}
fn reset_contents(&mut self) {
self.in_use.clear();
self.shallow_temp_mappings.clear();
- self.non_var_registers.clear();
- self.non_var_register_heap_locs.clear();
self.temp_free_list.clear();
}
self.arg_c += 1;
}
- fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) {
- let head_cell = heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(head_loc)));
-
- read_heap_cell!(head_cell,
- (HeapCellValueTag::Str, s) => {
- let arity = cell_as_atom_cell!(heap[s]).get_arity();
-
- self.reset_arg(arity);
- self.arity = arity;
+ fn reset_at_head(&mut self, args: &[Term]) {
+ self.reset_arg(args.len());
+ self.arity = args.len();
- for (c_idx, heap_idx) in (s+1 ..= s+arity).enumerate() {
- let arg = heap[heap_idx];
-
- if arg.is_var() {
- let var = heap_bound_store(
- heap,
- heap_bound_deref(heap, arg),
- );
-
- if !var.is_var() {
- continue;
- }
+ for (idx, arg) in args.iter().enumerate() {
+ if let Term::Var(_, ref var) = arg {
+ let var_num = var.to_var_num().unwrap();
+ let r = self.get_binding(var_num);
- let term_loc = var.get_value() as usize;
-
- match self.var_data.var_locs_to_nums.get(
- VarPtrIndex { chunk_num: 0, term_loc },
- ) {
- VarPtr::Numbered(var_num) => {
- let r = self.get_var_binding(var_num);
-
- if !r.is_perm() && r.reg_num() == 0 {
- self.in_use.insert(c_idx + 1);
- self.shallow_temp_mappings.insert(c_idx + 1, var_num);
- self.var_data.records[var_num]
- .allocation
- .set_register(c_idx + 1);
- }
- }
- VarPtr::Anon => {}
- }
- }
+ if !r.is_perm() && r.reg_num() == 0 {
+ self.in_use.insert(idx + 1);
+ self.shallow_temp_mappings.insert(idx + 1, var_num);
+ self.var_data.records[var_num]
+ .allocation
+ .set_register(idx + 1);
}
}
- _ => {
- self.reset_arg(0);
- }
- );
+ }
}
fn reset_arg(&mut self, arity: usize) {
use crate::functor_macro::*;
use crate::instructions::*;
use crate::machine::disjuncts::VarData;
-use crate::machine::heap::*;
-// use crate::machine::loader::PredicateQueue;
+use crate::machine::loader::PredicateQueue;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::parser::ast::*;
use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat;
+use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
Shallow,
}
+impl Level {
+ pub(crate) fn child_level(self) -> Level {
+ match self {
+ Level::Root => Level::Shallow,
+ _ => Level::Deep,
+ }
+ }
+}
+
#[derive(Debug, Clone, Copy)]
pub enum CallPolicy {
Default,
}
}
- #[inline]
- pub fn chunk_type(&self) -> ChunkType {
- match self {
- GenContext::Head => ChunkType::Head,
- GenContext::Mid(_) => ChunkType::Mid,
- GenContext::Last(_) => ChunkType::Last,
- }
- }
-
#[inline]
pub fn is_last(self) -> bool {
matches!(self, GenContext::Last(_))
Last,
}
+#[derive(Debug)]
+pub enum RootIterationPolicy {
+ Iterated,
+ NotIterated,
+}
+
+impl RootIterationPolicy {
+ #[inline(always)]
+ pub fn iterable(&self) -> bool {
+ matches!(self, RootIterationPolicy::Iterated)
+ }
+}
+
impl ChunkType {
#[inline(always)]
pub fn to_gen_context(self, chunk_num: usize) -> GenContext {
#[derive(Debug)]
pub enum ChunkedTerms {
Branch(Vec<VecDeque<ChunkedTerms>>),
- Chunk {
- chunk_num: usize,
- terms: VecDeque<QueryTerm>,
- },
+ Chunk { terms: VecDeque<QueryTerm> },
}
#[derive(Debug)]
pub struct ChunkedTermVec {
pub chunk_vec: VecDeque<ChunkedTerms>,
- pub current_chunk_num: usize,
- pub current_chunk_type: ChunkType,
}
impl Deref for ChunkedTermVec {
pub fn new() -> Self {
Self {
chunk_vec: VecDeque::new(),
- current_chunk_num: 0,
- current_chunk_type: ChunkType::Mid,
}
}
.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity)));
}
- pub fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
- if self.current_chunk_type.is_last() {
- self.current_chunk_type = ChunkType::Mid;
- self.current_chunk_num += 1;
- true
- } else {
- false
- }
- }
-
- pub fn try_set_chunk_at_call_boundary(&mut self) -> bool {
- if self.current_chunk_type.is_last() {
- self.current_chunk_num += 1;
- true
- } else {
- self.current_chunk_type = ChunkType::Last;
- false
- }
- }
-
#[inline]
pub fn add_chunk(&mut self) {
let chunk = ChunkedTerms::Chunk {
- chunk_num: self.current_chunk_num,
terms: VecDeque::from(vec![]),
};
self.chunk_vec.push_back(chunk);
}
- pub fn current_gen_context(&self) -> GenContext {
- self.current_chunk_type
- .to_gen_context(self.current_chunk_num)
- }
-
pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() {
Some(ChunkedTerms::Branch(_)) => {
let chunk = ChunkedTerms::Chunk {
- chunk_num: self.current_chunk_num,
terms: VecDeque::from(vec![term]),
};
}
None => {
let chunk = ChunkedTerms::Chunk {
- chunk_num: self.current_chunk_num,
terms: VecDeque::from(vec![term]),
};
}
}
-#[derive(Debug)]
-pub struct QueryClause {
- pub ct: ClauseType,
- pub term: HeapCellValue,
- pub code_indices: IndexMap<usize, CodeIndex, FxBuildHasher>,
- pub call_policy: CallPolicy,
-}
-
-impl QueryClause {
- pub fn term_loc(&self) -> usize {
- self.term.get_value() as usize
- }
-}
-
#[derive(Debug)]
pub enum QueryTerm {
- Clause(QueryClause),
+ // register, clause type, subterms, clause call policy.
+ Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
Fail,
- Succeed,
- LocalCut { var_num: usize, cut_prev: bool },
- GlobalCut(usize), // var_num
+ LocalCut { var_num: usize, cut_prev: bool }, // var_num
+ GlobalCut(usize), // var_num
GetCutPoint { var_num: usize, prev_b: bool },
GetLevel(usize), // var_num
}
-#[derive(Clone, Copy, Debug)]
+impl QueryTerm {
+ pub(crate) fn arity(&self) -> usize {
+ match self {
+ QueryTerm::Clause(_, _, subterms, ..) => subterms.len(),
+ &QueryTerm::GetLevel(_) | &QueryTerm::GetCutPoint { .. } => 1,
+ _ => 0,
+ }
+ }
+}
+
+#[derive(Debug)]
pub struct Fact {
- pub(crate) term_loc: usize,
+ pub(crate) head: Term,
}
#[derive(Debug)]
pub struct Rule {
- pub(crate) term_loc: usize,
+ pub(crate) head: (Atom, Vec<Term>),
pub(crate) clauses: ChunkedTermVec,
}
}
}
-pub fn clause_predicate_key_from_heap(
- heap: &impl SizedHeap,
- value: HeapCellValue,
-) -> Option<PredicateKey> {
- read_heap_cell!(value,
- (HeapCellValueTag::Atom, (name, _arity)) => {
- debug_assert_eq!(_arity, 0);
- Some((name, 0))
+pub trait ClauseInfo {
+ fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
+ match clauses.first() {
+ Some(cl) => {
+ self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl)
+ }
+ None => true,
}
- _ => {
- if value.is_ref() {
- clause_predicate_key(heap, value.get_value() as usize)
- } else {
- None
+ }
+
+ fn name(&self) -> Option<Atom>;
+ fn arity(&self) -> usize;
+}
+
+impl ClauseInfo for PredicateKey {
+ #[inline]
+ fn name(&self) -> Option<Atom> {
+ Some(self.0)
+ }
+
+ #[inline]
+ fn arity(&self) -> usize {
+ self.1
+ }
+}
+
+impl ClauseInfo for Term {
+ fn name(&self) -> Option<Atom> {
+ match self {
+ Term::Clause(_, name, terms) => {
+ match name {
+ atom!(":-") => {
+ match terms.len() {
+ 1 => None, // a declaration.
+ 2 => terms[0].name(),
+ _ => Some(*name),
+ }
+ }
+ _ => Some(*name), //str_buf),
+ }
}
+ Term::Literal(_, Literal::Atom(name)) => Some(*name),
+ _ => None,
+ }
+ }
+
+ fn arity(&self) -> usize {
+ match self {
+ Term::Clause(_, name, terms) => match &*name.as_str() {
+ ":-" => match terms.len() {
+ 1 => 0,
+ 2 => terms[0].arity(),
+ _ => terms.len(),
+ },
+ _ => terms.len(),
+ },
+ _ => 0,
}
- )
+ }
}
-pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option<PredicateKey> {
- let key_opt = term_predicate_key(heap, term_loc);
+impl ClauseInfo for Rule {
+ fn name(&self) -> Option<Atom> {
+ Some(self.head.0)
+ }
- if Some((atom!(":-"), 2)) == key_opt {
- term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_predicate_key(heap, arg_loc))
- } else {
- key_opt
+ fn arity(&self) -> usize {
+ self.head.1.len()
+ }
+}
+
+impl ClauseInfo for PredicateClause {
+ fn name(&self) -> Option<Atom> {
+ match self {
+ PredicateClause::Fact(ref term, ..) => term.head.name(),
+ PredicateClause::Rule(ref rule, ..) => rule.name(),
+ }
+ }
+
+ fn arity(&self) -> usize {
+ match self {
+ PredicateClause::Fact(ref term, ..) => term.head.arity(),
+ PredicateClause::Rule(ref rule, ..) => rule.arity(),
+ }
}
}
}
impl PredicateClause {
- pub(crate) fn args<'a>(&self, heap: &'a Heap) -> Option<std::ops::RangeInclusive<usize>> {
- let focus = match self {
- &PredicateClause::Fact(Fact { term_loc }, _) => term_loc,
- &PredicateClause::Rule(Rule { term_loc, .. }, _) => {
- term_nth_arg(heap, term_loc, 1).unwrap()
- }
- };
-
- let arity = clause_predicate_key(heap, focus)
- .map(|(_name, arity)| arity)
- .unwrap_or(0);
-
- read_heap_cell!(heap_bound_store(heap, heap_bound_deref(heap, heap[focus])),
- (HeapCellValueTag::Str, s) => {
- Some(s+1 ..= s+arity)
- }
- _ => {
- None
+ pub(crate) fn args(&self) -> Option<&[Term]> {
+ match self {
+ PredicateClause::Fact(term, ..) => match &term.head {
+ Term::Clause(_, _, args) => Some(args),
+ _ => None,
+ },
+ PredicateClause::Rule(rule, ..) => {
+ if rule.head.1.is_empty() {
+ None
+ } else {
+ Some(&rule.head.1)
+ }
}
- )
+ }
}
}
impl ArenaFrom<u64> for HeapCellValue {
#[inline]
fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue {
- fixnum!(value as i64, arena)
+ HeapCellValue::from(fixnum!(Literal, value as i64, arena))
}
}
}
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
pub(crate) enum OptArgIndexKey {
- Literal(usize, usize, HeapCellValue, Vec<HeapCellValue>), // index, IndexingCode location, opt arg, alternatives
- List(usize, usize), // index, IndexingCode location
+ Literal(usize, usize, Literal, Option<Literal>), // index, IndexingCode location, opt arg, alternatives
+ List(usize, usize), // index, IndexingCode location
None,
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity
}
1 + $res_len,
[$($subfunctor),*])
});
+ ([literal($e:expr) $(, $dt:ident($($value:tt),*))*],
+ [$($res:expr),*],
+ $res_len:expr,
+ [$($subfunctor:expr),*]) => ({
+ build_functor!([$($dt($($value),*)),*],
+ [$($res, )* FunctorElement::AbsoluteCell(HeapCellValue::from($e))],
+ 1 + $res_len,
+ [$($subfunctor),*])
+ });
([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*],
$res_len:expr,
start_value: HeapCellValue,
iter_stack: Vec<HeapCellValue>,
mark_phase: bool,
- pub heap: &'a mut Heap,
+ heap: &'a mut Heap,
}
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
}
}
-pub trait FocusedHeapIter: Deref<Target = Heap> + Iterator<Item = HeapCellValue> {
+pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
fn focus(&self) -> IterStackLoc;
}
}
}
-impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> {
- type Target = Heap;
-
- fn deref(&self) -> &Self::Target {
- &self.heap
- }
-}
-
impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
#[inline]
pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue {
#[inline]
fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self {
let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap);
- // heap.push(cell);
Self {
heap,
}
impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
- type Target = Heap;
+ type Target = Iter;
fn deref(&self) -> &Self::Target {
&self.base_iter
}
}
-/*
-impl<Iter: FocusedHeapIter> PostOrderIterator<Iter> {
- /* return true if the term at heap offset idx_loc is a
- * direct/inlined subterm of a structure at the focus of
- * self.stack.last(). this function is used to determine, e.g.,
- * ownership of inlined code indices.
- */
- #[inline]
- pub(crate) fn direct_subterm_of_str(&self, idx_loc: usize) -> bool {
- if let Some((_child_count, item, focus)) = self.parent_stack.last() {
- read_heap_cell!(item,
- (HeapCellValueTag::Atom, (_name, arity)) => {
- let focus = focus.value() as usize;
- return focus + arity >= idx_loc && focus < idx_loc;
- }
- _ => {}
- );
- }
-
- false
- }
-}
-*/
-
pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> =
PostOrderIterator<StackfulPreOrderHeapIter<'a, ElideLists>>;
-impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists> {
+impl<ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'_, ElideLists> {
#[inline]
pub fn pop_stack(&mut self) {
if let Some((child_count, ..)) = self.parent_stack.last() {
// two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars.
- wam.machine_st.allocate_pstr("abc ").unwrap();
+ wam.machine_st.heap.allocate_pstr("abc ").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
- wam.machine_st.allocate_pstr("def").unwrap();
+ wam.machine_st.heap.allocate_pstr("def").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- 1,
+ 0,
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
- heap_loc_as_cell!(0)
+ heap_loc_as_cell!(1)
);
assert_eq!(iter.next(), None);
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- 0,
+ 4,
);
// the cycle will be iterated twice before being detected.
);
assert_eq!(
unmark_cell_bits!(iter.next().unwrap()),
- list_loc_as_cell!(1)
- );
- assert_eq!(
- unmark_cell_bits!(iter.next().unwrap()),
- atom_as_cell!(a_atom)
- );
- assert_eq!(
- unmark_cell_bits!(iter.next().unwrap()),
- list_loc_as_cell!(3)
+ heap_loc_as_cell!(0)
);
assert_eq!(iter.next(), None);
// two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars.
- wam.machine_st.allocate_pstr("abc ").unwrap();
+ wam.machine_st.heap.allocate_pstr("abc ").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
}
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
- wam.machine_st.allocate_pstr("def").unwrap();
+ wam.machine_st.heap.allocate_pstr("def").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
section.push_cell(pstr_loc_as_cell!(0));
});
+ assert_eq!(wam.machine_st.heap.cell_len(), 4);
+
{
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap,
&mut wam.machine_st.stack,
- 2,
+ 3,
);
assert_eq!(iter.heap.slice_to_str(0, "a string".len()), "a string");
+ assert_eq!(iter.next().unwrap(), pstr_loc_as_cell!(0));
assert_eq!(iter.next().unwrap(), empty_list_as_cell!());
assert_eq!(iter.next(), None);
}
// two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars.
- wam.machine_st.allocate_pstr("abc ").unwrap();
+ wam.machine_st.heap.allocate_pstr("abc ").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
}
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
- wam.machine_st.allocate_pstr("def").unwrap();
+ wam.machine_st.heap.allocate_pstr("def").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(4)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
// two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars.
- wam.machine_st.allocate_pstr("abc ").unwrap();
+ wam.machine_st.heap.allocate_pstr("abc ").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
wam.machine_st.heap[2] = heap_loc_as_cell!(2);
assert_eq!(wam.machine_st.heap.cell_len(), 3);
- wam.machine_st.allocate_pstr("def").unwrap();
+ wam.machine_st.heap.allocate_pstr("def").unwrap();
assert_eq!(wam.machine_st.heap.cell_len(), 4);
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
toplevel_spec: Option<DirectedOp>,
last_item_idx: usize,
parent_of_first_op: Option<(DirectedOp, usize)>,
- pub var_names: IndexMap<HeapCellValue, Var>,
+ pub var_names: IndexMap<HeapCellValue, VarPtr>,
pub numbervars_offset: Integer,
pub numbervars: bool,
pub quoted: bool,
stack: &'a mut Stack,
op_dir: &'a OpDir,
output: Outputter,
- root_loc: usize,
+ term_loc: usize,
) -> Self {
HCPrinter {
outputter: output,
- iter: stackful_preorder_iter(heap, stack, root_loc),
+ iter: stackful_preorder_iter(heap, stack, term_loc),
op_dir,
state_stack: vec![],
toplevel_spec: None,
if let Some(var) = self.var_names.get(&cell) {
read_heap_cell!(cell,
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
- return Some(var.to_string());
+ return Some(var.borrow().to_string());
}
_ => {
self.iter.push_stack(h);
// short-circuits handle_heap_term.
// self.iter.pop_stack();
- let var_str = var.to_string();
+ let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str);
Some(var) => {
// If the term is bound to a named variable,
// print the variable's name to output.
- let var_str = var.to_string();
+ let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str);
printer
.var_names
- .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
+ .insert(list_loc_as_cell!(1), VarPtr::from("L"));
let output = printer.print();
printer
.var_names
- .insert(list_loc_as_cell!(1), Rc::new("L".to_string()));
+ .insert(list_loc_as_cell!(1), VarPtr::from("L"));
let output = printer.print();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_pstr("abc").unwrap();
+ wam.machine_st.heap.allocate_pstr("abc").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
use crate::atom_table::*;
+use crate::parser::ast::*;
+
use crate::forms::*;
use crate::instructions::*;
-use crate::machine::heap::*;
-use crate::parser::ast::Fixnum;
-use crate::types::*;
+use crate::types::HeapCellValue;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
match constant_key {
Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
- constants.insert(*constant, constant_ptr);
+ constants.insert(HeapCellValue::from(*constant), constant_ptr);
}
_ if constant_ptr.is_external() => {
// this must be a defunct clause, because it's been deleted
match &opt_arg_index_key {
OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
let offset = new_clause_loc - index_loc + 1;
- merging_ptr.index_constant(*constant, offset);
+ merging_ptr.index_constant(HeapCellValue::from(*constant), offset);
- for overlapping_constant in overlapping_constants {
+ if let Some(overlapping_constant) = overlapping_constants {
merging_ptr.offset = 0;
-
- merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset);
+ merging_ptr.index_overlapping_constant(
+ HeapCellValue::from(*constant),
+ HeapCellValue::from(*overlapping_constant),
+ offset,
+ );
}
}
OptArgIndexKey::Structure(_, index_loc, name, arity) => {
}
pub(crate) fn remove_constant_indices(
- constant: HeapCellValue,
- overlapping_constants: &[HeapCellValue],
+ constant: Literal,
+ overlapping_constants: Option<Literal>,
indexing_code: &mut [IndexingLine],
offset: usize,
) {
let mut constants_index = 0;
- for constant in iter {
+ for constant in iter.map(|l| HeapCellValue::from(*l)) {
loop {
match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
)) => {
constants_index = index;
- let constant = *constant;
-
match constants.get(&constant).cloned() {
Some(IndexingCodePtr::DynamicExternal(_))
| Some(IndexingCodePtr::External(_))
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
- constants.insert(*constant, ext);
+ constants.insert(constant, ext);
}
_ => {
unreachable!()
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants,
)) => {
- constants.insert(*constant, ext);
+ constants.insert(constant, ext);
}
_ => {
unreachable!()
) {
match opt_arg_index_key {
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => {
- remove_constant_indices(*constant, overlapping_constants, indexing_code, clause_loc);
+ remove_constant_indices(*constant, *overlapping_constants, indexing_code, clause_loc);
}
OptArgIndexKey::Structure(_, _, name, arity) => {
remove_structure_index(*name, *arity, indexing_code, clause_loc);
}
}
-pub(crate) fn constant_key_alternatives(
- constant: HeapCellValue,
- // atom_tbl: &AtomTable,
- // arena: &mut Arena,
-) -> Vec<HeapCellValue> {
- let mut constants = vec![];
-
- match Number::try_from(constant) {
- Ok(Number::Integer(n)) => {
- let result = (&*n).try_into();
- if let Ok(value) = result {
- constants.push(
- Fixnum::build_with_checked(value)
- .map(|n| fixnum_as_cell!(n))
- .unwrap(),
- );
- }
- }
- _ => {}
- }
+pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
+ let n = match &constant {
+ Literal::Rational(n) if n.denominator().is_one() => n.numerator(),
+ Literal::Integer(n) => n,
+ _ => return None,
+ };
- /*
- match constant {
- Literal::Atom(ref name) => {
- if let Some(c) = name.as_char() {
- constants.push(Literal::Char(c));
- }
- }
- Literal::Char(c) => {
- let atom = AtomTable::build_with(atom_tbl, &c.to_string());
- constants.push(Literal::Atom(atom));
- }
- /*
- // constant_to_literal takes care of the downward conversion from Integer to Fixnum
- // if possible.
- Literal::Fixnum(ref n) => {
- constants.push(Literal::Integer(arena_alloc!(n, arena)));
- }
- */
- Literal::Integer(ref n) => {
- let result = (&**n).try_into();
- if let Ok(value) = result {
- Fixnum::build_with_checked(value)
- .map(|n| {
- constants.push(Literal::Fixnum(n));
- })
- .unwrap();
- }
- }
- _ => {}
+ if let Ok(n) = n.try_into() {
+ Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
+ } else {
+ None
}
- */
-
- constants
}
#[derive(Debug)]
self.indices.lists().push_back(index);
}
- fn index_constant(&mut self, constant: HeapCellValue, index: usize) -> Vec<HeapCellValue> {
- let overlapping_constants = constant_key_alternatives(constant);
- let code = self.indices.constants().entry(constant).or_default();
+ fn index_constant(&mut self, constant: Literal, index: usize) -> Option<Literal> {
+ let overlapping_constant_opt = constant_key_alternatives(constant);
+ let code = self
+ .indices
+ .constants()
+ .entry(HeapCellValue::from(constant))
+ .or_default();
let is_initial_index = code.is_empty();
code.push_back(I::compute_index(
self.non_counted_bt,
));
- for constant in &overlapping_constants {
- let code = self.indices.constants().entry(*constant).or_default();
+ if let Some(constant) = overlapping_constant_opt.map(HeapCellValue::from) {
+ let code = self.indices.constants().entry(constant).or_default();
let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
code.push_back(index);
}
- overlapping_constants
+ overlapping_constant_opt
}
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
pub(crate) fn index_term(
&mut self,
- heap: &Heap,
- optimal_arg: HeapCellValue,
+ optimal_arg: &Term,
index: usize,
clause_index_info: &mut ClauseIndexInfo,
) {
- read_heap_cell!(optimal_arg,
- (HeapCellValueTag::Str, s) => {
- let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
-
- if (name, arity) == (atom!("."), 2) {
- clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
- self.index_list(index);
- } else {
- clause_index_info.opt_arg_index_key =
- OptArgIndexKey::Structure(self.optimal_index, 0, name, arity);
-
- self.index_structure(name, arity, index);
- }
- }
- (HeapCellValueTag::Atom, (name, arity)) => {
- debug_assert_eq!(arity, 0);
-
- let overlapping_constants = self.index_constant(atom_as_cell!(name), index);
-
- clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
- self.optimal_index,
- 0,
- atom_as_cell!(name),
- overlapping_constants,
- );
+ match optimal_arg {
+ &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
+ clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
+ self.index_list(index);
}
- (HeapCellValueTag::Lis
- // | HeapCellValueTag::CStr
- | HeapCellValueTag::PStrLoc) => {
+ &Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
- _ if optimal_arg.is_constant() => {
- let overlapping_constants = self.index_constant(optimal_arg, index);
-
- clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
- self.optimal_index,
- 0,
- optimal_arg,
- overlapping_constants,
- );
+ &Term::Clause(_, name, ref terms) => {
+ clause_index_info.opt_arg_index_key =
+ OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len());
+
+ self.index_structure(name, terms.len(), index);
+ }
+ &Term::Literal(_, constant) => {
+ let overlapping_constants = self.index_constant(constant, index);
+
+ clause_index_info.opt_arg_index_key =
+ OptArgIndexKey::Literal(self.optimal_index, 0, constant, overlapping_constants);
}
_ => {}
- );
+ }
}
pub(crate) fn no_indices(&mut self) -> bool {
-use crate::atom_table::AtomCell;
+use crate::atom_table::*;
use crate::forms::*;
-use crate::heap_iter::*;
-use crate::machine::heap::*;
-use crate::machine::stack::*;
-use crate::types::*;
-
-use bit_set::*;
-use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
+use crate::instructions::*;
+use crate::parser::ast::*;
+use std::cell::Cell;
use std::collections::VecDeque;
use std::iter::*;
-use std::ops::Deref;
+use std::rc::Rc;
use std::vec::Vec;
-pub(crate) trait TermIterator:
- Deref<Target = Heap> + Iterator<Item = HeapCellValue>
-{
- fn focus(&self) -> IterStackLoc;
- fn level(&mut self) -> Level;
+#[allow(clippy::borrowed_box)]
+#[derive(Debug, Clone)]
+pub(crate) enum TermRef<'a> {
+ AnonVar(Level),
+ Cons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+ Literal(Level, &'a Cell<RegType>, &'a Literal),
+ Clause(Level, &'a Cell<RegType>, Atom, &'a Vec<Term>),
+ PartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
+ CompleteString(Level, &'a Cell<RegType>, Rc<String>),
+ Var(Level, &'a Cell<VarReg>, VarPtr),
}
+#[allow(clippy::borrowed_box)]
#[derive(Debug)]
-pub(crate) struct TargetIterator<I: FocusedHeapIter, const SKIP_ROOT: bool> {
- shallow_terms: IndexMap<usize, BitSet<usize>, FxBuildHasher>,
- root_terms: BitSet<usize>,
- iter: I,
- arg_c: usize,
+pub(crate) enum TermIterState<'a> {
+ AnonVar(Level),
+ Clause(Level, usize, &'a Cell<RegType>, Atom, &'a Vec<Term>),
+ Literal(Level, &'a Cell<RegType>, &'a Literal),
+ InitialCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+ FinalCons(Level, &'a Cell<RegType>, &'a Term, &'a Term),
+ InitialPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
+ FinalPartialString(Level, &'a Cell<RegType>, Rc<String>, &'a Box<Term>),
+ CompleteString(Level, &'a Cell<RegType>, Rc<String>),
+ Var(Level, &'a Cell<VarReg>, VarPtr),
}
-fn record_path(
- heap: &impl SizedHeap,
- root_terms: &mut BitSet<usize>,
- mut root_loc: usize,
-) -> usize {
- loop {
- let cell = heap[root_loc];
- root_terms.insert(root_loc);
-
- read_heap_cell!(cell,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if h == root_loc {
- break;
- } else {
- root_loc = h;
- }
+impl<'a> TermIterState<'a> {
+ pub(crate) fn subterm_to_state(lvl: Level, term: &'a Term) -> TermIterState<'a> {
+ match term {
+ Term::AnonVar => TermIterState::AnonVar(lvl),
+ Term::Clause(cell, name, subterms) => {
+ TermIterState::Clause(lvl, 0, cell, *name, subterms)
}
- (HeapCellValueTag::Lis) => {
- root_terms.insert(root_loc);
- break;
+ Term::Cons(cell, head, tail) => {
+ TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
}
- _ => {
- if cell.is_ref() {
- root_terms.insert(cell.get_value() as usize);
- }
-
- break;
+ Term::Literal(cell, constant) => TermIterState::Literal(lvl, cell, constant),
+ Term::PartialString(cell, string_buf, tail) => {
+ TermIterState::InitialPartialString(lvl, cell, string_buf.clone(), tail)
+ }
+ Term::CompleteString(cell, string) => {
+ TermIterState::CompleteString(lvl, cell, string.clone())
}
- );
+ Term::Var(cell, var_ptr) => TermIterState::Var(lvl, cell, var_ptr.clone()),
+ }
}
-
- root_loc
}
-fn find_root_terms(heap: &impl SizedHeap, root_loc: usize) -> (usize, BitSet<usize>) {
- let mut root_terms = BitSet::<usize>::default();
- let root_loc = record_path(heap, &mut root_terms, root_loc);
- (root_loc, root_terms)
+#[derive(Debug)]
+pub(crate) struct QueryIterator<'a> {
+ state_stack: Vec<TermIterState<'a>>,
}
-fn find_shallow_terms(
- heap: &impl SizedHeap,
- root_loc: usize,
-) -> IndexMap<usize, BitSet<usize>, FxBuildHasher> {
- let mut shallow_terms_map = IndexMap::with_hasher(FxBuildHasher::default());
-
- let (h, arity) = read_heap_cell!(heap[root_loc],
- (HeapCellValueTag::Str, s) => {
- (s+1, cell_as_atom_cell!(heap[s]).get_arity())
- }
- (HeapCellValueTag::Lis, l) => {
- (l, 2)
- }
- (HeapCellValueTag::Atom, (_name, arity)) => {
- (root_loc + 1, arity)
- }
- _ => {
- (root_loc, 0)
- }
- );
-
- for idx in 0..arity {
- let mut shallow_terms = BitSet::default();
- record_path(heap, &mut shallow_terms, h + idx);
- shallow_terms_map.insert(idx + 1, shallow_terms);
+impl<'a> QueryIterator<'a> {
+ fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
+ self.state_stack
+ .push(TermIterState::subterm_to_state(lvl, term));
}
- shallow_terms_map
-}
-
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> TargetIterator<I, SKIP_ROOT> {
- fn new(iter: I, root_loc: usize, arg_c: usize) -> Self {
- let (derefed_root_loc, root_terms) = find_root_terms(iter.deref(), root_loc);
- let shallow_terms = find_shallow_terms(iter.deref(), derefed_root_loc);
+ /*
+ fn from_rule_head_clause(terms: &'a Vec<Term>) -> Self {
+ let state_stack = terms
+ .iter()
+ .rev()
+ .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
+ .collect();
- Self {
- shallow_terms,
- root_terms,
- iter,
- arg_c,
- }
+ QueryIterator { state_stack }
}
+ */
+
+ fn from_term(term: &'a Term) -> Self {
+ let state = match term {
+ Term::AnonVar
+ | Term::Cons(..)
+ | Term::Literal(..)
+ | Term::PartialString(..)
+ | Term::CompleteString(..) => {
+ return QueryIterator {
+ state_stack: vec![],
+ }
+ }
+ Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
+ Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
+ };
- fn current_level(&self, arg_c_inc: usize) -> Level {
- let current_focus = self.iter.focus().value() as usize;
-
- if self.root_terms.contains(current_focus) {
- return Level::Root;
+ QueryIterator {
+ state_stack: vec![state],
}
+ }
- if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) {
- if shallow_terms.contains(current_focus) {
- return Level::Shallow;
+ fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
+ match term {
+ QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
+ self.state_stack
+ .push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
+ }
+ QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
+ self.state_stack
+ .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
}
+ _ => {}
}
+ }
- Level::Deep
+ pub fn new(term: &'a QueryTerm) -> Self {
+ let mut iter = QueryIterator {
+ state_stack: vec![],
+ };
+ iter.extend_state(Level::Root, term);
+ iter
}
}
-impl<'a, const SKIP_ROOT: bool> TermIterator for FactIterator<'a, SKIP_ROOT> {
- fn focus(&self) -> IterStackLoc {
- self.iter.focus()
- }
+impl<'a> Iterator for QueryIterator<'a> {
+ type Item = TermRef<'a>;
- fn level(&mut self) -> Level {
- let lvl = self.current_level(1);
+ fn next(&mut self) -> Option<Self::Item> {
+ while let Some(iter_state) = self.state_stack.pop() {
+ match iter_state {
+ TermIterState::AnonVar(lvl) => {
+ return Some(TermRef::AnonVar(lvl));
+ }
+ TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
+ if child_num == child_terms.len() {
+ match name {
+ atom!("$call") if lvl == Level::Root => {
+ self.push_subterm(Level::Shallow, &child_terms[0]);
+ }
+ _ => {
+ return match lvl {
+ Level::Root => None,
+ lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
+ }
+ }
+ };
+ } else {
+ self.state_stack.push(TermIterState::Clause(
+ lvl,
+ child_num + 1,
+ cell,
+ name,
+ child_terms,
+ ));
+
+ self.push_subterm(lvl.child_level(), &child_terms[child_num]);
+ }
+ }
+ TermIterState::InitialCons(lvl, cell, head, tail) => {
+ self.state_stack
+ .push(TermIterState::FinalCons(lvl, cell, head, tail));
- if let Level::Shallow = lvl {
- self.arg_c += 1;
+ self.push_subterm(lvl.child_level(), tail);
+ self.push_subterm(lvl.child_level(), head);
+ }
+ TermIterState::InitialPartialString(lvl, cell, string, tail) => {
+ self.state_stack
+ .push(TermIterState::FinalPartialString(lvl, cell, string, tail));
+ self.push_subterm(lvl.child_level(), tail);
+ }
+ TermIterState::FinalPartialString(lvl, cell, string, tail) => {
+ return Some(TermRef::PartialString(lvl, cell, string, tail));
+ }
+ TermIterState::CompleteString(lvl, cell, string) => {
+ return Some(TermRef::CompleteString(lvl, cell, string));
+ }
+ TermIterState::FinalCons(lvl, cell, head, tail) => {
+ return Some(TermRef::Cons(lvl, cell, head, tail));
+ }
+ TermIterState::Literal(lvl, cell, constant) => {
+ return Some(TermRef::Literal(lvl, cell, constant));
+ }
+ TermIterState::Var(lvl, cell, var_ptr) => {
+ return Some(TermRef::Var(lvl, cell, var_ptr));
+ }
+ };
}
- lvl
+ None
}
}
-impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> {
- fn focus(&self) -> IterStackLoc {
- self.iter.focus()
+#[derive(Debug)]
+pub(crate) struct FactIterator<'a> {
+ state_queue: VecDeque<TermIterState<'a>>,
+ iterable_root: RootIterationPolicy,
+}
+
+impl<'a> FactIterator<'a> {
+ fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
+ self.state_queue
+ .push_back(TermIterState::subterm_to_state(lvl, term));
}
- fn level(&mut self) -> Level {
- let lvl = self.current_level(0);
+ pub(crate) fn from_rule_head_clause(terms: &'a [Term]) -> Self {
+ let state_queue = terms
+ .iter()
+ .map(|bt| TermIterState::subterm_to_state(Level::Shallow, bt))
+ .collect();
- if let Level::Shallow = lvl {
- self.arg_c += 1;
+ FactIterator {
+ state_queue,
+ iterable_root: RootIterationPolicy::NotIterated,
}
+ }
- lvl
+ fn new(term: &'a Term, iterable_root: RootIterationPolicy) -> Self {
+ let states = match term {
+ Term::AnonVar => {
+ vec![TermIterState::AnonVar(Level::Root)]
+ }
+ Term::Clause(cell, name, terms) => {
+ vec![TermIterState::Clause(Level::Root, 0, cell, *name, terms)]
+ }
+ Term::Cons(cell, head, tail) => vec![TermIterState::InitialCons(
+ Level::Root,
+ cell,
+ head.as_ref(),
+ tail.as_ref(),
+ )],
+ Term::PartialString(cell, string, tail) => {
+ vec![TermIterState::InitialPartialString(
+ Level::Root,
+ cell,
+ string.clone(),
+ tail,
+ )]
+ }
+ Term::CompleteString(cell, string) => {
+ vec![TermIterState::CompleteString(
+ Level::Root,
+ cell,
+ string.clone(),
+ )]
+ }
+ Term::Literal(cell, constant) => {
+ vec![TermIterState::Literal(Level::Root, cell, constant)]
+ }
+ Term::Var(cell, var_ptr) => {
+ vec![TermIterState::Var(Level::Root, cell, var_ptr.clone())]
+ }
+ };
+
+ FactIterator {
+ state_queue: VecDeque::from(states),
+ iterable_root,
+ }
}
}
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Iterator for TargetIterator<I, SKIP_ROOT> {
- type Item = HeapCellValue;
+impl<'a> Iterator for FactIterator<'a> {
+ type Item = TermRef<'a>;
fn next(&mut self) -> Option<Self::Item> {
- loop {
- let next_term = self.iter.next();
-
- if next_term.is_none() {
- return None;
- }
+ while let Some(state) = self.state_queue.pop_front() {
+ match state {
+ TermIterState::AnonVar(lvl) => {
+ return Some(TermRef::AnonVar(lvl));
+ }
+ TermIterState::Clause(lvl, _, cell, name, child_terms) => {
+ for child_term in child_terms {
+ self.push_subterm(lvl.child_level(), child_term);
+ }
- let focus = self.iter.focus().value() as usize;
+ match lvl {
+ Level::Root if !self.iterable_root.iterable() => continue,
+ _ => return Some(TermRef::Clause(lvl, cell, name, child_terms)),
+ };
+ }
+ TermIterState::InitialCons(lvl, cell, head, tail) => {
+ self.push_subterm(Level::Deep, head);
+ self.push_subterm(Level::Deep, tail);
- if SKIP_ROOT && self.root_terms.contains(focus) {
- continue;
- } else {
- return next_term;
+ return Some(TermRef::Cons(lvl, cell, head, tail));
+ }
+ TermIterState::InitialPartialString(lvl, cell, string_buf, tail) => {
+ self.push_subterm(Level::Deep, tail);
+ return Some(TermRef::PartialString(lvl, cell, string_buf, tail));
+ }
+ TermIterState::CompleteString(lvl, cell, atom) => {
+ return Some(TermRef::CompleteString(lvl, cell, atom));
+ }
+ TermIterState::Literal(lvl, cell, constant) => {
+ return Some(TermRef::Literal(lvl, cell, constant))
+ }
+ TermIterState::Var(lvl, cell, var_ptr) => {
+ return Some(TermRef::Var(lvl, cell, var_ptr));
+ }
+ _ => {}
}
}
- }
-}
-
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Deref for TargetIterator<I, SKIP_ROOT> {
- type Target = Heap;
- fn deref(&self) -> &Self::Target {
- self.iter.deref()
- }
-}
-
-impl<I: FocusedHeapIter, const SKIP_ROOT: bool> FocusedHeapIter for TargetIterator<I, SKIP_ROOT> {
- fn focus(&self) -> IterStackLoc {
- self.iter.focus()
+ None
}
}
-pub(crate) type FactIterator<'a, const SKIP_ROOT: bool> =
- TargetIterator<StackfulPreOrderHeapIter<'a, NonListElider>, SKIP_ROOT>;
-
-pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>(
- heap: &'a mut Heap,
- stack: &'a mut Stack,
- root_loc: usize,
-) -> FactIterator<'a, SKIP_ROOT> {
- TargetIterator::new(stackful_preorder_iter(heap, stack, root_loc), root_loc, 0)
+pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator {
+ QueryIterator::from_term(term)
}
-pub(crate) type QueryIterator<'a, const SKIP_ROOT: bool> =
- TargetIterator<PostOrderIterator<StackfulPreOrderHeapIter<'a, NonListElider>>, SKIP_ROOT>;
-
-pub(crate) fn query_iterator<'a, const SKIP_ROOT: bool>(
- heap: &'a mut Heap,
- stack: &'a mut Stack,
- root_loc: usize,
-) -> QueryIterator<'a, SKIP_ROOT> {
- TargetIterator::new(stackful_post_order_iter(heap, stack, root_loc), root_loc, 1)
+pub(crate) fn breadth_first_iter(
+ term: &'_ Term,
+ iterable_root: RootIterationPolicy,
+) -> FactIterator {
+ FactIterator::new(term, iterable_root)
}
#[derive(Debug, Copy, Clone)]
FirstBranch(usize),
NextBranch,
BranchEnd(usize),
- Chunk {
- chunk_num: usize,
- terms: &'a VecDeque<QueryTerm>,
- },
+ Chunk { terms: &'a VecDeque<QueryTerm> },
}
#[derive(Debug)]
self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, 0));
}
- &ChunkedTerms::Chunk {
- chunk_num,
- ref terms,
- } => {
- return Some(ClauseItem::Chunk { chunk_num, terms });
+ &ChunkedTerms::Chunk { ref terms } => {
+ return Some(ClauseItem::Chunk { terms });
}
}
}
!,
'$get_attr_list'(Var, Ls),
nonvar(Ls),
- atts:'$copy_attr_list'(Ls, Module, Attr))].
+ atts:'$copy_attr_list'(Ls, Module, Attr))].
put_attrs(Name/Arity, Module) -->
put_attr(Name, Arity, Module),
% Asserts (inserts) a new clause (rule or fact) into the current module.
% The clause will be inserted at the beginning of the module.
asserta(Clause0) :-
- loader:strip_subst_module(Clause0, user, Module, Clause),
- '$asserta'(Module, Clause).
+ loader:strip_module(Clause0, Module, Clause),
+ asserta_(Module, Clause).
+
+asserta_(Module, (Head :- Body)) :-
+ !,
+ '$asserta'(Module, Head, Body).
+asserta_(Module, Fact) :-
+ '$asserta'(Module, Fact, true).
:- meta_predicate assertz(:).
% Asserts (inserts) a new clause (rule or fact) into the current module.
% The clase will be inserted at the end of the module.
assertz(Clause0) :-
- loader:strip_subst_module(Clause0, user, Module, Clause),
- '$assertz'(Module, Clause).
+ loader:strip_module(Clause0, Module, Clause),
+ assertz_(Module, Clause).
+
+assertz_(Module, (Head :- Body)) :-
+ !,
+ '$assertz'(Module, Head, Body).
+assertz_(Module, Fact) :-
+ '$assertz'(Module, Fact, true).
:- meta_predicate retract(:).
when_condition_si((A ; B)) :-
when_condition_si(A),
when_condition_si(B).
+
filter_anonymous_vars([], []).
filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :-
+ '$debug_hook',
( atom_concat('_', _, VN) ->
filter_anonymous_vars(VNEqs0, VNEqs)
; VNEqs = [VN=V | VNEqs1],
match Number::try_from(value) {
Ok(n) => Ok(n),
- Err(_) => self.arith_eval_by_metacall(value),
+ Err(_) => {
+ self.heap[0] = value;
+ self.arith_eval_by_metacall(0)
+ }
}
}
&ArithmeticTerm::Interm(i) => Ok(mem::replace(
pub(crate) fn arith_eval_by_metacall(
&mut self,
- value: HeapCellValue,
+ term_loc: usize,
) -> Result<Number, MachineStub> {
- debug_assert!(value.is_ref());
-
let stub_gen = || functor_stub(atom!("is"), 2);
-
- let root_loc = if value.is_ref() && !value.is_stack_var() {
- value.get_value() as usize
- } else {
- let type_error = self.type_error(ValidType::Evaluable, value);
- return Err(self.error_form(type_error, stub_gen()));
- };
-
let mut iter =
- stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, root_loc);
+ stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term_loc);
while let Some(value) = iter.next() {
if value.get_forwarding_bit() {
parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
assert_eq!(
- wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)),
+ wam.arith_eval_by_metacall(term_write_result.heap_loc),
Ok(Number::Fixnum(Fixnum::build_with(8))),
);
parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
assert_eq!(
- wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)),
+ wam.arith_eval_by_metacall(term_write_result.heap_loc),
Ok(Number::Fixnum(Fixnum::build_with(19))),
);
parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
assert_eq!(
- wam.arith_eval_by_metacall(heap_loc_as_cell!(term_write_result.focus)),
+ wam.arith_eval_by_metacall(term_write_result.heap_loc),
Ok(Number::Fixnum(Fixnum::build_with(-1)))
);
}
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)]
-pub(crate) struct AttrVarInitializer {
- pub(crate) attr_var_queue: Vec<usize>,
+pub(super) struct AttrVarInitializer {
+ pub(super) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings,
pub(super) p: usize,
pub(super) cp: usize,
let mut seen_set = IndexSet::new();
let mut seen_vars = vec![];
- let root_loc = if cell.is_ref() {
- cell.get_value() as usize
- } else {
- return vec![];
- };
- let mut iter = stackful_preorder_iter::<NonListElider>(
- &mut self.heap,
- &mut self.stack,
- root_loc, // cell,
- );
+ self.heap[0] = cell;
+
+ let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
while let Some(value) = iter.next() {
read_heap_cell!(value,
use crate::machine::*;
use crate::parser::ast::*;
+use std::cell::Cell;
use std::collections::VecDeque;
use std::mem;
use std::ops::Range;
fn compile_standalone_clause(
&mut self,
- term: TermWriteResult,
+ term: Term,
settings: CodeGenSettings,
) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(settings);
-
let clause = preprocessor.try_term_to_tl(self, term)?;
- let machine_st = LS::machine_st(&mut self.payload);
- let mut cg = CodeGenerator::new(settings);
- let clause_code = cg.compile_predicate(&mut machine_st.heap, vec![clause])?;
+ let mut cg = CodeGenerator::new(settings);
+ let clause_code = cg.compile_predicate(vec![clause])?;
Ok(StandaloneCompileResult {
clause_code,
let code_len = self.wam_prelude.code.len();
let mut code_ptr = code_len;
+ if key == (atom!("..."), 2) {
+ print!("");
+ }
+
let mut clauses = vec![];
let mut preprocessor = Preprocessor::new(settings);
clauses.push(preprocessor.try_term_to_tl(self, term)?);
}
- let machine_st = LS::machine_st(&mut self.payload);
-
let mut cg = CodeGenerator::new(settings);
- let mut code = cg.compile_predicate(&mut machine_st.heap, clauses)?;
+ let mut code = cg.compile_predicate(clauses)?;
if settings.is_extensible {
let mut clause_clause_locs = VecDeque::new();
pub(super) fn incremental_compile_clause(
&mut self,
key: PredicateKey,
- clause: TermWriteResult,
+ clause: Term,
compilation_target: CompilationTarget,
non_counted_bt: bool,
append_or_prepend: AppendOrPrepend,
}
impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
- pub(super) fn compile_clause_clauses(
+ pub(super) fn compile_clause_clauses<ClauseIter: Iterator<Item = (Term, Term)>>(
&mut self,
key: PredicateKey,
compilation_target: CompilationTarget,
- clause_clauses: Vec<TermWriteResult>,
+ clause_clauses: ClauseIter,
append_or_prepend: AppendOrPrepend,
) -> Result<(), SessionError> {
+ let clause_predicates = clause_clauses
+ .map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body]));
+
let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
_ => compilation_target,
let mut num_clause_predicates = 0;
- for clause_term in clause_clauses {
+ for clause_term in clause_predicates {
self.incremental_compile_clause(
(atom!("$clause"), 2),
clause_term,
}
pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> {
- let key = match self.payload.predicates.first().map(|term| term.focus) {
- Some(focus) => clause_predicate_key(self.machine_heap(), focus)
- .ok_or(SessionError::NamelessEntry)?,
- None => {
- return Err(SessionError::NamelessEntry);
- }
- };
+ let key = self
+ .payload
+ .predicates
+ .first()
+ .and_then(|cl| {
+ let arity = ClauseInfo::arity(cl);
+ ClauseInfo::name(cl).map(|name| (name, arity))
+ })
+ .ok_or(SessionError::NamelessEntry)?;
let listing_src_file_name = self.listing_src_file_name();
.clause_clauses
.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
.collect();
+
let compilation_target = self.payload.predicates.compilation_target;
self.compile_clause_clauses(
key,
compilation_target,
- clauses_vec,
+ clauses_vec.into_iter(),
AppendOrPrepend::Append,
)?;
}
pub(crate) fn compile_standalone_clause(
&mut self,
- term_reg: RegType,
- vars: Vec<HeapCellValue>,
+ term_loc: RegType,
+ vars: &[Term],
) -> Result<(), SessionError> {
- let body_cell = self
- .machine_st
- .store(self.machine_st.deref(self.machine_st[term_reg]));
-
- let new_header_loc = self.machine_st.heap.cell_len();
- let arity = vars.len();
- let term_loc = self.machine_st.heap.cell_len() + 1 + arity;
-
- let mut writer = self
- .machine_st
- .heap
- .reserve(4 + arity)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
-
- writer.write_with(move |section| {
- section.push_cell(atom_as_cell!(atom!(""), arity));
-
- for var in vars {
- section.push_cell(var);
- }
-
- let head_loc = if arity > 0 {
- str_loc_as_cell!(new_header_loc)
- } else {
- heap_loc_as_cell!(new_header_loc)
- };
-
- section.push_cell(atom_as_cell!(atom!(":-"), 2));
- section.push_cell(head_loc);
- section.push_cell(body_cell);
- });
-
let mut compile = || {
let mut loader: Loader<'_, InlineLoadState<'_>> =
Loader::new(self, InlineTermStream {});
- let machine_st = InlineLoadState::machine_st(&mut loader.payload);
-
- let term_loc = str_loc_as_cell!(term_loc);
- let term = TermWriteResult::from(&mut machine_st.heap, term_loc)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+ let term = loader.read_term_from_heap(term_loc);
+ let clause = build_rule_body(vars, term);
let settings = CodeGenSettings {
global_clock_tick: None,
non_counted_bt: true,
};
- loader.compile_standalone_clause(term, settings)
+ loader.compile_standalone_clause(clause, settings)
};
let StandaloneCompileResult { clause_code, .. } = compile()?;
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
-use crate::iterators::fact_iterator;
-use crate::machine::heap::*;
+use crate::iterators::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
-use crate::machine::Stack;
use crate::parser::ast::*;
use crate::parser::dashu::Rational;
-use crate::types::*;
use crate::variable_records::*;
use dashu::Integer;
use indexmap::{IndexMap, IndexSet};
+use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
}
}
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum ClassifiedVar {
- Anon { term_loc: usize },
- InSitu { var_num: usize },
- Generated { term_loc: usize },
-}
-
-impl ClassifiedVar {
- fn term_loc(&self) -> Option<usize> {
- if let &ClassifiedVar::Generated { term_loc } = self {
- Some(term_loc)
- } else {
- None
- }
- }
-}
-
-fn to_classified_var(inverse_var_locs: &InverseVarLocs, term_loc: usize) -> ClassifiedVar {
- if inverse_var_locs.contains_key(&term_loc) {
- ClassifiedVar::Generated { term_loc }
- } else {
- ClassifiedVar::Anon { term_loc }
- }
-}
-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct VarInfo {
- var: ClassifiedVar,
+ var_ptr: VarPtr,
chunk_type: ChunkType,
classify_info: ClassifyInfo,
lvl: Level,
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ChunkInfo {
+ chunk_num: usize,
term_loc: GenContext,
// pointer to incidence, term occurrence arity.
vars: Vec<VarInfo>,
}
}
-type BranchMapInt = IndexMap<ClassifiedVar, Vec<BranchInfo>>;
+type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
#[derive(Debug, Clone)]
pub struct BranchMap(BranchMapInt);
// where it leaves off.
BuildFinalDisjunct(usize),
Fail,
- Succeed,
- GetCutPoint {
- var_num: usize,
- prev_b: bool,
- },
- Cut {
- var_num: usize,
- is_global: bool,
- },
+ GetCutPoint { var_num: usize, prev_b: bool },
+ Cut { var_num: usize, is_global: bool },
CutPrev(usize),
ResetCallPolicy(CallPolicy),
- Term {
- subterm: HeapCellValue,
- term_loc: usize,
- },
+ Term(Term),
OverrideGlobalCutVar(usize),
ResetGlobalCutVarOverride(Option<usize>),
RemoveBranchNum, // pop the current_branch_num and from the root set.
pub struct VariableClassifier {
call_policy: CallPolicy,
current_branch_num: BranchNumber,
+ current_chunk_num: usize,
+ current_chunk_type: ChunkType,
branch_map: BranchMap,
var_num: usize,
root_set: RootSet,
global_cut_var_num_override: Option<usize>,
}
-#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
-pub struct VarPtrIndex {
- pub chunk_num: usize,
- pub term_loc: usize,
-}
-
-#[derive(Debug)]
-pub enum VarPtr {
- Numbered(usize),
- Anon,
-}
-
-#[derive(Debug, Default)]
-pub struct VarLocsToNums {
- map: IndexMap<VarPtrIndex, usize>,
-}
-
-impl VarLocsToNums {
- pub fn insert(&mut self, key: VarPtrIndex, var_num: usize) {
- self.map.insert(key, var_num);
- }
-
- pub fn get(&self, idx: VarPtrIndex) -> VarPtr {
- self.map
- .get(&idx)
- .cloned()
- .map(VarPtr::Numbered)
- .unwrap_or_else(|| VarPtr::Anon)
- }
-}
-
#[derive(Debug, Default)]
pub struct VarData {
pub records: VariableRecords,
pub global_cut_var_num: Option<usize>,
pub allocates: bool,
- pub var_locs_to_nums: VarLocsToNums,
}
impl VarData {
fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
let global_cut_var_num = if let &Some(global_cut_var_num) = &self.global_cut_var_num {
match &self.records[global_cut_var_num].allocation {
- VarAlloc::Perm { .. } => Some(global_cut_var_num),
+ VarAlloc::Perm(..) => Some(global_cut_var_num),
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
Some(global_cut_var_num)
}
if let Some(global_cut_var_num) = global_cut_var_num {
let term = QueryTerm::GetLevel(global_cut_var_num);
- self.records[global_cut_var_num].allocation = VarAlloc::Perm {
- reg: 0,
- allocation: PermVarAllocation::Pending,
- };
+ self.records[global_cut_var_num].allocation =
+ VarAlloc::Perm(0, PermVarAllocation::Pending);
match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => {
build_stack.push_front(ChunkedTerms::Chunk {
- chunk_num: 0,
terms: VecDeque::from(vec![term]),
});
}
}
}
-pub type ClassifyFactResult = VarData;
-pub type ClassifyRuleResult = (ChunkedTermVec, VarData);
+pub type ClassifyFactResult = (Term, VarData);
+pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
let mut branch_info = BranchInfo::new(BranchNumber::default());
Self {
call_policy,
current_branch_num: BranchNumber::default(),
+ current_chunk_num: 0,
+ current_chunk_type: ChunkType::Head,
branch_map: BranchMap(BranchMapInt::new()),
root_set: RootSet::new(),
var_num: 0,
}
}
- pub fn classify_fact<'a, LS: LoadState<'a>>(
- mut self,
- loader: &mut Loader<'a, LS>,
- term: &TermWriteResult,
- ) -> Result<ClassifyFactResult, CompilationError> {
- self.classify_head_variables(loader, &term, term.focus)?;
- Ok(self.branch_map.separate_and_classify_variables(
- self.var_num,
- self.global_cut_var_num,
- 0,
+ pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
+ self.classify_head_variables(&term)?;
+ Ok((
+ term,
+ self.branch_map.separate_and_classify_variables(
+ self.var_num,
+ self.global_cut_var_num,
+ self.current_chunk_num,
+ ),
))
}
pub fn classify_rule<'a, LS: LoadState<'a>>(
mut self,
loader: &mut Loader<'a, LS>,
- term: &TermWriteResult,
+ head: Term,
+ body: Term,
) -> Result<ClassifyRuleResult, CompilationError> {
- let heap = &mut LS::machine_st(&mut loader.payload).heap;
-
- let head_loc = term_nth_arg(heap, term.focus, 1).unwrap();
- let body_loc = term_nth_arg(heap, term.focus, 2).unwrap();
-
- self.classify_head_variables(loader, &term, head_loc)?;
+ self.classify_head_variables(&head)?;
self.root_set.insert(self.current_branch_num.clone());
- let mut query_terms = self.classify_body_variables(loader, term, body_loc)?;
+ let mut query_terms = self.classify_body_variables(loader, body)?;
self.merge_branches();
let mut var_data = self.branch_map.separate_and_classify_variables(
self.var_num,
self.global_cut_var_num,
- query_terms.current_chunk_num,
+ self.current_chunk_num,
);
var_data.emit_initial_get_level(&mut query_terms);
- Ok((query_terms, var_data))
+ Ok((head, query_terms, var_data))
}
fn merge_branches(&mut self) {
}
}
- fn probe_body_term(
- &mut self,
- arg_c: usize,
- arity: usize,
- term: &mut FocusedHeapRefMut,
- inverse_var_locs: &InverseVarLocs,
- context: GenContext,
- ) {
- let classify_info = ClassifyInfo { arg_c, arity };
-
- let mut lvl = Level::Shallow;
- let mut stack = Stack::uninitialized();
- let mut iter = fact_iterator::<false>(term.heap, &mut stack, term.focus);
+ fn try_set_chunk_at_inlined_boundary(&mut self) -> bool {
+ if self.current_chunk_type.is_last() {
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
+ true
+ } else {
+ false
+ }
+ }
- // second arg is true to iterate the root, which may be a variable
- while let Some(subterm) = iter.next() {
- if !subterm.is_var() {
- lvl = Level::Deep;
- continue;
- }
+ fn try_set_chunk_at_call_boundary(&mut self) -> bool {
+ if self.current_chunk_type.is_last() {
+ self.current_chunk_num += 1;
+ true
+ } else {
+ self.current_chunk_type = ChunkType::Last;
+ false
+ }
+ }
- let var_loc = subterm.get_value() as usize;
- let var = to_classified_var(inverse_var_locs, var_loc);
+ fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
+ let classify_info = ClassifyInfo { arg_c, arity };
- self.probe_body_var(
- context,
- VarInfo {
- var,
+ // second arg is true to iterate the root, which may be a variable
+ for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
+ if let TermRef::Var(lvl, _, var_ptr) = term_ref {
+ // root terms are shallow here (since we're iterating a
+ // body term) so take the child level.
+ let lvl = lvl.child_level();
+ self.probe_body_var(VarInfo {
+ var_ptr,
lvl,
classify_info,
- chunk_type: context.chunk_type(),
- },
- );
+ chunk_type: self.current_chunk_type,
+ });
+ }
}
}
- fn probe_body_var(&mut self, context: GenContext, var_info: VarInfo) {
- let chunk_num = context.chunk_num();
- let branch_info_v = self.branch_map.entry(var_info.var).or_default();
+ fn probe_body_var(&mut self, var_info: VarInfo) {
+ let term_loc = self
+ .current_chunk_type
+ .to_gen_context(self.current_chunk_num);
+
+ let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone()).or_default();
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
!self.root_set.contains(&last_bi.branch_num)
let branch_info = branch_info_v.last_mut().unwrap();
let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() {
- last_ci.term_loc.chunk_num() != chunk_num
+ last_ci.chunk_num != self.current_chunk_num
} else {
true
};
if needs_new_chunk {
branch_info.chunks.push(ChunkInfo {
- term_loc: context,
+ chunk_num: self.current_chunk_num,
+ term_loc,
vars: vec![],
});
}
chunk_info.vars.push(var_info);
}
- fn probe_in_situ_var(&mut self, context: GenContext, var_num: usize) {
+ fn probe_in_situ_var(&mut self, var_num: usize) {
let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
let var_info = VarInfo {
- var: ClassifiedVar::InSitu { var_num },
+ var_ptr: VarPtr::from(Var::InSitu(var_num)),
classify_info,
- chunk_type: context.chunk_type(),
+ chunk_type: self.current_chunk_type,
lvl: Level::Shallow,
};
- self.probe_body_var(context, var_info);
+ self.probe_body_var(var_info);
}
- fn classify_head_variables<'a, LS: LoadState<'a>>(
- &mut self,
- loader: &mut Loader<'a, LS>,
- term: &TermWriteResult,
- head_loc: usize,
- ) -> Result<(), CompilationError> {
- let heap = &mut LS::machine_st(&mut loader.payload).heap;
- let arity = term_predicate_key(heap, head_loc)
- .and_then(|(_, arity)| Some(arity))
- .ok_or(CompilationError::InvalidRuleHead)?;
-
- let mut classify_info = ClassifyInfo { arg_c: 1, arity };
-
- if arity > 0 {
- let (_term_loc, value) = subterm_index(heap, head_loc);
- let str_offset = value.get_value() as usize;
-
- debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str);
-
- for idx in str_offset + 1..=str_offset + arity {
- let mut lvl = Level::Shallow;
- let mut stack = Stack::uninitialized();
- let mut iter = fact_iterator::<false>(heap, &mut stack, idx);
-
- while let Some(subterm) = iter.next() {
- if !subterm.is_var() {
- lvl = Level::Deep;
- continue;
- }
-
- let term_loc = subterm.get_value() as usize;
- let var = to_classified_var(&term.inverse_var_locs, term_loc);
+ fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
+ match term {
+ Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {}
+ _ => return Err(CompilationError::InvalidRuleHead),
+ }
- // the body of the if let here is an inlined
- // "probe_head_var". note the difference between it
- // and "probe_body_var".
- let branch_info_v = self.branch_map.entry(var).or_default();
- let needs_new_branch = branch_info_v.is_empty();
+ let mut classify_info = ClassifyInfo {
+ arg_c: 1,
+ arity: term.arity(),
+ };
- if needs_new_branch {
- branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
- }
+ if let Term::Clause(_, _, terms) = term {
+ for term in terms.iter() {
+ for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
+ if let TermRef::Var(lvl, _, var_ptr) = term_ref {
+ // a body term, so we need the child level here.
+ let lvl = lvl.child_level();
+
+ // the body of the if let here is an inlined
+ // "probe_head_var". note the difference between it
+ // and "probe_body_var".
+ let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
+ let needs_new_branch = branch_info_v.is_empty();
+
+ if needs_new_branch {
+ branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
+ }
- let branch_info = branch_info_v.last_mut().unwrap();
- let needs_new_chunk = branch_info.chunks.is_empty();
+ let branch_info = branch_info_v.last_mut().unwrap();
+ let needs_new_chunk = branch_info.chunks.is_empty();
- if needs_new_chunk {
- branch_info.chunks.push(ChunkInfo {
- term_loc: GenContext::Head,
- vars: vec![],
- });
- }
+ if needs_new_chunk {
+ branch_info.chunks.push(ChunkInfo {
+ chunk_num: self.current_chunk_num,
+ term_loc: GenContext::Head,
+ vars: vec![],
+ });
+ }
- let chunk_info = branch_info.chunks.last_mut().unwrap();
- let var_info = VarInfo {
- var,
- classify_info,
- chunk_type: ChunkType::Head,
- lvl,
- };
+ let chunk_info = branch_info.chunks.last_mut().unwrap();
+ let var_info = VarInfo {
+ var_ptr,
+ classify_info,
+ chunk_type: self.current_chunk_type,
+ lvl,
+ };
- chunk_info.vars.push(var_info);
+ chunk_info.vars.push(var_info);
+ }
}
classify_info.arg_c += 1;
Ok(())
}
- fn new_cut_state(&mut self, context: GenContext) -> TraversalState {
- let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override {
- (var_num, false)
- } else if let Some(var_num) = self.global_cut_var_num {
- (var_num, true)
- } else {
- let var_num = self.var_num;
-
- self.global_cut_var_num = Some(var_num);
- self.var_num += 1;
-
- (var_num, true)
- };
-
- self.probe_in_situ_var(context, var_num);
-
- TraversalState::Cut { var_num, is_global }
- }
-
fn classify_body_variables<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
- terms: &TermWriteResult,
- term_loc: usize,
+ term: Term,
) -> Result<ChunkedTermVec, CompilationError> {
- let mut state_stack = vec![TraversalState::Term {
- subterm: loader.machine_heap()[term_loc],
- term_loc,
- }];
+ let mut state_stack = vec![TraversalState::Term(term)];
let mut build_stack = ChunkedTermVec::new();
- 'outer: while let Some(traversal_st) = state_stack.pop() {
+ self.current_chunk_type = ChunkType::Mid;
+
+ while let Some(traversal_st) = state_stack.pop() {
match traversal_st {
TraversalState::AddBranchNum(branch_num) => {
self.root_set.insert(branch_num.clone());
TraversalState::BuildDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len);
- build_stack.current_chunk_type = ChunkType::Mid;
- build_stack.current_chunk_num += 1;
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
}
TraversalState::BuildFinalDisjunct(preceding_len) => {
flatten_into_disjunct(&mut build_stack, preceding_len);
- build_stack.current_chunk_type = ChunkType::Mid;
- build_stack.current_chunk_num += 1;
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
}
TraversalState::GetCutPoint { var_num, prev_b } => {
- if build_stack.try_set_chunk_at_inlined_boundary() {
+ if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
- let context = build_stack.current_gen_context();
- self.probe_in_situ_var(context, var_num);
+ self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
}
TraversalState::OverrideGlobalCutVar(var_num) => {
self.global_cut_var_num_override = old_override;
}
TraversalState::Cut { var_num, is_global } => {
- if build_stack.try_set_chunk_at_inlined_boundary() {
+ if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
- let context = build_stack.current_gen_context();
- self.probe_in_situ_var(context, var_num);
+ self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(if is_global {
QueryTerm::GlobalCut(var_num)
});
}
TraversalState::CutPrev(var_num) => {
- if build_stack.try_set_chunk_at_inlined_boundary() {
+ if self.try_set_chunk_at_inlined_boundary() {
build_stack.add_chunk();
}
- let context = build_stack.current_gen_context();
- self.probe_in_situ_var(context, var_num);
+ self.probe_in_situ_var(var_num);
build_stack.push_chunk_term(QueryTerm::LocalCut {
var_num,
TraversalState::Fail => {
build_stack.push_chunk_term(QueryTerm::Fail);
}
- TraversalState::Succeed => {
- build_stack.push_chunk_term(QueryTerm::Succeed);
- }
- TraversalState::Term {
- mut subterm,
- mut term_loc,
- } => {
+ TraversalState::Term(term) => {
// return true iff new chunk should be added.
- let update_chunk_data =
- |build_stack: &mut ChunkedTermVec, key: PredicateKey| {
- if ClauseType::is_inlined(key.0, key.1) {
- build_stack.try_set_chunk_at_inlined_boundary()
- } else {
- build_stack.try_set_chunk_at_call_boundary()
- }
- };
+ let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
+ if ClauseType::is_inlined(predicate_name, arity) {
+ classifier.try_set_chunk_at_inlined_boundary()
+ } else {
+ classifier.try_set_chunk_at_call_boundary()
+ }
+ };
- macro_rules! add_chunk {
- ($key:expr, $tag:expr, $term_loc:expr) => {{
- if update_chunk_data(&mut build_stack, $key) {
- build_stack.add_chunk();
- }
+ let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec<Term>| {
+ if update_chunk_data(classifier, name, terms.len()) {
+ build_stack.add_chunk();
+ }
+
+ for (arg_c, term) in terms.iter().enumerate() {
+ classifier.probe_body_term(arg_c + 1, terms.len(), term);
+ }
- let context = build_stack.current_gen_context();
+ build_stack.push_chunk_term(clause_to_query_term(
+ loader,
+ name,
+ terms,
+ classifier.call_policy,
+ ));
+ };
- for (arg_c, term_loc) in
- ($term_loc + 1..=$term_loc + $key.1).enumerate()
- {
- let mut term =
- FocusedHeapRefMut::from(loader.machine_heap(), term_loc);
-
- self.probe_body_term(
- arg_c + 1,
- $key.1,
- &mut term,
- &terms.inverse_var_locs,
- context,
- );
+ match term {
+ Term::Clause(
+ _,
+ name @ (atom!("->") | atom!(";") | atom!(",")),
+ mut terms,
+ ) if terms.len() == 3 => {
+ if let Some(last_arg) = terms.last() {
+ if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
+ terms.pop();
+ state_stack.push(TraversalState::Term(Term::Clause(
+ Cell::default(),
+ name,
+ terms,
+ )));
+ } else {
+ add_chunk(self, name, terms);
+ }
}
+ }
+ Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
+ let tail = terms.pop().unwrap();
+ let head = terms.pop().unwrap();
- build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
- loader,
- $key,
- &terms,
- HeapCellValue::build_with($tag, $term_loc as u64),
- self.call_policy,
- )));
- }};
- }
+ let iter = unfold_by_str(tail, atom!(","))
+ .into_iter()
+ .rev()
+ .chain(std::iter::once(head))
+ .map(TraversalState::Term);
- macro_rules! add_qualified_chunk {
- ($module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
- if update_chunk_data(&mut build_stack, $key) {
- build_stack.add_chunk();
- }
+ state_stack.extend(iter);
+ }
+ Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
+ let tail = terms.pop().unwrap();
+ let head = terms.pop().unwrap();
- let context = build_stack.current_gen_context();
+ let first_branch_num = self.current_branch_num.split();
+ let branches: Vec<_> = std::iter::once(head)
+ .chain(unfold_by_str(tail, atom!(";")).into_iter())
+ .collect();
- for (arg_c, term_loc) in
- ($term_loc + 1..=$term_loc + $key.1).enumerate()
- {
- let mut term =
- FocusedHeapRefMut::from(loader.machine_heap(), term_loc);
-
- self.probe_body_term(
- arg_c + 1,
- $key.1,
- &mut term,
- &terms.inverse_var_locs,
- context,
- );
+ let mut branch_numbers = vec![first_branch_num];
+
+ for idx in 1..branches.len() {
+ let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
+
+ branch_numbers.push(if idx + 1 < branches.len() {
+ succ_branch_number.split()
+ } else {
+ succ_branch_number
+ });
}
- build_stack.push_chunk_term(QueryTerm::Clause(
- qualified_clause_to_query_term(
- loader,
- $key,
- $module_name,
- &terms,
- HeapCellValue::build_with($tag, $term_loc as u64),
- self.call_policy,
- ),
+ let build_stack_len = build_stack.len();
+ build_stack.reserve_branch(branches.len());
+
+ state_stack.push(TraversalState::RepBranchNum(
+ self.current_branch_num.halve_delta(),
));
- }};
- }
- loop {
- let heap = loader.machine_heap();
+ let iter = branches.into_iter().zip(branch_numbers.into_iter());
+ let final_disjunct_loc = state_stack.len();
- read_heap_cell!(subterm,
- (HeapCellValueTag::Str, subterm_loc) => {
- let (name, arity) = cell_as_atom_cell!(heap[subterm_loc])
- .get_name_and_arity();
+ for (term, branch_num) in iter.rev() {
+ state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
+ state_stack.push(TraversalState::RemoveBranchNum);
+ state_stack.push(TraversalState::Term(term));
+ state_stack.push(TraversalState::AddBranchNum(branch_num));
+ }
- match (name, arity) {
- (atom!("->") | atom!(";") | atom!(","), 3) => {
- if blunt_index_ptr(heap, (name, 2), subterm_loc) {
- subterm = heap[subterm_loc];
- continue;
- }
+ if let TraversalState::BuildDisjunct(build_stack_len) =
+ state_stack[final_disjunct_loc]
+ {
+ state_stack[final_disjunct_loc] =
+ TraversalState::BuildFinalDisjunct(build_stack_len);
+ }
- add_chunk!((name, 2), HeapCellValueTag::Str, subterm_loc);
- }
- (atom!(","), 2) => {
- let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
- let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
- let head = heap[head_loc];
-
- let iter = unfold_by_str_locs(heap, tail_loc, atom!(","))
- .into_iter()
- .rev()
- .chain(std::iter::once((head, head_loc)))
- .map(|(subterm, term_loc)| {
- TraversalState::Term { subterm, term_loc }
- });
- state_stack.extend(iter);
- }
- (atom!(";"), 2) => {
- let head_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
- let tail_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
-
- let head = heap[head_loc];
-
- let first_branch_num = self.current_branch_num.split();
- let branches: Vec<_> = std::iter::once((head, head_loc))
- .chain(
- unfold_by_str_locs(heap, tail_loc, atom!(";"))
- .into_iter(),
- )
- .collect();
-
- let mut branch_numbers = vec![first_branch_num];
-
- for idx in 1..branches.len() {
- let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
-
- branch_numbers.push(if idx + 1 < branches.len() {
- succ_branch_number.split()
- } else {
- succ_branch_number
- });
- }
-
- let build_stack_len = build_stack.len();
- build_stack.reserve_branch(branches.len());
-
- state_stack.push(TraversalState::RepBranchNum(
- self.current_branch_num.halve_delta(),
- ));
-
- let iter = branches.into_iter().zip(branch_numbers.into_iter());
- let final_disjunct_loc = state_stack.len();
-
- for ((subterm, term_loc), branch_num) in iter.rev() {
- state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
- state_stack.push(TraversalState::RemoveBranchNum);
- state_stack.push(TraversalState::Term { subterm, term_loc });
- state_stack.push(TraversalState::AddBranchNum(branch_num));
- }
-
- if let TraversalState::BuildDisjunct(build_stack_len) =
- state_stack[final_disjunct_loc]
- {
- state_stack[final_disjunct_loc] =
- TraversalState::BuildFinalDisjunct(build_stack_len);
- }
-
- build_stack.current_chunk_type = ChunkType::Mid;
- build_stack.current_chunk_num += 1;
- }
- (atom!("->"), 2) => {
- let if_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
- let then_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
-
- let if_term = heap[if_term_loc];
- let then_term = heap[then_term_loc];
-
- let prev_b = if matches!(
- state_stack.last(),
- Some(TraversalState::RemoveBranchNum)
- ) {
- // check if the second-to-last element
- // is a regular BuildDisjunct, as we
- // don't want to add GetPrevLevel in
- // case of a TrustMe.
- match state_stack.iter().rev().nth(1) {
- Some(&TraversalState::BuildDisjunct(preceding_len)) => {
- preceding_len + 1 == build_stack.len()
- }
- _ => false,
- }
- } else {
- false
- };
-
- state_stack.push(TraversalState::Term {
- subterm: then_term,
- term_loc: then_term_loc,
- });
- state_stack.push(TraversalState::Cut {
- var_num: self.var_num,
- is_global: false,
- });
- state_stack.push(TraversalState::Term {
- subterm: if_term,
- term_loc: if_term_loc,
- });
- state_stack.push(TraversalState::GetCutPoint {
- var_num: self.var_num,
- prev_b,
- });
-
- self.var_num += 1;
- }
- (atom!("\\+"), 1) => {
- let not_term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
- let not_term = heap[not_term_loc];
- let build_stack_len = build_stack.len();
-
- build_stack.reserve_branch(2);
-
- let branch_num = self.current_branch_num.split();
- let succ_branch_num = branch_num.incr_by_delta();
-
- state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
- state_stack.push(TraversalState::Succeed);
- state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
- state_stack.push(TraversalState::RepBranchNum(succ_branch_num));
- state_stack.push(TraversalState::Fail);
- state_stack.push(TraversalState::CutPrev(self.var_num));
- state_stack.push(TraversalState::ResetGlobalCutVarOverride(
- self.global_cut_var_num_override,
- ));
- state_stack.push(TraversalState::Term {
- subterm: not_term,
- term_loc: not_term_loc,
- });
- state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
- state_stack.push(TraversalState::GetCutPoint {
- var_num: self.var_num,
- prev_b: false,
- });
- state_stack.push(TraversalState::AddBranchNum(branch_num));
-
- build_stack.current_chunk_type = ChunkType::Mid;
- build_stack.current_chunk_num += 1;
-
- self.var_num += 1;
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
+ }
+ Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
+ let then_term = terms.pop().unwrap();
+ let if_term = terms.pop().unwrap();
+
+ let prev_b = if matches!(
+ state_stack.last(),
+ Some(TraversalState::RemoveBranchNum)
+ ) {
+ // check if the second-to-last element
+ // is a regular BuildDisjunct, as we
+ // don't want to add GetPrevLevel in
+ // case of a TrustMe.
+ match state_stack.iter().rev().nth(1) {
+ Some(&TraversalState::BuildDisjunct(preceding_len)) => {
+ preceding_len + 1 == build_stack.len()
}
- (atom!(":"), 2) => {
- let module_name_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
- let predicate_term_loc = term_nth_arg(heap, subterm_loc, 2).unwrap();
- let mut focused = FocusedHeapRefMut::from(heap, module_name_loc);
-
- let module_name = focused.deref_loc(module_name_loc);
- let predicate_term = focused.deref_loc(predicate_term_loc);
-
- read_heap_cell!(module_name,
- (HeapCellValueTag::Atom, (module_name, arity)) => {
- if arity == 0 {
- read_heap_cell!(predicate_term,
- (HeapCellValueTag::Str, s) => {
- let key = cell_as_atom_cell!(heap[s])
- .get_name_and_arity();
-
- add_qualified_chunk!(
- module_name,
- key,
- HeapCellValueTag::Str,
- s
- );
- }
- (HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => {
- debug_assert_eq!(predicate_arity, 0);
- let key = (predicate_name, predicate_arity);
-
- add_qualified_chunk!(
- module_name,
- key,
- HeapCellValueTag::Str,
- predicate_term_loc
- );
- }
- _ => {}
- );
-
- continue 'outer;
- }
- }
- _ => {}
- );
-
- if update_chunk_data(&mut build_stack, (atom!("call"), 2)) {
- build_stack.add_chunk();
- }
-
- let context = build_stack.current_gen_context();
-
- focused.focus = module_name_loc;
-
- self.probe_body_term(
- 1, 0, &mut focused, &terms.inverse_var_locs, context,
- );
-
- focused.focus = predicate_term_loc;
-
- self.probe_body_term(
- 2, 0, &mut focused, &terms.inverse_var_locs, context,
- );
-
- let h = heap.cell_len();
-
- heap.push_cell(atom_as_cell!(atom!("call"), 1))
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
- heap.push_cell(str_loc_as_cell!(subterm_loc))
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
-
- build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
- loader,
- (atom!("call"), 1),
- terms,
- str_loc_as_cell!(h),
- self.call_policy,
- )));
+ _ => false,
+ }
+ } else {
+ false
+ };
+
+ state_stack.push(TraversalState::Term(then_term));
+ state_stack.push(TraversalState::Cut {
+ var_num: self.var_num,
+ is_global: false,
+ });
+ state_stack.push(TraversalState::Term(if_term));
+ state_stack.push(TraversalState::GetCutPoint {
+ var_num: self.var_num,
+ prev_b,
+ });
+
+ self.var_num += 1;
+ }
+ Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
+ let not_term = terms.pop().unwrap();
+ let build_stack_len = build_stack.len();
+
+ build_stack.reserve_branch(2);
+
+ state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
+ state_stack.push(TraversalState::Term(Term::Clause(
+ Cell::default(),
+ atom!("$succeed"),
+ vec![],
+ )));
+ state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
+ state_stack.push(TraversalState::Fail);
+ state_stack.push(TraversalState::CutPrev(self.var_num));
+ state_stack.push(TraversalState::ResetGlobalCutVarOverride(
+ self.global_cut_var_num_override,
+ ));
+ state_stack.push(TraversalState::Term(not_term));
+ state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
+ state_stack.push(TraversalState::GetCutPoint {
+ var_num: self.var_num,
+ prev_b: false,
+ });
+
+ self.current_chunk_type = ChunkType::Mid;
+ self.current_chunk_num += 1;
+
+ self.var_num += 1;
+ }
+ Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
+ let predicate_name = terms.pop().unwrap();
+ let module_name = terms.pop().unwrap();
+
+ match (module_name, predicate_name) {
+ (
+ Term::Literal(_, Literal::Atom(module_name)),
+ Term::Literal(_, Literal::Atom(predicate_name)),
+ ) => {
+ if update_chunk_data(self, predicate_name, 0) {
+ build_stack.add_chunk();
}
- (atom!("$call_with_inference_counting"), 1) => {
- let term_loc = term_nth_arg(heap, subterm_loc, 1).unwrap();
- let heap = loader.machine_heap();
- let subterm = heap_bound_store(
- heap,
- heap_bound_deref(heap, heap[term_loc]),
- );
-
- state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
- state_stack.push(TraversalState::Term { subterm, term_loc });
-
- self.call_policy = CallPolicy::Counted;
+
+ build_stack.push_chunk_term(qualified_clause_to_query_term(
+ loader,
+ module_name,
+ predicate_name,
+ vec![],
+ self.call_policy,
+ ));
+ }
+ (
+ Term::Literal(_, Literal::Atom(module_name)),
+ Term::Clause(_, name, terms),
+ ) => {
+ if update_chunk_data(self, name, terms.len()) {
+ build_stack.add_chunk();
}
- (name, arity) => {
- add_chunk!((name, arity), HeapCellValueTag::Str, subterm_loc);
+
+ for (arg_c, term) in terms.iter().enumerate() {
+ self.probe_body_term(arg_c + 1, terms.len(), term);
}
+
+ build_stack.push_chunk_term(qualified_clause_to_query_term(
+ loader,
+ module_name,
+ name,
+ terms,
+ self.call_policy,
+ ));
}
- }
- (HeapCellValueTag::Atom, (name, arity)) => {
- debug_assert_eq!(arity, 0);
+ (module_name, predicate_name) => {
+ if update_chunk_data(self, atom!("call"), 2) {
+ build_stack.add_chunk();
+ }
- if name == atom!("!") {
- let context = build_stack.current_gen_context();
- state_stack.push(self.new_cut_state(context));
- } else {
- add_chunk!((name, 0), HeapCellValueTag::Var, term_loc);
+ self.probe_body_term(1, 0, &module_name);
+ self.probe_body_term(2, 0, &predicate_name);
+
+ terms.push(module_name);
+ terms.push(predicate_name);
+
+ build_stack.push_chunk_term(clause_to_query_term(
+ loader,
+ atom!("call"),
+ vec![Term::Clause(Cell::default(), atom!(":"), terms)],
+ self.call_policy,
+ ));
}
}
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if h != term_loc {
- subterm = heap[h];
- term_loc = h;
- continue;
- }
+ }
+ Term::Clause(_, atom!("$call_with_inference_counting"), mut terms)
+ if terms.len() == 1 =>
+ {
+ state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
+ state_stack.push(TraversalState::Term(terms.pop().unwrap()));
- add_chunk!((atom!("call"), 1), HeapCellValueTag::Var, h);
+ self.call_policy = CallPolicy::Counted;
+ }
+ Term::Clause(_, name, terms) => {
+ add_chunk(self, name, terms);
+ }
+ var @ Term::Var(..) => {
+ if update_chunk_data(self, atom!("call"), 1) {
+ build_stack.add_chunk();
}
- _ => {
- return Err(CompilationError::InadmissibleQueryTerm);
+
+ self.probe_body_term(1, 1, &var);
+
+ build_stack.push_chunk_term(clause_to_query_term(
+ loader,
+ atom!("call"),
+ vec![var],
+ self.call_policy,
+ ));
+ }
+ Term::Literal(_, Literal::Atom(atom!("!"))) => {
+ let (var_num, is_global) =
+ if let Some(var_num) = self.global_cut_var_num_override {
+ (var_num, false)
+ } else if let Some(var_num) = self.global_cut_var_num {
+ (var_num, true)
+ } else {
+ let var_num = self.var_num;
+
+ self.global_cut_var_num = Some(var_num);
+ self.var_num += 1;
+
+ (var_num, true)
+ };
+
+ self.probe_in_situ_var(var_num);
+
+ state_stack.push(TraversalState::Cut { var_num, is_global });
+ }
+ Term::Literal(_, Literal::Atom(name)) => {
+ if update_chunk_data(self, name, 0) {
+ build_stack.add_chunk();
}
- );
- break;
+ build_stack.push_chunk_term(clause_to_query_term(
+ loader,
+ name,
+ vec![],
+ self.call_policy,
+ ));
+ }
+ _ => {
+ return Err(CompilationError::InadmissibleQueryTerm);
+ }
}
}
}
records: VariableRecords::new(var_num),
global_cut_var_num,
allocates: current_chunk_num > 0,
- var_locs_to_nums: VarLocsToNums::default(),
};
for (var, branches) in self.iter_mut() {
- let (mut var_num, var_num_incr) = match var {
- &ClassifiedVar::InSitu { var_num } => (var_num, false),
- _ => (var_data.records.len(), true),
+ let (mut var_num, var_num_incr) = if let Var::InSitu(var_num) = *var.borrow() {
+ (var_num, false)
+ } else {
+ (var_data.records.len(), true)
};
for branch in branches.iter_mut() {
for var_info in chunk.vars.iter_mut() {
if var_info.lvl == Level::Shallow {
- let context = var_info
- .chunk_type
- .to_gen_context(chunk.term_loc.chunk_num());
-
+ let context = var_info.chunk_type.to_gen_context(chunk.chunk_num);
temp_var_data
.use_set
.insert((context, var_info.classify_info.arg_c));
for chunk in branch.chunks.iter_mut() {
var_data.records[var_num].num_occurrences += chunk.vars.len();
- if let Some(term_loc) = var.term_loc() {
- let chunk_num = chunk.term_loc.chunk_num();
-
- var_data.var_locs_to_nums.insert(
- VarPtrIndex {
- chunk_num,
- term_loc,
- },
- var_num,
- );
+ for var_info in chunk.vars.iter_mut() {
+ var_info.var_ptr.set(Var::Generated(var_num));
}
}
}
Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => {
let cell = backtrack_on_resource_error!(
self.machine_st,
- self.machine_st.allocate_pstr(string)
+ self.machine_st.heap.allocate_pstr(string)
);
self.machine_st.mode = MachineMode::Write;
HeapCellValueTag::Var) => {
let target_cell = backtrack_on_resource_error!(
self.machine_st,
- self.machine_st.allocate_pstr(string)
+ self.machine_st.heap.allocate_pstr(string)
);
self.machine_st.bind(
&Instruction::PutPartialString(_, ref string, reg) => {
self.machine_st[reg] = backtrack_on_resource_error!(
self.machine_st,
- self.machine_st.allocate_pstr(&string)
+ self.machine_st.heap.allocate_pstr(&string)
);
self.machine_st.p += 1;
#[cfg(test)]
-use crate::atom_table::*;
-#[cfg(test)]
-use crate::machine::heap::*;
+use fxhash::FxBuildHasher;
#[cfg(test)]
-use crate::types::*;
-
+use indexmap::IndexMap;
#[cfg(test)]
-use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
+use std::collections::BTreeMap;
#[cfg(test)]
-use std::collections::BTreeMap;
+use crate::atom_table::*;
#[cfg(test)]
-use std::ops::Deref;
-
+use crate::machine::heap::*;
#[cfg(test)]
-use fxhash::FxBuildHasher;
+use crate::types::*;
#[cfg(test)]
-use indexmap::IndexMap;
+use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
#[cfg(test)]
pub(crate) trait UnmarkPolicy {
pstr_loc_values: PStrLocValuesMap,
}
-#[cfg(test)]
-impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> {
- type Target = Heap;
-
- fn deref(&self) -> &Self::Target {
- self.heap
- }
-}
-
#[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline]
// two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars.
- let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3));
- wam.machine_st.allocate_pstr("abcdef ").unwrap();
+ wam.machine_st.heap.allocate_pstr("abcdef ").unwrap();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap();
mark_cells(&mut wam.machine_st.heap, 2);
use crate::types::*;
use std::alloc;
+use std::cmp::Ordering;
use std::convert::TryFrom;
use std::ops::{Bound, Index, IndexMut, Range, RangeBounds};
use std::ptr;
use std::sync::Once;
-use super::MachineState;
-
const ALIGN: usize = Heap::heap_cell_alignment();
#[derive(Debug)]
}
// return the string at ptr and the tail location relative to ptr.
-unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> {
+unsafe fn scan_slice_to_str(heap_slice: &[u8]) -> HeapStringScan {
let string_len = heap_slice.iter().position(|b| *b == 0u8).unwrap();
let zero_byte_addr = heap_slice.as_ptr().add(string_len);
+
let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize);
let tail_idx = cell_index!(
(string_len + sentinel_len).next_multiple_of(ALIGN)
#[derive(Debug, Clone, Copy)]
pub(crate) enum PStrSegmentCmpResult {
- Mismatch {
- c1: char,
- c2: char,
- },
- FirstMatch {
- pstr_loc1: usize,
- pstr_loc2: usize,
- l1_offset: usize,
- },
- SecondMatch {
- pstr_loc1: usize,
- pstr_loc2: usize,
- l2_offset: usize,
- },
- BothMatch {
- pstr_loc1: usize,
- pstr_loc2: usize,
- null_offset: usize,
- },
-}
-
-impl PStrSegmentCmpResult {
- pub(crate) fn continue_pstr_compare(
- self,
- pdl: &mut Vec<HeapCellValue>,
- ) -> Option<std::cmp::Ordering> {
- match self {
- PStrSegmentCmpResult::FirstMatch {
- pstr_loc1,
- pstr_loc2,
- l1_offset,
- } => {
- let tail1 = Heap::pstr_tail_idx(pstr_loc1 + l1_offset);
- let rest_of_l2 = pstr_loc_as_cell!(pstr_loc2 + l1_offset);
-
- pdl.push(heap_loc_as_cell!(tail1));
- pdl.push(rest_of_l2);
- }
- PStrSegmentCmpResult::SecondMatch {
- pstr_loc1,
- pstr_loc2,
- l2_offset,
- } => {
- let tail2 = Heap::pstr_tail_idx(pstr_loc2 + l2_offset);
- let rest_of_l1 = pstr_loc_as_cell!(pstr_loc1 + l2_offset);
-
- pdl.push(rest_of_l1);
- pdl.push(heap_loc_as_cell!(tail2));
- }
- PStrSegmentCmpResult::BothMatch {
- pstr_loc1,
- pstr_loc2,
- null_offset,
- } => {
- // exhaustive match
- let tail1 = Heap::pstr_tail_idx(pstr_loc1 + null_offset);
- let tail2 = Heap::pstr_tail_idx(pstr_loc2 + null_offset);
-
- pdl.push(heap_loc_as_cell!(tail1));
- pdl.push(heap_loc_as_cell!(tail2));
- }
- PStrSegmentCmpResult::Mismatch { c1, c2 } => {
- return Some(c1.cmp(&c2));
- }
- }
-
- None
- }
-}
-
-#[derive(Debug)]
-pub struct PStrWriteInfo {
- cell: HeapCellValue,
+ Less,
+ Greater,
+ Continue(HeapCellValue, HeapCellValue),
}
#[derive(Debug)]
}
self.push_cell(char_as_cell!('\u{0}'));
-
src = &src[1..];
}
return ret;
}
- debug_assert!(!src.is_empty());
-
if let Some(null_char_idx) = src.find('\u{0}') {
debug_assert_ne!(null_char_idx, 0);
self.push_cell(char_as_cell!('\u{0}'));
src = &src[null_char_idx + 1..];
+
if src.is_empty() {
return ret;
}
}
self.push_pstr_segment(&src);
-
return ret;
}
}
result,
}
}
-
- #[inline]
- pub(crate) fn truncate(&mut self, cell_offset: usize) {
- self.section.heap_cell_len = cell_offset;
- // self.section.pstr_vec.truncate(cell_offset);
- *self.heap_byte_len = heap_index!(cell_offset);
- }
-
- #[inline]
- pub(crate) fn is_empty(&self) -> bool {
- self.section.heap_cell_len == 0
- }
-
- #[inline]
- pub(crate) fn cell_len(&self) -> usize {
- self.section.heap_cell_len
- }
}
impl<'a> Index<usize> for HeapWriter<'a> {
}
}
-impl<'a> SizedHeapMut for HeapWriter<'a> {}
-
impl Heap {
pub(crate) fn new() -> Self {
Self {
self.inner.byte_len == 0
}
- pub(crate) fn index_of(&mut self, cell: HeapCellValue) -> Result<usize, usize> {
- Ok(if cell.is_var() {
- cell.get_value() as usize
- } else {
- let focus = self.cell_len();
- self.push_cell(cell)?;
- focus
- })
- }
-
pub(crate) fn clear(&mut self) {
unsafe {
let layout = alloc::Layout::array::<u8>(self.inner.byte_cap).unwrap();
pstr_loc1: usize,
pstr_loc2: usize,
) -> PStrSegmentCmpResult {
- unsafe {
- let slice1 = std::slice::from_raw_parts(
- self.inner.ptr.add(pstr_loc1),
- self.inner.byte_len - pstr_loc1,
- );
+ let slice1 = &self.as_slice()[pstr_loc1..];
+ let slice2 = &self.as_slice()[pstr_loc2..];
+
+ let find_tail = |null_idx: usize| -> usize { self.scan_slice_to_str(null_idx).tail_idx };
+
+ match slice1
+ .iter()
+ .zip(slice2.iter())
+ .position(|(b1, b2)| b1 != b2 || *b1 == 0 || *b2 == 0)
+ {
+ Some(pos) => {
+ if slice1[pos] == 0 {
+ // subtract 1 from pos to offset the increment of scan_slice_to_str if the
+ // string is "\0\".
+ let tail1_idx = find_tail(pstr_loc1 + pos);
+
+ if slice2[pos] == 0 {
+ let tail2_idx = find_tail(pstr_loc2 + pos);
+
+ PStrSegmentCmpResult::Continue(
+ heap_loc_as_cell!(tail1_idx),
+ heap_loc_as_cell!(tail2_idx),
+ )
+ } else {
+ PStrSegmentCmpResult::Continue(
+ heap_loc_as_cell!(tail1_idx),
+ pstr_loc_as_cell!(pstr_loc2 + pos),
+ )
+ }
+ } else if slice2[pos] == 0 {
+ let tail2_idx = find_tail(pstr_loc2 + pos);
- let slice2 = std::slice::from_raw_parts(
- self.inner.ptr.add(pstr_loc2),
- self.inner.byte_len - pstr_loc2,
- );
+ PStrSegmentCmpResult::Continue(
+ pstr_loc_as_cell!(pstr_loc1 + pos),
+ heap_loc_as_cell!(tail2_idx),
+ )
+ } else {
+ // Compute 7-byte chunks with the mismatching character at pos in the middle of
+ // each. This way, the character of which the byte at pos is a part will be
+ // validated and reached eventually by the utf8_chunks() iterator.
- let str1 = std::str::from_utf8_unchecked(&slice1);
- let str2 = std::str::from_utf8_unchecked(&slice2);
+ let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len());
+ let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len());
- debug_assert!(!str1.is_empty());
- debug_assert!(!str2.is_empty());
+ let chars1_iter = slice1[slice1_range].utf8_chunks();
+ let chars2_iter = slice2[slice2_range].utf8_chunks();
- for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) {
- if c1 == '\u{0}' && c2 == '\u{0}' {
- return PStrSegmentCmpResult::BothMatch {
- pstr_loc1,
- pstr_loc2,
- null_offset: idx,
- };
- } else if c1 == '\u{0}' {
- return PStrSegmentCmpResult::FirstMatch {
- pstr_loc1,
- pstr_loc2,
- l1_offset: idx,
- };
- } else if c2 == '\u{0}' {
- return PStrSegmentCmpResult::SecondMatch {
- pstr_loc1,
- pstr_loc2,
- l2_offset: idx,
- };
- } else if c1 != c2 {
- return PStrSegmentCmpResult::Mismatch { c1, c2 };
+ for (chunk1, chunk2) in chars1_iter.zip(chars2_iter) {
+ let result = chunk1.valid().cmp(chunk2.valid());
+
+ if result == Ordering::Greater {
+ return PStrSegmentCmpResult::Greater;
+ } else if result == Ordering::Less {
+ return PStrSegmentCmpResult::Less;
+ }
+ }
+
+ unreachable!()
}
}
-
- unreachable!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len()))
+ None => {
+ unreachable!()
+ }
}
}
Range { start, end }
}
- /*
- pub(crate) fn splice<R: RangeBounds<usize>>(
- &self,
- range: R,
- ) -> HeapView {
- let range = self.slice_range(range);
-
- HeapView {
- slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) },
- cell_offset: range.start,
- slice_cell_len: range.end - range.start,
- // pstr_slice: &self.pstr_vec.as_bitslice()[range],
- }
- }
+ pub fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
+ let size_in_heap = Self::compute_pstr_size(src);
+ let mut writer = self.reserve(size_in_heap)?;
+ let HeapSectionWriteResult { result, .. } =
+ writer.write_with(|section| match section.push_pstr(src) {
+ None => empty_list_as_cell!(),
+ Some(cell) => cell,
+ });
- pub(crate) fn splice_mut<R: RangeBounds<usize>>(
- &self,
- range: R,
- ) -> HeapViewMut {
- let range = self.slice_range(range);
-
- HeapViewMut {
- slice: unsafe { self.inner.ptr.add(heap_index!(range.start)) },
- cell_offset: range.start,
- slice_cell_len: range.end - range.start,
- // pstr_slice: &self.pstr_vec.as_bitslice()[range],
- }
+ Ok(result)
}
- */
- pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> {
+ // note that allocate_cstr emits a tail cell to the string (completing it with the empty list)
+ // unlike any version of allocate_pstr.
+
+ pub fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
let size_in_heap = Self::compute_pstr_size(src);
- let mut writer = self.reserve(size_in_heap)?;
+ let mut writer = self.reserve(size_in_heap + 1)?;
let HeapSectionWriteResult { result, .. } =
- writer.write_with(|section| section.push_pstr(src));
+ writer.write_with(|section| match section.push_pstr(src) {
+ None => empty_list_as_cell!(),
+ Some(cell) => {
+ section.push_cell(empty_list_as_cell!());
+ cell
+ }
+ });
- Ok(result.map(|cell| PStrWriteInfo { cell }))
+ Ok(result)
}
pub const fn heap_cell_alignment() -> usize {
// by at least two null bytes so one of them may be used
// to mark partial strings e.g. during iteration
- if (null_idx + 1) % ALIGN == 0 {
+ if (null_idx + 1).next_multiple_of(ALIGN) == null_idx + 1 {
byte_size += 2 * size_of::<HeapCellValue>();
} else {
byte_size += size_of::<HeapCellValue>();
}
}
-impl MachineState {
- pub(crate) fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
- match self.heap.allocate_pstr(src)? {
- None => Ok(empty_list_as_cell!()),
- Some(PStrWriteInfo { cell }) => Ok(cell),
- }
- }
-
- // note that allocate_cstr emits a tail cell to the string (completing it with the empty list)
- // unlike any version of allocate_pstr.
- pub(crate) fn allocate_cstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
- match self.heap.allocate_pstr(src)? {
- None => Ok(empty_list_as_cell!()),
- Some(PStrWriteInfo { cell }) => {
- self.heap.push_cell(empty_list_as_cell!())?;
- Ok(cell)
- }
- }
- }
-}
-
pub trait SizedHeap: Index<usize, Output = HeapCellValue> {
// return the size of the instance in cells
fn cell_len(&self) -> usize;
// fn pstr_at(&self, cell_offset: usize) -> bool;
}
-pub trait SizedHeapMut: IndexMut<usize, Output = HeapCellValue> + SizedHeap {}
-
impl Index<usize> for Heap {
type Output = HeapCellValue;
}
}
-impl SizedHeapMut for Heap {}
-
// sometimes we need to dereference variables that are found only in
// the heap without access to the full WAM (e.g., while detecting
// cycles in terms), and which therefore may only point other cells in
+use std::cmp::Ordering;
use std::collections::BTreeMap;
+use std::rc::Rc;
use crate::atom_table;
use crate::heap_iter::{stackful_post_order_iter, NonListElider};
+use crate::machine::machine_indices::VarKey;
use crate::machine::mock_wam::CompositeOpDir;
use crate::machine::{
ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC,
LIB_QUERY_SUCCESS,
};
-use crate::parser::ast::{TermWriteResult, Var};
-use crate::parser::lexer::LexerParser;
-use crate::parser::parser::Tokens;
+use crate::parser::ast::{Var, VarPtr};
+use crate::parser::parser::{Parser, Tokens};
+use crate::read::{write_term_to_heap, TermWriteResult};
use crate::types::UntypedArenaPtr;
use dashu::{Integer, Rational};
pub(crate) fn from_heapcell(
machine: &mut Machine,
heap_cell: HeapCellValue,
- var_names: &mut IndexMap<HeapCellValue, Var>,
+ var_names: &mut IndexMap<HeapCellValue, VarPtr>,
) -> Self {
// Adapted from MachineState::read_term_from_heap
let mut term_stack = vec![];
);
let mut anon_count: usize = 0;
+ let var_ptr_cmp = |a, b| match a {
+ Var::Named(name_a) => match b {
+ Var::Named(name_b) => name_a.cmp(&name_b),
+ _ => Ordering::Less,
+ },
+ _ => match b {
+ Var::Named(_) => Ordering::Greater,
+ _ => Ordering::Equal,
+ },
+ };
while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr);
term_stack.push(list);
}
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
- let var = var_names.get(&addr).cloned();
+ let var = var_names.get(&addr).map(|x| x.borrow().clone());
match var {
- Some(name) => term_stack.push(Term::Var(name.to_string())),
+ Some(Var::Named(name)) => term_stack.push(Term::Var(name.as_ref().to_owned())),
_ => {
let anon_name = loop {
// Generate a name for the anonymous variable
- let anon_name = count_to_letter_code(anon_count);
+ let anon_name = Rc::new(count_to_letter_code(anon_count));
// Find if this name is already being used
- var_names.sort_by(|_, a, _, b| a.cmp(b));
-
+ var_names.sort_by(|_, a, _, b| {
+ var_ptr_cmp(a.borrow().clone(), b.borrow().clone())
+ });
let binary_result = var_names.binary_search_by(|_,a| {
- let a: &String = a.as_ref();
- a.cmp(&anon_name)
+ let var_ptr = Var::Named(anon_name.clone());
+ var_ptr_cmp(a.borrow().clone(), var_ptr.clone())
});
match binary_result {
Ok(_) => anon_count += 1, // Name already used
Err(_) => {
// Name not used, assign it to this variable
- let var = anon_name.clone();
- var_names.insert(addr, Var::from(var));
+ let var_ptr = VarPtr::from(Var::Named(anon_name.clone()));
+ var_names.insert(addr, var_ptr);
break anon_name;
},
}
};
- term_stack.push(Term::Var(anon_name));
+ term_stack.push(Term::Var(anon_name.as_ref().to_owned()));
},
}
}
machine: &'a mut Machine,
term: TermWriteResult,
stub_b: usize,
- var_names: IndexMap<HeapCellValue, Var>,
+ var_names: IndexMap<HeapCellValue, VarPtr>,
called: bool,
}
}
if machine.machine_st.p == LIB_QUERY_SUCCESS {
- if term_write_result.inverse_var_locs.is_empty() {
+ if term_write_result.var_dict.is_empty() {
self.machine.machine_st.backtrack();
return Some(Ok(LeafAnswer::True));
}
}
let mut bindings: BTreeMap<String, Term> = BTreeMap::new();
- let inverse_var_locs = &term_write_result.inverse_var_locs;
- for (var_loc, var_name) in inverse_var_locs.iter() {
+ let var_dict = &term_write_result.var_dict;
+
+ for (var_key, term_to_be_printed) in var_dict.iter() {
+ let mut var_name = var_key.to_string();
if var_name.starts_with('_') {
- let should_print = var_names.values().any(|v| v == var_name);
+ let should_print = var_names.values().any(|x| match x.borrow().clone() {
+ Var::Named(v) => *v == *var_name,
+ _ => false,
+ });
if !should_print {
continue;
}
}
- let var_loc = *var_loc;
- let term =
- Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone());
+ let mut term =
+ Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone());
if let Term::Var(ref term_str) = term {
- if *term_str == **var_name {
+ if *term_str == var_name {
continue;
}
- // inverse_var_locs is in the order things appear in
- // the query. If var_name appears after term in the
- // query, switch their places.
- let var_cell = machine
- .machine_st
- .store(machine.machine_st.deref(machine.machine_st.heap[var_loc]));
-
- if (var_cell.get_value() as usize) < var_loc {
- bindings.insert(term_str.clone(), Term::Var(var_name.to_string()));
- continue;
+ // Var dict is in the order things appear in the query. If var_name appears
+ // after term in the query, switch their places.
+ let var_name_idx = var_dict
+ .get_index_of(&VarKey::VarPtr(Var::from(var_name.clone()).into()))
+ .unwrap();
+ let term_idx =
+ var_dict.get_index_of(&VarKey::VarPtr(Var::from(term_str.clone()).into()));
+ if let Some(idx) = term_idx {
+ if idx < var_name_idx {
+ let new_term = Term::Var(var_name);
+ let new_var_name = term_str.into();
+ term = new_term;
+ var_name = new_var_name;
+ }
}
}
- bindings.insert(var_name.to_string(), term);
+ bindings.insert(var_name, term);
}
// NOTE: there are outstanding choicepoints, backtrack
pub fn consult_module_string(&mut self, module_name: &str, program: impl Into<String>) {
let stream = Stream::from_owned_string(program.into(), &mut self.machine_st.arena);
self.machine_st.registers[1] = stream_as_cell!(stream);
- self.machine_st.registers[2] = atom_as_cell!(atom_table::AtomTable::build_with(
+ self.machine_st.registers[2] = atom_as_cell!(&atom_table::AtomTable::build_with(
&self.machine_st.atom_tbl,
- module_name,
+ module_name
));
self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
/// Runs a query.
pub fn run_query(&mut self, query: impl Into<String>) -> QueryState {
- let mut parser = LexerParser::new(
+ let mut parser = Parser::new(
Stream::from_owned_string(query.into(), &mut self.machine_st.arena),
&mut self.machine_st,
);
self.allocate_stub_choice_point();
+ // Write parsed term to heap
+ let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap)
+ .expect("couldn't write term to heap");
+
+ let var_names: IndexMap<_, _> = term_write_result
+ .var_dict
+ .iter()
+ .map(|(var_key, cell)| match var_key {
+ // NOTE: not the intention behind Var::InSitu here but
+ // we can hijack it to store anonymous variables
+ // without creating problems.
+ VarKey::AnonVar(h) => (*cell, VarPtr::from(Var::InSitu(*h))),
+ VarKey::VarPtr(var_ptr) => (*cell, var_ptr.clone()),
+ })
+ .collect();
+
// Write term to heap
- self.machine_st.registers[1] = self.machine_st.heap[term.focus];
- self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
+ self.machine_st.registers[1] = self.machine_st.heap[term_write_result.heap_loc];
+ self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
let call_index_p = self
.indices
.code_dir
.local()
.unwrap();
- let var_names: IndexMap<_, _> = term
- .inverse_var_locs
- .iter()
- .map(|(var_loc, var)| {
- let cell = self.machine_st.heap[*var_loc];
- (cell, var.clone())
- })
- .collect();
-
self.machine_st.execute_at_index(1, call_index_p);
let stub_b = self.machine_st.b;
-
QueryState {
machine: self,
- term,
+ term: term_write_result,
stub_b,
var_names,
called: false,
let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl");
- let file = File::open(&path_buf)
- .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
+ let file = File::open(&path_buf)?;
(
Stream::from_file_as_input(
ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl");
- let file = File::open(&path_buf)
- .map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
+ let file = File::open(&path_buf)?;
(
Stream::from_file_as_input(
use indexmap::IndexSet;
+use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Deref, DerefMut};
-
-impl TermWriteResult {
- pub(super) fn from(heap: &mut Heap, value: HeapCellValue) -> Result<Self, usize> {
- let focus = heap.index_of(value)?;
- let mut stack = Stack::uninitialized();
-
- heap[0] = value;
-
- let inverse_var_locs = inverse_var_locs_from_iter(stackful_preorder_iter::<NonListElider>(
- heap, &mut stack, 0,
- ));
-
- Ok(Self {
- focus,
- inverse_var_locs,
- })
- }
-}
+use std::rc::Rc;
/*
* The loader compiles Prolog terms read from a TermStream instance,
}
pub struct PredicateQueue {
- pub predicates: Vec<TermWriteResult>,
- pub compilation_target: CompilationTarget,
+ pub(super) predicates: Vec<Term>,
+ pub(super) compilation_target: CompilationTarget,
}
impl PredicateQueue {
#[inline]
- pub(super) fn push(&mut self, term_write_result: TermWriteResult) {
- self.predicates.push(term_write_result);
+ pub(super) fn push(&mut self, clause: Term) {
+ self.predicates.push(clause);
}
#[inline]
- pub(crate) fn first(&self) -> Option<&TermWriteResult> {
+ pub(crate) fn first(&self) -> Option<&Term> {
self.predicates.first()
}
#[inline(always)]
fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState {
- loader.term_stream.lexer_parser.machine_st
+ loader.term_stream.parser.lexer.machine_st
}
#[inline(always)]
}
}
- #[inline]
- pub(super) fn machine_heap(&mut self) -> &mut Heap {
- &mut LS::machine_st(&mut self.payload).heap
+ pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term {
+ let machine_st = LS::machine_st(&mut self.payload);
+ let cell = machine_st[r];
+
+ machine_st.read_term_from_heap(cell)
}
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
let compilation_target = &load_state.compilation_target;
let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target);
- let mut term = load_state.term_stream.next(&composite_op_dir)?;
- let predicate_focus_opt = load_state
- .predicates
- .first()
- .map(|term_write_result| term_write_result.focus);
-
- let machine_st = LS::machine_st(&mut self.payload);
- let term_key_opt = clause_predicate_key(&machine_st.heap, term.focus);
-
- if let Some(predicate_focus) = predicate_focus_opt {
- let predicate_key_opt = clause_predicate_key(&machine_st.heap, predicate_focus);
-
- debug_assert!(predicate_key_opt.is_some());
+ let term = load_state.term_stream.next(&composite_op_dir)?;
- if term_key_opt != predicate_key_opt {
- self.compile_and_submit()?;
- }
+ if !term.is_consistent(&load_state.predicates) {
+ self.compile_and_submit()?;
}
- if Some((atom!(":-"), 1)) == term_key_opt {
- let machine_st = LS::machine_st(&mut self.payload);
- term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap();
- return Ok(Some(setup_declaration(self, term)?));
- }
+ let term = match term {
+ Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
+ return Ok(Some(setup_declaration(self, terms)?));
+ }
+ term => term,
+ };
self.payload.predicates.push(term);
}
) => {
remove_constant_indices(
constant,
- &overlapping_constants,
+ overlapping_constants,
indexing_code,
clause_loc - index_loc, // WAS: &inner_index_locs,
);
let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r];
- let focus = machine_st.heap.cell_len();
- machine_st
- .heap
- .push_cell(cell)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
-
- let export_list = FocusedHeapRefMut {
- heap: &mut machine_st.heap,
- focus,
- };
+ let export_list = machine_st.read_term_from_heap(cell);
let export_list = setup_module_export_list(export_list)?;
Ok(export_list.into_iter().collect())
}
- fn clause_clause(&mut self, cell: HeapCellValue) -> Result<TermWriteResult, CompilationError> {
- let machine_st = LS::machine_st(&mut self.payload);
- let focus = machine_st.heap.cell_len();
-
- read_heap_cell!(cell,
- (HeapCellValueTag::Str, s) => {
- let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
- .get_name_and_arity();
-
- let mut writer = machine_st.heap.reserve(4)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+ fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
+ match term {
+ Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => {
+ let body = terms.pop().unwrap();
+ let head = terms.pop().unwrap();
- writer.write_with(|section| {
- section.push_cell(str_loc_as_cell!(focus+1));
- section.push_cell(atom_as_cell!(atom!("clause"), 2));
-
- match (name, arity) {
- (atom!(":-"), 2) => {
- section.push_cell(heap_loc_as_cell!(s+1));
- section.push_cell(heap_loc_as_cell!(s+2));
- }
- _ => {
- section.push_cell(str_loc_as_cell!(s));
- section.push_cell(atom_as_cell!(atom!("true")));
- }
- }
- });
+ self.payload.clause_clauses.push((head, body));
}
- (HeapCellValueTag::Atom, (name, arity)) => {
- if arity == 0 {
- let mut writer = machine_st.heap.reserve(4)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
-
- writer.write_with(|section| {
- section.push_cell(str_loc_as_cell!(focus+1));
- section.push_cell(atom_as_cell!(atom!("clause"), 2));
- section.push_cell(atom_as_cell!(name));
- section.push_cell(atom_as_cell!(atom!("true")));
- });
- } else {
- return Err(CompilationError::InadmissibleFact);
- }
+ head @ (Term::Clause(..) | Term::Literal(_, Literal::Atom(_))) => {
+ let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
+ self.payload.clause_clauses.push((head, body));
}
_ => {
return Err(CompilationError::InadmissibleFact);
}
- );
+ }
- Ok(
- TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus))
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?,
- )
+ Ok(())
}
fn add_extensible_predicate_declaration(
)
}
- fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> {
- let machine_st = LS::machine_st(&mut self.payload);
- let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value);
-
- if let Some((predicate_name, predicate_arity)) = key_opt {
+ fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
+ if let Some(predicate_name) = ClauseInfo::name(term) {
+ let predicate_arity = ClauseInfo::arity(term);
let predicates_compilation_target = self.payload.predicates.compilation_target;
let is_dynamic = self
.unwrap_or(false);
if is_dynamic {
- let clause_clause_term = self.clause_clause(value)?;
- self.payload.clause_clauses.push(clause_clause_term);
+ self.add_clause_clause(term.clone())?;
}
}
}
}
+impl MachineState {
+ pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
+ let mut term_stack = vec![];
+ self.heap[0] = term_addr;
+ let mut iter =
+ stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
+
+ while let Some(addr) = iter.next() {
+ let addr = unmark_cell_bits!(addr);
+
+ if let Ok(literal) = Literal::try_from(addr) {
+ term_stack.push(Term::Literal(Cell::default(), literal));
+ } else {
+ read_heap_cell!(addr,
+ (HeapCellValueTag::Lis) => {
+ use crate::parser::parser::as_partial_string;
+
+ let tail = term_stack.pop().unwrap();
+ let head = term_stack.pop().unwrap();
+
+ match as_partial_string(head, tail) {
+ Ok((string, Some(tail))) => {
+ term_stack.push(Term::PartialString(Cell::default(), Rc::new(string), tail));
+ }
+ Ok((string, None)) => {
+ term_stack.push(Term::CompleteString(Cell::default(), Rc::new(string)));
+ }
+ Err(cons_term) => term_stack.push(cons_term),
+ }
+ }
+ (HeapCellValueTag::StackVar, h) => {
+ term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("s_{}", h))));
+ }
+ (HeapCellValueTag::Var | HeapCellValueTag::AttrVar, h) => {
+ term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
+ }
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ let h = iter.focus().value() as usize;
+ let mut arity = arity;
+ let value = iter.heap[h.saturating_sub(1)];
+
+ if let Some(idx) = get_structure_index(value) {
+ term_stack.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
+ arity += 1;
+ }
+
+ if arity == 0 {
+ term_stack.push(Term::Literal(Cell::default(), Literal::Atom(name)));
+ } else {
+ let subterms = term_stack
+ .drain(term_stack.len() - arity ..)
+ .collect();
+
+ term_stack.push(Term::Clause(Cell::default(), name, subterms));
+ }
+ }
+ (HeapCellValueTag::PStrLoc, h) => {
+ let HeapStringScan { string, .. } = iter.heap.scan_slice_to_str(h);
+ let tail = term_stack.pop().unwrap();
+
+ term_stack.push(if matches!(tail, Term::Literal(_, Literal::Atom(atom!("[]")))) {
+ Term::CompleteString(
+ Cell::default(),
+ Rc::new(string.to_owned()),
+ )
+ } else {
+ Term::PartialString(
+ Cell::default(),
+ Rc::new(string.to_owned()),
+ Box::new(tail),
+ )
+ });
+ }
+ _ => {
+ }
+ );
+ }
+ }
+
+ debug_assert!(term_stack.len() == 1);
+ term_stack.pop().unwrap()
+ }
+}
+
impl Machine {
pub(crate) fn use_module(&mut self) -> CallResult {
let subevacuable_addr = self
}
pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
- let value = self.machine_st.registers[1];
- let term = resource_error_call_result!(
- self.machine_st,
- TermWriteResult::from(&mut self.machine_st.heap, value)
- );
-
let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
let add_clause = || {
+ let term = loader.read_term_from_heap(temp_v!(1));
+
loader.incremental_compile_clause(
(atom!("term_expansion"), 2),
term,
.machine_st
.store(self.machine_st.deref(self.machine_st.registers[1])));
+ let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
+
let compilation_target = match target_module_name {
atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(target_module_name),
};
- let value = self.machine_st.registers[2];
- let term = resource_error_call_result!(
- self.machine_st,
- TermWriteResult::from(&mut self.machine_st.heap, value)
- );
-
let add_clause = || {
- let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) {
- Some((atom!(":-"), _)) => term_nth_arg(&self.machine_st.heap, term.focus, 1)
- .and_then(|h| term_nth_arg(&self.machine_st.heap, h, 1)),
- Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1),
+ let term = loader.read_term_from_heap(temp_v!(2));
+
+ let indexing_arg = match term.name() {
+ Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
+ Some(_) => term.first_arg(),
None => None,
};
- let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| {
- term_predicate_key(&self.machine_st.heap, indexing_term_loc)
- });
-
- let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
-
- if let Some((name, arity)) = key_opt {
- loader
- .wam_prelude
- .indices
- .goal_expansion_indices
- .insert((name, arity));
+ if let Some(indexing_term) = indexing_arg {
+ if let Some(indexing_name) = indexing_term.name() {
+ loader
+ .wam_prelude
+ .indices
+ .goal_expansion_indices
+ .insert((indexing_name, indexing_term.arity()));
+ }
}
loader.incremental_compile_clause(
};
let stub_gen = || functor_stub(key.0, key.1);
- let assert_clause = self.machine_st.registers[2];
- let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause);
+ let head = self.deref_register(2);
+
+ if head.is_var() {
+ let err = self.machine_st.instantiation_error();
+ return Err(self.machine_st.error_form(err, stub_gen()));
+ }
- let mut compile_assert = |assert_clause, key_opt| {
+ let mut compile_assert = || {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target;
- let (name, arity) = if let Some(key) = key_opt {
- key
+ let head =
+ LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head);
+
+ let name = if let Some(name) = head.name() {
+ name
} else {
return Err(SessionError::from(CompilationError::InvalidRuleHead));
};
+ let arity = head.arity();
let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
let is_dynamic_predicate = loader
return LiveLoadAndMachineState::evacuate(loader);
}
- // if a new predicate was just created, make it dynamic.
- loader.add_dynamic_predicate(compilation_target, name, arity)?;
+ let body = loader.read_term_from_heap(temp_v!(3));
- let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload);
- // let asserted_clause = loader.copy_term_from_heap(assert_clause);
+ let asserted_clause = Term::Clause(
+ Cell::default(),
+ atom!(":-"),
+ vec![head.clone(), body.clone()],
+ );
- let term = TermWriteResult::from(&mut machine_st.heap, assert_clause)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+ // if a new predicate was just created, make it dynamic.
+ loader.add_dynamic_predicate(compilation_target, name, arity)?;
loader.incremental_compile_clause(
(name, arity),
- term,
+ asserted_clause,
compilation_target,
false,
append_or_prepend,
)?;
- let clause_clause_term = loader.clause_clause(assert_clause)?;
-
// the global clock is incremented after each assertion.
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses(
(name, arity),
compilation_target,
- vec![clause_clause_term],
+ std::iter::once((head, body)),
append_or_prepend,
)?;
LiveLoadAndMachineState::evacuate(loader)
};
- match compile_assert(assert_clause, key_opt) {
+ match compile_assert() {
Ok(_) => Ok(()),
Err(SessionError::CompilationError(
CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
};
let mut loader = self.loader_from_heap_evacuable(temp_v!(4));
- let predicate_focus_opt = loader
- .payload
- .predicates
- .first()
- .map(|term_write_result| term_write_result.focus);
-
- let is_consistent = if let Some(predicate_focus) = predicate_focus_opt {
- let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload);
- clause_predicate_key(&machine_st.heap, predicate_focus) == Some(key)
- } else {
- true
- };
LiveLoadAndMachineState::machine_st(&mut loader.payload).fail =
(!loader.payload.predicates.is_empty()
&& loader.payload.predicates.compilation_target != compilation_target)
- || !is_consistent;
+ || !key.is_consistent(&loader.payload.predicates);
let result = LiveLoadAndMachineState::evacuate(loader);
self.restore_load_state_payload(result)
self.payload.predicates.compilation_target = compilation_target;
}
- let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
- let value = machine_st.store(MachineState::deref(machine_st, machine_st[term_reg]));
-
- self.add_clause_clause_if_dynamic(value)?;
-
- let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
-
- let term = TermWriteResult::from(&mut machine_st.heap, value)
- .map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
+ let term = self.read_term_from_heap(term_reg);
+ self.add_clause_clause_if_dynamic(&term)?;
self.payload.term_stream.term_queue.push_back(term);
+
self.load()
}
}
#[derive(Debug)]
pub(crate) struct MachineError {
stub: MachineStub,
- location: Option<ParserErrorSrc>,
+ location: Option<(usize, usize)>, // line_num, col_num
}
// from 7.12.2 b) of 13211-1:1995
}
}
- pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError {
+ pub(super) fn resource_error(err: ResourceError) -> MachineError {
let stub = match err {
ResourceError::FiniteMemory(size_requested) => {
functor!(
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
match err {
ArithmeticError::NonEvaluableFunctor(cell, arity) => {
- let culprit = functor!(atom!("/"), [cell(cell), fixnum(arity)]);
-
+ let culprit = functor!(atom!("/"), [literal(cell), fixnum(arity)]);
self.type_error(ValidType::Evaluable, culprit)
}
+ ArithmeticError::UninstantiatedVar => self.instantiation_error(),
}
}
}
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub {
- if let Some(ParserErrorSrc { line_num, .. }) = err.location {
+ if let Some((line_num, _col_num)) = err.location {
functor!(
atom!("error"),
[
InvalidRuleHead,
InvalidUseModuleDecl,
InvalidModuleResolution(Atom),
+ FiniteMemoryInHeap(usize),
}
#[derive(Debug)]
pub enum DirectiveError {
- ExpectedDirective(HeapCellValue),
+ ExpectedDirective(Term),
InvalidDirective(Atom, usize /* arity */),
- InvalidOpDeclNameType(HeapCellValue),
- InvalidOpDeclSpecDomain(HeapCellValue),
+ InvalidOpDeclNameType(Term),
+ InvalidOpDeclSpecDomain(Term),
InvalidOpDeclSpecValue(Atom),
- InvalidOpDeclPrecType(HeapCellValue),
+ InvalidOpDeclPrecType(Term),
InvalidOpDeclPrecDomain(Fixnum),
ShallNotCreate(Atom),
ShallNotModify(Atom),
}
impl CompilationError {
- pub(crate) fn line_and_col_num(&self) -> Option<ParserErrorSrc> {
+ pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self {
- CompilationError::ParserError(err) => Some(err.err_src()),
+ CompilationError::ParserError(err) => err.line_and_col_num(),
_ => None,
}
}
CompilationError::ParserError(ref err) => {
functor!(err.as_atom())
}
+ CompilationError::FiniteMemoryInHeap(h) => {
+ vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))]
+ }
}
}
}
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
}
+impl From<std::io::Error> for SessionError {
+ #[inline]
+ fn from(err: std::io::Error) -> SessionError {
+ SessionError::from(ParserError::from(err))
+ }
+}
+
impl From<ParserError> for SessionError {
#[inline]
fn from(err: ParserError) -> Self {
use std::ops::{Deref, DerefMut};
use crate::types::*;
-// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-// pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
// 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
*/
}
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum VarKey {
+ AnonVar(usize),
+ VarPtr(VarPtr),
+}
+
+impl VarKey {
+ #[allow(clippy::inherent_to_string)]
+ #[inline]
+ pub(crate) fn to_string(&self) -> String {
+ match self {
+ VarKey::AnonVar(h) => format!("_{}", h),
+ VarKey::VarPtr(var) => var.borrow().to_string(),
+ }
+ }
+
+ #[inline(always)]
+ pub(crate) fn is_anon(&self) -> bool {
+ matches!(self, VarKey::AnonVar(_))
+ }
+}
+
+pub(crate) type HeapVarDict = IndexMap<VarKey, HeapCellValue, FxBuildHasher>;
+
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
_ => self
.get_meta_predicate_spec(key.0, key.1, &compilation_target)
.map(|meta_specs| {
- meta_specs.iter().find(|meta_spec| match meta_spec {
- MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true,
- _ => false,
+ meta_specs.iter().find(|meta_spec| {
+ matches!(
+ meta_spec,
+ MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_)
+ )
})
})
.map(|meta_spec_opt| meta_spec_opt.is_some())
use crate::machine::streams::*;
use crate::machine::Machine;
use crate::parser::ast::*;
+use crate::read::TermWriteResult;
use crate::types::*;
use crate::parser::dashu::Integer;
use std::convert::TryFrom;
use std::fmt;
use std::ops::{Index, IndexMut, Range};
-use std::rc::Rc;
use std::sync::Arc;
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
pub(super) e: usize,
pub(super) num_of_args: usize,
pub(super) cp: usize,
- pub(crate) attr_var_init: AttrVarInitializer,
+ pub(super) attr_var_init: AttrVarInitializer,
pub(super) fail: bool,
pub heap: Heap,
pub(super) mode: MachineMode,
}
*/
-fn push_var_eq_functors(
+// size may be an upper bound.
+// true_size is calculated to compute the exact offset.
+
+fn push_var_eq_functors<'a>(
heap: &mut Heap,
size: usize,
- iter: impl Iterator<Item = (usize, Var)>,
+ iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
atom_tbl: &AtomTable,
) -> Result<HeapCellValue, usize> {
let src_h = heap.cell_len();
- if size > 0 {
- let mut writer = heap.reserve(1 + 5 * size)?;
+ let true_size = if size > 0 {
+ let mut writer = heap.reserve(2 + 5 * size)?;
- writer.write_with(|section| {
- for (var_loc, var) in iter {
- // (var, binding) in iter {
- let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
- let binding = heap_loc_as_cell!(var_loc);
+ writer
+ .write_with(|section| {
+ let mut size = 0;
- section.push_cell(atom_as_cell!(atom!("="), 2));
- section.push_cell(atom_as_cell!(var_atom));
- section.push_cell(binding);
- }
+ for (var, binding) in iter {
+ let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
- for idx in 0..size {
- section.push_cell(list_loc_as_cell!(section.cell_len() + 1));
- section.push_cell(str_loc_as_cell!(src_h + 3 * idx));
- }
+ section.push_cell(atom_as_cell!(atom!("="), 2));
+ section.push_cell(atom_as_cell!(var_atom));
+ section.push_cell(*binding);
- section.push_cell(empty_list_as_cell!());
- });
+ size += 1;
+ }
+
+ for idx in 0..size {
+ section.push_cell(list_loc_as_cell!(section.cell_len() + 1));
+ section.push_cell(str_loc_as_cell!(src_h + 3 * idx));
+ }
+
+ if size > 0 {
+ section.push_cell(empty_list_as_cell!());
+ }
- Ok(heap_loc_as_cell!(src_h + 3 * size))
+ size
+ })
+ .result
} else {
- Ok(empty_list_as_cell!())
- }
-}
+ size
+ };
-/*
-pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
- iter: Iter,
- boundary: i64,
- h: i64,
-) -> impl Iterator<Item = HeapCellValue> {
- let diff = boundary - h;
- iter.map(move |heap_value| heap_value - diff)
+ Ok(if true_size > 0 {
+ heap_loc_as_cell!(src_h + 3 * true_size)
+ } else {
+ empty_list_as_cell!()
+ })
}
-*/
#[derive(Debug)]
pub struct Ball {
}
#[derive(Debug)]
-pub(crate) struct CopyBallTerm<'a> {
+pub(super) struct CopyBallTerm<'a> {
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
}
impl<'a> CopyBallTerm<'a> {
- pub(crate) fn new(
+ pub(super) fn new(
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
pub fn write_read_term_options(
&mut self,
- mut var_list: Vec<(Var, HeapCellValue, usize)>,
- singletons_heap_list: HeapCellValue,
+ mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
+ singleton_heap_list: HeapCellValue,
) -> CallResult {
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
- /*
- let list_of_var_eqs = push_var_eq_functors(
- &mut self.heap,
- var_list.iter().map(|(var_name, var, _)| {
- (var.get_value() as usize, var_name.clone())
- }),
- num_vars,
- &self.atom_tbl,
- );
- */
-
let singleton_addr = self.registers[3];
- unify_fn!(*self, singletons_heap_list, singleton_addr);
+ unify_fn!(*self, singleton_heap_list, singleton_addr);
if self.fail {
return Ok(());
}
let var_names_addr = self.registers[5];
- /*
- let var_names_offset = heap_loc_as_cell!(iter_to_heap_list(
- &mut self.heap,
- list_of_var_eqs.into_iter()
- ));
- */
-
let var_names_offset = resource_error_call_result!(
self,
push_var_eq_functors(
&mut self.heap,
var_list.len(),
- var_list
- .iter()
- .map(|(var_name, var, _)| { (var.get_value() as usize, var_name.clone()) }),
+ var_list.iter().filter_map(|(var_name, var, _)| {
+ if var_name.is_anon() {
+ None
+ } else {
+ Some((var_name, var))
+ }
+ }),
&self.atom_tbl,
)
);
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
}
- pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult {
- let heap_loc = self.heap[term.focus];
-
- /*
- read_heap_cell!(self.heap[term.heap_loc],
- (HeapCellValueTag::PStr) => { // | HeapCellValueTag::PStrOffset) => {
- pstr_loc_as_cell!(term.heap_loc)
- }
- _ => {
- heap_loc_as_cell!(term.heap_loc)
- }
- );
- */
-
+ pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
+ let heap_loc = heap_loc_as_cell!(term_write_result.heap_loc);
unify_fn!(*self, heap_loc, self.registers[2]);
if self.fail {
return Ok(());
}
- /*
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
- */
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
+ self.heap[0] = heap_loc;
- for cell in
- stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, term.focus)
- {
+ for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0) {
let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.as_var() {
self,
push_var_eq_functors(
&mut self.heap,
- singleton_var_set
+ term_write_result.var_dict.len(),
+ term_write_result
+ .var_dict
.iter()
- .filter(|(var, is_singleton)| {
- **is_singleton
- && term
- .inverse_var_locs
- .contains_key(&(var.get_value() as usize))
- })
- .count(),
- term.inverse_var_locs
- .iter()
- .filter_map(|(var_loc, var_name)| {
- let r = Ref::heap_cell(*var_loc);
+ .filter(|(var_name, binding)| {
+ if var_name.is_anon() {
+ return false;
+ }
- if singleton_var_set.get(&r).cloned().unwrap_or(false) {
- Some((*var_loc, var_name.clone()))
+ if let Some(r) = binding.as_var() {
+ *singleton_var_set.get(&r).unwrap_or(&false)
} else {
- None
+ false
}
}),
&self.atom_tbl,
)
);
- let mut var_list = Vec::with_capacity(singleton_var_set.len());
+ for var in term_write_result.var_dict.values_mut() {
+ *var = heap_bound_deref(&self.heap, *var);
+ }
- for (var_loc, var_name) in term.inverse_var_locs {
- let r = Ref::heap_cell(var_loc);
- let cell = self.heap[var_loc];
+ let mut var_list = Vec::with_capacity(singleton_var_set.len());
- if let Some(idx) = singleton_var_set.get_index_of(&r) {
- var_list.push((var_name, cell, idx));
+ for (var_name, addr) in term_write_result.var_dict {
+ if let Some(var) = addr.as_var() {
+ if let Some(idx) = singleton_var_set.get_index_of(&var) {
+ var_list.push((var_name, addr, idx));
+ }
}
}
}
loop {
- match self.read_to_heap(stream, &indices.op_dir) {
- Ok(term) => return self.read_term_body(term),
+ match self.read(stream, &indices.op_dir) {
+ Ok(term_write_result) => return self.read_term_body(term_write_result),
Err(err) => {
match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
let printer = match self.try_from_list(self.registers[6], stub_gen) {
Ok(addrs) => {
- let mut var_names: IndexMap<HeapCellValue, Var> = IndexMap::new();
+ let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
for addr in addrs {
read_heap_cell!(addr,
read_heap_cell!(atom,
(HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0);
- var_names.insert(var, Rc::new(name.as_str().to_owned()));
+ var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
}
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity();
debug_assert_eq!(arity, 0);
- var_names.insert(var, Rc::new(name.as_str().to_owned()));
+ var_names.insert(var, VarPtr::from(name.as_str().to_owned()));
}
_ => {
unreachable!();
}
);
- let term_loc = self.heap.cell_len();
-
- step_or_resource_error!(self, self.heap.push_cell(term_to_be_printed), {
- return Ok(None);
- });
+ self.heap[0] = term_to_be_printed;
let mut printer = HCPrinter::new(
&mut self.heap,
&mut self.stack,
op_dir,
PrinterOutputter::new(),
- term_loc,
+ 0,
);
printer.ignore_ops = ignore_ops;
}
printer.var_names = var_names;
-
printer
}
Err(err) => {
(HeapCellValueTag::PStrLoc, l1) => {
read_heap_cell!(v2,
(HeapCellValueTag::PStrLoc, l2) => {
- let cmp_result = self.heap.compare_pstr_segments(l1, l2);
-
- if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) {
- return Some(ordering);
+ match self.heap.compare_pstr_segments(l1, l2) {
+ PStrSegmentCmpResult::Continue(v1, v2) => {
+ self.pdl.push(v1);
+ self.pdl.push(v2);
+ }
+ PStrSegmentCmpResult::Less => {
+ return Some(Ordering::Less);
+ }
+ PStrSegmentCmpResult::Greater => {
+ return Some(Ordering::Greater);
+ }
}
}
(HeapCellValueTag::Lis, l2) => {
Some(Ordering::Equal)
}
- /* TODO: new, inlined match_partial_string. now inlined into GetPartialString,
- * the only place it is called from. Therefore, it has been inlined.
-
- pub fn match_partial_string(
- &mut self,
- value: HeapCellValue,
- string: &str,
- ) -> Result<(), usize> {
- debug_assert!(value.is_ref());
-
- self.heap[0] = value;
- let mut heap_pstr_iter = HeapPStrIter::new(&self.heap, 0);
-
- match heap_pstr_iter.compare_pstr_to_string(string) {
- Some(PStrCmpResult::CompleteMatch { bytes_matched, pstr_loc }) => {
- self.s_offset = bytes_matched;
- self.s = HeapPtr::PStr(pstr_loc);
- self.mode = MachineMode::Read;
- }
- Some(PStrCmpResult::PartialMatch { string, var_loc }) => {
- let cell = self.heap.allocate_pstr(string)?;
- unify!(self, cell, heap_loc_as_loc!(var_loc));
- }
- None => {
- self.fail = true;
- }
- }
-
- Ok(())
- }
- */
-
pub(crate) fn setup_call_n_init_goal_info(
&mut self,
goal: HeapCellValue,
#[cfg(test)]
use crate::machine::copier::CopierTarget;
+use crate::read::TermWriteResult;
#[cfg(test)]
use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
&mut self,
input_stream: Stream,
) -> Result<TermWriteResult, CompilationError> {
- self.machine_st.read_to_heap(input_stream, &self.op_dir)
+ self.machine_st.read(input_stream, &self.op_dir)
}
pub fn parse_and_write_parsed_term_to_heap(
term_string: &'static str,
) -> Result<String, CompilationError> {
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
-
- print_heap_terms(&self.machine_st.heap, term_write_result.focus);
-
- let var_names = term_write_result
- .inverse_var_locs
- .iter()
- .map(|(var_loc, var_name)| (self.machine_st.heap[*var_loc], var_name.clone()))
- .collect();
+ print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc);
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
&mut self.machine_st.stack,
&self.op_dir,
PrinterOutputter::new(),
- term_write_result.focus,
+ term_write_result.heap_loc,
);
- printer.var_names = var_names;
+ printer.var_names = term_write_result
+ .var_dict
+ .into_iter()
+ .map(|(var, cell)| match var {
+ VarKey::VarPtr(var) => (cell, var.clone()),
+ VarKey::AnonVar(_) => (cell, VarPtr::from(var.to_string())),
+ })
+ .collect();
Ok(printer.print().result())
}
input_stream: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, CompilationError> {
- machine_st.read_to_heap(input_stream, op_dir)
+ machine_st.read(input_stream, op_dir)
}
#[cfg(test)]
unify!(
wam,
str_loc_as_cell!(0),
- str_loc_as_cell!(term_write_result_2.focus)
+ str_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
wam.heap.clear();
{
- let term_write_result_1 =
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(term_write_result_1.focus),
- heap_loc_as_cell!(term_write_result_2.focus)
+ str_loc_as_cell!(1),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
wam.heap.clear();
{
- let term_write_result_1 =
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(term_write_result_1.focus),
- heap_loc_as_cell!(term_write_result_2.focus)
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
wam.heap.clear();
{
- let term_write_result_1 =
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(term_write_result_1.focus),
- heap_loc_as_cell!(term_write_result_2.focus)
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
wam.heap.clear();
{
- let term_write_result_1 =
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(term_write_result_1.focus),
- heap_loc_as_cell!(term_write_result_2.focus)
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
wam.heap.clear();
{
- let term_write_result_1 =
- parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
+ parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
unify!(
wam,
- heap_loc_as_cell!(term_write_result_1.focus),
- heap_loc_as_cell!(term_write_result_2.focus)
+ heap_loc_as_cell!(0),
+ heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(!wam.fail);
});
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
+
assert!(!wam.fail);
all_cells_unmarked(&wam.heap);
+ wam.heap.clear();
+
+ {
+ let term_write_result_1 =
+ parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
+
+ print_heap_terms(&wam.heap, term_write_result_1.heap_loc);
+
+ unify!(wam, heap_loc_as_cell!(2), str_loc_as_cell!(4));
+
+ assert_eq!(wam.heap[2], str_loc_as_cell!(4));
+ }
}
#[test]
unify_with_occurs_check!(
wam,
- heap_loc_as_cell!(0),
- heap_loc_as_cell!(term_write_result_2.focus)
+ str_loc_as_cell!(0),
+ str_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);
Some(Ordering::Equal)
);
- let cstr_cell = wam.allocate_cstr("string").unwrap();
+ let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!(
compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
Some(Ordering::Greater)
);
- let cstr_cell = wam.allocate_cstr("string").unwrap();
+ let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!(
compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
wam.heap.clear();
let h = wam.heap.cell_len();
- wam.allocate_cstr("a string").unwrap();
+ wam.heap.allocate_cstr("a string").unwrap();
assert!(!wam.is_cyclic_term(h));
}
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
self.try_execute(name, arity, idx.get())
} else {
- println!("aaand undefined!");
self.undefined_procedure(name, arity)
}
} else if let Some(module) = self.indices.modules.get(&module_name) {
fn pstr_iter_tests() {
let mut wam = MockWAM::new();
- let pstr_cell = wam.machine_st.allocate_pstr("abc ").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_pstr("abc ").unwrap();
wam.machine_st
.heap
.push_cell(empty_list_as_cell!())
wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3));
- wam.machine_st.allocate_pstr("def").unwrap();
+ wam.machine_st.heap.allocate_pstr("def").unwrap();
let h = wam.machine_st.heap.cell_len();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap();
wam.machine_st.heap.clear();
- let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- let pstr_cell = wam.machine_st.allocate_cstr("d").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_cstr("d").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- let pstr_cell = wam.machine_st.allocate_cstr("abc").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_cstr("abc").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- let pstr_cell = wam.machine_st.allocate_cstr("abcdef").unwrap();
+ let pstr_cell = wam.machine_st.heap.allocate_cstr("abcdef").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr("abc").unwrap();
+ wam.machine_st.heap.allocate_cstr("abc").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr("a ").unwrap();
+ wam.machine_st.heap.allocate_cstr("a ").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr(" a").unwrap();
+ wam.machine_st.heap.allocate_cstr(" a").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr("a b").unwrap();
+ wam.machine_st.heap.allocate_cstr("a b").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr(" a ").unwrap();
+ wam.machine_st.heap.allocate_cstr(" a ").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr(" a bc").unwrap();
+ wam.machine_st.heap.allocate_cstr(" a bc").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr("abc").unwrap();
+ wam.machine_st.heap.allocate_cstr("abc").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
// #2293, test7.
wam.machine_st.heap.clear();
- wam.machine_st.allocate_cstr("abcde").unwrap();
+ wam.machine_st.heap.allocate_cstr("abcde").unwrap();
let start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap();
use crate::forms::*;
use crate::instructions::*;
use crate::machine::disjuncts::*;
-use crate::machine::heap::*;
use crate::machine::loader::*;
use crate::machine::machine_errors::*;
-use crate::machine::CodeIndex;
use crate::parser::ast::*;
-use crate::types::*;
-use fxhash::FxBuildHasher;
-use indexmap::IndexMap;
use indexmap::IndexSet;
+use std::cell::Cell;
use std::convert::TryFrom;
pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl {
OpDecl::new(OpDesc::build_with(prec, spec), name)
})
}
-fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
- let (focus, _cell) = subterm_index(term.heap, term.focus);
-
- let name = match term_predicate_key(term.heap, focus + 3) {
- Some((name, 0)) => name,
- _ => {
+fn setup_op_decl(mut terms: Vec<Term>) -> Result<OpDecl, CompilationError> {
+ // should allow non-partial lists?
+ let name = match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => name,
+ other => {
return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclNameType(term.heap[focus + 3]),
+ DirectiveError::InvalidOpDeclNameType(other),
));
}
};
- let spec = match term_predicate_key(term.heap, focus + 2) {
- Some((name, _)) => name,
- None => {
+ let spec = match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => name,
+ other => {
return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus + 2]),
- ));
+ DirectiveError::InvalidOpDeclSpecDomain(other),
+ ))
}
};
let spec = to_op_decl_spec(spec)?;
- let prec = term.deref_loc(focus + 1);
- let prec = read_heap_cell!(prec,
- (HeapCellValueTag::Fixnum, n) => {
- match u16::try_from(n.get_num()) {
- Ok(n) if n <= 1200 => n,
- _ => {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclPrecDomain(n),
- ));
- }
+ let prec = match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
+ Ok(n) if n <= 1200 => n,
+ _ => {
+ return Err(CompilationError::InvalidDirective(
+ DirectiveError::InvalidOpDeclPrecDomain(bi),
+ ));
}
- }
- _ => {
+ },
+ other => {
return Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidOpDeclPrecType(prec),
+ DirectiveError::InvalidOpDeclPrecType(other),
));
}
- );
+ };
if name == "[]" || name == "{}" {
return Err(CompilationError::InvalidDirective(
Ok(to_op_decl(prec, spec, name))
}
-fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> {
- let key_opt = term_predicate_key(term.heap, term.focus);
-
- if let Some((atom!("/") | atom!("//"), 2)) = key_opt {
- let arity_loc = term.nth_arg(term.focus, 2).unwrap();
-
- let arity = match Number::try_from(term.deref_loc(arity_loc)) {
- Ok(Number::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
- Ok(Number::Integer(n)) => (&*n).try_into().ok(),
- _ => None,
- }
- .ok_or(CompilationError::InvalidModuleExport)?;
+fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
+ match term {
+ Term::Clause(_, slash, ref mut terms)
+ if (*slash == atom!("/") || *slash == atom!("//")) && terms.len() == 2 =>
+ {
+ let arity = terms.pop().unwrap();
+ let name = terms.pop().unwrap();
+
+ let arity = match arity {
+ Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
+ Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
+ _ => None,
+ }
+ .ok_or(CompilationError::InvalidModuleExport)?;
- let name_loc = term.nth_arg(term.focus, 1).unwrap();
- let name = term_predicate_key(term.heap, name_loc)
- .map(|(name, _)| name)
+ let name = match name {
+ Term::Literal(_, Literal::Atom(name)) => Some(name),
+ _ => None,
+ }
.ok_or(CompilationError::InvalidModuleExport)?;
- if matches!(key_opt, Some((atom!("/"), _))) {
- Ok((name, arity))
- } else {
- Ok((name, arity + 2))
+ if *slash == atom!("/") {
+ Ok((name, arity))
+ } else {
+ Ok((name, arity + 2))
+ }
}
- } else {
- Err(CompilationError::InvalidModuleExport)
+ _ => Err(CompilationError::InvalidModuleExport),
}
}
-fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, CompilationError> {
- setup_predicate_indicator(term)
+fn setup_module_export(mut term: Term) -> Result<ModuleExport, CompilationError> {
+ setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
- let key_opt = term_predicate_key(term.heap, term.focus);
-
- if let Some((atom!("op"), 3)) = key_opt {
- Ok(ModuleExport::OpDecl(setup_op_decl(term)?))
+ if let Term::Clause(_, name, terms) = term {
+ if terms.len() == 3 && name == atom!("op") {
+ Ok(ModuleExport::OpDecl(setup_op_decl(terms)?))
+ } else {
+ Err(CompilationError::InvalidModuleDecl)
+ }
} else {
Err(CompilationError::InvalidModuleDecl)
}
})
}
-/* TODO: should be unnecessary now.
-
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec());
let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule)
}
-*/
pub(super) fn setup_module_export_list(
- term: FocusedHeapRefMut,
+ mut export_list: Term,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
- let mut focus = term.focus;
-
- loop {
- read_heap_cell!(term.heap[focus],
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if h == focus {
- break;
- } else {
- focus = h;
- }
- }
- (HeapCellValueTag::Lis, l) => {
- let term = FocusedHeapRefMut {
- heap: term.heap,
- focus: l,
- };
-
- exports.push(setup_module_export(&term)?);
- focus = l + 1;
- }
- (HeapCellValueTag::Atom, (name, _arity)) => {
- if name == atom!("[]") {
- return Ok(exports);
- } else {
- break;
- }
- }
- _ => {
- break;
- }
- );
+
+ while let Term::Cons(_, t1, t2) = export_list {
+ let module_export = setup_module_export(*t1)?;
+
+ exports.push(module_export);
+ export_list = *t2;
}
- Err(CompilationError::InvalidModuleDecl)
+ if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
+ Ok(exports)
+ } else {
+ Err(CompilationError::InvalidModuleDecl)
+ }
}
-fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> {
- let name = term_predicate_key(term.heap, term.focus + 1)
- .map(|(name, _)| name)
- .ok_or(CompilationError::InvalidModuleDecl)?;
+fn setup_module_decl(mut terms: Vec<Term>) -> Result<ModuleDecl, CompilationError> {
+ let export_list = terms.pop().unwrap();
+ let name = terms.pop().unwrap();
- term.focus = term.focus + 2;
- let exports = setup_module_export_list(term)?;
+ let name = match name {
+ Term::Literal(_, Literal::Atom(name)) => Some(name),
+ _ => None,
+ }
+ .ok_or(CompilationError::InvalidModuleDecl)?;
+ let exports = setup_module_export_list(export_list)?;
Ok(ModuleDecl { name, exports })
}
-fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result<ModuleSource, CompilationError> {
- read_heap_cell!(term.deref_loc(term.focus+1),
- (HeapCellValueTag::Str, s) => {
- let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity();
-
- if (name, arity) == (atom!("library"), 1) {
- read_heap_cell!(term.deref_loc(s+1),
- (HeapCellValueTag::Atom, (name, arity)) => {
- if arity == 0 {
- return Ok(ModuleSource::Library(name));
- }
- }
- _ => {
- }
- )
- }
-
- return Err(CompilationError::InvalidModuleDecl);
- }
- (HeapCellValueTag::Atom, (name, arity)) => {
- if arity == 0 {
- Ok(ModuleSource::File(name))
- } else {
- Err(CompilationError::InvalidUseModuleDecl)
+fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
+ match terms.pop().unwrap() {
+ Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
+ match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
+ _ => Err(CompilationError::InvalidModuleDecl),
}
}
- _ => {
- Err(CompilationError::InvalidUseModuleDecl)
- }
- )
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
+ _ => Err(CompilationError::InvalidUseModuleDecl),
+ }
}
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
-fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, CompilationError> {
- let module_src = setup_use_module_decl(&term)?;
- let mut exports = IndexSet::new();
-
- let mut focus = term.focus + 2;
-
- while let HeapCellValueTag::Lis = term.heap[focus].get_tag() {
- focus = term.heap[focus].get_value() as usize;
+fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, CompilationError> {
+ let mut export_list = terms.pop().unwrap();
+ let module_src = match terms.pop().unwrap() {
+ Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
+ match terms.pop().unwrap() {
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
+ _ => Err(CompilationError::InvalidModuleDecl),
+ }
+ }
+ Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
+ _ => Err(CompilationError::InvalidUseModuleDecl),
+ }?;
- let term = FocusedHeapRefMut {
- heap: term.heap,
- focus,
- };
+ let mut exports = IndexSet::new();
- exports.insert(setup_module_export(&term)?);
- focus = focus + 1;
+ while let Term::Cons(_, t1, t2) = export_list {
+ exports.insert(setup_module_export(*t1)?);
+ export_list = *t2;
}
- if term.heap[focus] == empty_list_as_cell!() {
+ if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok((module_src, exports))
} else {
Err(CompilationError::InvalidModuleDecl)
*/
fn setup_meta_predicate<'a, LS: LoadState<'a>>(
- term: TermWriteResult,
+ mut terms: Vec<Term>,
loader: &mut Loader<'a, LS>,
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
- fn get_meta_specs(
- term: FocusedHeapRefMut,
- arity: usize,
- ) -> Result<Vec<MetaSpec>, CompilationError> {
+ fn get_name_and_meta_specs(
+ name: Atom,
+ terms: &mut [Term],
+ ) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![];
- for meta_spec_loc in term.focus + 1..term.focus + arity + 1 {
- read_heap_cell!(term.deref_loc(meta_spec_loc),
- (HeapCellValueTag::Atom, (meta_spec, arity)) => {
- debug_assert_eq!(arity, 0);
-
+ for meta_spec in terms.iter_mut() {
+ match meta_spec {
+ Term::Literal(_, Literal::Atom(meta_spec)) => {
let meta_spec = match meta_spec {
atom!("+") => MetaSpec::Plus,
atom!("-") => MetaSpec::Minus,
meta_specs.push(meta_spec);
}
- (HeapCellValueTag::Fixnum, n) => {
- match usize::try_from(n.get_num()) {
- Ok(n) if n <= MAX_ARITY => {
- meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
- }
- _ => {
- return Err(CompilationError::InvalidMetaPredicateDecl);
- }
+ Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
+ Ok(n) if n <= MAX_ARITY => {
+ meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
}
- }
+ _ => {
+ return Err(CompilationError::InvalidMetaPredicateDecl);
+ }
+ },
_ => {
return Err(CompilationError::InvalidMetaPredicateDecl);
}
- );
+ }
}
- Ok(meta_specs)
+ Ok((name, meta_specs))
}
- let heap = loader.machine_heap();
- let cell = heap_bound_store(heap, heap_bound_deref(heap, heap[term.focus + 1]));
-
- read_heap_cell!(cell,
- (HeapCellValueTag::Str, s) => {
- let (name, arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
-
- match (name, arity) {
- (atom!(":"), 2) => {
- let module_name = heap[s+1];
- let spec = heap[s+2];
-
- read_heap_cell!(module_name,
- (HeapCellValueTag::Atom, (module_name, arity)) => {
- if arity == 0 {
- read_heap_cell!(spec,
- (HeapCellValueTag::Str, s) => {
- let (name, arity) = cell_as_atom_cell!(heap[s])
- .get_name_and_arity();
-
- let term = FocusedHeapRefMut { heap, focus: s };
- return Ok((module_name, name, get_meta_specs(term, arity)?));
- }
- _ => {
- }
- );
- } else {
- return Err(CompilationError::InvalidMetaPredicateDecl);
- }
- }
- _ => {
- }
- );
- }
- _ => {
- let term = FocusedHeapRefMut { heap, focus: s };
- let specs = get_meta_specs(term, arity)?;
- let module_name = loader.payload.compilation_target.module_name();
+ match terms.pop().unwrap() {
+ Term::Clause(_, name, mut terms) if name == atom!(":") && terms.len() == 2 => {
+ let spec = terms.pop().unwrap();
+ let module_name = terms.pop().unwrap();
- return Ok((module_name, name, specs));
- }
+ match module_name {
+ Term::Literal(_, Literal::Atom(module_name)) => match spec {
+ Term::Clause(_, name, mut terms) => {
+ let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
+ Ok((module_name, name, meta_specs))
+ }
+ _ => Err(CompilationError::InvalidMetaPredicateDecl),
+ },
+ _ => Err(CompilationError::InvalidMetaPredicateDecl),
}
-
- Err(CompilationError::InvalidMetaPredicateDecl)
}
- _ => {
- Err(CompilationError::InvalidMetaPredicateDecl)
+ Term::Clause(_, name, mut terms) => {
+ let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
+ Ok((
+ loader.payload.compilation_target.module_name(),
+ name,
+ meta_specs,
+ ))
}
- )
+ _ => Err(CompilationError::InvalidMetaPredicateDecl),
+ }
}
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
- mut term: TermWriteResult,
+ mut terms: Vec<Term>,
) -> Result<Declaration, CompilationError> {
- let mut focus = term.focus;
- let machine_st = LS::machine_st(&mut loader.payload);
-
- loop {
- let decl = machine_st.heap[focus];
+ let term = terms.pop().unwrap();
- read_heap_cell!(decl,
- (HeapCellValueTag::Atom, (name, arity)) => {
- let mut focused = FocusedHeapRefMut::from(&mut machine_st.heap, focus);
-
- return match (name, arity) {
- (atom!("dynamic"), 1) => {
- let (name, arity) = setup_predicate_indicator(&focused)?;
- Ok(Declaration::Dynamic(name, arity))
- }
- (atom!("module"), 2) => {
- Ok(Declaration::Module(setup_module_decl(focused)?))
- }
- (atom!("op"), 3) => {
- Ok(Declaration::Op(setup_op_decl(&focused)?))
- }
- (atom!("non_counted_backtracking"), 1) => {
- focused.focus = focused.nth_arg(focused.focus, 1).unwrap();
- let (name, arity) = setup_predicate_indicator(&focused)?;
- Ok(Declaration::NonCountedBacktracking(name, arity))
- }
- (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)),
- (atom!("use_module"), 2) => {
- let (name, exports) = setup_qualified_import(focused)?;
- Ok(Declaration::UseQualifiedModule(name, exports))
- }
- (atom!("meta_predicate"), 1) => {
- term.focus = focus;
- let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?;
- Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
- }
- _ => Err(CompilationError::InvalidDirective(
- DirectiveError::InvalidDirective(name, arity)
- ))
- };
+ match term {
+ Term::Clause(_, name, mut terms) => match (name, terms.len()) {
+ (atom!("dynamic"), 1) => {
+ let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
+ Ok(Declaration::Dynamic(name, arity))
}
- (HeapCellValueTag::Str, s) => {
- focus = s;
+ (atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)),
+ (atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)),
+ (atom!("non_counted_backtracking"), 1) => {
+ let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
+ Ok(Declaration::NonCountedBacktracking(name, arity))
}
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if focus != h {
- focus = h;
- } else {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::ExpectedDirective(decl),
- ));
- }
+ (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
+ (atom!("use_module"), 2) => {
+ let (name, exports) = setup_qualified_import(terms)?;
+ Ok(Declaration::UseQualifiedModule(name, exports))
}
- _ => {
- return Err(CompilationError::InvalidDirective(
- DirectiveError::ExpectedDirective(decl),
- ));
+ (atom!("meta_predicate"), 1) => {
+ let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
+ Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
}
- );
+ _ => Err(CompilationError::InvalidDirective(
+ DirectiveError::InvalidDirective(name, terms.len()),
+ )),
+ },
+ other => Err(CompilationError::InvalidDirective(
+ DirectiveError::ExpectedDirective(other),
+ )),
}
}
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
module_name: Atom,
- arity: usize,
- term: &TermWriteResult,
+ terms: Vec<Term>,
meta_specs: Vec<MetaSpec>,
-) -> IndexMap<usize, CodeIndex, FxBuildHasher> {
- use crate::machine::heap::Heap;
- let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
-
- let focus = {
- let heap = loader.machine_heap();
- let focus_cell =
- heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(term.focus)));
-
- if focus_cell.get_tag() == HeapCellValueTag::Str {
- focus_cell.get_value() as usize
- } else {
- return index_ptrs;
- }
- };
+) -> Vec<Term> {
+ let mut arg_terms = Vec::with_capacity(terms.len());
- for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) {
+ for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
- let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
-
- if let Some((name, arity)) = predicate_key_opt {
+ if let Some(name) = term.name() {
if name == atom!("$call") {
+ arg_terms.push(term);
continue;
}
- struct QualifiedNameInfo {
- module_name: Atom,
- name: Atom,
- arity: usize,
- qualified_term_loc: usize,
- }
+ let arity = term.arity();
fn get_qualified_name(
- heap: &Heap,
- module_term_loc: usize,
- qualified_term_loc: usize,
- ) -> Option<QualifiedNameInfo> {
- let (module_term_loc, _) = subterm_index(heap, module_term_loc);
- let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc);
-
- read_heap_cell!(heap[module_term_loc],
- (HeapCellValueTag::Atom, (module_name, arity)) => {
- if arity == 0 {
- if let Some((name, arity)) = term_predicate_key(heap, qualified_term_loc) {
- return Some(QualifiedNameInfo {
- module_name,
- name,
- arity,
- qualified_term_loc,
- });
- }
- }
+ module_term: &Term,
+ qualified_term: &Term,
+ ) -> Option<(Atom, Atom)> {
+ if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
+ if let Some(name) = qualified_term.name() {
+ return Some((*module_name, name));
}
- _ => {}
- );
+ }
None
}
- let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc);
- let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc);
+ fn identity_fn(_module_name: Atom, term: Term) -> Term {
+ term
+ }
- let (module_name, key, term_loc) = if subterm_key_opt == Some((atom!(":"), 2)) {
- match get_qualified_name(
- loader.machine_heap(),
- subterm_loc + 1,
- subterm_loc + 2,
- ) {
- Some(QualifiedNameInfo {
- module_name,
- name,
- arity,
- qualified_term_loc,
- }) => (module_name, (name, arity + supp_args), qualified_term_loc),
- None => {
+ fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
+ Term::Clause(
+ Cell::default(),
+ atom!(":"),
+ vec![
+ Term::Literal(Cell::default(), Literal::Atom(module_name)),
+ term,
+ ],
+ )
+ }
+
+ let process_term: fn(Atom, Term) -> Term;
+
+ let (module_name, key, term) = match term {
+ Term::Clause(cell, atom!(":"), mut terms) if terms.len() == 2 => {
+ if let Some((module_name, name)) = get_qualified_name(&terms[0], &terms[1])
+ {
+ process_term = tag_with_module_name;
+ (
+ module_name,
+ (name, terms[1].arity() + supp_args),
+ terms.pop().unwrap(),
+ )
+ } else {
+ arg_terms.push(Term::Clause(cell, atom!(":"), terms));
continue;
}
}
- } else {
- (module_name, (name, arity + supp_args), subterm_loc)
+ term => {
+ process_term = identity_fn;
+ (module_name, (name, arity + supp_args), term)
+ }
};
- if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) {
- index_ptrs.insert(term_loc, index_ptr);
- continue;
- }
+ let term = match term {
+ Term::Clause(cell, name, mut terms) => {
+ if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
+ arg_terms
+ .push(process_term(module_name, Term::Clause(cell, name, terms)));
+
+ continue;
+ }
+
+ let idx = loader.get_or_insert_qualified_code_index(module_name, key);
- index_ptrs.insert(
- term_loc,
- loader.get_or_insert_qualified_code_index(module_name, key),
- );
+ terms.push(Term::Literal(Cell::default(), Literal::CodeIndex(idx)));
+ process_term(module_name, Term::Clause(cell, name, terms))
+ }
+ Term::Literal(cell, Literal::Atom(name)) => {
+ let idx = loader.get_or_insert_qualified_code_index(module_name, key);
+
+ process_term(
+ module_name,
+ Term::Clause(
+ cell,
+ name,
+ vec![Term::Literal(Cell::default(), Literal::CodeIndex(idx))],
+ ),
+ )
+ }
+ term => term,
+ };
+
+ arg_terms.push(term);
+ continue;
}
}
+
+ arg_terms.push(term);
}
- index_ptrs
+ arg_terms
}
#[inline]
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
- key: PredicateKey,
- terms: &TermWriteResult,
- term: HeapCellValue,
+ name: Atom,
+ mut terms: Vec<Term>,
call_policy: CallPolicy,
-) -> QueryClause {
- // supplementary code vector indices are unnecessary for
- // root-level clauses.
- blunt_index_ptr(loader.machine_heap(), key, terms.focus);
+) -> QueryTerm {
+ if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
+ // supplementary code vector indices are unnecessary for
+ // root-level clauses.
+ terms.pop();
+ }
- let mut ct = loader.get_clause_type(key.0, key.1);
+ let mut ct = loader.get_clause_type(name, terms.len());
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let module_name = loader.payload.compilation_target.module_name();
- let code_indices =
- build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs);
+ let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
- return QueryClause {
- ct: ClauseType::Named(key.1, key.0, idx),
- term,
- code_indices,
+ return QueryTerm::Clause(
+ Cell::default(),
+ ClauseType::Named(arity, name, idx),
+ terms,
call_policy,
- };
+ );
}
- ct = ClauseType::Named(key.1, key.0, idx);
+ ct = ClauseType::Named(arity, name, idx);
}
- QueryClause {
- ct,
- term,
- code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
- call_policy,
- }
+ QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
}
#[inline]
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>,
- key: PredicateKey,
module_name: Atom,
- terms: &TermWriteResult,
- term: HeapCellValue,
+ name: Atom,
+ mut terms: Vec<Term>,
call_policy: CallPolicy,
-) -> QueryClause {
- // supplementary code vector indices are unnecessary for
- // root-level clauses.
- blunt_index_ptr(loader.machine_heap(), key, terms.focus);
+) -> QueryTerm {
+ if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
+ // supplementary code vector indices are unnecessary for
+ // root-level clauses.
+ terms.pop();
+ }
- let mut ct = loader.get_qualified_clause_type(module_name, key.0, key.1);
+ let mut ct = loader.get_qualified_clause_type(module_name, name, terms.len());
if let ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
- let code_indices =
- build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
+ let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
- return QueryClause {
- ct: ClauseType::Named(key.1, key.0, idx),
- term,
- code_indices,
+ return QueryTerm::Clause(
+ Cell::default(),
+ ClauseType::Named(arity, name, idx),
+ terms,
call_policy,
- };
+ );
}
- ct = ClauseType::Named(key.1, key.0, idx);
+ ct = ClauseType::Named(arity, name, idx);
}
- QueryClause {
- ct,
- term,
- code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
- call_policy,
- }
+ QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
}
#[derive(Debug)]
Preprocessor { settings }
}
- pub fn setup_fact<'a, LS: LoadState<'a>>(
- &mut self,
- loader: &mut Loader<'a, LS>,
- term: TermWriteResult,
- ) -> Result<(Fact, VarData), CompilationError> {
- let heap = loader.machine_heap();
+ fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
+ match term {
+ Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
+ let classifier = VariableClassifier::new(self.settings.default_call_policy());
- if term_predicate_key(heap, term.focus).is_some() {
- let classifier = VariableClassifier::new(self.settings.default_call_policy());
- let var_data = classifier.classify_fact(loader, &term)?;
-
- Ok((
- Fact {
- term_loc: term.focus,
- },
- var_data,
- ))
- } else {
- Err(CompilationError::InadmissibleFact)
+ let (head, var_data) = classifier.classify_fact(term)?;
+ Ok((Fact { head }, var_data))
+ }
+ _ => Err(CompilationError::InadmissibleFact),
}
}
fn setup_rule<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
- term: TermWriteResult,
+ head: Term,
+ body: Term,
) -> Result<(Rule, VarData), CompilationError> {
let classifier = VariableClassifier::new(self.settings.default_call_policy());
- let (clauses, var_data) = classifier.classify_rule(loader, &term)?;
- let heap = loader.machine_heap();
- let head_loc = term_nth_arg(heap, term.focus, 1).unwrap();
+ let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
- if term_predicate_key(heap, head_loc).is_some() {
- Ok((
+ match head {
+ Term::Clause(_, name, terms) => Ok((
Rule {
- term_loc: term.focus,
+ head: (name, terms),
clauses,
},
var_data,
- ))
- } else {
- Err(CompilationError::InvalidRuleHead)
+ )),
+ Term::Literal(_, Literal::Atom(name)) => Ok((
+ Rule {
+ head: (name, vec![]),
+ clauses,
+ },
+ var_data,
+ )),
+ _ => Err(CompilationError::InvalidRuleHead),
}
}
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
- term: TermWriteResult,
+ term: Term,
) -> Result<PredicateClause, CompilationError> {
- let heap = &LS::machine_st(&mut loader.payload).heap;
+ match term {
+ Term::Clause(r, name, mut terms) => {
+ let is_rule = name == atom!(":-") && terms.len() == 2;
- match term_predicate_key(heap, term.focus) {
- Some((atom!(":-"), 2)) => {
- let (rule, var_data) = self.setup_rule(loader, term)?;
- Ok(PredicateClause::Rule(rule, var_data))
+ if is_rule {
+ let tail = terms.pop().unwrap();
+ let head = terms.pop().unwrap();
+
+ let (rule, var_data) = self.setup_rule(loader, head, tail)?;
+ Ok(PredicateClause::Rule(rule, var_data))
+ } else {
+ let term = Term::Clause(r, name, terms);
+ let (fact, var_data) = self.setup_fact(term)?;
+ Ok(PredicateClause::Fact(fact, var_data))
+ }
}
- _ => {
- let (fact, var_data) = self.setup_fact(loader, term)?;
+ term => {
+ let (fact, var_data) = self.setup_fact(term)?;
Ok(PredicateClause::Fact(fact, var_data))
}
}
impl<T: RawBlockTraits> RawBlock<T> {
pub(crate) fn new() -> Self {
- let mut block = Self::uninitialized();
+ let mut block = RawBlock {
+ size: 0,
+ base: ptr::null(),
+ top: ptr::null(),
+ _marker: PhantomData,
+ };
unsafe {
block.grow();
block
}
- pub(crate) fn uninitialized() -> Self {
- Self {
- size: 0,
- base: ptr::null(),
- top: ptr::null(),
- _marker: PhantomData,
- }
- }
-
unsafe fn init_at_size(&mut self, cap: usize) {
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());
}
}
- pub(crate) fn uninitialized() -> Self {
- Stack {
- buf: RawBlock::empty_block(),
- _marker: PhantomData,
- }
- }
-
#[inline(always)]
unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
loop {
let addr = self.store(MachineState::deref(self, addr));
read_heap_cell!(addr,
- (HeapCellValueTag::Atom, (name, arity)) => {
- debug_assert_eq!(arity, 0);
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ debug_assert_eq!(arity, 0);
- return match indices.get_stream(name) {
- Some(stream) if !stream.is_null_stream() => Ok(stream),
- _ => {
- let stub = functor_stub(caller, arity);
- let addr = atom_as_cell!(name);
-
- let existence_error = self.existence_error(ExistenceError::Stream(addr));
+ return match indices.get_stream(name) {
+ Some(stream) if !stream.is_null_stream() => Ok(stream),
+ _ => {
+ let stub = functor_stub(caller, arity);
+ let addr = atom_as_cell!(name);
- Err(self.error_form(existence_error, stub))
- }
- };
- }
- (HeapCellValueTag::Str, s) => {
- let (name, arity) = cell_as_atom_cell!(self.heap[s])
- .get_name_and_arity();
+ let existence_error = self.existence_error(ExistenceError::Stream(addr));
- debug_assert_eq!(arity, 0);
+ Err(self.error_form(existence_error, stub))
+ }
+ };
+ }
+ (HeapCellValueTag::Str, s) => {
+ let (name, arity) = cell_as_atom_cell!(self.heap[s])
+ .get_name_and_arity();
- return match indices.get_stream(name) {
- Some(stream) if !stream.is_null_stream() => Ok(stream),
- _ => {
- let stub = functor_stub(caller, arity);
- let addr = atom_as_cell!(name);
+ debug_assert_eq!(arity, 0);
- let existence_error = self.existence_error(ExistenceError::Stream(addr));
+ return match indices.get_stream(name) {
+ Some(stream) if !stream.is_null_stream() => Ok(stream),
+ _ => {
+ let stub = functor_stub(caller, arity);
+ let addr = atom_as_cell!(name);
- Err(self.error_form(existence_error, stub))
- }
- };
- }
- (HeapCellValueTag::Cons, ptr) => {
- match_untyped_arena_ptr!(ptr,
- (ArenaHeaderTag::Stream, stream) => {
- return if stream.is_null_stream() {
- Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
- } else {
- Ok(stream)
- };
- }
- (ArenaHeaderTag::Dropped, _value) => {
- let stub = functor_stub(caller, arity);
- let err = self.existence_error(ExistenceError::Stream(addr));
+ let existence_error = self.existence_error(ExistenceError::Stream(addr));
- return Err(self.error_form(err, stub));
- }
- _ => {
- }
- );
- }
- _ => {
- }
+ Err(self.error_form(existence_error, stub))
+ }
+ };
+ }
+ (HeapCellValueTag::Cons, ptr) => {
+ match_untyped_arena_ptr!(ptr,
+ (ArenaHeaderTag::Stream, stream) => {
+ return if stream.is_null_stream() {
+ Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
+ } else {
+ Ok(stream)
+ };
+ }
+ (ArenaHeaderTag::Dropped, _value) => {
+ let stub = functor_stub(caller, arity);
+ let err = self.existence_error(ExistenceError::Stream(addr));
+
+ return Err(self.error_form(err, stub));
+ }
+ _ => {
+ }
+ );
+ }
+ _ => {
+ }
);
let stub = functor_stub(caller, arity);
) -> Result<Stream, ParserError> {
match stream.peek_char() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
- Some(Err(e)) => Err(ParserError::IO(e, ParserErrorSrc::default())),
+ Some(Err(e)) => Err(ParserError::IO(e)),
Some(Ok(c)) => {
if c == '\u{feff}' {
// skip UTF-8 BOM
_ => {
// assume the OS is out of file descriptors.
let stub = functor_stub(atom!("open"), 4);
- let err = self.resource_error(ResourceError::OutOfFiles);
+ let err = Self::resource_error(ResourceError::OutOfFiles);
return Err(self.error_form(err, stub));
}
-use crate::parser::ast::*;
-use crate::parser::lexer::LexerParser;
-use crate::parser::parser::*;
-
use base64::Engine;
use dashu::integer::{Sign, UBig};
use lazy_static::lazy_static;
use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
+use crate::parser::ast::*;
use crate::parser::char_reader::*;
-use crate::parser::dashu::{Integer, Rational};
+use crate::parser::dashu::Integer;
+use crate::parser::parser::*;
use crate::read::*;
use crate::types::*;
use rand::rngs::StdRng;
use fxhash::{FxBuildHasher, FxHasher};
use indexmap::IndexSet;
+use std::cell::Cell;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::env;
) {
let mut seen_set = IndexSet::new();
- if term.is_ref() {
- let mut iter = stackful_post_order_iter::<NonListElider>(
- &mut self.heap,
- &mut self.stack,
- term.get_value() as usize,
- );
+ {
+ self.heap[0] = term;
+ let mut iter =
+ stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
while let Some(value) = iter.next() {
if iter.parent_stack_len() >= max_depth {
let outcome = step_or_resource_error!(
self,
- sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter(),)
+ sized_iter_to_heap_list(&mut self.heap, seen_set.len(), seen_set.into_iter())
);
-
unify_fn!(*self, list_of_vars, outcome);
}
std::io::Cursor::new(dot_buf)
});
- let mut lexer_parser = LexerParser::new(CharReader::new(iter), self);
+ let mut lexer = Lexer::new(CharReader::new(iter), self);
let mut tokens = vec![];
- match lexer_parser.next_token() {
- Ok(token @ Token::Literal(atom)) if atom == atom_as_cell!(atom!("-")) => {
+ match lexer.next_token() {
+ Ok(token @ Token::Literal(Literal::Atom(atom!("-")))) => {
tokens.push(token);
- if let Ok(token) = lexer_parser.next_token() {
+ if let Ok(token) = lexer.next_token() {
tokens.push(token);
}
}
}
loop {
- match lexer_parser.lookahead_char() {
+ match lexer.lookahead_char() {
Err(e) if e.is_unexpected_eof() => {
+ let mut parser = Parser::from_lexer(lexer);
let op_dir = CompositeOpDir::new(&indices.op_dir, None);
tokens.reverse();
- let byte_size = heap_index!(tokens.len());
-
- match lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) {
- Ok(term) => {
- read_heap_cell!(lexer_parser.machine_st.heap[term.focus],
- (HeapCellValueTag::Cons, c) => {
- match_untyped_arena_ptr!(c,
- (ArenaHeaderTag::Rational, n) => {
- self.unify_rational(n, nx);
- }
- (ArenaHeaderTag::Integer, n) => {
- self.unify_big_int(n, nx);
- }
- _ => {
- let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src());
- let e = self.syntax_error(e);
-
- return Err(self.error_form(e, stub_gen()));
- }
- )
- }
- (HeapCellValueTag::F64, n) => {
- self.unify_f64(n, nx);
- }
- (HeapCellValueTag::Fixnum, n) => {
- self.unify_fixnum(n, nx);
- }
- _ => {
- let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src());
- let e = self.syntax_error(e);
-
- return Err(self.error_form(e, stub_gen()));
- }
- );
- return Ok(());
+ match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
+ Err(err) => {
+ let err = self.syntax_error(err);
+ return Err(self.error_form(err, stub_gen()));
}
- Err(e) => {
- let e = self.syntax_error(e);
- return Err(self.error_form(e, stub_gen()));
+ Ok(Term::Literal(_, cell)) => {
+ unify!(self, nx, HeapCellValue::from(cell));
+ }
+ _ => {
+ let err = ParserError::ParseBigInt(0, 0);
+ let err = self.syntax_error(err);
+
+ return Err(self.error_form(err, stub_gen()));
}
}
+
+ return Ok(());
}
Ok('.') => {
- lexer_parser.skip_char('.');
+ lexer.skip_char('.');
}
Ok(c) => {
- let err_src = lexer_parser.loc_to_err_src();
+ let (line_num, col_num) = (lexer.line_num, lexer.col_num);
- let err = ParserError::UnexpectedChar(c, err_src);
+ let err = ParserError::UnexpectedChar(c, line_num, col_num);
let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen()));
let vars: Vec<_> = vars
.union(&result.supp_vars) // difference + union does not cancel.
- .cloned()
+ .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
.collect();
let helper_clause_loc = self.code.len();
- match self.compile_standalone_clause(temp_v!(1), vars) {
+ match self.compile_standalone_clause(temp_v!(1), &vars) {
Err(e) => {
let err = self.machine_st.session_error(e);
let stub = functor_stub(atom!("call"), result.key.1);
if let Some(name) = entry.file_name().to_str() {
let file_string_cell = resource_error_call_result!(
self.machine_st,
- self.machine_st.allocate_cstr(name)
+ self.machine_st.heap.allocate_cstr(name)
);
files.push(file_string_cell);
let cstr_cell = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_cstr(&chars_string)
+ self.machine_st.heap.allocate_cstr(&chars_string)
);
unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]);
let current_string = resource_error_call_result!(
self.machine_st,
- self.machine_st.allocate_cstr(current)
+ self.machine_st.heap.allocate_cstr(current)
);
unify!(
}
};
- let canonical_string =
- resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(cs));
+ let canonical_string = resource_error_call_result!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(cs)
+ );
unify!(
self.machine_st,
let cell = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_cstr(&*name.as_str())
+ self.machine_st.heap.allocate_cstr(&*name.as_str())
);
unify!(self.machine_st, self.machine_st.registers[2], cell);
let pstr_loc_cell = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_pstr(&*atom.as_str())
+ self.machine_st.heap.allocate_pstr(&*atom.as_str())
);
let tail_loc = Heap::pstr_tail_idx(atom.as_str().len() + heap_index!(pstr_h));
let cstr_cell = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_cstr(string.trim())
+ self.machine_st.heap.allocate_cstr(string.trim())
);
unify!(self.machine_st, cstr_cell, chs);
let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
let upper_str = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_cstr(&c.to_uppercase().to_string())
+ self.machine_st.heap.allocate_cstr(&c.to_uppercase().to_string())
);
unify!(self.machine_st, reg, upper_str);
}
let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
let lower_str = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_cstr(&c.to_uppercase().to_string())
+ self.machine_st.heap.allocate_cstr(&c.to_uppercase().to_string())
);
unify!(self.machine_st, reg, lower_str);
}
Some(Err(e)) => {
let stub = functor_stub(atom!("$get_n_chars"), 3);
- let err =
- self.machine_st
- .session_error(SessionError::from(ParserError::IO(
- e,
- ParserErrorSrc::default(),
- )));
+ let err = self.machine_st.session_error(SessionError::from(e));
return Err(self.machine_st.error_form(err, stub));
}
};
let output = self.deref_register(3);
- let cstr_cell =
- resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&string));
+ let cstr_cell = resource_error_call_result!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(&string)
+ );
unify!(self.machine_st, cstr_cell, output);
Ok(())
Ok(Number::Integer(n)) => match (&*n).try_into() as Result<usize, _> {
Ok(n) => n,
Err(_) => {
- let err = self
- .machine_st
- .resource_error(ResourceError::FiniteMemory(len));
+ let err = MachineState::resource_error(ResourceError::FiniteMemory(len));
return Err(self.machine_st.error_form(err, stub_gen()));
}
},
let string_cell = resource_error_call_result!(
self.machine_st,
self.machine_st
+ .heap
.allocate_cstr(header_value.to_str().unwrap())
);
}
}
- Ok(())
+ Ok::<(), _>(())
})?;
} else {
let err = self
let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path);
let path_cell = resource_error_call_result!(
self.machine_st,
- self.machine_st.allocate_cstr(&request.request_data.path)
+ self.machine_st.heap.allocate_cstr(&request.request_data.path)
);
let mut headers = vec![];
for (header_name, header_value) in request.request_data.headers {
let header_value = resource_error_call_result!(
self.machine_st,
- self.machine_st.allocate_cstr(header_value.to_str().unwrap())
+ self.machine_st.heap.allocate_cstr(header_value.to_str().unwrap())
);
let header_term = functor!(
let query_str = request.request_data.query;
let query_cell = resource_error_call_result!(
self.machine_st,
- self.machine_st.allocate_cstr(&query_str)
+ self.machine_st.heap.allocate_cstr(&query_str)
);
let mut stream = Stream::from_http_stream(
Value::CString(cstr) => {
let str_cell = resource_error_call_result!(
self.machine_st,
- self.machine_st.allocate_cstr(cstr.to_str().unwrap())
+ self.machine_st.heap.allocate_cstr(cstr.to_str().unwrap())
);
unify!(self.machine_st, str_cell, return_value);
let mut args_pstrs = vec![];
for arg in env::args() {
- let pstr_cell =
- resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&arg));
+ let pstr_cell = resource_error_call_result!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(&arg)
+ );
args_pstrs.push(pstr_cell);
}
#[inline(always)]
pub(crate) fn current_time(&mut self) {
let timestamp = self.systemtime_to_timestamp(SystemTime::now());
- let cstr_cell =
- step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(×tamp));
+ let cstr_cell = step_or_resource_error!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(×tamp)
+ );
unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
}
}
#[inline(always)]
- fn read_term_from_atom(
+ fn read_term_and_write_to_heap(
&mut self,
atom_or_string: AtomOrString,
) -> Result<Option<TermWriteResult>, MachineStub> {
};
let chars = CharReader::new(ByteStream::from_string(string));
- let mut parser = LexerParser::new(chars, &mut self.machine_st);
+ let mut parser = Parser::new(chars, &mut self.machine_st);
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
- let term = parser
+ let term_write_result = parser
.read_term(&op_dir, Tokens::Default)
- .map_err(|e| error_after_read_term(e, 0));
+ .map_err(|err| error_after_read_term(err, 0, &parser))
+ .and_then(|term| write_term_to_heap(&term, &mut self.machine_st.heap));
- match term {
- Ok(term) => Ok(Some(term)),
+ match term_write_result {
+ Ok(term_write_result) => Ok(Some(term_write_result)),
Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
let value = self.machine_st.registers[2];
self.machine_st.unify_atom(atom!("end_of_file"), value);
#[inline(always)]
pub(crate) fn read_from_chars(&mut self) -> CallResult {
- let atom_or_string = self
+ if let Some(atom_or_string) = self
.machine_st
.value_to_str_like(self.machine_st.registers[1])
- .unwrap();
+ {
+ if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
+ let result = heap_loc_as_cell!(term_write_result.heap_loc);
+ let var = self.deref_register(2).as_var().unwrap();
- if let Some(term) = self.read_term_from_atom(atom_or_string)? {
- let result = self.machine_st.heap[term.focus];
- let var = self.deref_register(2).as_var().unwrap();
+ self.machine_st.bind(var, result);
+ }
- self.machine_st.bind(var, result);
+ Ok(())
+ } else {
+ unreachable!()
}
-
- Ok(())
}
#[inline(always)]
pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
- let atom_or_string = self
+ if let Some(atom_or_string) = self
.machine_st
.value_to_str_like(self.machine_st.registers[1])
- .unwrap();
-
- let string = match atom_or_string {
- AtomOrString::Atom(atom!("[]")) => "".to_owned(),
- _ => atom_or_string.into(),
- };
-
- let chars = CharReader::new(ByteStream::from_string(string));
- let term = self
- .machine_st
- .read(chars, &self.indices.op_dir)
- .map(|(term, _)| term)
- .map_err(|e| {
- let e = self.machine_st.session_error(SessionError::from(e));
- let stub = functor_stub(atom!("read_term_from_chars"), 3);
-
- self.machine_st.error_form(e, stub)
- })?;
+ {
+ if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
+ self.machine_st.read_term_body(term_write_result)
+ } else {
+ if !self.machine_st.fail {
+ // wrote end_of_file term in this case.
+ self.machine_st
+ .write_read_term_options(vec![], empty_list_as_cell!())?;
+ }
- self.machine_st.read_term_body(term)
+ Ok(())
+ }
+ } else {
+ unreachable!()
+ }
}
#[inline(always)]
};
let result = printer.print().result();
- let chars =
- resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result));
+ let chars = resource_error_call_result!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(&result)
+ );
let result_addr = self.deref_register(1);
let var = result_addr.as_var().unwrap();
let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
let cstr_cell =
- step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer));
+ step_or_resource_error!(self.machine_st, self.machine_st.heap.allocate_cstr(&buffer));
unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
}
if buffer.is_empty() {
empty_list_as_cell!()
} else {
- step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&buffer))
+ step_or_resource_error!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(&buffer)
+ )
}
};
Ok(value) => {
let cstr = step_or_resource_error!(
self.machine_st,
- self.machine_st.allocate_cstr(&value)
+ self.machine_st.heap.allocate_cstr(&value)
);
unify!(self.machine_st, self.machine_st.registers[2], cstr);
1,
)?;
- let mut lexer_parser = LexerParser::new(stream, &mut self.machine_st);
+ let mut parser = Parser::new(stream, &mut self.machine_st);
- match devour_whitespace(&mut lexer_parser) {
+ match devour_whitespace(&mut parser.lexer) {
Ok(false) => {
- // not at EOF ...
- stream.add_lines_read(lexer_parser.line_num());
-
- // ... unless we are.
- if stream.at_end_of_stream() {
- self.machine_st.fail = true;
- }
+ // not at EOF.
+ stream.add_lines_read(parser.lines_read());
}
Ok(true) => {
- stream.add_lines_read(lexer_parser.line_num());
+ stream.add_lines_read(parser.lexer.line_num);
self.machine_st.fail = true;
}
Err(err) => {
if path.is_dir() {
if let Some(path) = path.to_str() {
- let path_string =
- step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path));
+ let path_string = step_or_resource_error!(
+ self.machine_st,
+ self.machine_st.heap.allocate_cstr(path)
+ );
unify!(self.machine_st, self.machine_st.registers[1], path_string);
return;
node: roxmltree::Node,
) -> Result<HeapCellValue, usize> {
if node.is_text() {
- self.machine_st.allocate_cstr(node.text().unwrap())
+ self.machine_st.heap.allocate_cstr(node.text().unwrap())
} else {
let mut avec = Vec::new();
for attr in node.attributes() {
let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.name());
- let value = self.machine_st.allocate_cstr(attr.value())?;
+ let value = self.machine_st.heap.allocate_cstr(attr.value())?;
avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
match node.value().as_element() {
None => self
.machine_st
+ .heap
.allocate_cstr(&node.value().as_text().unwrap().text),
Some(element) => {
let mut avec = Vec::new();
for attr in element.attrs() {
let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.0);
- let value = self.machine_st.allocate_cstr(attr.1)?;
+ let value = self.machine_st.heap.allocate_cstr(attr.1)?;
avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
if buffer.is_empty() {
Ok(empty_list_as_cell!())
} else {
- self.machine_st.allocate_cstr(&buffer)
+ self.machine_st.heap.allocate_cstr(&buffer)
}
}
}
pub(super) module_op_exports: ModuleOpExports,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>,
pub(super) predicates: PredicateQueue,
- pub(super) clause_clauses: Vec<TermWriteResult>,
+ pub(super) clause_clauses: Vec<(Term, Term)>,
}
pub trait TermStream: Sized {
- fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError>;
+ fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
}
#[derive(Debug)]
pub struct BootstrappingTermStream<'a> {
listing_src: ListingSource,
- pub(super) lexer_parser: LexerParser<'a, Stream>,
+ pub(super) parser: Parser<'a, Stream>,
}
impl<'a> BootstrappingTermStream<'a> {
machine_st: &'a mut MachineState,
listing_src: ListingSource,
) -> Self {
- let lexer_parser = LexerParser::new(stream, machine_st);
+ let parser = Parser::new(stream, machine_st);
Self {
- lexer_parser,
+ parser,
listing_src,
}
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
#[inline]
- fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
- let result = self
- .lexer_parser
+ fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
+ self.parser.reset();
+ self.parser
.read_term(op_dir, Tokens::Default)
- .map_err(CompilationError::from);
-
- result
+ .map_err(CompilationError::from)
}
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
- devour_whitespace(&mut self.lexer_parser) // eliminate dangling comments before checking for EOF.
+ devour_whitespace(&mut self.parser.lexer) // eliminate dangling comments before checking for EOF.
.map_err(CompilationError::from)
}
}
pub struct LiveTermStream {
- pub(super) term_queue: VecDeque<TermWriteResult>,
+ pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource,
}
impl TermStream for LiveTermStream {
#[inline]
- fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
+ fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
}
pub struct InlineTermStream {}
impl TermStream for InlineTermStream {
- fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> {
- Err(CompilationError::from(ParserError::unexpected_eof(
- ParserErrorSrc::default(),
- )))
+ fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
+ Err(CompilationError::from(ParserError::unexpected_eof()))
}
fn eof(&mut self) -> Result<bool, CompilationError> {
machine_st.partial_string_to_pdl(pstr_loc, l);
}
(HeapCellValueTag::PStrLoc, other_pstr_loc) => {
- let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc);
-
- if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() {
- debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. }));
- machine_st.fail = true;
+ match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) {
+ PStrSegmentCmpResult::Continue(v1, v2) => {
+ machine_st.pdl.push(v1);
+ machine_st.pdl.push(v2);
+ }
+ _ => {
+ machine_st.fail = true;
+ }
}
}
_ => {
let mut occurs_triggered = false;
- let machine_st: &mut MachineState = unifier.deref_mut();
- let value = machine_st.store(MachineState::deref(machine_st, value));
-
- if value.is_ref() && !value.is_stack_var() {
+ if !value.is_constant() {
+ let machine_st: &mut MachineState = unifier.deref_mut();
machine_st.heap[0] = value;
for cell in
#[allow(unused_braces)]
$code
}};
- ($cell:ident, Atom, (_, $arity:ident), $code:expr) => {{
- let $arity = cell_as_atom_cell!($cell).get_arity();
- #[allow(unused_braces)]
- $code
- }};
- /*
($cell:ident, PStr, $atom:ident, $code:expr) => {{
let $atom = cell_as_atom!($cell);
#[allow(unused_braces)]
#[allow(unused_braces)]
$code
}};
- */
($cell:ident, Fixnum, $value:ident, $code:expr) => {{
let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)]
macro_rules! resource_error_call_result {
($machine_st:expr, $val:expr) => {
step_or_resource_error!($machine_st, $val, {
- return Err(vec![]); // TODO: return Ok(());
+ return Err(vec![]);
})
};
}
use crate::arena::*;
use crate::atom_table::*;
-use crate::forms::PredicateKey;
-use crate::machine::heap::*;
-use crate::machine::machine_indices::*;
-use crate::types::*;
+use crate::machine::machine_indices::CodeIndex;
+use crate::parser::char_reader::*;
+use crate::types::HeapCellValueTag;
+use std::cell::{Cell, Ref, RefCell, RefMut};
use std::fmt;
use std::hash::Hash;
+use std::hash::Hasher;
use std::io::{Error as IOError, ErrorKind};
-use std::ops::Neg;
+use std::ops::{Deref, Neg};
use std::rc::Rc;
+use std::sync::Arc;
use std::vec::Vec;
+use dashu::Integer;
+use dashu::Rational;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use scryer_modular_bitfield::error::OutOfBounds;
pub const NEGATIVE_SIGN: u32 = 0x0200;
macro_rules! fixnum {
- ($n:expr, $arena:expr) => {
- Fixnum::build_with_checked($n)
- .map(|n| fixnum_as_cell!(n))
- .unwrap_or_else(|_| {
- typed_arena_ptr_as_cell!(
- arena_alloc!(Integer::from($n), $arena) as TypedArenaPtr<Integer>
- )
- })
- };
- ($wrapper:ty, $n:expr, $arena:expr) => {
+ ($wrapper:tt, $n:expr, $arena:expr) => {
Fixnum::build_with_checked($n)
.map(<$wrapper>::Fixnum)
.unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
}
}
+#[derive(Debug, PartialEq, Eq, 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,
+ }
+ }
+}
+
+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 Default for VarReg {
+ fn default() -> Self {
+ VarReg::Norm(RegType::default())
+ }
+}
+
macro_rules! temp_v {
($x:expr) => {
$crate::parser::ast::RegType::Temp($x)
op_dir
}
-#[derive(Debug, Clone)]
+#[derive(Debug, Copy, Clone)]
pub enum ArithmeticError {
- NonEvaluableFunctor(HeapCellValue, usize),
-}
-
-#[derive(Debug, Copy, Clone, Default)]
-pub struct ParserErrorSrc {
- pub col_num: usize,
- pub line_num: usize,
+ NonEvaluableFunctor(Literal, usize),
+ UninstantiatedVar,
}
+#[allow(dead_code)]
#[derive(Debug)]
pub enum ParserError {
- BackQuotedString(ParserErrorSrc),
- IO(IOError, ParserErrorSrc),
- IncompleteReduction(ParserErrorSrc),
- InvalidSingleQuotedCharacter(ParserErrorSrc),
- LexicalError(ParserErrorSrc),
- MissingQuote(ParserErrorSrc),
- NonPrologChar(ParserErrorSrc),
- ParseBigInt(ParserErrorSrc),
- ResourceError(ParserErrorSrc),
- UnexpectedChar(char, ParserErrorSrc),
+ BackQuotedString(usize, usize),
+ IO(IOError),
+ IncompleteReduction(usize, usize),
+ InvalidSingleQuotedCharacter(char),
+ LexicalError(lexical::Error),
+ MissingQuote(usize, usize),
+ NonPrologChar(usize, usize),
+ ParseBigInt(usize, usize),
+ UnexpectedChar(char, usize, usize),
// UnexpectedEOF,
- Utf8Error(ParserErrorSrc),
+ Utf8Error(usize, usize),
}
impl ParserError {
- pub fn err_src(&self) -> ParserErrorSrc {
+ pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self {
- &ParserError::BackQuotedString(err_src)
- | &ParserError::IO(_, err_src)
- | &ParserError::IncompleteReduction(err_src)
- | &ParserError::InvalidSingleQuotedCharacter(err_src)
- | &ParserError::LexicalError(err_src)
- | &ParserError::MissingQuote(err_src)
- | &ParserError::NonPrologChar(err_src)
- | &ParserError::ParseBigInt(err_src)
- | &ParserError::ResourceError(err_src)
- | &ParserError::UnexpectedChar(_, err_src)
- | &ParserError::Utf8Error(err_src) => err_src,
+ &ParserError::BackQuotedString(line_num, col_num)
+ | &ParserError::IncompleteReduction(line_num, col_num)
+ | &ParserError::MissingQuote(line_num, col_num)
+ | &ParserError::NonPrologChar(line_num, col_num)
+ | &ParserError::ParseBigInt(line_num, col_num)
+ | &ParserError::UnexpectedChar(_, line_num, col_num)
+ | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
+ _ => None,
}
}
ParserError::InvalidSingleQuotedCharacter(..) => {
atom!("invalid_single_quoted_character")
}
- ParserError::IO(e, _) if e.kind() == ErrorKind::UnexpectedEof => {
+ ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
atom!("unexpected_end_of_file")
}
- ParserError::IO(e, _) if e.kind() == ErrorKind::InvalidData => {
+ ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
atom!("invalid_data")
}
- ParserError::IO(..) => atom!("input_output_error"),
- ParserError::LexicalError(..) => atom!("lexical_error"),
+ ParserError::IO(_) => atom!("input_output_error"),
+ ParserError::LexicalError(_) => atom!("lexical_error"),
ParserError::MissingQuote(..) => atom!("missing_quote"),
ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
- ParserError::ResourceError(..) => atom!("resource_error"),
}
}
#[inline]
- pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self {
- ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src)
+ pub fn unexpected_eof() -> Self {
+ ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof))
}
#[inline]
pub fn is_unexpected_eof(&self) -> bool {
- if let ParserError::IO(e, _) = self {
+ if let ParserError::IO(e) = self {
e.kind() == ErrorKind::UnexpectedEof
} else {
false
}
}
-impl From<ParserErrorSrc> for ParserError {
- fn from(err_src: ParserErrorSrc) -> ParserError {
- ParserError::LexicalError(err_src)
+impl From<lexical::Error> for ParserError {
+ fn from(e: lexical::Error) -> ParserError {
+ ParserError::LexicalError(e)
+ }
+}
+
+impl From<IOError> for ParserError {
+ fn from(e: IOError) -> ParserError {
+ ParserError::IO(e)
+ }
+}
+
+impl From<&IOError> for ParserError {
+ fn from(error: &IOError) -> ParserError {
+ if error.get_ref().filter(|e| e.is::<BadUtf8Error>()).is_some() {
+ ParserError::Utf8Error(0, 0)
+ } else {
+ ParserError::IO(error.kind().into())
+ }
}
}
}
}
-/*
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum Literal {
Atom(Atom),
CodeIndex(CodeIndex),
Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>),
Float(F64Offset),
- String(Rc<String>),
}
impl From<F64Ptr> for Literal {
Literal::Integer(ref n) => write!(f, "{}", n),
Literal::Rational(ref n) => write!(f, "{}", n),
Literal::Float(ref n) => write!(f, "{}", *n),
- Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
}
}
}
}
}
}
-*/
-pub type Var = Rc<String>;
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct VarPtr(Rc<RefCell<Var>>);
+
+impl Hash for VarPtr {
+ #[inline(always)]
+ fn hash<H: Hasher>(&self, hasher: &mut H) {
+ self.borrow().hash(hasher)
+ }
+}
-pub(crate) fn subterm_index(heap: &impl SizedHeap, subterm_loc: usize) -> (usize, HeapCellValue) {
- let subterm = heap[subterm_loc];
+impl Deref for VarPtr {
+ type Target = RefCell<Var>;
- if subterm.is_ref() {
- let subterm = heap_bound_deref(heap, subterm);
- let subterm_loc = subterm.get_value() as usize;
- let subterm = heap_bound_store(heap, subterm);
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ self.0.deref()
+ }
+}
- let subterm_loc = if subterm.is_ref() {
- subterm.get_value() as usize
- } else {
- subterm_loc
- };
+impl VarPtr {
+ #[inline(always)]
+ pub(crate) fn borrow(&self) -> Ref<'_, Var> {
+ self.0.borrow()
+ }
- (subterm_loc, subterm)
- } else {
- (subterm_loc, subterm)
+ #[inline(always)]
+ pub(crate) fn borrow_mut(&self) -> RefMut<'_, Var> {
+ self.0.borrow_mut()
+ }
+
+ pub(crate) fn to_var_num(&self) -> Option<usize> {
+ match *self.borrow() {
+ Var::Generated(var_num) => Some(var_num),
+ _ => None,
+ }
+ }
+
+ pub(crate) fn set(&self, var: Var) {
+ let mut var_ref = self.borrow_mut();
+ *var_ref = var;
+ }
+}
+
+impl From<Var> for VarPtr {
+ #[inline(always)]
+ fn from(value: Var) -> VarPtr {
+ VarPtr(Rc::new(RefCell::new(value)))
+ }
+}
+
+impl From<String> for VarPtr {
+ #[inline(always)]
+ fn from(value: String) -> VarPtr {
+ VarPtr::from(Var::from(value))
+ }
+}
+
+impl From<&str> for VarPtr {
+ #[inline(always)]
+ fn from(value: &str) -> VarPtr {
+ VarPtr::from(value.to_owned())
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub enum Var {
+ Generated(usize),
+ InSitu(usize),
+ Named(Rc<String>),
+}
+
+impl From<String> for Var {
+ #[inline(always)]
+ fn from(value: String) -> Var {
+ Var::Named(Rc::new(value))
+ }
+}
+
+impl From<&str> for Var {
+ #[inline(always)]
+ fn from(value: &str) -> Var {
+ Var::Named(Rc::new(value.to_owned()))
+ }
+}
+
+impl Var {
+ #[allow(clippy::inherent_to_string)]
+ #[inline(always)]
+ pub fn to_string(&self) -> String {
+ match self {
+ Var::InSitu(n) | Var::Generated(n) => format!("_{}", n),
+ Var::Named(value) => value.as_ref().clone(),
+ }
}
}
-/*
#[derive(Debug, Clone)]
pub enum Term {
AnonVar,
Clause(Cell<RegType>, Atom, Vec<Term>),
Cons(Cell<RegType>, Box<Term>, Box<Term>),
- Literal(Cell<RegType>, HeapCellValue),
- // Literal(Cell<RegType>, Literal),
+ Literal(Cell<RegType>, Literal),
// PartialString wraps a String in anticipation of it absorbing
// other PartialString variants in as_partial_string.
PartialString(Cell<RegType>, Rc<String>, Box<Term>),
pub fn name(&self) -> Option<Atom> {
match self {
- Term::Literal(_, cell) => {
- cell.to_atom()
- }
- &Term::Clause(_, atom, ..) => {
- Some(atom)
- }
+ &Term::Literal(_, Literal::Atom(atom)) => Some(atom),
+ &Term::Clause(_, atom, ..) => Some(atom),
_ => None,
}
}
terms.push(term);
terms
}
- */
-
-pub(crate) fn fetch_index_ptr(heap: &impl SizedHeap, term_loc: usize) -> Option<CodeIndex> {
- let index_cell_loc = term_loc.saturating_sub(1);
-
- read_heap_cell!(heap[index_cell_loc],
- (HeapCellValueTag::Cons, c) => {
- match_untyped_arena_ptr!(c,
- (ArenaHeaderTag::IndexPtr, ptr) => {
- return Some(CodeIndex::from(ptr));
- }
- _ => {}
- );
- }
- _ => {}
- );
-
- None
-}
-
-pub(crate) fn blunt_index_ptr(
- heap: &mut impl SizedHeapMut,
- key: PredicateKey,
- term_loc: usize,
-) -> bool {
- if fetch_index_ptr(heap, term_loc).is_some() {
- heap[term_loc] = atom_as_cell!(key.0, key.1);
- true
- } else {
- false
- }
-}
-
-pub(crate) fn unfold_by_str_once(
- heap: &mut impl SizedHeapMut,
- start_term: HeapCellValue,
- atom: Atom,
-) -> Option<usize> {
- let start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term));
-
- if let HeapCellValueTag::Str = start_term.get_tag() {
- let s = start_term.get_value() as usize;
-
- let (s_atom, s_arity) = cell_as_atom_cell!(heap[s]).get_name_and_arity();
- blunt_index_ptr(heap, (s_atom, s_arity), s);
-
- if (s_atom, s_arity) == (atom, 2) {
- return Some(s + 1);
- }
- }
-
- None
-}
-
-pub fn unfold_by_str(
- heap: &mut impl SizedHeapMut,
- mut start_term: HeapCellValue,
- atom: Atom,
-) -> Vec<HeapCellValue> {
- let mut terms = vec![];
- start_term = heap_bound_store(heap, heap_bound_deref(heap, start_term));
-
- while let Some(fst_loc) = unfold_by_str_once(heap, start_term, atom) {
- let (_, snd) = subterm_index(heap, fst_loc + 1);
- let (_, fst) = subterm_index(heap, fst_loc);
- terms.push(fst);
- start_term = snd;
- }
-
- terms
-}
-
-/*
-pub fn unfold_by_str_locs(
- heap: &mut [HeapCellValue],
- mut term_loc: usize,
- atom: Atom,
-) -> Vec<(HeapCellValue, usize)> {
- let mut terms = vec![];
- let mut current_term = heap_bound_store(
- heap,
- heap_bound_deref(heap, heap[term_loc]),
- );
-
- while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
- (term_loc, current_term) = subterm_index(heap, fst_loc + 1);
- let (fst_loc, fst) = subterm_index(heap, fst_loc);
- terms.push((fst, fst_loc));
- }
-
- terms.push((current_term, term_loc));
- terms
-}
-*/
-
-pub fn unfold_by_str_locs(
- heap: &mut impl SizedHeapMut,
- mut term_loc: usize,
- atom: Atom,
-) -> Vec<(HeapCellValue, usize)> {
- let mut terms = vec![];
- let mut current_term = heap[term_loc];
-
- while let Some(fst_loc) = unfold_by_str_once(heap, current_term, atom) {
- term_loc = fst_loc + 1;
- current_term = heap[term_loc];
- let fst = heap[fst_loc];
- terms.push((fst, fst_loc));
- }
-
- terms.push((current_term, term_loc));
- terms
-}
-
-pub fn term_predicate_key(heap: &impl SizedHeap, mut term_loc: usize) -> Option<PredicateKey> {
- loop {
- read_heap_cell!(heap[term_loc],
- (HeapCellValueTag::Atom, (name, arity)) => {
- return Some((name, arity));
- }
- (HeapCellValueTag::Str, s) => {
- term_loc = s;
- }
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if h != term_loc {
- term_loc = h;
- } else {
- return None;
- }
- }
- _ => {
- return None;
- }
- );
- }
-}
-
-pub fn inverse_var_locs_from_iter<I: Iterator<Item = HeapCellValue>>(iter: I) -> InverseVarLocs {
- let mut occurrence_set: IndexMap<HeapCellValue, usize, FxBuildHasher> =
- IndexMap::with_hasher(FxBuildHasher::default());
-
- for term in iter {
- if term.is_var() {
- let var_count = occurrence_set.entry(term).or_insert(0);
- *var_count += 1;
- }
- }
-
- let mut inverse_var_locs = InverseVarLocs::default();
-
- for (var, count) in occurrence_set {
- let var_loc = var.get_value() as usize;
-
- if count > 1 {
- inverse_var_locs.insert(var_loc, Rc::new(format!("_{}", var_loc)));
- }
- }
-
- inverse_var_locs
-}
-
-/*
-pub fn term_deref(heap: &[HeapCellValue], mut term_loc: usize) -> HeapCellValue {
- loop {
- read_heap_cell!(heap[term_loc],
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if h != term_loc {
- term_loc = h;
- } else {
- return heap[h];
- }
- }
- _ => {
- return heap[term_loc];
- }
- )
- }
-}
-*/
-
-pub fn term_nth_arg(heap: &impl SizedHeap, mut term_loc: usize, n: usize) -> Option<usize> {
- loop {
- read_heap_cell!(heap[term_loc],
- (HeapCellValueTag::Str, s) => {
- return if cell_as_atom_cell!(heap[s]).get_arity() >= n {
- Some(s+n)
- } else {
- None
- };
- }
- (HeapCellValueTag::Atom, (_name, arity)) => {
- return if arity >= n {
- Some(term_loc + n)
- } else {
- None
- };
- }
- (HeapCellValueTag::Lis, l) => {
- return if 1 <= n && n <= 2 {
- Some(l+n-1)
- } else if n == 0 {
- Some(term_loc)
- } else {
- None
- };
- }
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if h != term_loc {
- term_loc = h;
- } else {
- return None;
- }
- }
- _ => {
- return None;
- }
- );
- }
-}
-
-#[derive(Debug)]
-pub struct TermWriteResult {
- pub focus: usize,
- pub inverse_var_locs: InverseVarLocs,
-}
-
-pub type VarLocs = IndexMap<Var, HeapCellValue, FxBuildHasher>;
-pub type InverseVarLocs = IndexMap<usize, Var, FxBuildHasher>;
-
-#[derive(Debug)]
-pub struct FocusedHeapRefMut<'a> {
- pub heap: &'a mut Heap,
- pub focus: usize,
-}
-
-impl<'a> FocusedHeapRefMut<'a> {
- #[inline]
- pub fn from(heap: &'a mut Heap, focus: usize) -> Self {
- Self { heap, focus }
- }
-
- pub fn predicate_key(&self, term_loc: usize) -> Option<PredicateKey> {
- term_predicate_key(self.heap, term_loc)
- }
-
- pub fn arity(&self, term_loc: usize) -> usize {
- self.predicate_key(term_loc)
- .map(|(_, arity)| arity)
- .unwrap_or(0)
- }
-
- pub fn deref_loc(&self, term_loc: usize) -> HeapCellValue {
- let cell = self.heap[term_loc];
- heap_bound_store(self.heap, heap_bound_deref(self.heap, cell))
- }
-
- pub fn nth_arg(&self, term_loc: usize, n: usize) -> Option<usize> {
- term_nth_arg(self.heap, term_loc, n)
- }
-
- /*
- pub fn from_cell(heap: &'a mut Heap, cell: HeapCellValue) -> Self {
- let focus = read_heap_cell!(cell,
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- h
- }
- _ => {
- let h = heap.len();
- heap.push_cell(cell).unwrap();
-
- h
- }
- );
-
- Self { heap, focus }
- }
- */
-}
-use lexical::{parse, FromLexical};
-
use crate::arena::*;
use crate::atom_table::*;
-use crate::machine::heap::*;
pub use crate::machine::machine_state::*;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::dashu::Integer;
-use crate::types::*;
use std::convert::TryFrom;
use std::fmt;
#[derive(Debug, PartialEq)]
pub enum Token {
- Literal(HeapCellValue),
+ Literal(Literal),
Var(String),
String(String),
Open, // '('
}
impl Token {
- pub(super) fn byte_size(&self, flags: MachineFlags) -> usize {
- match self {
- Token::String(string) if flags.double_quotes.is_codes() => {
- 2 * string.chars().count() + 1
- }
- Token::String(string) => Heap::compute_pstr_size(&string),
- Token::Literal(_)
- | Token::Comma
- | Token::HeadTailSeparator
- | Token::Open
- | Token::OpenCT
- | Token::OpenCurly
- | Token::OpenList
- | Token::Var(_) => {
- heap_index!(1)
- }
- _ => 0,
- }
- }
-
#[inline]
pub(super) fn is_end(&self) -> bool {
matches!(self, Token::End)
}
}
-pub(crate) struct LexerParser<'a, R> {
+pub(crate) struct Lexer<'a, R> {
pub(crate) reader: R,
pub(crate) machine_st: &'a mut MachineState,
pub(crate) line_num: usize,
pub(crate) col_num: usize,
}
-impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> {
+impl<'a, R: fmt::Debug> fmt::Debug for Lexer<'a, R> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LexerParser")
.field("reader", &"&'a mut R") // Hacky solution.
}
}
-impl<'a, R: CharRead> LexerParser<'a, R> {
+impl<'a, R: CharRead> Lexer<'a, R> {
pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
- LexerParser {
+ Self {
reader: src,
machine_st,
line_num: 0,
pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
match self.reader.peek_char() {
Some(Ok(c)) => Ok(c),
- _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
+ _ => Err(ParserError::unexpected_eof()),
}
}
pub fn read_char(&mut self) -> Result<char, ParserError> {
match self.reader.read_char() {
Some(Ok(c)) => Ok(c),
- _ => Err(ParserError::unexpected_eof(self.loc_to_err_src())),
+ _ => Err(ParserError::unexpected_eof()),
}
}
match comment_loop() {
Err(e) if e.is_unexpected_eof() => {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+ return Err(ParserError::IncompleteReduction(
+ self.line_num,
+ self.col_num,
+ ));
}
Err(e) => {
return Err(e);
self.skip_char(c);
Ok(true)
} else {
- Err(ParserError::NonPrologChar(self.loc_to_err_src()))
+ Err(ParserError::NonPrologChar(self.line_num, self.col_num))
}
} else {
self.return_char('/');
if !back_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+ Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else {
self.skip_char(c2);
Ok(c2)
Ok(None)
} else {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+ Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
}
} else {
self.get_back_quoted_char().map(Some)
self.skip_char(c);
Ok(token)
} else {
- Err(ParserError::MissingQuote(self.loc_to_err_src()))
+ Err(ParserError::MissingQuote(self.line_num, self.col_num))
}
} else {
- Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+ Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
}
}
if !single_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+ Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else {
self.skip_char(c2);
Ok(c2)
if !double_quote_char!(c2) {
self.return_char(c);
- Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()))
+ Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else {
self.skip_char(c2);
Ok(c2)
't' => '\t',
'n' => '\n',
'r' => '\r',
- c => return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())),
+ c => return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num)),
};
self.skip_char(c);
if hexadecimal_digit_char!(c) {
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
} else {
- Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
+ Err(ParserError::IncompleteReduction(
+ self.line_num,
+ self.col_num,
+ ))
}
}
if backslash_char!(c) {
self.skip_char(c);
u32::from_str_radix(&token, radix).map_or_else(
- |_| Err(ParserError::ParseBigInt(self.loc_to_err_src())),
- |n| char::try_from(n).map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())),
+ |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
+ |n| {
+ char::try_from(n)
+ .map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
+ },
)
} else {
- Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
+ Err(ParserError::IncompleteReduction(
+ self.line_num,
+ self.col_num,
+ ))
}
}
Ok(c)
} else {
if !backslash_char!(c) {
- return Err(ParserError::UnexpectedChar(c, self.loc_to_err_src()));
+ return Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num));
}
self.skip_char(c);
self.skip_char(c);
Ok(token)
} else {
- Err(ParserError::MissingQuote(self.loc_to_err_src()))
+ Err(ParserError::MissingQuote(self.line_num, self.col_num))
}
}
}
i64::from_str_radix(&token, 16)
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
Integer::from_str_radix(&token, 16)
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+ Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
}
}
i64::from_str_radix(&token, 8)
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
Integer::from_str_radix(&token, 8)
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+ Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
}
}
i64::from_str_radix(&token, 2)
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
Integer::from_str_radix(&token, 2)
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else {
self.return_char(start);
- Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+ Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
}
if !token.is_empty() && token.chars().nth(1).is_none() {
if let Some(c) = token.chars().next() {
- return Ok(Token::Literal(char_as_cell!(c)));
+ return Ok(Token::Literal(Literal::Atom(
+ AtomCell::new_char_inlined(c).get_name(),
+ )));
}
}
} else {
- return Err(ParserError::InvalidSingleQuotedCharacter(
- self.loc_to_err_src(),
- ));
+ return Err(ParserError::InvalidSingleQuotedCharacter(c));
}
} else {
match self.get_back_quoted_string() {
- Ok(_) => return Err(ParserError::BackQuotedString(self.loc_to_err_src())),
+ Ok(_) => return Err(ParserError::BackQuotedString(self.line_num, self.col_num)),
Err(e) => return Err(e),
}
}
if token.as_str() == "[]" {
- Ok(Token::Literal(empty_list_as_cell!()))
+ Ok(Token::Literal(Literal::Atom(atom!("[]"))))
} else {
- Ok(Token::Literal(atom_as_cell!(AtomTable::build_with(
+ Ok(Token::Literal(Literal::Atom(AtomTable::build_with(
&self.machine_st.atom_tbl,
&token,
))))
}
}
- fn parse_lossy_wrapper<T: FromLexical>(&self, token: &str) -> Result<T, ParserError> {
- match parse::<T, _>(token.as_bytes()) {
- Ok(n) => Ok(n),
- Err(_) => return Err(ParserError::LexicalError(self.loc_to_err_src())),
- }
- }
-
fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
self.return_char(token.pop().unwrap());
- let n = self.parse_lossy_wrapper::<f64>(&token)?;
- Ok(Token::Literal(HeapCellValue::from(float_alloc!(
+
+ let n = parse_float_lossy(&token)?;
+
+ Ok(Token::Literal(Literal::from(float_alloc!(
n,
self.machine_st.arena
))))
if decimal_digit_char!(c) {
Ok(c)
} else {
- Err(ParserError::ParseBigInt(self.loc_to_err_src()))
+ Err(ParserError::ParseBigInt(self.line_num, self.col_num))
}
} else {
Ok(c)
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
} else if decimal_digit_char!(self.lookahead_char()?) {
token.push('.');
}
}
- let n = self.parse_lossy_wrapper::<f64>(&token)?;
- Ok(Token::Literal(HeapCellValue::from(float_alloc!(
+ let n = parse_float_lossy(&token)?;
+ Ok(Token::Literal(Literal::from(float_alloc!(
n,
self.machine_st.arena
))))
return self.vacate_with_float(token);
}
} else {
- let n = self.parse_lossy_wrapper::<f64>(&token)?;
- Ok(Token::Literal(HeapCellValue::from(float_alloc!(
+ let n = parse_float_lossy(&token)?;
+ Ok(Token::Literal(Literal::from(float_alloc!(
n,
self.machine_st.arena
))))
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
} else if token.starts_with('0') && token.len() == 1 {
if let ParserError::ParseBigInt(..) = e {
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| {
+ Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+ })
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
+ })
+ .map_err(|_| {
+ ParserError::ParseBigInt(self.line_num, self.col_num)
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else {
Err(e)
if let ParserError::ParseBigInt(..) = e {
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| {
+ Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+ })
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
+ })
+ .map_err(|_| {
+ ParserError::ParseBigInt(self.line_num, self.col_num)
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else {
Err(e)
if let ParserError::ParseBigInt(..) = e {
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| {
+ Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+ })
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
+ })
+ .map_err(|_| {
+ ParserError::ParseBigInt(self.line_num, self.col_num)
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
} else {
Err(e)
self.skip_char(c);
self.return_char('\'');
- return Ok(Token::Literal(fixnum_as_cell!(Fixnum::build_with(0))));
+ return Ok(Token::Literal(Literal::Fixnum(Fixnum::build_with(0))));
} else {
self.return_char('\\');
}
}
self.get_single_quoted_char()
- .map(|c| Token::Literal(fixnum_as_cell!(Fixnum::build_with(c as i64))))
+ .map(|c| Token::Literal(Literal::Fixnum(Fixnum::build_with(c as i64))))
.or_else(|err| {
match err {
ParserError::UnexpectedChar('\'', ..) => {}
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| {
+ Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena))
+ })
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
+ })
+ .map_err(|_| {
+ ParserError::ParseBigInt(self.line_num, self.col_num)
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
})
})
} else {
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
- )
- as TypedArenaPtr<Integer>))
+ )))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
} else {
token
.parse::<i64>()
- .map(|n| Token::Literal(fixnum!(n, &mut self.machine_st.arena)))
+ .map(|n| Token::Literal(fixnum!(Literal, n, &mut self.machine_st.arena)))
.or_else(|_| {
token
.parse::<Integer>()
.map(|n| {
- Token::Literal(typed_arena_ptr_as_cell!(arena_alloc!(
+ Token::Literal(Literal::Integer(arena_alloc!(
n,
&mut self.machine_st.arena
)
as TypedArenaPtr<Integer>))
})
- .map_err(|_| ParserError::ParseBigInt(self.loc_to_err_src()))
+ .map_err(|_| ParserError::ParseBigInt(self.line_num, self.col_num))
})
}
}
return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s);
- Ok(Token::Literal(atom_as_cell!(atom)))
+ Ok(Token::Literal(Literal::Atom(atom)))
} else {
Ok(Token::String(s))
};
}
if c == '\u{0}' {
- return Err(ParserError::unexpected_eof(self.loc_to_err_src()));
+ return Err(ParserError::unexpected_eof());
}
self.name_token(c)
}
}
}
+
+fn parse_float_lossy(token: &str) -> Result<f64, ParserError> {
+ const FORMAT: u128 = lexical::format::STANDARD;
+ let options = lexical::ParseFloatOptions::builder()
+ .lossy(true)
+ .build()
+ .unwrap();
+ let n = lexical::parse_with_options::<f64, _, FORMAT>(token.as_bytes(), &options)?;
+ Ok(n)
+}
use crate::arena::*;
use crate::atom_table::*;
-use crate::forms::Number;
-use crate::machine::heap::*;
use crate::parser::ast::*;
use crate::parser::char_reader::*;
use crate::parser::lexer::*;
-use crate::types::*;
+use std::cell::Cell;
+use std::mem;
use std::ops::Neg;
use std::rc::Rc;
#[derive(Debug, Clone, Copy, PartialEq)]
enum TokenType {
- Term { heap_loc: HeapCellValue },
+ Term,
Open,
OpenCT,
OpenList, // '['
End,
}
-impl TokenType {
- fn sep_to_atom(self) -> Option<Atom> {
- match self {
- TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
- TokenType::Close => Some(atom!(")")),
- TokenType::OpenList => Some(atom!("[")),
- TokenType::CloseList => Some(atom!("]")),
- TokenType::OpenCurly => Some(atom!("{")),
- TokenType::CloseCurly => Some(atom!("}")),
- TokenType::HeadTailSeparator => Some(atom!("|")),
- TokenType::Comma => Some(atom!(",")),
- TokenType::End => Some(atom!(".")),
- _ => None,
- }
- }
-}
-
/*
Specifies whether the token sequence should be read from the lexer or
provided via the Provided variant.
#[derive(Debug)]
pub enum Tokens {
Default,
- Provided(Vec<Token>, usize),
+ Provided(Vec<Token>),
}
impl TokenType {
unfold_bounds: usize,
}
+pub(crate) fn as_partial_string(
+ head: Term,
+ mut tail: Term,
+) -> Result<(String, Option<Box<Term>>), Term> {
+ let mut string = match &head {
+ Term::Literal(_, Literal::Atom(atom)) => {
+ if let Some(c) = atom.as_char() {
+ c.to_string()
+ } else {
+ return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
+ }
+ }
+ _ => {
+ return Err(Term::Cons(Cell::default(), Box::new(head), Box::new(tail)));
+ }
+ };
+
+ let mut orig_tail = Box::new(tail);
+ let mut tail_ref = &mut orig_tail;
+
+ loop {
+ match &mut **tail_ref {
+ Term::Cons(_, prev, succ) => {
+ match prev.as_ref() {
+ Term::Literal(_, Literal::Atom(atom)) => {
+ if let Some(c) = atom.as_char() {
+ string.push(c);
+ } else {
+ return Err(Term::Cons(Cell::default(), Box::new(head), orig_tail));
+ }
+ }
+ _ => {
+ tail = Term::Cons(
+ Cell::default(),
+ Box::new((**prev).clone()),
+ Box::new((**succ).clone()),
+ );
+ break;
+ }
+ }
+
+ tail_ref = succ;
+ }
+ Term::PartialString(_, pstr, tail) => {
+ string += pstr;
+ tail_ref = tail;
+ }
+ Term::CompleteString(_, cstr) => {
+ string += &*cstr.as_str();
+ tail = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
+ break;
+ }
+ tail_ref => {
+ tail = mem::replace(tail_ref, Term::AnonVar);
+ break;
+ }
+ }
+ }
+
+ match tail {
+ Term::AnonVar | Term::Var(..) => Ok((string, Some(Box::new(tail)))),
+ Term::Literal(_, Literal::Atom(atom!("[]"))) => Ok((string, None)),
+ Term::CompleteString(_, tail) => {
+ string += &tail;
+ Ok((string, None))
+ }
+ Term::PartialString(_, tail_string, tail) => {
+ string += &tail_string;
+ Ok((string, Some(tail)))
+ }
+ _ => Ok((string, Some(Box::new(tail)))),
+ }
+}
+
pub fn get_op_desc(name: Atom, op_dir: &CompositeOpDir) -> Option<CompositeOpDesc> {
let mut op_desc = CompositeOpDesc {
pre: 0,
}
#[derive(Debug)]
-struct Parser<'a> {
+pub struct Parser<'a, R> {
+ pub lexer: Lexer<'a, R>,
tokens: Vec<Token>,
stack: Vec<TokenDesc>,
- terms: HeapWriter<'a>,
- arena: &'a mut Arena,
- flags: MachineFlags,
- line_num: &'a mut usize,
- col_num: &'a mut usize,
- var_locs: VarLocs,
- inverse_var_locs: InverseVarLocs,
+ terms: Vec<Term>,
}
-pub fn read_tokens<R: CharRead>(
- lexer: &mut LexerParser<R>,
-) -> Result<(Vec<Token>, usize), ParserError> {
+pub fn read_tokens<R: CharRead>(lexer: &mut Lexer<'_, R>) -> Result<Vec<Token>, ParserError> {
let mut tokens = vec![];
- let mut term_size = 0;
loop {
match lexer.next_token() {
Ok(token) => {
let at_end = token.is_end();
- term_size += token.byte_size(lexer.machine_st.flags);
tokens.push(token);
if at_end {
}
}
Err(e) if e.is_unexpected_eof() && !tokens.is_empty() => {
- return Err(ParserError::IncompleteReduction(lexer.loc_to_err_src()));
+ return Err(ParserError::IncompleteReduction(
+ lexer.line_num,
+ lexer.col_num,
+ ));
}
Err(e) => {
return Err(e);
}
tokens.reverse();
+ Ok(tokens)
+}
- Ok((tokens, term_size))
+fn atomize_term(term: &Term) -> Option<Atom> {
+ match term {
+ &Term::Literal(_, Literal::Atom(c)) => Some(c),
+ _ => None,
+ }
}
-pub(crate) fn as_partial_string(
- heap: &impl SizedHeap,
- head: HeapCellValue,
- tail: HeapCellValue,
-) -> Option<(String, Option<HeapCellValue>)> {
- let head = heap_bound_store(heap, heap_bound_deref(heap, head));
- let mut tail = heap_bound_store(heap, heap_bound_deref(heap, tail));
-
- let mut string = read_heap_cell!(head,
- (HeapCellValueTag::Atom, (atom, arity)) => {
- if arity == 0 {
- if let Some(c) = atom.as_char() {
- c.to_string()
- } else {
- return None;
- }
- } else {
- return None;
- }
- }
- _ => {
- return None;
- }
- );
+impl TokenType {
+ fn sep_to_atom(&mut self) -> Option<Atom> {
+ match self {
+ TokenType::Open | TokenType::OpenCT => Some(atom!("(")),
+ TokenType::Close => Some(atom!(")")),
+ TokenType::OpenList => Some(atom!("[")),
+ TokenType::CloseList => Some(atom!("]")),
+ TokenType::OpenCurly => Some(atom!("{")),
+ TokenType::CloseCurly => Some(atom!("}")),
+ TokenType::HeadTailSeparator => Some(atom!("|")),
+ TokenType::Comma => Some(atom!(",")),
+ TokenType::End => Some(atom!(".")),
+ _ => None,
+ }
+ }
+}
- loop {
- read_heap_cell!(tail,
- (HeapCellValueTag::Lis, l) => {
- read_heap_cell!(heap[l],
- (HeapCellValueTag::Atom, (atom, arity)) => {
- if arity == 0 {
- if let Some(c) = atom.as_char() {
- string.push(c);
- } else {
- return None;
- }
- } else {
- break;
- }
- }
- _ => {
- return None;
- }
- );
-
- tail = heap[l+1];
- }
- (HeapCellValueTag::PStrLoc, l) => {
- let HeapStringScan { string: pstr, tail_idx } = heap.scan_slice_to_str(l);
- string += pstr;
- tail = heap[tail_idx];
- }
- (HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
- if heap[h] != tail {
- tail = heap[h];
- } else {
- break;
- }
- }
- _ => {
- // Anon
- break;
- }
- );
+impl<'a, R: CharRead> Parser<'a, R> {
+ pub fn new(stream: R, machine_st: &'a mut MachineState) -> Self {
+ Parser {
+ lexer: Lexer::new(stream, machine_st),
+ tokens: vec![],
+ stack: vec![],
+ terms: vec![],
+ }
}
- read_heap_cell!(tail,
- (HeapCellValueTag::Var) => {
- Some((string, Some(tail)))
- }
- (HeapCellValueTag::Atom, (atom, arity)) => {
- if atom == atom!("[]") && arity == 0 {
- Some((string, None))
- } else {
- Some((string, Some(tail)))
- }
- }
- _ => {
- Some((string, Some(tail)))
- }
- )
-}
+ pub fn from_lexer(lexer: Lexer<'a, R>) -> Self {
+ Parser {
+ lexer,
+ tokens: vec![],
+ stack: vec![],
+ terms: vec![],
+ }
+ }
-impl<'a> Parser<'a> {
- fn get_term_name(&self, td: TokenDesc) -> Option<Atom> {
+ fn get_term_name(&mut self, td: TokenDesc) -> Option<Atom> {
match td.tt {
TokenType::HeadTailSeparator => Some(atom!("|")),
TokenType::Comma => Some(atom!(",")),
- TokenType::Term { heap_loc } => {
- if heap_loc.is_ref() {
- term_predicate_key(&self.terms, heap_loc.get_value() as usize).map(|key| key.0)
- } else {
+ TokenType::Term => match self.terms.pop() {
+ Some(Term::Literal(_, Literal::Atom(atom))) => Some(atom),
+ Some(term) => {
+ self.terms.push(term);
None
}
- }
+ _ => None,
+ },
_ => None,
}
}
- fn push_binary_op(
- &mut self,
- op: TokenDesc,
- operand_1: TokenDesc,
- operand_2: TokenDesc,
- spec: Specifier,
- ) {
- if let TokenDesc {
- tt: TokenType::Term { heap_loc: arg2 },
- ..
- } = operand_2
- {
- if let TokenDesc {
- tt: TokenType::Term { heap_loc: arg1 },
- ..
- } = operand_1
- {
- if let Some(name) = self.get_term_name(op) {
- let str_loc = self.terms.cell_len();
-
- self.terms.write_with(|section| {
- section.push_cell(atom_as_cell!(name, 2));
- section.push_cell(arg1);
- section.push_cell(arg2);
-
- section.push_cell(str_loc_as_cell!(str_loc));
- });
+ fn push_binary_op(&mut self, td: TokenDesc, spec: Specifier) {
+ if let Some(arg2) = self.terms.pop() {
+ if let Some(name) = self.get_term_name(td) {
+ if let Some(arg1) = self.terms.pop() {
+ let term = Term::Clause(Cell::default(), name, vec![arg1, arg2]);
+ self.terms.push(term);
self.stack.push(TokenDesc {
- tt: TokenType::Term {
- heap_loc: heap_loc_as_cell!(str_loc + 3),
- },
- priority: op.priority,
+ tt: TokenType::Term,
+ priority: td.priority,
spec,
unfold_bounds: 0,
});
}
}
- fn push_unary_op(&mut self, op: TokenDesc, operand: TokenDesc, spec: Specifier) {
- if let TokenDesc {
- tt: TokenType::Term { heap_loc: arg1 },
- ..
- } = operand
- {
- if let TokenDesc {
- tt: TokenType::Term { .. },
- ..
- } = op
- {
- if let Some(name) = self.get_term_name(op) {
- let str_loc = self.terms.cell_len();
+ fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: OpDeclSpec) {
+ if let Some(mut arg1) = self.terms.pop() {
+ if let Some(mut name) = self.terms.pop() {
+ if assoc.is_postfix() {
+ mem::swap(&mut arg1, &mut name);
+ }
- self.terms.write_with(|section| {
- section.push_cell(atom_as_cell!(name, 1));
- section.push_cell(arg1);
- section.push_cell(str_loc_as_cell!(str_loc));
- });
+ if let Term::Literal(_, Literal::Atom(name)) = name {
+ let term = Term::Clause(Cell::default(), name, vec![arg1]);
+ self.terms.push(term);
self.stack.push(TokenDesc {
- tt: TokenType::Term {
- heap_loc: heap_loc_as_cell!(str_loc + 2),
- },
- priority: op.priority,
+ tt: TokenType::Term,
+ priority: td.priority,
spec,
unfold_bounds: 0,
});
}
fn promote_atom_op(&mut self, atom: Atom, priority: usize, assoc: u32) {
- let h = self.terms.cell_len();
self.terms
- .write_with(|section| section.push_cell(atom_as_cell!(atom)));
+ .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
self.stack.push(TokenDesc {
- tt: TokenType::Term {
- heap_loc: heap_loc_as_cell!(h),
- },
+ tt: TokenType::Term,
priority,
spec: assoc,
unfold_bounds: 0,
}
fn shift(&mut self, token: Token, priority: usize, spec: Specifier) {
- let heap_loc = heap_loc_as_cell!(self.terms.cell_len());
-
let tt = match token {
- Token::String(s) if self.flags.double_quotes.is_codes() => {
- let mut list = empty_list_as_cell!();
-
- self.terms.write_with(|section| {
- for c in s.as_str().chars().rev() {
- let h = section.cell_len();
-
- section.push_cell(fixnum_as_cell!(Fixnum::build_with(c as i64)));
- section.push_cell(list);
-
- list = list_loc_as_cell!(h);
- }
-
- section.push_cell(list);
- });
+ Token::String(s) if self.lexer.machine_st.flags.double_quotes.is_codes() => {
+ let mut list = Term::Literal(Cell::default(), Literal::Atom(atom!("[]")));
+
+ for c in s.as_str().chars().rev() {
+ list = Term::Cons(
+ Cell::default(),
+ Box::new(Term::Literal(
+ Cell::default(),
+ Literal::Fixnum(Fixnum::build_with(c as i64)),
+ )),
+ Box::new(list),
+ );
+ }
- TokenType::Term { heap_loc: list }
+ self.terms.push(list);
+ TokenType::Term
}
Token::String(s) => {
- debug_assert!(self.flags.double_quotes.is_chars());
- let mut pstr_cell = heap_loc;
-
- if s == "\u{0}" {
- let h = self.terms.cell_len();
-
- self.terms.write_with(|section| {
- section.push_cell(char_as_cell!('\u{0}'));
- section.push_cell(empty_list_as_cell!());
- section.push_cell(list_loc_as_cell!(h));
- });
-
- TokenType::Term {
- heap_loc: heap_loc_as_cell!(h + 2),
- }
- } else {
- self.terms
- .write_with(|section| match section.push_pstr(&s) {
- Some(pstr_loc_cell) => {
- section.push_cell(empty_list_as_cell!());
- let h = section.cell_len();
- section.push_cell(pstr_loc_cell);
- pstr_cell = heap_loc_as_cell!(h);
- }
- None => {
- section.push_cell(empty_list_as_cell!());
- }
- });
-
- TokenType::Term {
- heap_loc: pstr_cell,
- }
- }
+ debug_assert!(self.lexer.machine_st.flags.double_quotes.is_chars());
+ self.terms
+ .push(Term::CompleteString(Cell::default(), Rc::new(s)));
+ TokenType::Term
}
Token::Literal(c) => {
- self.terms.write_with(|section| section.push_cell(c));
- TokenType::Term { heap_loc }
+ self.terms.push(Term::Literal(Cell::default(), c));
+ TokenType::Term
}
- Token::Var(var_string) => {
- let var = Rc::new(var_string);
-
- match self.var_locs.get(&var).cloned() {
- Some(heap_loc) => {
- self.terms.write_with(|section| section.push_cell(heap_loc));
- TokenType::Term { heap_loc }
- }
- None => {
- self.terms.write_with(|section| section.push_cell(heap_loc));
-
- // if var_string == "_", it not being present
- // as a key of self.var_locs means it is
- // anonymous.
-
- if var.trim() != "_" {
- self.var_locs.insert(var.clone(), heap_loc);
- self.inverse_var_locs
- .insert(heap_loc.get_value() as usize, var);
- }
-
- TokenType::Term { heap_loc }
- }
+ Token::Var(v) => {
+ if v.trim() == "_" {
+ self.terms.push(Term::AnonVar);
+ } else {
+ self.terms.push(Term::Var(Cell::default(), VarPtr::from(v)));
}
+
+ TokenType::Term
}
Token::Comma => TokenType::Comma,
Token::Open => TokenType::Open,
if is_xfx!(desc2.spec) && affirm_xfx(priority, desc2, desc3, desc1)
|| is_yfx!(desc2.spec) && affirm_yfx(priority, desc2, desc3, desc1)
{
- self.push_binary_op(desc2, desc3, desc1, LTERM);
+ self.push_binary_op(desc2, LTERM);
continue;
} else if is_xfy!(desc2.spec) && affirm_xfy(priority, desc2, desc3, desc1) {
- self.push_binary_op(desc2, desc3, desc1, TERM);
+ self.push_binary_op(desc2, TERM);
continue;
} else {
self.stack.push(desc3);
}
if is_yf!(desc1.spec) && affirm_yf(desc1, desc2) {
- self.push_unary_op(desc1, desc2, LTERM);
+ self.push_unary_op(desc1, LTERM, YF);
continue;
} else if is_xf!(desc1.spec) && affirm_xf(desc1, desc2) {
- self.push_unary_op(desc1, desc2, LTERM);
+ self.push_unary_op(desc1, LTERM, XF);
continue;
} else if is_fy!(desc2.spec) && affirm_fy(priority, desc1, desc2) {
- self.push_unary_op(desc2, desc1, TERM);
+ self.push_unary_op(desc2, TERM, FY);
continue;
} else if is_fx!(desc2.spec) && affirm_fx(priority, desc1, desc2) {
- self.push_unary_op(desc2, desc1, TERM);
+ self.push_unary_op(desc2, TERM, FX);
continue;
} else {
self.stack.push(desc2);
None
}
- fn term_from_stack(&self, idx: usize) -> Option<HeapCellValue> {
- if let TokenType::Term { heap_loc } = self.stack[idx].tt {
- Some(heap_loc)
- } else {
- None
- }
- }
-
fn reduce_term(&mut self) -> bool {
if self.stack.is_empty() {
return false;
return false;
}
- if self.terms.cell_len() < arity {
+ if self.terms.len() < 1 + arity {
return false;
}
let stack_len = self.stack.len() - 2 * arity - 1;
- let term_idx = self.terms.cell_len();
-
- let push_structure = |parser: &mut Self, name: Atom| -> TokenType {
- parser
- .terms
- .write_with(|section| section.push_cell(atom_as_cell!(name, arity)));
-
- for idx in (stack_len + 2..parser.stack.len()).step_by(2) {
- let subterm = parser.term_from_stack(idx).unwrap();
- parser
- .terms
- .write_with(|section| section.push_cell(subterm));
- }
+ let idx = self.terms.len() - arity;
- let str_loc_idx = parser.terms.cell_len();
- parser
- .terms
- .write_with(|section| section.push_cell(str_loc_as_cell!(term_idx)));
-
- TokenType::Term {
- heap_loc: heap_loc_as_cell!(str_loc_idx),
- }
- };
-
- if let TokenDesc {
- tt: TokenType::Term { heap_loc },
- ..
- } = self.stack[stack_len]
+ if TokenType::Term == self.stack[stack_len].tt
+ && atomize_term(&self.terms[idx - 1]).is_some()
{
- let idx = heap_loc.get_value() as usize;
+ self.stack.truncate(stack_len + 1);
- if let Some((name, arity)) = term_predicate_key(&self.terms, idx) {
+ let mut subterms: Vec<_> = self.terms.drain(idx..).collect();
+
+ if let Some(name) = self.terms.pop().and_then(|t| atomize_term(&t)) {
// reduce the '.' functor to a cons cell if it applies.
- let new_tt = if name == atom!(".") && arity == 2 {
- let head = self.term_from_stack(stack_len + 2).unwrap();
- let tail = self.term_from_stack(stack_len + 4).unwrap();
- let cell_len = self.terms.cell_len();
-
- match as_partial_string(&self.terms, head, tail) {
- Some((string_buf, tail_opt)) => {
- let HeapSectionWriteResult { bytes_written, .. } =
- self.terms.write_with(|section| {
- if let Some(pstr_cell) = section.push_pstr(&string_buf) {
- section
- .push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
- section.push_cell(pstr_cell);
- } else {
- section.push_cell(empty_list_as_cell!());
- }
- });
-
- if cell_index!(bytes_written) > 1 {
- TokenType::Term {
- heap_loc: heap_loc_as_cell!(
- cell_index!(bytes_written) - 1 + cell_len
- ),
- }
- } else {
- TokenType::Term {
- heap_loc: heap_loc_as_cell!(cell_len),
- }
- }
+ if name == atom!(".") && subterms.len() == 2 {
+ let tail = subterms.pop().unwrap();
+ let head = subterms.pop().unwrap();
+
+ self.terms.push(match as_partial_string(head, tail) {
+ Ok((string_buf, Some(tail))) => {
+ Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
}
- None => {
- let HeapSectionWriteResult { bytes_written, .. } =
- self.terms.write_with(|section| {
- section.push_cell(head);
- section.push_cell(tail);
- section.push_cell(list_loc_as_cell!(term_idx));
- });
-
- TokenType::Term {
- heap_loc: heap_loc_as_cell!(
- cell_len + cell_index!(bytes_written) - 1
- ),
- }
+ Ok((string_buf, None)) => {
+ Term::CompleteString(Cell::default(), Rc::new(string_buf))
}
- }
+ Err(term) => term,
+ });
} else {
- push_structure(self, name)
- };
-
- self.stack.truncate(stack_len + 1);
+ self.terms
+ .push(Term::Clause(Cell::default(), name, subterms));
+ }
if let Some(&mut TokenDesc {
ref mut tt,
return false;
}
- *tt = new_tt;
+ *tt = TokenType::Term;
*priority = 0;
*spec = TERM;
*unfold_bounds = 0;
}
- } else {
- return false;
- };
- return true;
+ return true;
+ }
}
false
}
- fn loc_to_err_src(&self) -> ParserErrorSrc {
- ParserErrorSrc {
- line_num: *self.line_num,
- col_num: *self.col_num,
- }
+ pub fn reset(&mut self) {
+ self.stack.clear()
}
fn expand_comma_compacted_terms(&mut self, index: usize) -> usize {
- if let Some(term) = self.term_from_stack(index - 1) {
+ if let Some(mut term) = self.terms.pop() {
let mut op_desc = self.stack[index - 1];
- let mut term = heap_bound_store(&self.terms, heap_bound_deref(&self.terms, term));
- if term.is_ref()
- && 0 < op_desc.priority
- && op_desc.priority < self.stack[index].priority
- {
+ if 0 < op_desc.priority && op_desc.priority < self.stack[index].priority {
/* '|' is a head-tail separator here, not
* an operator, so expand the
* terms it compacted out again. */
-
- let focus = term.get_value() as usize;
- let key_opt = term_predicate_key(&self.terms, focus);
-
- if key_opt == Some((atom!(","), 2)) {
+ if let (Some(atom!(",")), 2) = (term.name(), term.arity()) {
let terms = if op_desc.unfold_bounds == 0 {
- unfold_by_str(&mut self.terms, term, atom!(","))
+ unfold_by_str(term, atom!(","))
} else {
let mut terms = vec![];
- while let Some(fst_loc) =
- unfold_by_str_once(&mut self.terms, term, atom!(","))
- {
- let (_, snd) = subterm_index(&self.terms, fst_loc + 1);
- let (_, fst) = subterm_index(&self.terms, fst_loc);
-
+ while let Some((fst, snd)) = unfold_by_str_once(&mut term, atom!(",")) {
terms.push(fst);
term = snd;
};
let arity = terms.len() - 1;
- self.stack
- .extend(terms.into_iter().map(|heap_loc| TokenDesc {
- tt: TokenType::Term { heap_loc },
- priority: 0,
- spec: 0,
- unfold_bounds: 0,
- }));
+
+ self.terms.extend(terms);
return arity;
}
}
+
+ self.terms.push(term);
}
0
}
if let Some(ref mut td) = self.stack.last_mut() {
- // parsed an empty list token
if td.tt == TokenType::OpenList {
- let h = self.terms.cell_len();
- self.terms
- .write_with(|section| section.push_cell(empty_list_as_cell!()));
-
td.spec = TERM;
- td.tt = TokenType::Term {
- heap_loc: heap_loc_as_cell!(h),
- };
+ td.tt = TokenType::Term;
td.priority = 0;
+ self.terms
+ .push(Term::Literal(Cell::default(), Literal::Atom(atom!("[]"))));
return Ok(true);
}
}
// we know that self.stack.len() >= 2 by this point.
let idx = self.stack.len() - 2;
- let list_start_idx = self.stack.len() - 2 * arity;
+ let list_len = self.stack.len() - 2 * arity;
- let mut tail_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
- empty_list_as_cell!()
+ let end_term = if self.stack[idx].tt != TokenType::HeadTailSeparator {
+ Term::Literal(Cell::default(), Literal::Atom(atom!("[]")))
} else {
- let tail_term = match self.term_from_stack(idx + 1) {
+ let term = match self.terms.pop() {
Some(term) => term,
- None => {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+ _ => {
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ))
}
};
- self.stack.pop();
-
if self.stack[idx].priority > 1000 {
arity += self.expand_comma_compacted_terms(idx);
}
- // decrement for the removal of tail term.
- arity -= 1;
- tail_term
- };
-
- if arity > self.terms.cell_len() {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
- }
-
- let pre_terms_len = self.terms.cell_len();
-
- while let Some(token_desc) = self.stack.pop() {
- let subterm = match token_desc.tt {
- TokenType::Term { heap_loc } => heap_loc,
- _ => {
- continue;
- }
- };
-
arity -= 1;
- let link_cell = list_loc_as_cell!(self.terms.cell_len() + 1);
-
- self.terms.write_with(|section| {
- section.push_cell(link_cell);
- section.push_cell(subterm);
- section.push_cell(tail_term);
- });
-
- tail_term = link_cell;
+ term
+ };
- if arity == 0 {
- break;
- }
+ if arity > self.terms.len() {
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ));
}
- debug_assert_eq!(arity, 0);
-
- self.stack.truncate(list_start_idx);
-
- let list_loc = self.terms.cell_len() - 3;
-
- let head_term = self.terms[list_loc + 1];
- let tail_term = self.terms[list_loc + 2];
+ let idx = self.terms.len() - arity;
- let heap_loc = match as_partial_string(&self.terms, head_term, tail_term) {
- Some((string_buf, tail_opt)) => {
- self.terms.truncate(pre_terms_len);
+ let list = self.terms.drain(idx..).rev().fold(end_term, |acc, t| {
+ Term::Cons(Cell::default(), Box::new(t), Box::new(acc))
+ });
- let HeapSectionWriteResult { bytes_written, .. } =
- self.terms.write_with(|section| {
- if let Some(pstr_cell) = section.push_pstr(&string_buf) {
- section.push_cell(tail_opt.unwrap_or(empty_list_as_cell!()));
- section.push_cell(pstr_cell);
- }
- });
-
- if bytes_written > 0 {
- heap_loc_as_cell!(pre_terms_len + cell_index!(bytes_written) - 1)
- } else {
- empty_list_as_cell!()
- }
- }
- None => {
- heap_loc_as_cell!(list_loc) // head_term
- }
- };
+ self.stack.truncate(list_len);
self.stack.push(TokenDesc {
- tt: TokenType::Term { heap_loc },
+ tt: TokenType::Term,
priority: 0,
spec: TERM,
unfold_bounds: 0,
});
+ self.terms.push(match list {
+ Term::Cons(_, head, tail) => match as_partial_string(*head, *tail) {
+ Ok((string_buf, Some(tail))) => {
+ Term::PartialString(Cell::default(), Rc::new(string_buf), tail)
+ }
+ Ok((string_buf, None)) => {
+ Term::CompleteString(Cell::default(), Rc::new(string_buf))
+ }
+ Err(term) => term,
+ },
+ term => term,
+ });
+
Ok(true)
}
if let Some(ref mut td) = self.stack.last_mut() {
if td.tt == TokenType::OpenCurly {
- let h = self.terms.cell_len();
-
- self.terms
- .write_with(|section| section.push_cell(atom_as_cell!(atom!("{}"))));
-
- td.tt = TokenType::Term {
- heap_loc: heap_loc_as_cell!(h),
- };
+ td.tt = TokenType::Term;
td.priority = 0;
td.spec = TERM;
+ let term = Term::Literal(Cell::default(), Literal::Atom(atom!("{}")));
+
+ self.terms.push(term);
return Ok(true);
}
}
if self.stack.len() > 1 {
if let Some(td) = self.stack.pop() {
if let Some(ref mut oc) = self.stack.last_mut() {
- if !matches!(td.tt, TokenType::Term { .. }) {
+ if td.tt != TokenType::Term {
return Ok(false);
}
if oc.tt == TokenType::OpenCurly {
- if let TokenType::Term { heap_loc } = td.tt {
- let curly_idx = self.terms.cell_len();
-
- oc.tt = TokenType::Term {
- heap_loc: heap_loc_as_cell!(curly_idx + 2),
- };
- oc.priority = 0;
- oc.spec = TERM;
-
- self.terms.write_with(|section| {
- section.push_cell(atom_as_cell!(atom!("{}"), 1));
- section.push_cell(heap_loc);
- section.push_cell(str_loc_as_cell!(curly_idx));
- });
-
- /*
- let term = match self.terms.pop() {
- Some(term) => term,
- _ => {
- return Err(ParserError::IncompleteReduction(
- self.lexer.line_num,
- self.lexer.col_num,
- ))
- }
- };
-
- self.terms
- .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
- */
-
- return Ok(true);
- }
+ oc.tt = TokenType::Term;
+ oc.priority = 0;
+ oc.spec = TERM;
+
+ let term = match self.terms.pop() {
+ Some(term) => term,
+ _ => {
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ))
+ }
+ };
+
+ self.terms
+ .push(Term::Clause(Cell::default(), atom!("{}"), vec![term]));
+
+ return Ok(true);
}
}
}
return false;
}
- match self.stack.last().map(|token| token.tt) {
- Some(TokenType::Open | TokenType::OpenCT) => return false,
- _ => {}
+ if let Some(TokenType::Open | TokenType::OpenCT) = self.stack.last().map(|token| token.tt) {
+ return false;
}
let idx = self.stack.len() - 2;
return false;
}
- let term = if self.stack[idx].tt.sep_to_atom().is_some() {
- atom_as_cell!(atom!("|"))
- } else {
- self.term_from_stack(idx).unwrap()
- };
+ if let Some(atom) = self.stack[idx].tt.sep_to_atom() {
+ self.terms
+ .push(Term::Literal(Cell::default(), Literal::Atom(atom)));
+ }
self.stack[idx].spec = BTERM;
- self.stack[idx].tt = TokenType::Term { heap_loc: term };
+ self.stack[idx].tt = TokenType::Term;
self.stack[idx].priority = 0;
true
}) = get_op_desc(name, op_dir)
{
if (pre > 0 && inf + post > 0) || is_negate!(spec) {
- match self
- .tokens
- .last()
- .ok_or(ParserError::unexpected_eof(self.loc_to_err_src()))?
- {
+ match self.tokens.last().ok_or(ParserError::unexpected_eof())? {
// do this when layout hasn't been inserted,
// ie. why we don't match on Token::Open.
Token::OpenCT => {
fn negate_number<N, Negator, ToLiteral>(&mut self, n: N, negator: Negator, constr: ToLiteral)
where
Negator: Fn(N, &mut Arena) -> N,
- ToLiteral: Fn(N, &mut Arena) -> HeapCellValue,
+ ToLiteral: Fn(N, &mut Arena) -> Literal,
{
- match self.stack.last().cloned() {
- Some(
- td @ TokenDesc {
- tt: TokenType::Term { .. },
- spec,
- ..
- },
- ) => {
- if let Some(name) = self.get_term_name(td) {
- if name == atom!("-") && (is_prefix!(spec) || is_negate!(spec)) {
+ if let Some(desc) = self.stack.last().cloned() {
+ if let Some(term) = self.terms.last().cloned() {
+ match term {
+ Term::Literal(_, Literal::Atom(name))
+ if name == atom!("-")
+ && (is_prefix!(desc.spec) || is_negate!(desc.spec)) =>
+ {
self.stack.pop();
+ self.terms.pop();
- let arena = &mut self.arena;
+ let arena = &mut self.lexer.machine_st.arena;
let literal = constr(negator(n, arena), arena);
self.shift(Token::Literal(literal), 0, TERM);
return;
}
+ _ => {}
}
}
- _ => {}
}
- let literal = constr(n, &mut self.arena);
+ let literal = constr(n, &mut self.lexer.machine_st.arena);
self.shift(Token::Literal(literal), 0, TERM);
}
Token::String(string) => {
self.shift(Token::String(string), 0, TERM);
}
- Token::Literal(c) => match Number::try_from(c) {
- Ok(Number::Integer(n)) => {
- self.negate_number(n, negate_int_rc, |n, _| typed_arena_ptr_as_cell!(n))
- }
- Ok(Number::Rational(n)) => {
- self.negate_number(n, negate_rat_rc, |r, _| typed_arena_ptr_as_cell!(r))
- }
- Ok(Number::Float(n)) => {
- use ordered_float::OrderedFloat;
-
- self.negate_number(
- n,
- |n, _| -n,
- |OrderedFloat(n), arena| HeapCellValue::from(float_alloc!(n, arena)),
- )
- }
- Ok(Number::Fixnum(n)) => {
- self.negate_number(n, |n, _| -n, |n, _| fixnum_as_cell!(n))
- }
- Err(_) => {
- if let Some(name) = c.to_atom() {
- if !self.shift_op(name, op_dir)? {
- self.shift(Token::Literal(c), 0, TERM);
- }
- } else {
+ Token::Literal(Literal::Integer(n)) => {
+ self.negate_number(n, negate_int_rc, |n, _| Literal::Integer(n))
+ }
+ Token::Literal(Literal::Rational(n)) => {
+ self.negate_number(n, negate_rat_rc, |r, _| Literal::Rational(r))
+ }
+ Token::Literal(Literal::Float(n)) => self.negate_number(
+ **n.as_ptr(),
+ |n, _| -n,
+ |n, arena| Literal::from(float_alloc!(n, arena)),
+ ),
+ Token::Literal(Literal::Fixnum(n)) => {
+ self.negate_number(n, |n, _| -n, |n, _| Literal::Fixnum(n))
+ }
+ Token::Literal(c) => {
+ if let Literal::Atom(name) = c {
+ if !self.shift_op(name, op_dir)? {
self.shift(Token::Literal(c), 0, TERM);
}
+ } else {
+ self.shift(Token::Literal(c), 0, TERM);
}
- },
+ }
Token::Var(v) => self.shift(Token::Var(v), 0, TERM),
Token::Open => self.shift(Token::Open, 1300, DELIMITER),
Token::OpenCT => self.shift(Token::OpenCT, 1300, DELIMITER),
Token::Close => {
if !self.reduce_term() && !self.reduce_brackets() {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ));
}
}
Token::OpenList => self.shift(Token::OpenList, 1300, DELIMITER),
Token::CloseList => {
if !self.reduce_list()? {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ));
}
}
Token::OpenCurly => self.shift(Token::OpenCurly, 1300, DELIMITER),
Token::CloseCurly => {
if !self.reduce_curly()? {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()));
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ));
}
}
Token::HeadTailSeparator => {
| Some(TokenType::OpenCurly)
| Some(TokenType::HeadTailSeparator)
| Some(TokenType::Comma) => {
- return Err(ParserError::IncompleteReduction(self.loc_to_err_src()))
+ return Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ))
}
_ => {}
},
Ok(())
}
-}
-impl<'a, R: CharRead> LexerParser<'a, R> {
#[inline]
- pub fn line_num(&self) -> usize {
- self.line_num
+ pub fn add_lines_read(&mut self, lines_read: usize) {
+ self.lexer.line_num += lines_read;
}
- pub fn loc_to_err_src(&self) -> ParserErrorSrc {
- ParserErrorSrc {
- line_num: self.line_num,
- col_num: self.col_num,
- }
+ #[inline]
+ pub fn lines_read(&self) -> usize {
+ self.lexer.line_num
}
// on success, returns the parsed term and the number of lines read.
&mut self,
op_dir: &CompositeOpDir,
tokens: Tokens,
- ) -> Result<TermWriteResult, ParserError> {
- let (tokens, term_byte_size) = match tokens {
- Tokens::Default => read_tokens(self)?,
- Tokens::Provided(tokens, size) => (tokens, size),
+ ) -> Result<Term, ParserError> {
+ self.tokens = match tokens {
+ Tokens::Default => read_tokens(&mut self.lexer)?,
+ Tokens::Provided(tokens) => tokens,
};
- // the parser uses conditional indirection in many places so
- // the reserved size should be at least 4 * term_byte_size
- // so all cells are accounted for.
- let writer = match self
- .machine_st
- .heap
- .reserve(cell_index!(4 * term_byte_size))
- {
- Ok(term) => term,
- Err(_err_loc) => {
- return Err(ParserError::ResourceError(self.loc_to_err_src()));
- }
- };
-
- let before_len = writer.cell_len();
-
- let mut parser_impl = Parser {
- tokens,
- stack: vec![],
- terms: writer,
- arena: &mut self.machine_st.arena,
- flags: self.machine_st.flags,
- line_num: &mut self.line_num,
- col_num: &mut self.col_num,
- var_locs: VarLocs::default(),
- inverse_var_locs: InverseVarLocs::default(),
- };
-
- while let Some(token) = parser_impl.tokens.pop() {
- parser_impl.shift_token(token, op_dir)?;
+ while let Some(token) = self.tokens.pop() {
+ self.shift_token(token, op_dir)?;
}
- parser_impl.reduce_op(1400);
-
- let after_len = parser_impl.terms.cell_len();
-
- debug_assert!(after_len - before_len <= cell_index!(4 * term_byte_size));
+ self.reduce_op(1400);
- if parser_impl.stack.len() > 1 || parser_impl.terms.is_empty() {
+ if self.terms.len() > 1 || self.stack.len() > 1 {
return Err(ParserError::IncompleteReduction(
- parser_impl.loc_to_err_src(),
+ self.lexer.line_num,
+ self.lexer.col_num,
));
}
- match parser_impl.stack.pop() {
- Some(TokenDesc {
- tt: TokenType::Term { heap_loc },
- ..
- }) => Ok(TermWriteResult {
- focus: heap_loc.get_value() as usize,
- inverse_var_locs: parser_impl.inverse_var_locs,
- }),
+ match self.terms.pop() {
+ Some(term) => {
+ if self.terms.is_empty() {
+ Ok(term)
+ } else {
+ Err(ParserError::IncompleteReduction(
+ self.lexer.line_num,
+ self.lexer.col_num,
+ ))
+ }
+ }
_ => Err(ParserError::IncompleteReduction(
- parser_impl.loc_to_err_src(),
+ self.lexer.line_num,
+ self.lexer.col_num,
)),
}
}
impl<T: RawBlockTraits> RawBlock<T> {
#[inline]
- pub(crate) fn empty_block() -> Self {
+ fn empty_block() -> Self {
RawBlock {
base: ptr::null(),
top: ptr::null(),
use crate::parser::ast::*;
+use crate::parser::lexer::Lexer;
use crate::parser::parser::*;
use crate::atom_table::*;
+use crate::forms::*;
+use crate::iterators::*;
+use crate::machine::heap::*;
use crate::machine::machine_errors::*;
+use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState;
use crate::machine::streams::*;
use crate::parser::char_reader::*;
-use crate::parser::lexer::LexerParser;
#[cfg(feature = "repl")]
use crate::repl_helper::Helper;
+use crate::types::*;
+
+use fxhash::FxBuildHasher;
#[cfg(feature = "repl")]
use rustyline::error::ReadlineError;
#[cfg(feature = "repl")]
use rustyline::{Config, Editor};
+use std::collections::VecDeque;
use std::io::{Cursor, Read};
#[cfg(feature = "repl")]
use std::io::{Error, ErrorKind};
use std::sync::Arc;
+type SubtermDeque = VecDeque<(usize, usize)>;
+
pub(crate) fn devour_whitespace<R: CharRead>(
- lexer: &mut LexerParser<'_, R>,
+ lexer: &mut Lexer<'_, R>,
) -> Result<bool, ParserError> {
match lexer.scan_for_layout() {
Err(e) if e.is_unexpected_eof() => Ok(true),
}
}
-pub(crate) fn error_after_read_term(
+pub(crate) fn error_after_read_term<R>(
err: ParserError,
prior_num_lines_read: usize,
+ parser: &Parser<R>,
) -> CompilationError {
if err.is_unexpected_eof() {
- let ParserErrorSrc { line_num, col_num } = err.err_src();
+ let line_num = parser.lexer.line_num;
+ let col_num = parser.lexer.col_num;
// rough overlap with errors 8.14.1.3 k) & l) of the ISO standard here
if !(line_num == prior_num_lines_read && col_num == 0) {
- return CompilationError::from(ParserError::IncompleteReduction(err.err_src()));
+ return CompilationError::from(ParserError::IncompleteReduction(line_num, col_num));
}
}
}
impl MachineState {
- pub(crate) fn read<R: CharRead>(
+ pub(crate) fn read(
&mut self,
- inner: R,
+ mut inner: Stream,
op_dir: &OpDir,
- ) -> Result<(TermWriteResult, usize), ParserError> {
- let mut lexer_parser = LexerParser::new(inner, self);
- let op_dir = CompositeOpDir::new(op_dir, None);
+ ) -> Result<TermWriteResult, CompilationError> {
+ let (term, num_lines_read) = {
+ let prior_num_lines_read = inner.lines_read();
+ let mut parser = Parser::new(inner, self);
+ let op_dir = CompositeOpDir::new(op_dir, None);
- let term_result = lexer_parser.read_term(&op_dir, Tokens::Default);
- let lines_read = lexer_parser.line_num();
+ parser.add_lines_read(prior_num_lines_read);
- term_result.map(|term| (term, lines_read))
- }
+ let term = parser
+ .read_term(&op_dir, Tokens::Default)
+ .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
- pub(crate) fn read_to_heap(
- &mut self,
- mut inner: Stream,
- op_dir: &OpDir,
- ) -> Result<TermWriteResult, CompilationError> {
- let prior_num_lines_read = inner.lines_read();
- let term = match self.read(inner, op_dir) {
- Ok((term, num_lines_read)) => {
- inner.add_lines_read(num_lines_read);
- term
- }
- Err(e) => {
- return Err(error_after_read_term(e, prior_num_lines_read));
- }
+ (term, parser.lines_read() - prior_num_lines_read)
};
- Ok(term)
+ inner.add_lines_read(num_lines_read);
+ write_term_to_heap(&term, &mut self.heap)
}
}
}
}
}
+
#[inline]
fn consume(&mut self, nread: usize) {
self.pending_input.consume(nread);
self.pending_input.put_back_char(c);
}
}
+
+#[inline]
+pub(crate) fn write_term_to_heap(
+ term: &Term,
+ heap: &mut Heap,
+) -> Result<TermWriteResult, CompilationError> {
+ let term_writer = TermWriter::new(heap);
+ term_writer.write_term_to_heap(term)
+}
+
+#[derive(Debug)]
+struct TermWriter<'a> {
+ heap: &'a mut Heap,
+ queue: SubtermDeque,
+ var_dict: HeapVarDict,
+}
+
+#[derive(Debug)]
+pub struct TermWriteResult {
+ pub heap_loc: usize,
+ pub var_dict: HeapVarDict,
+}
+
+impl<'a> TermWriter<'a> {
+ #[inline]
+ fn new(heap: &'a mut Heap) -> Self {
+ TermWriter {
+ heap,
+ queue: SubtermDeque::new(),
+ var_dict: HeapVarDict::with_hasher(FxBuildHasher::default()),
+ }
+ }
+
+ #[inline]
+ fn modify_head_of_queue(&mut self, term: &TermRef, h: usize) {
+ if let Some((arity, site_h)) = self.queue.pop_front() {
+ self.heap[site_h] = self.term_as_addr(term, h);
+
+ if arity > 1 {
+ self.queue.push_front((arity - 1, site_h + 1));
+ }
+ }
+ }
+
+ #[inline]
+ fn push_stub_addr(&mut self) -> Result<(), CompilationError> {
+ let h = self.heap.cell_len();
+ self.push_cell(heap_loc_as_cell!(h))
+ }
+
+ #[inline]
+ fn push_cell(&mut self, cell: HeapCellValue) -> Result<(), CompilationError> {
+ self.heap
+ .push_cell(cell)
+ .map_err(|h| CompilationError::FiniteMemoryInHeap(h))
+ }
+
+ fn term_as_addr(&mut self, term: &TermRef, h: usize) -> HeapCellValue {
+ match term {
+ &TermRef::Cons(..) => list_loc_as_cell!(h),
+ &TermRef::AnonVar(_) | &TermRef::Var(..) => heap_loc_as_cell!(h),
+ TermRef::PartialString(..) | TermRef::CompleteString(..) => heap_loc_as_cell!(h),
+ &TermRef::Literal(_, _, literal) => HeapCellValue::from(*literal),
+ &TermRef::Clause(_, _, _, subterms) if subterms.is_empty() => heap_loc_as_cell!(h),
+ &TermRef::Clause(..) => str_loc_as_cell!(h),
+ }
+ }
+
+ fn write_term_to_heap(mut self, term: &Term) -> Result<TermWriteResult, CompilationError> {
+ let heap_loc = self.heap.cell_len();
+
+ for term in breadth_first_iter(term, RootIterationPolicy::Iterated) {
+ let h = self.heap.cell_len();
+
+ match &term {
+ &TermRef::Cons(Level::Root, ..) => {
+ self.queue.push_back((2, h + 1));
+ self.push_cell(list_loc_as_cell!(h + 1))?;
+
+ self.push_stub_addr()?;
+ self.push_stub_addr()?;
+
+ continue;
+ }
+ &TermRef::Cons(..) => {
+ self.queue.push_back((2, h));
+
+ self.push_stub_addr()?;
+ self.push_stub_addr()?;
+ }
+ &TermRef::Clause(Level::Root, _, name, subterms) => {
+ if subterms.len() > MAX_ARITY {
+ return Err(CompilationError::ExceededMaxArity);
+ }
+
+ self.push_cell(if subterms.is_empty() {
+ heap_loc_as_cell!(heap_loc + 1)
+ } else {
+ str_loc_as_cell!(heap_loc + 1)
+ })?;
+
+ self.queue.push_back((subterms.len(), h + 2));
+ let named = atom_as_cell!(name, subterms.len());
+
+ self.push_cell(named)?;
+
+ for _ in 0..subterms.len() {
+ self.push_stub_addr()?;
+ }
+
+ continue;
+ }
+ &TermRef::Clause(_, _, name, subterms) => {
+ self.queue.push_back((subterms.len(), h + 1));
+ let named = atom_as_cell!(name, subterms.len());
+
+ self.push_cell(named)?;
+
+ for _ in 0..subterms.len() {
+ self.push_stub_addr()?;
+ }
+ }
+ &TermRef::AnonVar(Level::Root) | TermRef::Literal(Level::Root, ..) => {
+ let addr = self.term_as_addr(&term, h);
+ self.push_cell(addr)?;
+ }
+ &TermRef::Var(Level::Root, _, ref var_ptr) => {
+ let addr = self.term_as_addr(&term, h);
+ self.var_dict.insert(VarKey::VarPtr(var_ptr.clone()), addr);
+ self.push_cell(addr)?;
+ }
+ &TermRef::AnonVar(_) => {
+ if let Some((arity, site_h)) = self.queue.pop_front() {
+ self.var_dict
+ .insert(VarKey::AnonVar(h), heap_loc_as_cell!(site_h));
+
+ if arity > 1 {
+ self.queue.push_front((arity - 1, site_h + 1));
+ }
+ }
+
+ continue;
+ }
+ TermRef::CompleteString(lvl, _, src) => {
+ let cell = self
+ .heap
+ .allocate_cstr(src)
+ .map_err(CompilationError::FiniteMemoryInHeap)?;
+
+ let h = self.heap.cell_len();
+ self.push_cell(cell)?;
+
+ if !matches!(lvl, Level::Root) {
+ self.modify_head_of_queue(&term, h);
+ }
+
+ continue;
+ }
+ TermRef::PartialString(lvl, _, src, _) => {
+ if let Level::Root = lvl {
+ self.push_stub_addr()?;
+ }
+
+ let cell = self
+ .heap
+ .allocate_pstr(src)
+ .map_err(CompilationError::FiniteMemoryInHeap)?;
+
+ let tail_h = self.heap.cell_len();
+ self.push_stub_addr()?;
+
+ if let Level::Root = lvl {
+ self.heap[h] = cell;
+ } else {
+ self.push_cell(cell)?;
+ };
+
+ self.queue.push_back((1, tail_h));
+
+ if !matches!(lvl, Level::Root) {
+ self.modify_head_of_queue(&term, tail_h + 1);
+ }
+
+ continue;
+ }
+ TermRef::Var(.., var) => {
+ if let Some((arity, site_h)) = self.queue.pop_front() {
+ let var_key = VarKey::VarPtr(var.clone());
+
+ if let Some(addr) = self.var_dict.get(&var_key).cloned() {
+ self.heap[site_h] = addr;
+ } else {
+ self.var_dict.insert(var_key, heap_loc_as_cell!(site_h));
+ }
+
+ if arity > 1 {
+ self.queue.push_front((arity - 1, site_h + 1));
+ }
+ }
+
+ continue;
+ }
+ _ => {}
+ };
+
+ self.modify_head_of_queue(&term, h);
+ }
+
+ Ok(TermWriteResult {
+ heap_loc,
+ var_dict: self.var_dict,
+ })
+ }
+}
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
+use crate::iterators::*;
use crate::types::*;
use std::rc::Rc;
pub(crate) struct QueryInstruction;
pub(crate) trait CompilationTarget<'a> {
- fn to_constant(lvl: Level, cell: HeapCellValue, r: RegType) -> Instruction;
+ type Iterator: Iterator<Item = TermRef<'a>>;
+
+ fn iter(term: &'a Term) -> Self::Iterator;
+
+ fn to_constant(lvl: Level, constant: Literal, r: RegType) -> Instruction;
fn to_list(lvl: Level, r: RegType) -> Instruction;
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
fn incr_void_instr(instr: &mut Instruction);
- fn constant_subterm(literal: HeapCellValue) -> Instruction;
+ fn constant_subterm(literal: Literal) -> Instruction;
fn argument_to_variable(r: RegType, r: usize) -> Instruction;
fn argument_to_value(r: RegType, val: usize) -> Instruction;
}
impl<'a> CompilationTarget<'a> for FactInstruction {
- fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction {
- Instruction::GetConstant(lvl, cell, reg)
+ type Iterator = FactIterator<'a>;
+
+ fn iter(term: &'a Term) -> Self::Iterator {
+ breadth_first_iter(term, RootIterationPolicy::NotIterated)
+ }
+
+ fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+ Instruction::GetConstant(lvl, HeapCellValue::from(constant), reg)
}
fn to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction {
}
}
- fn constant_subterm(constant: HeapCellValue) -> Instruction {
- Instruction::UnifyConstant(constant)
+ fn constant_subterm(constant: Literal) -> Instruction {
+ Instruction::UnifyConstant(HeapCellValue::from(constant))
}
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
}
impl<'a> CompilationTarget<'a> for QueryInstruction {
- fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction {
- Instruction::PutConstant(lvl, constant, reg)
+ type Iterator = QueryIterator<'a>;
+
+ fn iter(term: &'a Term) -> Self::Iterator {
+ post_order_iter(term)
}
fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
}
}
- fn constant_subterm(constant: HeapCellValue) -> Instruction {
- Instruction::SetConstant(constant)
+ fn constant_subterm(constant: Literal) -> Instruction {
+ Instruction::SetConstant(HeapCellValue::from(constant))
+ }
+
+ fn to_constant(lvl: Level, constant: Literal, reg: RegType) -> Instruction {
+ Instruction::PutConstant(lvl, HeapCellValue::from(constant), reg)
}
fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
\+ float([1,2,_]),
\+ (X is 3 rdiv 4, float(X)),
\+ \+ (X is 3 rdiv 4, rational(X)),
- rational(3),
+ \+ rational(3),
\+ rational(f(_)),
\+ rational("sdfa"),
\+ rational(atom),
[true, 4],
[!, 5]]),
findall([R,X],
- (call_with_inference_limit(g(X), 2, R), call(true)),
+ (call_with_inference_limit(g(X), 5, R), call(true)),
[[true, 1],
[true, 2],
[inference_limit_exceeded, _]]),
use crate::machine::machine_indices::*;
use crate::machine::streams::*;
use crate::parser::ast::Fixnum;
+use crate::parser::ast::Literal;
use std::cmp::Ordering;
use std::convert::TryFrom;
use std::mem;
use std::ops::{Add, Sub, SubAssign};
+use dashu::{Integer, Rational};
+
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)]
#[bits = 6]
#[inline(always)]
pub fn as_ptr(self) -> *mut u8 {
- unsafe {
- mem::transmute::<_, *mut u8>(self.ptr())
- }
+ unsafe { mem::transmute::<_, *mut u8>(self.ptr()) }
}
#[inline(always)]
}
}
+impl From<Literal> for HeapCellValue {
+ #[inline]
+ fn from(literal: Literal) -> Self {
+ match literal {
+ Literal::Atom(name) => atom_as_cell!(name),
+ Literal::CodeIndex(ptr) => {
+ untyped_arena_ptr_as_cell!(UntypedArenaPtr::from(ptr))
+ }
+ Literal::Fixnum(n) => fixnum_as_cell!(n),
+ Literal::Integer(bigint_ptr) => {
+ typed_arena_ptr_as_cell!(bigint_ptr)
+ }
+ Literal::Rational(bigint_ptr) => {
+ typed_arena_ptr_as_cell!(bigint_ptr)
+ }
+ Literal::Float(f) => HeapCellValue::from(f.as_ptr()),
+ }
+ }
+}
+
+impl TryFrom<HeapCellValue> for Literal {
+ type Error = ();
+
+ fn try_from(value: HeapCellValue) -> Result<Literal, ()> {
+ read_heap_cell!(value,
+ (HeapCellValueTag::Atom, (name, arity)) => {
+ if arity == 0 {
+ Ok(Literal::Atom(name))
+ } else {
+ Err(())
+ }
+ }
+ (HeapCellValueTag::Fixnum, n) => {
+ Ok(Literal::Fixnum(n))
+ }
+ (HeapCellValueTag::F64, f) => {
+ Ok(Literal::Float(f.as_offset()))
+ }
+ (HeapCellValueTag::Cons, cons_ptr) => {
+ match_untyped_arena_ptr!(cons_ptr,
+ (ArenaHeaderTag::Integer, n) => {
+ Ok(Literal::Integer(n))
+ }
+ (ArenaHeaderTag::Rational, n) => {
+ Ok(Literal::Rational(n))
+ }
+ (ArenaHeaderTag::IndexPtr, ip) => {
+ Ok(Literal::CodeIndex(CodeIndex::from(ip)))
+ }
+ _ => {
+ Err(())
+ }
+ )
+ }
+ _ => {
+ Err(())
+ }
+ )
+ }
+}
+
impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue
where
T::Payload: Sized,
#[inline]
pub fn get_ptr(self) -> *const ArenaHeader {
- unsafe {
- mem::transmute::<_, *const ArenaHeader>(self.ptr())
- }
+ unsafe { mem::transmute::<_, *const ArenaHeader>(self.ptr()) }
}
#[inline]
safety: VarSafetyStatus,
to_perm_var_num: Option<usize>,
},
- Perm {
- reg: usize,
- allocation: PermVarAllocation,
- }, // stack offset, allocation info
+ Perm(usize, PermVarAllocation), // stack offset, allocation info
}
impl VarAlloc {
pub(crate) fn as_reg_type(&self) -> RegType {
match *self {
VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg),
- VarAlloc::Perm { reg, .. } => RegType::Perm(reg),
+ VarAlloc::Perm(r, _) => RegType::Perm(r),
}
}
#[inline]
pub(crate) fn set_register(&mut self, reg_num: usize) {
match self {
- VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num,
+ VarAlloc::Perm(ref mut p, _) => *p = reg_num,
VarAlloc::Temp {
ref mut temp_reg, ..
} => *temp_reg = reg_num,
impl Default for VariableRecord {
fn default() -> Self {
VariableRecord {
- allocation: VarAlloc::Perm {
- reg: 0,
- allocation: PermVarAllocation::Pending,
- },
+ allocation: VarAlloc::Perm(0, PermVarAllocation::Pending),
num_occurrences: 0,
running_count: 0,
}
test_229 :- test_syntax_error("\"\\z.\"", syntax_error(missing_quote)).
-test_300 :- writeq_term_to_chars("\0\", C),
+test_300 :- '$debug_hook',
+ writeq_term_to_chars("\0\", C),
C == "['\\x0\\']".
test_172 :- X is 10.0** -323,
fn syntax_error() {
load_module_test(
"tests-pl/syntax_error.pl",
- " error(syntax_error(incomplete_reduction),read_term/3:3).\n",
+ " error(syntax_error(incomplete_reduction),read_term/3:6).\n",
);
}