Revert "remove Term"

This reverts commit 3b5879841aedecba5057c70c71da0ba23e5cd84a.
This commit is contained in:
Mark Thom
2025-03-15 13:19:26 -07:00
committed by Mark Thom
parent eef7b06919
commit 9e1e99f961
53 changed files with 3726 additions and 4517 deletions

View File

@@ -194,9 +194,9 @@ enum ReplCodePtr {
DynamicProperty, DynamicProperty,
#[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$abolish_clause")))]
AbolishClause, AbolishClause,
#[strum_discriminants(strum(props(Arity = "2", Name = "$asserta")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$asserta")))]
Asserta, Asserta,
#[strum_discriminants(strum(props(Arity = "2", Name = "$assertz")))] #[strum_discriminants(strum(props(Arity = "3", Name = "$assertz")))]
Assertz, Assertz,
#[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))] #[strum_discriminants(strum(props(Arity = "4", Name = "$retract_clause")))]
Retract, Retract,
@@ -3126,6 +3126,14 @@ pub fn generate_instructions_rs() -> TokenStream {
} }
} }
pub fn name(&self) -> Atom {
match self {
#(
#clause_type_name_arms,
)*
}
}
pub fn is_inbuilt(name: Atom, arity: usize) -> bool { pub fn is_inbuilt(name: Atom, arity: usize) -> bool {
matches!((name, arity), matches!((name, arity),
#(#is_inbuilt_arms)|* #(#is_inbuilt_arms)|*

View File

@@ -2,9 +2,10 @@ use crate::parser::ast::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::heap::Heap;
use crate::targets::*; use crate::targets::*;
use std::cell::Cell;
pub(crate) trait Allocator { pub(crate) trait Allocator {
fn new() -> Self; fn new() -> Self;
@@ -18,21 +19,22 @@ pub(crate) trait Allocator {
fn mark_non_var<'a, Target: CompilationTarget<'a>>( fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
lvl: Level, lvl: Level,
heap_loc: usize,
context: GenContext, context: GenContext,
cell: &'a Cell<RegType>,
code: &mut CodeDeque, code: &mut CodeDeque,
) -> RegType; );
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn mark_reserved_var<'a, Target: CompilationTarget<'a>>( fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var_num: usize, var_num: usize,
lvl: Level, lvl: Level,
context: GenContext, cell: &Cell<VarReg>,
term_loc: GenContext,
code: &mut CodeDeque, code: &mut CodeDeque,
r: RegType, r: RegType,
is_new_var: bool, is_new_var: bool,
) -> RegType; );
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType; fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType;
@@ -40,13 +42,14 @@ pub(crate) trait Allocator {
&mut self, &mut self,
var_num: usize, var_num: usize,
lvl: Level, lvl: Level,
cell: &Cell<VarReg>,
context: GenContext, context: GenContext,
code: &mut CodeDeque, code: &mut CodeDeque,
) -> RegType; );
fn reset(&mut self); fn reset(&mut self);
fn reset_arg(&mut self, arg_num: usize); 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 reset_contents(&mut self);
fn advance_arg(&mut self); fn advance_arg(&mut self);

View File

@@ -7,8 +7,6 @@ use crate::debray_allocator::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::machine::disjuncts::*;
use crate::machine::stack::Stack;
use crate::targets::QueryInstruction; use crate::targets::QueryInstruction;
use crate::types::*; use crate::types::*;
@@ -22,6 +20,7 @@ use dashu::base::BitTest;
use num_order::NumOrd; use num_order::NumOrd;
use ordered_float::{Float, OrderedFloat}; use ordered_float::{Float, OrderedFloat};
use std::cell::Cell;
use std::cmp::{max, min, Ordering}; use std::cmp::{max, min, Ordering};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::f64; use std::f64;
@@ -52,8 +51,89 @@ impl Default for ArithmeticTerm {
} }
} }
#[derive(Debug)]
pub(crate) struct ArithInstructionIterator<'a> {
state_stack: Vec<TermIterState<'a>>,
}
pub(crate) type ArithCont = (CodeDeque, Option<ArithmeticTerm>); 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)] #[derive(Debug)]
pub(crate) struct ArithmeticEvaluator<'a> { pub(crate) struct ArithmeticEvaluator<'a> {
marker: &'a mut DebrayAllocator, marker: &'a mut DebrayAllocator,
@@ -61,47 +141,37 @@ pub(crate) struct ArithmeticEvaluator<'a> {
interm_c: usize, interm_c: usize,
} }
fn push_literal(interm: &mut Vec<ArithmeticTerm>, c: HeapCellValue) -> Result<(), ArithmeticError> { pub(crate) trait ArithmeticTermIter<'a> {
let c = unmark_cell_bits!(c); type Iter: Iterator<Item = Result<ArithTermRef<'a>, ArithmeticError>>;
read_heap_cell!(c, fn iter(self) -> Result<Self::Iter, ArithmeticError>;
(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 { impl<'a> ArithmeticTermIter<'a> for &'a Term {
atom!("pi") => interm.push(ArithmeticTerm::Number( type Iter = ArithInstructionIterator<'a>;
Number::Float(OrderedFloat(std::f64::consts::PI)),
)), fn iter(self) -> Result<Self::Iter, ArithmeticError> {
atom!("epsilon") => interm.push(ArithmeticTerm::Number( ArithInstructionIterator::from(self)
Number::Float(OrderedFloat(std::f64::EPSILON)), }
)), }
atom!("e") => interm.push(ArithmeticTerm::Number(
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)), Number::Float(OrderedFloat(std::f64::consts::E)),
)), )),
_ => unreachable!(), 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)),
} }
}
(HeapCellValueTag::F64, n) => {
interm.push(ArithmeticTerm::Number(Number::Float(*n)));
}
_ => {
return Err(ArithmeticError::NonEvaluableFunctor(c, 0));
}
);
Ok(()) Ok(())
} }
@@ -143,7 +213,7 @@ impl<'a> ArithmeticEvaluator<'a> {
atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)), atom!("float_fractional_part") => Ok(Instruction::FloatFractionalPart(a1, t)),
atom!("sign") => Ok(Instruction::Sign(a1, t)), atom!("sign") => Ok(Instruction::Sign(a1, t)),
atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)), atom!("\\") => Ok(Instruction::BitwiseComplement(a1, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(atom_as_cell!(name), 1)), _ => Err(ArithmeticError::NonEvaluableFunctor(Literal::Atom(name), 1)),
} }
} }
@@ -175,7 +245,7 @@ impl<'a> ArithmeticEvaluator<'a> {
atom!("rem") => Ok(Instruction::Rem(a1, a2, t)), atom!("rem") => Ok(Instruction::Rem(a1, a2, t)),
atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)), atom!("gcd") => Ok(Instruction::Gcd(a1, a2, t)),
atom!("atan2") => Ok(Instruction::ATan2(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)),
} }
} }
@@ -231,7 +301,7 @@ impl<'a> ArithmeticEvaluator<'a> {
self.get_binary_instr(name, a1, a2, ninterm) self.get_binary_instr(name, a1, a2, ninterm)
} }
_ => Err(ArithmeticError::NonEvaluableFunctor( _ => Err(ArithmeticError::NonEvaluableFunctor(
atom_as_cell!(name), Literal::Atom(name),
arity, arity,
)), )),
} }
@@ -239,62 +309,44 @@ impl<'a> ArithmeticEvaluator<'a> {
pub(crate) fn compile_is( pub(crate) fn compile_is(
&mut self, &mut self,
src: &mut FocusedHeapRefMut, src: &'a Term,
term_loc: usize, term_loc: GenContext,
context: GenContext,
arg: usize, arg: usize,
) -> Result<ArithCont, ArithmeticError> { ) -> Result<ArithCont, ArithmeticError> {
let mut code = CodeDeque::new(); 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(); 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();
while let Some(term) = iter.next() { let r = if lvl == Level::Shallow {
read_heap_cell!(term, self.marker
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, term_loc) => { .mark_non_callable(var_num, arg, term_loc, cell, &mut code)
let lvl = iter.level(); } else if term_loc.is_last() || cell.get().norm().reg_num() == 0 {
let r = self.marker.get_binding(var_num);
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 { if r.reg_num() == 0 {
self.marker.mark_var::<QueryInstruction>( self.marker.mark_var::<QueryInstruction>(
var_num, lvl, context, &mut code, var_num, lvl, cell, term_loc, &mut code,
) );
cell.get().norm()
} else { } else {
self.marker.increment_running_count(var_num); self.marker.increment_running_count(var_num);
r r
} }
} else { } else {
self.marker.increment_running_count(var_num); self.marker.increment_running_count(var_num);
old_r cell.get().norm()
}
}
VarPtr::Anon => {
self.marker.mark_anon_var::<QueryInstruction>(lvl, context, &mut code)
}
}; };
self.interm.push(ArithmeticTerm::Reg(r)); self.interm.push(ArithmeticTerm::Reg(r));
} }
(HeapCellValueTag::Atom, (name, arity)) => { ArithTermRef::Op(name, arity) => {
if arity == 0 {
push_literal(&mut self.interm, atom_as_cell!(name))?;
} else {
code.push_back(self.instr_from_clause(name, arity)?); code.push_back(self.instr_from_clause(name, arity)?);
} }
} }
_ => {
push_literal(&mut self.interm, term)?;
}
);
} }
Ok((code, self.interm.pop())) Ok((code, self.interm.pop()))

View File

@@ -222,7 +222,7 @@ pub enum AtomString<'a> {
Dynamic(AtomTableRef<str>), 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 // allow the '\0\' atom to be represented as the 0-valued inlined atom
let slice_len = if bytes[0] == 0 { let slice_len = if bytes[0] == 0 {
1 1
@@ -543,61 +543,3 @@ impl AtomTable {
unsafe impl Send for AtomTable {} unsafe impl Send for AtomTable {}
unsafe impl Sync 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())
}
}
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,13 +1,10 @@
use crate::allocator::*; use crate::allocator::*;
use crate::atom_table::*;
use crate::codegen::SubsumedBranchHits; use crate::codegen::SubsumedBranchHits;
use crate::forms::{GenContext, Level}; use crate::forms::{GenContext, Level};
use crate::instructions::*; use crate::instructions::*;
use crate::machine::disjuncts::*; use crate::machine::disjuncts::VarData;
use crate::machine::heap::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::targets::*; use crate::targets::*;
use crate::types::*;
use crate::variable_records::*; use crate::variable_records::*;
use bit_set::*; use bit_set::*;
@@ -15,6 +12,7 @@ use bitvec::prelude::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@@ -154,8 +152,6 @@ pub(crate) struct DebrayAllocator {
in_use: BitSet<usize>, // deep and non-var allocations in_use: BitSet<usize>, // deep and non-var allocations
temp_free_list: Vec<usize>, temp_free_list: Vec<usize>,
perm_free_list: VecDeque<(usize, usize)>, // chunk_num, var_num 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 { impl DebrayAllocator {
@@ -172,9 +168,7 @@ impl DebrayAllocator {
for var_num in subsumed_hits { for var_num in subsumed_hits {
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { VarAlloc::Perm(_, ref mut allocation) => {
ref mut allocation, ..
} => {
if let PermVarAllocation::Done { if let PermVarAllocation::Done {
shallow_safety, shallow_safety,
deep_safety, deep_safety,
@@ -235,7 +229,7 @@ impl DebrayAllocator {
let num_occurrences = self.var_data.records[var_num].num_occurrences; let num_occurrences = self.var_data.records[var_num].num_occurrences;
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { allocation, .. } => { VarAlloc::Perm(_, allocation) => {
let shallow_safety = VarSafetyStatus::needed_if( let shallow_safety = VarSafetyStatus::needed_if(
shallow_safety.contains(var_num), shallow_safety.contains(var_num),
branch_designator, branch_designator,
@@ -372,7 +366,7 @@ impl DebrayAllocator {
&mut self, &mut self,
chunk_num: usize, chunk_num: usize,
code: &mut CodeDeque, code: &mut CodeDeque,
) -> Option<RegType> { ) {
if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) { if let Some((var_num, r)) = self.alloc_in_last_goal_hint(chunk_num) {
let k = self.arg_c; let k = self.arg_c;
@@ -388,12 +382,8 @@ impl DebrayAllocator {
.allocation .allocation
.set_register(r.reg_num()); .set_register(r.reg_num());
self.in_use.insert(r.reg_num()); self.in_use.insert(r.reg_num());
return Some(r);
} }
}; };
None
} }
fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>( fn alloc_reg_to_var<'a, Target: CompilationTarget<'a>>(
@@ -443,7 +433,6 @@ impl DebrayAllocator {
} }
self.temp_lb = final_index + 1; self.temp_lb = final_index + 1;
final_index final_index
} }
@@ -467,11 +456,7 @@ impl DebrayAllocator {
p p
}; };
self.var_data.records[var_num].allocation = VarAlloc::Perm { self.var_data.records[var_num].allocation = VarAlloc::Perm(p, PermVarAllocation::done());
reg: p,
allocation: PermVarAllocation::done(),
};
p p
} }
@@ -487,15 +472,10 @@ impl DebrayAllocator {
} }
#[inline(always)] #[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() 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 { pub fn num_perm_vars(&self) -> usize {
self.perm_lb - 1 self.perm_lb - 1
} }
@@ -505,7 +485,7 @@ impl DebrayAllocator {
} }
fn add_perm_to_free_list(&mut self, chunk_num: usize, var_num: usize) { 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.push_back((chunk_num, var_num));
} }
} }
@@ -516,10 +496,7 @@ impl DebrayAllocator {
self.perm_free_list.pop_front(); self.perm_free_list.pop_front();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { VarAlloc::Perm(p, PermVarAllocation::Pending) if *p > 0 => {
reg: p,
allocation: PermVarAllocation::Pending,
} if *p > 0 => {
return Some(std::mem::replace(p, 0)); return Some(std::mem::replace(p, 0));
} }
_ => {} _ => {}
@@ -533,28 +510,24 @@ impl DebrayAllocator {
} }
pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) { pub(crate) fn free_var(&mut self, chunk_num: usize, var_num: usize) {
match &mut self.var_data.records[var_num].allocation { if let VarAlloc::Perm(_, allocation) = &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { allocation, .. } => {
*allocation = PermVarAllocation::Pending; *allocation = PermVarAllocation::Pending;
self.add_perm_to_free_list(chunk_num, var_num); self.add_perm_to_free_list(chunk_num, var_num);
} }
_ => {}
}
} }
pub(crate) fn mark_safe_var_unconditionally(&mut self, var_num: usize) { pub(crate) fn mark_safe_var_unconditionally(&mut self, var_num: usize) {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { VarAlloc::Perm(
allocation: _,
PermVarAllocation::Done { PermVarAllocation::Done {
deep_safety, deep_safety,
shallow_safety, shallow_safety,
.. ..
}, },
.. ) => {
} => {
*deep_safety = VarSafetyStatus::unneeded(branch_designator); *deep_safety = VarSafetyStatus::unneeded(branch_designator);
*shallow_safety = VarSafetyStatus::unneeded(branch_designator); *shallow_safety = VarSafetyStatus::unneeded(branch_designator);
} }
@@ -562,8 +535,7 @@ impl DebrayAllocator {
*safety = VarSafetyStatus::unneeded(branch_designator); *safety = VarSafetyStatus::unneeded(branch_designator);
} }
_ => { _ => {
// the (permanent) variable might have been freed by unreachable!()
// this point, in which case we do nothing.
} }
} }
} }
@@ -572,15 +544,14 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { VarAlloc::Perm(
allocation: _,
PermVarAllocation::Done { PermVarAllocation::Done {
deep_safety, deep_safety,
shallow_safety, shallow_safety,
.. ..
}, },
.. ) => {
} => {
// GetVariable in head chunk is considered safe. // GetVariable in head chunk is considered safe.
if lvl == Level::Deep { if lvl == Level::Deep {
*deep_safety = VarSafetyStatus::unneeded(branch_designator); *deep_safety = VarSafetyStatus::unneeded(branch_designator);
@@ -617,14 +588,13 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { VarAlloc::Perm(
allocation: _,
PermVarAllocation::Done { PermVarAllocation::Done {
ref mut shallow_safety, ref mut shallow_safety,
.. ..
}, },
.. ) => {
} => {
if !self.in_tail_position if !self.in_tail_position
|| self || self
.branch_stack .branch_stack
@@ -654,14 +624,13 @@ impl DebrayAllocator {
let branch_designator = self.branch_stack.current_branch_designator(); let branch_designator = self.branch_stack.current_branch_designator();
match &mut self.var_data.records[var_num].allocation { match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { VarAlloc::Perm(
allocation: _,
PermVarAllocation::Done { PermVarAllocation::Done {
ref mut deep_safety, ref mut deep_safety,
.. ..
}, },
.. ) => {
} => {
if self if self
.branch_stack .branch_stack
.safety_unneeded_in_branch(deep_safety, &branch_designator) .safety_unneeded_in_branch(deep_safety, &branch_designator)
@@ -704,15 +673,13 @@ impl Allocator for DebrayAllocator {
temp_free_list: vec![], temp_free_list: vec![],
perm_free_list: VecDeque::new(), perm_free_list: VecDeque::new(),
branch_stack: BranchStack { stack: vec![] }, 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>>( fn mark_anon_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
lvl: Level, lvl: Level,
context: GenContext, term_loc: GenContext,
code: &mut CodeDeque, code: &mut CodeDeque,
) -> RegType { ) -> RegType {
let r = RegType::Temp(self.alloc_reg_to_non_var()); let r = RegType::Temp(self.alloc_reg_to_non_var());
@@ -722,7 +689,7 @@ impl Allocator for DebrayAllocator {
Level::Root | Level::Shallow => { Level::Root | Level::Shallow => {
let k = self.arg_c; 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); self.evacuate_arg::<Target>(chunk_num, code);
} }
@@ -738,69 +705,55 @@ impl Allocator for DebrayAllocator {
fn mark_non_var<'a, Target: CompilationTarget<'a>>( fn mark_non_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
lvl: Level, lvl: Level,
heap_loc: usize, term_loc: GenContext,
context: GenContext, cell: &'a Cell<RegType>,
code: &mut CodeDeque, code: &mut CodeDeque,
) -> RegType { ) {
let r = self.get_non_var_binding(heap_loc); let r = cell.get();
let r = match lvl { let r = match lvl {
Level::Shallow => { Level::Shallow => {
let k = self.arg_c; let k = self.arg_c;
if let GenContext::Last(chunk_num) = context { if let GenContext::Last(chunk_num) = term_loc {
if let Some(new_r) = self.evacuate_arg::<Target>(chunk_num, code) { 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);
}
} }
self.arg_c += 1; self.arg_c += 1;
RegType::Temp(k) RegType::Temp(k)
} }
_ if r.reg_num() == 0 => { _ if r.reg_num() == 0 => RegType::Temp(self.alloc_reg_to_non_var()),
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
}
_ => { _ => {
self.in_use.insert(r.reg_num()); self.in_use.insert(r.reg_num());
r r
} }
}; };
r cell.set(r);
} }
fn mark_var<'a, Target: CompilationTarget<'a>>( fn mark_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var_num: usize, var_num: usize,
lvl: Level, lvl: Level,
context: GenContext, cell: &Cell<VarReg>,
term_loc: GenContext,
code: &mut CodeDeque, 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) => { 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::Temp(o), true)
} }
RegType::Perm(0) => { 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) (RegType::Perm(p), true)
} }
r @ RegType::Perm(_) => { r @ RegType::Perm(_) => {
let is_new_var = match &mut self.var_data.records[var_num].allocation { let is_new_var = match &mut self.var_data.records[var_num].allocation {
VarAlloc::Perm { allocation, .. } => { VarAlloc::Perm(_, allocation) => {
if allocation.pending() { if allocation.pending() {
*allocation = PermVarAllocation::done(); *allocation = PermVarAllocation::done();
true true
@@ -816,29 +769,32 @@ impl Allocator for DebrayAllocator {
r => (r, false), 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>>( fn mark_reserved_var<'a, Target: CompilationTarget<'a>>(
&mut self, &mut self,
var_num: usize, var_num: usize,
lvl: Level, lvl: Level,
context: GenContext, cell: &Cell<VarReg>,
term_loc: GenContext,
code: &mut CodeDeque, code: &mut CodeDeque,
r: RegType, r: RegType,
is_new_var: bool, is_new_var: bool,
) -> RegType { ) {
match lvl { match lvl {
Level::Root | Level::Shallow => { Level::Root | Level::Shallow => {
let k = self.arg_c; let k = self.arg_c;
if self.is_curr_arg_distinct_from(var_num) { 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 { 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)); code.push_back(Target::argument_to_variable(r, k));
} else { } else {
code.push_back(self.argument_to_value::<Target>(var_num, r, k)); code.push_back(self.argument_to_value::<Target>(var_num, r, k));
@@ -848,15 +804,15 @@ impl Allocator for DebrayAllocator {
self.arg_c += 1; self.arg_c += 1;
} }
Level::Deep if is_new_var => { 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()) { if self.occurs_shallowly_in_head(var_num, r.reg_num()) {
code.push_back(self.subterm_to_value::<Target>(var_num, r)); code.push_back(self.subterm_to_value::<Target>(var_num, r));
} else { } 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)); code.push_back(Target::subterm_to_variable(r));
} }
} else { } 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)); code.push_back(Target::subterm_to_variable(r));
} }
} }
@@ -878,15 +834,14 @@ impl Allocator for DebrayAllocator {
if record.running_count < record.num_occurrences { if record.running_count < record.num_occurrences {
record.running_count += 1; record.running_count += 1;
} else { } else {
self.free_var(context.chunk_num(), var_num); self.free_var(term_loc.chunk_num(), var_num);
} }
self.in_use.insert(o); self.in_use.insert(o);
r
} }
fn mark_cut_var(&mut self, var_num: usize, chunk_num: usize) -> RegType { 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::Perm(0) => RegType::Perm(self.alloc_perm_var(var_num, chunk_num)),
RegType::Temp(0) => { RegType::Temp(0) => {
let t = self.alloc_reg_to_non_var(); let t = self.alloc_reg_to_non_var();
@@ -910,8 +865,6 @@ impl Allocator for DebrayAllocator {
fn reset(&mut self) { fn reset(&mut self) {
self.perm_lb = 1; self.perm_lb = 1;
self.shallow_temp_mappings.clear(); self.shallow_temp_mappings.clear();
self.non_var_registers.clear();
self.non_var_register_heap_locs.clear();
self.in_use.clear(); self.in_use.clear();
self.temp_free_list.clear(); self.temp_free_list.clear();
} }
@@ -919,8 +872,6 @@ impl Allocator for DebrayAllocator {
fn reset_contents(&mut self) { fn reset_contents(&mut self) {
self.in_use.clear(); self.in_use.clear();
self.shallow_temp_mappings.clear(); self.shallow_temp_mappings.clear();
self.non_var_registers.clear();
self.non_var_register_heap_locs.clear();
self.temp_free_list.clear(); self.temp_free_list.clear();
} }
@@ -928,55 +879,25 @@ impl Allocator for DebrayAllocator {
self.arg_c += 1; self.arg_c += 1;
} }
fn reset_at_head(&mut self, heap: &mut Heap, head_loc: usize) { fn reset_at_head(&mut self, args: &[Term]) {
let head_cell = heap_bound_store(heap, heap_bound_deref(heap, heap_loc_as_cell!(head_loc))); self.reset_arg(args.len());
self.arity = args.len();
read_heap_cell!(head_cell, for (idx, arg) in args.iter().enumerate() {
(HeapCellValueTag::Str, s) => { if let Term::Var(_, ref var) = arg {
let arity = cell_as_atom_cell!(heap[s]).get_arity(); let var_num = var.to_var_num().unwrap();
let r = self.get_binding(var_num);
self.reset_arg(arity);
self.arity = arity;
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;
}
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 { if !r.is_perm() && r.reg_num() == 0 {
self.in_use.insert(c_idx + 1); self.in_use.insert(idx + 1);
self.shallow_temp_mappings.insert(c_idx + 1, var_num); self.shallow_temp_mappings.insert(idx + 1, var_num);
self.var_data.records[var_num] self.var_data.records[var_num]
.allocation .allocation
.set_register(c_idx + 1); .set_register(idx + 1);
}
}
VarPtr::Anon => {}
} }
} }
} }
} }
_ => {
self.reset_arg(0);
}
);
}
fn reset_arg(&mut self, arity: usize) { fn reset_arg(&mut self, arity: usize) {
self.arity = 0; self.arity = 0;

View File

@@ -3,8 +3,7 @@ use crate::atom_table::*;
use crate::functor_macro::*; use crate::functor_macro::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::disjuncts::VarData; 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_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::parser::ast::*; use crate::parser::ast::*;
@@ -18,6 +17,7 @@ use fxhash::FxBuildHasher;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use ordered_float::OrderedFloat; use ordered_float::OrderedFloat;
use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
@@ -55,6 +55,15 @@ pub enum Level {
Shallow, Shallow,
} }
impl Level {
pub(crate) fn child_level(self) -> Level {
match self {
Level::Root => Level::Shallow,
_ => Level::Deep,
}
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum CallPolicy { pub enum CallPolicy {
Default, Default,
@@ -77,15 +86,6 @@ impl GenContext {
} }
} }
#[inline]
pub fn chunk_type(&self) -> ChunkType {
match self {
GenContext::Head => ChunkType::Head,
GenContext::Mid(_) => ChunkType::Mid,
GenContext::Last(_) => ChunkType::Last,
}
}
#[inline] #[inline]
pub fn is_last(self) -> bool { pub fn is_last(self) -> bool {
matches!(self, GenContext::Last(_)) matches!(self, GenContext::Last(_))
@@ -99,6 +99,19 @@ pub enum ChunkType {
Last, Last,
} }
#[derive(Debug)]
pub enum RootIterationPolicy {
Iterated,
NotIterated,
}
impl RootIterationPolicy {
#[inline(always)]
pub fn iterable(&self) -> bool {
matches!(self, RootIterationPolicy::Iterated)
}
}
impl ChunkType { impl ChunkType {
#[inline(always)] #[inline(always)]
pub fn to_gen_context(self, chunk_num: usize) -> GenContext { pub fn to_gen_context(self, chunk_num: usize) -> GenContext {
@@ -118,17 +131,12 @@ impl ChunkType {
#[derive(Debug)] #[derive(Debug)]
pub enum ChunkedTerms { pub enum ChunkedTerms {
Branch(Vec<VecDeque<ChunkedTerms>>), Branch(Vec<VecDeque<ChunkedTerms>>),
Chunk { Chunk { terms: VecDeque<QueryTerm> },
chunk_num: usize,
terms: VecDeque<QueryTerm>,
},
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ChunkedTermVec { pub struct ChunkedTermVec {
pub chunk_vec: VecDeque<ChunkedTerms>, pub chunk_vec: VecDeque<ChunkedTerms>,
pub current_chunk_num: usize,
pub current_chunk_type: ChunkType,
} }
impl Deref for ChunkedTermVec { impl Deref for ChunkedTermVec {
@@ -153,8 +161,6 @@ impl ChunkedTermVec {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
chunk_vec: VecDeque::new(), chunk_vec: VecDeque::new(),
current_chunk_num: 0,
current_chunk_type: ChunkType::Mid,
} }
} }
@@ -163,45 +169,18 @@ impl ChunkedTermVec {
.push_back(ChunkedTerms::Branch(Vec::with_capacity(capacity))); .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] #[inline]
pub fn add_chunk(&mut self) { pub fn add_chunk(&mut self) {
let chunk = ChunkedTerms::Chunk { let chunk = ChunkedTerms::Chunk {
chunk_num: self.current_chunk_num,
terms: VecDeque::from(vec![]), terms: VecDeque::from(vec![]),
}; };
self.chunk_vec.push_back(chunk); 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) { pub fn push_chunk_term(&mut self, term: QueryTerm) {
match self.chunk_vec.back_mut() { match self.chunk_vec.back_mut() {
Some(ChunkedTerms::Branch(_)) => { Some(ChunkedTerms::Branch(_)) => {
let chunk = ChunkedTerms::Chunk { let chunk = ChunkedTerms::Chunk {
chunk_num: self.current_chunk_num,
terms: VecDeque::from(vec![term]), terms: VecDeque::from(vec![term]),
}; };
@@ -212,7 +191,6 @@ impl ChunkedTermVec {
} }
None => { None => {
let chunk = ChunkedTerms::Chunk { let chunk = ChunkedTerms::Chunk {
chunk_num: self.current_chunk_num,
terms: VecDeque::from(vec![term]), terms: VecDeque::from(vec![term]),
}; };
@@ -222,39 +200,35 @@ impl ChunkedTermVec {
} }
} }
#[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)] #[derive(Debug)]
pub enum QueryTerm { pub enum QueryTerm {
Clause(QueryClause), // register, clause type, subterms, clause call policy.
Clause(Cell<RegType>, ClauseType, Vec<Term>, CallPolicy),
Fail, Fail,
Succeed, LocalCut { var_num: usize, cut_prev: bool }, // var_num
LocalCut { var_num: usize, cut_prev: bool },
GlobalCut(usize), // var_num GlobalCut(usize), // var_num
GetCutPoint { var_num: usize, prev_b: bool }, GetCutPoint { var_num: usize, prev_b: bool },
GetLevel(usize), // var_num 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 struct Fact {
pub(crate) term_loc: usize, pub(crate) head: Term,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct Rule { pub struct Rule {
pub(crate) term_loc: usize, pub(crate) head: (Atom, Vec<Term>),
pub(crate) clauses: ChunkedTermVec, pub(crate) clauses: ChunkedTermVec,
} }
@@ -271,32 +245,90 @@ impl ListingSource {
} }
} }
pub fn clause_predicate_key_from_heap( pub trait ClauseInfo {
heap: &impl SizedHeap, fn is_consistent(&self, clauses: &PredicateQueue) -> bool {
value: HeapCellValue, match clauses.first() {
) -> Option<PredicateKey> { Some(cl) => {
read_heap_cell!(value, self.name() == ClauseInfo::name(cl) && self.arity() == ClauseInfo::arity(cl)
(HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0);
Some((name, 0))
} }
_ => { 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;
} }
pub fn clause_predicate_key(heap: &impl SizedHeap, term_loc: usize) -> Option<PredicateKey> { impl ClauseInfo for PredicateKey {
let key_opt = term_predicate_key(heap, term_loc); #[inline]
fn name(&self) -> Option<Atom> {
Some(self.0)
}
if Some((atom!(":-"), 2)) == key_opt { #[inline]
term_nth_arg(heap, term_loc, 1).and_then(|arg_loc| term_predicate_key(heap, arg_loc)) fn arity(&self) -> usize {
} else { self.1
key_opt }
}
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,
}
}
}
impl ClauseInfo for Rule {
fn name(&self) -> Option<Atom> {
Some(self.head.0)
}
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(),
}
} }
} }
@@ -307,26 +339,20 @@ pub enum PredicateClause {
} }
impl PredicateClause { impl PredicateClause {
pub(crate) fn args<'a>(&self, heap: &'a Heap) -> Option<std::ops::RangeInclusive<usize>> { pub(crate) fn args(&self) -> Option<&[Term]> {
let focus = match self { match self {
&PredicateClause::Fact(Fact { term_loc }, _) => term_loc, PredicateClause::Fact(term, ..) => match &term.head {
&PredicateClause::Rule(Rule { term_loc, .. }, _) => { Term::Clause(_, _, args) => Some(args),
term_nth_arg(heap, term_loc, 1).unwrap() _ => None,
} },
}; PredicateClause::Rule(rule, ..) => {
if rule.head.1.is_empty() {
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 None
} else {
Some(&rule.head.1)
}
}
} }
)
} }
} }
@@ -699,7 +725,7 @@ impl ArenaFrom<Number> for Literal {
impl ArenaFrom<u64> for HeapCellValue { impl ArenaFrom<u64> for HeapCellValue {
#[inline] #[inline]
fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue { fn arena_from(value: u64, arena: &mut Arena) -> HeapCellValue {
fixnum!(value as i64, arena) HeapCellValue::from(fixnum!(Literal, value as i64, arena))
} }
} }
@@ -779,9 +805,9 @@ impl Number {
} }
} }
#[derive(Debug, Clone)] #[derive(Debug, Copy, Clone)]
pub(crate) enum OptArgIndexKey { pub(crate) enum OptArgIndexKey {
Literal(usize, usize, HeapCellValue, Vec<HeapCellValue>), // index, IndexingCode location, opt arg, alternatives Literal(usize, usize, Literal, Option<Literal>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location List(usize, usize), // index, IndexingCode location
None, None,
Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity Structure(usize, usize, Atom, usize), // index, IndexingCode location, name, arity

View File

@@ -84,6 +84,15 @@ macro_rules! build_functor {
1 + $res_len, 1 + $res_len,
[$($subfunctor),*]) [$($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),*))*], ([number($n:expr, $arena:expr) $(, $dt:ident($($value:tt),*))*],
[$($res:expr),*], [$($res:expr),*],
$res_len:expr, $res_len:expr,

View File

@@ -34,7 +34,7 @@ pub struct EagerStackfulPreOrderHeapIter<'a> {
start_value: HeapCellValue, start_value: HeapCellValue,
iter_stack: Vec<HeapCellValue>, iter_stack: Vec<HeapCellValue>,
mark_phase: bool, mark_phase: bool,
pub heap: &'a mut Heap, heap: &'a mut Heap,
} }
impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> { impl<'a> Drop for EagerStackfulPreOrderHeapIter<'a> {
@@ -253,7 +253,7 @@ impl<'a, ElideLists> Drop for StackfulPreOrderHeapIter<'a, ElideLists> {
} }
} }
pub trait FocusedHeapIter: Deref<Target = Heap> + Iterator<Item = HeapCellValue> { pub trait FocusedHeapIter: Iterator<Item = HeapCellValue> {
fn focus(&self) -> IterStackLoc; fn focus(&self) -> IterStackLoc;
} }
@@ -266,14 +266,6 @@ impl<'a, ElideLists: ListElisionPolicy> FocusedHeapIter
} }
} }
impl<'a, ElideLists> Deref for StackfulPreOrderHeapIter<'a, ElideLists> {
type Target = Heap;
fn deref(&self) -> &Self::Target {
&self.heap
}
}
impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> { impl<'a, ElideLists> StackfulPreOrderHeapIter<'a, ElideLists> {
#[inline] #[inline]
pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue { pub fn read_cell_mut(&mut self, loc: IterStackLoc) -> &mut HeapCellValue {
@@ -352,7 +344,6 @@ impl<'a, ElideLists: ListElisionPolicy> StackfulPreOrderHeapIter<'a, ElideLists>
#[inline] #[inline]
fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self { fn new(heap: &'a mut Heap, stack: &'a mut Stack, root_loc: usize) -> Self {
let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap); let h = IterStackLoc::iterable_loc(root_loc, HeapOrStackTag::Heap);
// heap.push(cell);
Self { Self {
heap, heap,
@@ -539,7 +530,7 @@ pub(crate) struct PostOrderIterator<Iter: FocusedHeapIter> {
} }
impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> { impl<Iter: FocusedHeapIter> Deref for PostOrderIterator<Iter> {
type Target = Heap; type Target = Iter;
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
&self.base_iter &self.base_iter
@@ -611,34 +602,10 @@ impl<Iter: FocusedHeapIter> FocusedHeapIter for PostOrderIterator<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> = pub(crate) type LeftistPostOrderHeapIter<'a, ElideLists> =
PostOrderIterator<StackfulPreOrderHeapIter<'a, ElideLists>>; PostOrderIterator<StackfulPreOrderHeapIter<'a, ElideLists>>;
impl<'a, ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'a, ElideLists> { impl<ElideLists: ListElisionPolicy> LeftistPostOrderHeapIter<'_, ElideLists> {
#[inline] #[inline]
pub fn pop_stack(&mut self) { pub fn pop_stack(&mut self) {
if let Some((child_count, ..)) = self.parent_stack.last() { if let Some((child_count, ..)) = self.parent_stack.last() {
@@ -870,7 +837,7 @@ mod tests {
// two-part complete string, then a three-part cyclic string // two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars. // 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(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -891,7 +858,7 @@ mod tests {
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); 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(heap_loc_as_cell!(4)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -1795,12 +1762,12 @@ mod tests {
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new( let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
1, 0,
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
heap_loc_as_cell!(0) heap_loc_as_cell!(1)
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
@@ -1857,7 +1824,7 @@ mod tests {
let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new( let mut iter = StackfulPreOrderHeapIter::<NonListElider>::new(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
0, 4,
); );
// the cycle will be iterated twice before being detected. // the cycle will be iterated twice before being detected.
@@ -1879,15 +1846,7 @@ mod tests {
); );
assert_eq!( assert_eq!(
unmark_cell_bits!(iter.next().unwrap()), unmark_cell_bits!(iter.next().unwrap()),
list_loc_as_cell!(1) heap_loc_as_cell!(0)
);
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)
); );
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
@@ -1928,7 +1887,7 @@ mod tests {
// two-part complete string, then a three-part cyclic string // two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars. // 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(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -1952,7 +1911,7 @@ mod tests {
} }
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); 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(heap_loc_as_cell!(4)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -2208,14 +2167,17 @@ mod tests {
section.push_cell(pstr_loc_as_cell!(0)); section.push_cell(pstr_loc_as_cell!(0));
}); });
assert_eq!(wam.machine_st.heap.cell_len(), 4);
{ {
let mut iter = stackful_preorder_iter::<NonListElider>( let mut iter = stackful_preorder_iter::<NonListElider>(
&mut wam.machine_st.heap, &mut wam.machine_st.heap,
&mut wam.machine_st.stack, &mut wam.machine_st.stack,
2, 3,
); );
assert_eq!(iter.heap.slice_to_str(0, "a string".len()), "a string"); 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().unwrap(), empty_list_as_cell!());
assert_eq!(iter.next(), None); assert_eq!(iter.next(), None);
} }
@@ -2528,7 +2490,7 @@ mod tests {
// two-part complete string, then a three-part cyclic string // two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars. // 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(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -2552,7 +2514,7 @@ mod tests {
} }
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); 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(heap_loc_as_cell!(4)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -2993,7 +2955,7 @@ mod tests {
// two-part complete string, then a three-part cyclic string // two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars. // 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(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();
@@ -3016,7 +2978,7 @@ mod tests {
wam.machine_st.heap[2] = heap_loc_as_cell!(2); wam.machine_st.heap[2] = heap_loc_as_cell!(2);
assert_eq!(wam.machine_st.heap.cell_len(), 3); 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); assert_eq!(wam.machine_st.heap.cell_len(), 4);
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();

View File

@@ -477,7 +477,7 @@ pub struct HCPrinter<'a, Outputter> {
toplevel_spec: Option<DirectedOp>, toplevel_spec: Option<DirectedOp>,
last_item_idx: usize, last_item_idx: usize,
parent_of_first_op: Option<(DirectedOp, 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_offset: Integer,
pub numbervars: bool, pub numbervars: bool,
pub quoted: bool, pub quoted: bool,
@@ -544,11 +544,11 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
stack: &'a mut Stack, stack: &'a mut Stack,
op_dir: &'a OpDir, op_dir: &'a OpDir,
output: Outputter, output: Outputter,
root_loc: usize, term_loc: usize,
) -> Self { ) -> Self {
HCPrinter { HCPrinter {
outputter: output, outputter: output,
iter: stackful_preorder_iter(heap, stack, root_loc), iter: stackful_preorder_iter(heap, stack, term_loc),
op_dir, op_dir,
state_stack: vec![], state_stack: vec![],
toplevel_spec: None, toplevel_spec: None,
@@ -795,7 +795,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
if let Some(var) = self.var_names.get(&cell) { if let Some(var) = self.var_names.get(&cell) {
read_heap_cell!(cell, read_heap_cell!(cell,
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { (HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => {
return Some(var.to_string()); return Some(var.borrow().to_string());
} }
_ => { _ => {
self.iter.push_stack(h); self.iter.push_stack(h);
@@ -837,7 +837,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
// short-circuits handle_heap_term. // short-circuits handle_heap_term.
// self.iter.pop_stack(); // self.iter.pop_stack();
let var_str = var.to_string(); let var_str = var.borrow().to_string();
push_space_if_amb!(self, &var_str, { push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str); append_str!(self, &var_str);
@@ -865,7 +865,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
Some(var) => { Some(var) => {
// If the term is bound to a named variable, // If the term is bound to a named variable,
// print the variable's name to output. // 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, { push_space_if_amb!(self, &var_str, {
append_str!(self, &var_str); append_str!(self, &var_str);
@@ -1956,7 +1956,7 @@ mod tests {
printer printer
.var_names .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(); let output = printer.print();
@@ -2033,7 +2033,7 @@ mod tests {
printer printer
.var_names .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(); let output = printer.print();
@@ -2078,7 +2078,7 @@ mod tests {
wam.machine_st.heap.clear(); 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(heap_loc_as_cell!(1)).unwrap();
wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap(); wam.machine_st.heap.push_cell(pstr_loc_as_cell!(0)).unwrap();

View File

@@ -1,9 +1,9 @@
use crate::atom_table::*; use crate::atom_table::*;
use crate::parser::ast::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::heap::*; use crate::types::HeapCellValue;
use crate::parser::ast::Fixnum;
use crate::types::*;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
@@ -113,7 +113,7 @@ impl<'a> IndexingCodeMergingPtr<'a> {
match constant_key { match constant_key {
Some(OptArgIndexKey::Literal(_, _, constant, _)) => { Some(OptArgIndexKey::Literal(_, _, constant, _)) => {
constants.insert(*constant, constant_ptr); constants.insert(HeapCellValue::from(*constant), constant_ptr);
} }
_ if constant_ptr.is_external() => { _ if constant_ptr.is_external() => {
// this must be a defunct clause, because it's been deleted // this must be a defunct clause, because it's been deleted
@@ -634,12 +634,15 @@ pub(crate) fn merge_clause_index(
match &opt_arg_index_key { match &opt_arg_index_key {
OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => { OptArgIndexKey::Literal(_, index_loc, constant, ref overlapping_constants) => {
let offset = new_clause_loc - index_loc + 1; 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.offset = 0;
merging_ptr.index_overlapping_constant(
merging_ptr.index_overlapping_constant(*constant, *overlapping_constant, offset); HeapCellValue::from(*constant),
HeapCellValue::from(*overlapping_constant),
offset,
);
} }
} }
OptArgIndexKey::Structure(_, index_loc, name, arity) => { OptArgIndexKey::Structure(_, index_loc, name, arity) => {
@@ -664,8 +667,8 @@ pub(crate) fn merge_clause_index(
} }
pub(crate) fn remove_constant_indices( pub(crate) fn remove_constant_indices(
constant: HeapCellValue, constant: Literal,
overlapping_constants: &[HeapCellValue], overlapping_constants: Option<Literal>,
indexing_code: &mut [IndexingLine], indexing_code: &mut [IndexingLine],
offset: usize, offset: usize,
) { ) {
@@ -694,7 +697,7 @@ pub(crate) fn remove_constant_indices(
let mut constants_index = 0; let mut constants_index = 0;
for constant in iter { for constant in iter.map(|l| HeapCellValue::from(*l)) {
loop { loop {
match &mut indexing_code[index] { match &mut indexing_code[index] {
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
@@ -702,8 +705,6 @@ pub(crate) fn remove_constant_indices(
)) => { )) => {
constants_index = index; constants_index = index;
let constant = *constant;
match constants.get(&constant).cloned() { match constants.get(&constant).cloned() {
Some(IndexingCodePtr::DynamicExternal(_)) Some(IndexingCodePtr::DynamicExternal(_))
| Some(IndexingCodePtr::External(_)) | Some(IndexingCodePtr::External(_))
@@ -741,7 +742,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants, ref mut constants,
)) => { )) => {
constants.insert(*constant, ext); constants.insert(constant, ext);
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -774,7 +775,7 @@ pub(crate) fn remove_constant_indices(
IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant( IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(
ref mut constants, ref mut constants,
)) => { )) => {
constants.insert(*constant, ext); constants.insert(constant, ext);
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -1034,7 +1035,7 @@ pub(crate) fn remove_index(
) { ) {
match opt_arg_index_key { match opt_arg_index_key {
OptArgIndexKey::Literal(_, _, constant, ref overlapping_constants) => { 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) => { OptArgIndexKey::Structure(_, _, name, arity) => {
remove_structure_index(*name, *arity, indexing_code, clause_loc); remove_structure_index(*name, *arity, indexing_code, clause_loc);
@@ -1096,60 +1097,18 @@ fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) {
} }
} }
pub(crate) fn constant_key_alternatives( pub(crate) fn constant_key_alternatives(constant: Literal) -> Option<Literal> {
constant: HeapCellValue, let n = match &constant {
// atom_tbl: &AtomTable, Literal::Rational(n) if n.denominator().is_one() => n.numerator(),
// arena: &mut Arena, Literal::Integer(n) => n,
) -> Vec<HeapCellValue> { _ => return None,
let mut constants = vec![]; };
match Number::try_from(constant) { if let Ok(n) = n.try_into() {
Ok(Number::Integer(n)) => { Fixnum::build_with_checked(n).map(Literal::Fixnum).ok()
let result = (&*n).try_into(); } else {
if let Ok(value) = result { None
constants.push(
Fixnum::build_with_checked(value)
.map(|n| fixnum_as_cell!(n))
.unwrap(),
);
} }
}
_ => {}
}
/*
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();
}
}
_ => {}
}
*/
constants
} }
#[derive(Debug)] #[derive(Debug)]
@@ -1464,9 +1423,13 @@ impl<I: Indexer> CodeOffsets<I> {
self.indices.lists().push_back(index); self.indices.lists().push_back(index);
} }
fn index_constant(&mut self, constant: HeapCellValue, index: usize) -> Vec<HeapCellValue> { fn index_constant(&mut self, constant: Literal, index: usize) -> Option<Literal> {
let overlapping_constants = constant_key_alternatives(constant); let overlapping_constant_opt = constant_key_alternatives(constant);
let code = self.indices.constants().entry(constant).or_default(); let code = self
.indices
.constants()
.entry(HeapCellValue::from(constant))
.or_default();
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
code.push_back(I::compute_index( code.push_back(I::compute_index(
@@ -1475,8 +1438,8 @@ impl<I: Indexer> CodeOffsets<I> {
self.non_counted_bt, self.non_counted_bt,
)); ));
for constant in &overlapping_constants { if let Some(constant) = overlapping_constant_opt.map(HeapCellValue::from) {
let code = self.indices.constants().entry(*constant).or_default(); let code = self.indices.constants().entry(constant).or_default();
let is_initial_index = code.is_empty(); let is_initial_index = code.is_empty();
let index = I::compute_index(is_initial_index, index, self.non_counted_bt); let index = I::compute_index(is_initial_index, index, self.non_counted_bt);
@@ -1484,7 +1447,7 @@ impl<I: Indexer> CodeOffsets<I> {
code.push_back(index); code.push_back(index);
} }
overlapping_constants overlapping_constant_opt
} }
fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize { fn index_structure(&mut self, name: Atom, arity: usize, index: usize) -> usize {
@@ -1503,55 +1466,33 @@ impl<I: Indexer> CodeOffsets<I> {
pub(crate) fn index_term( pub(crate) fn index_term(
&mut self, &mut self,
heap: &Heap, optimal_arg: &Term,
optimal_arg: HeapCellValue,
index: usize, index: usize,
clause_index_info: &mut ClauseIndexInfo, clause_index_info: &mut ClauseIndexInfo,
) { ) {
read_heap_cell!(optimal_arg, match optimal_arg {
(HeapCellValueTag::Str, s) => { &Term::Clause(_, atom!("."), ref terms) if terms.len() == 2 => {
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); clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index); self.index_list(index);
} else { }
&Term::Cons(..) | &Term::PartialString(..) | &Term::CompleteString(..) => {
clause_index_info.opt_arg_index_key = OptArgIndexKey::List(self.optimal_index, 0);
self.index_list(index);
}
&Term::Clause(_, name, ref terms) => {
clause_index_info.opt_arg_index_key = clause_index_info.opt_arg_index_key =
OptArgIndexKey::Structure(self.optimal_index, 0, name, arity); OptArgIndexKey::Structure(self.optimal_index, 0, name, terms.len());
self.index_structure(name, arity, index); self.index_structure(name, terms.len(), index);
} }
} &Term::Literal(_, constant) => {
(HeapCellValueTag::Atom, (name, arity)) => { let overlapping_constants = self.index_constant(constant, index);
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, constant, overlapping_constants);
clause_index_info.opt_arg_index_key = OptArgIndexKey::Literal(
self.optimal_index,
0,
atom_as_cell!(name),
overlapping_constants,
);
}
(HeapCellValueTag::Lis
// | HeapCellValueTag::CStr
| HeapCellValueTag::PStrLoc) => {
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,
);
} }
_ => {} _ => {}
); }
} }
pub(crate) fn no_indices(&mut self) -> bool { pub(crate) fn no_indices(&mut self) -> bool {

View File

@@ -1,222 +1,319 @@
use crate::atom_table::AtomCell; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::heap_iter::*; use crate::instructions::*;
use crate::machine::heap::*; use crate::parser::ast::*;
use crate::machine::stack::*;
use crate::types::*;
use bit_set::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::iter::*; use std::iter::*;
use std::ops::Deref; use std::rc::Rc;
use std::vec::Vec; use std::vec::Vec;
pub(crate) trait TermIterator: #[allow(clippy::borrowed_box)]
Deref<Target = Heap> + Iterator<Item = HeapCellValue> #[derive(Debug, Clone)]
{ pub(crate) enum TermRef<'a> {
fn focus(&self) -> IterStackLoc; AnonVar(Level),
fn level(&mut self) -> 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) 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),
}
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)
}
Term::Cons(cell, head, tail) => {
TermIterState::InitialCons(lvl, cell, head.as_ref(), tail.as_ref())
}
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()),
}
}
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct TargetIterator<I: FocusedHeapIter, const SKIP_ROOT: bool> { pub(crate) struct QueryIterator<'a> {
shallow_terms: IndexMap<usize, BitSet<usize>, FxBuildHasher>, state_stack: Vec<TermIterState<'a>>,
root_terms: BitSet<usize>,
iter: I,
arg_c: usize,
} }
fn record_path( impl<'a> QueryIterator<'a> {
heap: &impl SizedHeap, fn push_subterm(&mut self, lvl: Level, term: &'a Term) {
root_terms: &mut BitSet<usize>, self.state_stack
mut root_loc: usize, .push(TermIterState::subterm_to_state(lvl, term));
) -> 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;
}
}
(HeapCellValueTag::Lis) => {
root_terms.insert(root_loc);
break;
}
_ => {
if cell.is_ref() {
root_terms.insert(cell.get_value() as usize);
} }
break; /*
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();
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![],
} }
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)
}
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) => { Term::Clause(r, name, terms) => TermIterState::Clause(Level::Root, 0, r, *name, terms),
(l, 2) Term::Var(cell, var_ptr) => TermIterState::Var(Level::Root, cell, var_ptr.clone()),
} };
(HeapCellValueTag::Atom, (_name, arity)) => {
(root_loc + 1, arity)
}
_ => {
(root_loc, 0)
}
);
for idx in 0..arity { QueryIterator {
let mut shallow_terms = BitSet::default(); state_stack: vec![state],
record_path(heap, &mut shallow_terms, h + idx);
shallow_terms_map.insert(idx + 1, shallow_terms);
}
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);
Self {
shallow_terms,
root_terms,
iter,
arg_c,
} }
} }
fn current_level(&self, arg_c_inc: usize) -> Level { fn extend_state(&mut self, lvl: Level, term: &'a QueryTerm) {
let current_focus = self.iter.focus().value() as usize; match term {
QueryTerm::Clause(ref cell, ClauseType::CallN(_), ref terms, _) => {
if self.root_terms.contains(current_focus) { self.state_stack
return Level::Root; .push(TermIterState::Clause(lvl, 1, cell, atom!("$call"), terms));
} }
QueryTerm::Clause(ref cell, ref ct, ref terms, _) => {
if let Some(shallow_terms) = self.shallow_terms.get(&(self.arg_c + arg_c_inc)) { self.state_stack
if shallow_terms.contains(current_focus) { .push(TermIterState::Clause(lvl, 0, cell, ct.name(), terms));
return Level::Shallow; }
_ => {}
} }
} }
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> { impl<'a> Iterator for QueryIterator<'a> {
fn focus(&self) -> IterStackLoc { type Item = TermRef<'a>;
self.iter.focus()
}
fn level(&mut self) -> Level {
let lvl = self.current_level(1);
if let Level::Shallow = lvl {
self.arg_c += 1;
}
lvl
}
}
impl<'a, const SKIP_ROOT: bool> TermIterator for QueryIterator<'a, SKIP_ROOT> {
fn focus(&self) -> IterStackLoc {
self.iter.focus()
}
fn level(&mut self) -> Level {
let lvl = self.current_level(0);
if let Level::Shallow = lvl {
self.arg_c += 1;
}
lvl
}
}
impl<I: FocusedHeapIter, const SKIP_ROOT: bool> Iterator for TargetIterator<I, SKIP_ROOT> {
type Item = HeapCellValue;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { while let Some(iter_state) = self.state_stack.pop() {
let next_term = self.iter.next(); match iter_state {
TermIterState::AnonVar(lvl) => {
if next_term.is_none() { return Some(TermRef::AnonVar(lvl));
return None;
} }
TermIterState::Clause(lvl, child_num, cell, name, child_terms) => {
let focus = self.iter.focus().value() as usize; if child_num == child_terms.len() {
match name {
if SKIP_ROOT && self.root_terms.contains(focus) { atom!("$call") if lvl == Level::Root => {
continue; self.push_subterm(Level::Shallow, &child_terms[0]);
}
_ => {
return match lvl {
Level::Root => None,
lvl => Some(TermRef::Clause(lvl, cell, name, child_terms)),
}
}
};
} else { } else {
return next_term; 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));
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));
}
};
}
None
}
}
#[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));
}
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();
FactIterator {
state_queue,
iterable_root: RootIterationPolicy::NotIterated,
}
}
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> Deref for TargetIterator<I, SKIP_ROOT> { impl<'a> Iterator for FactIterator<'a> {
type Target = Heap; type Item = TermRef<'a>;
fn deref(&self) -> &Self::Target { fn next(&mut self) -> Option<Self::Item> {
self.iter.deref() 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);
}
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);
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));
}
_ => {}
}
}
None
} }
} }
impl<I: FocusedHeapIter, const SKIP_ROOT: bool> FocusedHeapIter for TargetIterator<I, SKIP_ROOT> { pub(crate) fn post_order_iter(term: &'_ Term) -> QueryIterator {
fn focus(&self) -> IterStackLoc { QueryIterator::from_term(term)
self.iter.focus()
}
} }
pub(crate) type FactIterator<'a, const SKIP_ROOT: bool> = pub(crate) fn breadth_first_iter(
TargetIterator<StackfulPreOrderHeapIter<'a, NonListElider>, SKIP_ROOT>; term: &'_ Term,
iterable_root: RootIterationPolicy,
pub(crate) fn fact_iterator<'a, const SKIP_ROOT: bool>( ) -> FactIterator {
heap: &'a mut Heap, FactIterator::new(term, iterable_root)
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) 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)
} }
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
@@ -230,10 +327,7 @@ pub(crate) enum ClauseItem<'a> {
FirstBranch(usize), FirstBranch(usize),
NextBranch, NextBranch,
BranchEnd(usize), BranchEnd(usize),
Chunk { Chunk { terms: &'a VecDeque<QueryTerm> },
chunk_num: usize,
terms: &'a VecDeque<QueryTerm>,
},
} }
#[derive(Debug)] #[derive(Debug)]
@@ -309,11 +403,8 @@ impl<'a> Iterator for ClauseIterator<'a> {
self.state_stack self.state_stack
.push(ClauseIteratorState::RemainingBranches(branches, 0)); .push(ClauseIteratorState::RemainingBranches(branches, 0));
} }
&ChunkedTerms::Chunk { &ChunkedTerms::Chunk { ref terms } => {
chunk_num, return Some(ClauseItem::Chunk { terms });
ref terms,
} => {
return Some(ClauseItem::Chunk { chunk_num, terms });
} }
} }
} }

View File

@@ -1175,8 +1175,14 @@ clause(H, B) :-
% Asserts (inserts) a new clause (rule or fact) into the current module. % Asserts (inserts) a new clause (rule or fact) into the current module.
% The clause will be inserted at the beginning of the module. % The clause will be inserted at the beginning of the module.
asserta(Clause0) :- asserta(Clause0) :-
loader:strip_subst_module(Clause0, user, Module, Clause), loader:strip_module(Clause0, Module, Clause),
'$asserta'(Module, Clause). asserta_(Module, Clause).
asserta_(Module, (Head :- Body)) :-
!,
'$asserta'(Module, Head, Body).
asserta_(Module, Fact) :-
'$asserta'(Module, Fact, true).
:- meta_predicate assertz(:). :- meta_predicate assertz(:).
@@ -1185,8 +1191,14 @@ asserta(Clause0) :-
% Asserts (inserts) a new clause (rule or fact) into the current module. % Asserts (inserts) a new clause (rule or fact) into the current module.
% The clase will be inserted at the end of the module. % The clase will be inserted at the end of the module.
assertz(Clause0) :- assertz(Clause0) :-
loader:strip_subst_module(Clause0, user, Module, Clause), loader:strip_module(Clause0, Module, Clause),
'$assertz'(Module, Clause). assertz_(Module, Clause).
assertz_(Module, (Head :- Body)) :-
!,
'$assertz'(Module, Head, Body).
assertz_(Module, Fact) :-
'$assertz'(Module, Fact, true).
:- meta_predicate retract(:). :- meta_predicate retract(:).

View File

@@ -126,3 +126,4 @@ when_condition_si((A, B)) :-
when_condition_si((A ; B)) :- when_condition_si((A ; B)) :-
when_condition_si(A), when_condition_si(A),
when_condition_si(B). when_condition_si(B).

View File

@@ -177,6 +177,7 @@ print_comma_separated_list([VN=_, VNEq | VNEqs]) :-
filter_anonymous_vars([], []). filter_anonymous_vars([], []).
filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :- filter_anonymous_vars([VN=V | VNEqs0], VNEqs) :-
'$debug_hook',
( atom_concat('_', _, VN) -> ( atom_concat('_', _, VN) ->
filter_anonymous_vars(VNEqs0, VNEqs) filter_anonymous_vars(VNEqs0, VNEqs)
; VNEqs = [VN=V | VNEqs1], ; VNEqs = [VN=V | VNEqs1],

View File

@@ -1126,7 +1126,10 @@ impl MachineState {
match Number::try_from(value) { match Number::try_from(value) {
Ok(n) => Ok(n), 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( &ArithmeticTerm::Interm(i) => Ok(mem::replace(
@@ -1152,21 +1155,11 @@ impl MachineState {
pub(crate) fn arith_eval_by_metacall( pub(crate) fn arith_eval_by_metacall(
&mut self, &mut self,
value: HeapCellValue, term_loc: usize,
) -> Result<Number, MachineStub> { ) -> Result<Number, MachineStub> {
debug_assert!(value.is_ref());
let stub_gen = || functor_stub(atom!("is"), 2); 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 = 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() { while let Some(value) = iter.next() {
if value.get_forwarding_bit() { if value.get_forwarding_bit() {
@@ -1459,7 +1452,7 @@ mod tests {
parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap(); parse_and_write_parsed_term_to_heap(&mut wam, "3 + 4 - 1 + 2.", &op_dir).unwrap();
assert_eq!( 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))), Ok(Number::Fixnum(Fixnum::build_with(8))),
); );
@@ -1469,7 +1462,7 @@ mod tests {
parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap(); parse_and_write_parsed_term_to_heap(&mut wam, "5 * 4 - 1.", &op_dir).unwrap();
assert_eq!( 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))), Ok(Number::Fixnum(Fixnum::build_with(19))),
); );
@@ -1479,7 +1472,7 @@ mod tests {
parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap(); parse_and_write_parsed_term_to_heap(&mut wam, "sign(-1).", &op_dir).unwrap();
assert_eq!( 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))) Ok(Number::Fixnum(Fixnum::build_with(-1)))
); );
} }

View File

@@ -10,8 +10,8 @@ use std::cmp::Ordering;
pub(super) type Bindings = Vec<(usize, HeapCellValue)>; pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct AttrVarInitializer { pub(super) struct AttrVarInitializer {
pub(crate) attr_var_queue: Vec<usize>, pub(super) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings, pub(super) bindings: Bindings,
pub(super) p: usize, pub(super) p: usize,
pub(super) cp: usize, pub(super) cp: usize,
@@ -138,17 +138,10 @@ impl MachineState {
let mut seen_set = IndexSet::new(); let mut seen_set = IndexSet::new();
let mut seen_vars = vec![]; 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>( self.heap[0] = cell;
&mut self.heap,
&mut self.stack, let mut iter = stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
root_loc, // cell,
);
while let Some(value) = iter.next() { while let Some(value) = iter.next() {
read_heap_cell!(value, read_heap_cell!(value,

View File

@@ -11,6 +11,7 @@ use crate::machine::term_stream::*;
use crate::machine::*; use crate::machine::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::mem; use std::mem;
use std::ops::Range; use std::ops::Range;
@@ -1232,16 +1233,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
fn compile_standalone_clause( fn compile_standalone_clause(
&mut self, &mut self,
term: TermWriteResult, term: Term,
settings: CodeGenSettings, settings: CodeGenSettings,
) -> Result<StandaloneCompileResult, SessionError> { ) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(settings); let mut preprocessor = Preprocessor::new(settings);
let clause = preprocessor.try_term_to_tl(self, term)?; 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 { Ok(StandaloneCompileResult {
clause_code, clause_code,
@@ -1262,6 +1261,10 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let code_len = self.wam_prelude.code.len(); let code_len = self.wam_prelude.code.len();
let mut code_ptr = code_len; let mut code_ptr = code_len;
if key == (atom!("..."), 2) {
print!("");
}
let mut clauses = vec![]; let mut clauses = vec![];
let mut preprocessor = Preprocessor::new(settings); let mut preprocessor = Preprocessor::new(settings);
@@ -1269,10 +1272,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
clauses.push(preprocessor.try_term_to_tl(self, term)?); 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 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 { if settings.is_extensible {
let mut clause_clause_locs = VecDeque::new(); let mut clause_clause_locs = VecDeque::new();
@@ -1469,7 +1470,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn incremental_compile_clause( pub(super) fn incremental_compile_clause(
&mut self, &mut self,
key: PredicateKey, key: PredicateKey,
clause: TermWriteResult, clause: Term,
compilation_target: CompilationTarget, compilation_target: CompilationTarget,
non_counted_bt: bool, non_counted_bt: bool,
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
@@ -2004,13 +2005,16 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
impl<'a, LS: LoadState<'a>> Loader<'a, LS> { 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, &mut self,
key: PredicateKey, key: PredicateKey,
compilation_target: CompilationTarget, compilation_target: CompilationTarget,
clause_clauses: Vec<TermWriteResult>, clause_clauses: ClauseIter,
append_or_prepend: AppendOrPrepend, append_or_prepend: AppendOrPrepend,
) -> Result<(), SessionError> { ) -> 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 { let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => CompilationTarget::Module(atom!("builtins")), CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
_ => compilation_target, _ => compilation_target,
@@ -2018,7 +2022,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut num_clause_predicates = 0; let mut num_clause_predicates = 0;
for clause_term in clause_clauses { for clause_term in clause_predicates {
self.incremental_compile_clause( self.incremental_compile_clause(
(atom!("$clause"), 2), (atom!("$clause"), 2),
clause_term, clause_term,
@@ -2102,13 +2106,15 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> { pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> {
let key = match self.payload.predicates.first().map(|term| term.focus) { let key = self
Some(focus) => clause_predicate_key(self.machine_heap(), focus) .payload
.ok_or(SessionError::NamelessEntry)?, .predicates
None => { .first()
return Err(SessionError::NamelessEntry); .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(); let listing_src_file_name = self.listing_src_file_name();
@@ -2247,12 +2253,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.clause_clauses .clause_clauses
.drain(0..std::cmp::min(predicates_len, clause_clauses_len)) .drain(0..std::cmp::min(predicates_len, clause_clauses_len))
.collect(); .collect();
let compilation_target = self.payload.predicates.compilation_target; let compilation_target = self.payload.predicates.compilation_target;
self.compile_clause_clauses( self.compile_clause_clauses(
key, key,
compilation_target, compilation_target,
clauses_vec, clauses_vec.into_iter(),
AppendOrPrepend::Append, AppendOrPrepend::Append,
)?; )?;
} }
@@ -2281,50 +2288,15 @@ impl Machine {
pub(crate) fn compile_standalone_clause( pub(crate) fn compile_standalone_clause(
&mut self, &mut self,
term_reg: RegType, term_loc: RegType,
vars: Vec<HeapCellValue>, vars: &[Term],
) -> Result<(), SessionError> { ) -> 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 compile = || {
let mut loader: Loader<'_, InlineLoadState<'_>> = let mut loader: Loader<'_, InlineLoadState<'_>> =
Loader::new(self, InlineTermStream {}); Loader::new(self, InlineTermStream {});
let machine_st = InlineLoadState::machine_st(&mut loader.payload); let term = loader.read_term_from_heap(term_loc);
let clause = build_rule_body(vars, term);
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 settings = CodeGenSettings { let settings = CodeGenSettings {
global_clock_tick: None, global_clock_tick: None,
@@ -2332,7 +2304,7 @@ impl Machine {
non_counted_bt: true, non_counted_bt: true,
}; };
loader.compile_standalone_clause(term, settings) loader.compile_standalone_clause(clause, settings)
}; };
let StandaloneCompileResult { clause_code, .. } = compile()?; let StandaloneCompileResult { clause_code, .. } = compile()?;

File diff suppressed because it is too large Load Diff

View File

@@ -2829,7 +2829,7 @@ impl Machine {
Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => { Some(PStrCmpResult::PartialPStrMatch { string, var_loc }) => {
let cell = backtrack_on_resource_error!( let cell = backtrack_on_resource_error!(
self.machine_st, self.machine_st,
self.machine_st.allocate_pstr(string) self.machine_st.heap.allocate_pstr(string)
); );
self.machine_st.mode = MachineMode::Write; self.machine_st.mode = MachineMode::Write;
@@ -2851,7 +2851,7 @@ impl Machine {
HeapCellValueTag::Var) => { HeapCellValueTag::Var) => {
let target_cell = backtrack_on_resource_error!( let target_cell = backtrack_on_resource_error!(
self.machine_st, self.machine_st,
self.machine_st.allocate_pstr(string) self.machine_st.heap.allocate_pstr(string)
); );
self.machine_st.bind( self.machine_st.bind(
@@ -3196,7 +3196,7 @@ impl Machine {
&Instruction::PutPartialString(_, ref string, reg) => { &Instruction::PutPartialString(_, ref string, reg) => {
self.machine_st[reg] = backtrack_on_resource_error!( self.machine_st[reg] = backtrack_on_resource_error!(
self.machine_st, self.machine_st,
self.machine_st.allocate_pstr(&string) self.machine_st.heap.allocate_pstr(&string)
); );
self.machine_st.p += 1; self.machine_st.p += 1;

View File

@@ -1,3 +1,10 @@
#[cfg(test)]
use fxhash::FxBuildHasher;
#[cfg(test)]
use indexmap::IndexMap;
#[cfg(test)]
use std::collections::BTreeMap;
#[cfg(test)] #[cfg(test)]
use crate::atom_table::*; use crate::atom_table::*;
#[cfg(test)] #[cfg(test)]
@@ -8,17 +15,6 @@ use crate::types::*;
#[cfg(test)] #[cfg(test)]
use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc}; use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
#[cfg(test)]
use std::collections::BTreeMap;
#[cfg(test)]
use std::ops::Deref;
#[cfg(test)]
use fxhash::FxBuildHasher;
#[cfg(test)]
use indexmap::IndexMap;
#[cfg(test)] #[cfg(test)]
pub(crate) trait UnmarkPolicy { pub(crate) trait UnmarkPolicy {
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue> fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
@@ -185,15 +181,6 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
pstr_loc_values: PStrLocValuesMap, 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)] #[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> { impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline] #[inline]
@@ -778,7 +765,7 @@ mod tests {
// two-part complete string, then a three-part cyclic string // two-part complete string, then a three-part cyclic string
// involving an uncompacted list of chars. // 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.push_cell(heap_loc_as_cell!(1)).unwrap();
@@ -812,7 +799,7 @@ mod tests {
wam.machine_st.heap[1] = pstr_loc_as_cell!(heap_index!(3)); 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(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(5)).unwrap();
mark_cells(&mut wam.machine_st.heap, 2); mark_cells(&mut wam.machine_st.heap, 2);

View File

@@ -4,13 +4,12 @@ use crate::functor_macro::*;
use crate::types::*; use crate::types::*;
use std::alloc; use std::alloc;
use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ops::{Bound, Index, IndexMut, Range, RangeBounds}; use std::ops::{Bound, Index, IndexMut, Range, RangeBounds};
use std::ptr; use std::ptr;
use std::sync::Once; use std::sync::Once;
use super::MachineState;
const ALIGN: usize = Heap::heap_cell_alignment(); const ALIGN: usize = Heap::heap_cell_alignment();
#[derive(Debug)] #[derive(Debug)]
@@ -92,9 +91,10 @@ pub struct HeapStringScan<'a> {
} }
// return the string at ptr and the tail location relative to ptr. // 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 string_len = heap_slice.iter().position(|b| *b == 0u8).unwrap();
let zero_byte_addr = heap_slice.as_ptr().add(string_len); let zero_byte_addr = heap_slice.as_ptr().add(string_len);
let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize); let sentinel_len = pstr_sentinel_length(zero_byte_addr as usize);
let tail_idx = cell_index!( let tail_idx = cell_index!(
(string_len + sentinel_len).next_multiple_of(ALIGN) (string_len + sentinel_len).next_multiple_of(ALIGN)
@@ -111,79 +111,9 @@ unsafe fn scan_slice_to_str<'a>(heap_slice: &'a [u8]) -> HeapStringScan<'a> {
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub(crate) enum PStrSegmentCmpResult { pub(crate) enum PStrSegmentCmpResult {
Mismatch { Less,
c1: char, Greater,
c2: char, Continue(HeapCellValue, HeapCellValue),
},
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,
} }
#[derive(Debug)] #[derive(Debug)]
@@ -269,7 +199,6 @@ impl ReservedHeapSection {
} }
self.push_cell(char_as_cell!('\u{0}')); self.push_cell(char_as_cell!('\u{0}'));
src = &src[1..]; src = &src[1..];
} }
@@ -277,8 +206,6 @@ impl ReservedHeapSection {
return ret; return ret;
} }
debug_assert!(!src.is_empty());
if let Some(null_char_idx) = src.find('\u{0}') { if let Some(null_char_idx) = src.find('\u{0}') {
debug_assert_ne!(null_char_idx, 0); debug_assert_ne!(null_char_idx, 0);
@@ -300,6 +227,7 @@ impl ReservedHeapSection {
self.push_cell(char_as_cell!('\u{0}')); self.push_cell(char_as_cell!('\u{0}'));
src = &src[null_char_idx + 1..]; src = &src[null_char_idx + 1..];
if src.is_empty() { if src.is_empty() {
return ret; return ret;
} }
@@ -316,7 +244,6 @@ impl ReservedHeapSection {
} }
self.push_pstr_segment(&src); self.push_pstr_segment(&src);
return ret; return ret;
} }
} }
@@ -449,23 +376,6 @@ impl<'a> HeapWriter<'a> {
result, 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> Index<usize> for HeapWriter<'a> {
@@ -517,8 +427,6 @@ impl<'a> SizedHeap for HeapWriter<'a> {
} }
} }
impl<'a> SizedHeapMut for HeapWriter<'a> {}
impl Heap { impl Heap {
pub(crate) fn new() -> Self { pub(crate) fn new() -> Self {
Self { Self {
@@ -638,16 +546,6 @@ impl Heap {
self.inner.byte_len == 0 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) { pub(crate) fn clear(&mut self) {
unsafe { unsafe {
let layout = alloc::Layout::array::<u8>(self.inner.byte_cap).unwrap(); let layout = alloc::Layout::array::<u8>(self.inner.byte_cap).unwrap();
@@ -699,48 +597,69 @@ impl Heap {
pstr_loc1: usize, pstr_loc1: usize,
pstr_loc2: usize, pstr_loc2: usize,
) -> PStrSegmentCmpResult { ) -> PStrSegmentCmpResult {
unsafe { let slice1 = &self.as_slice()[pstr_loc1..];
let slice1 = std::slice::from_raw_parts( let slice2 = &self.as_slice()[pstr_loc2..];
self.inner.ptr.add(pstr_loc1),
self.inner.byte_len - pstr_loc1,
);
let slice2 = std::slice::from_raw_parts( let find_tail = |null_idx: usize| -> usize { self.scan_slice_to_str(null_idx).tail_idx };
self.inner.ptr.add(pstr_loc2),
self.inner.byte_len - pstr_loc2,
);
let str1 = std::str::from_utf8_unchecked(&slice1); match slice1
let str2 = std::str::from_utf8_unchecked(&slice2); .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);
debug_assert!(!str1.is_empty()); if slice2[pos] == 0 {
debug_assert!(!str2.is_empty()); let tail2_idx = find_tail(pstr_loc2 + pos);
for ((idx, c1), c2) in str1.char_indices().zip(str2.chars()) { PStrSegmentCmpResult::Continue(
if c1 == '\u{0}' && c2 == '\u{0}' { heap_loc_as_cell!(tail1_idx),
return PStrSegmentCmpResult::BothMatch { heap_loc_as_cell!(tail2_idx),
pstr_loc1, )
pstr_loc2, } else {
null_offset: idx, PStrSegmentCmpResult::Continue(
}; heap_loc_as_cell!(tail1_idx),
} else if c1 == '\u{0}' { pstr_loc_as_cell!(pstr_loc2 + pos),
return PStrSegmentCmpResult::FirstMatch { )
pstr_loc1, }
pstr_loc2, } else if slice2[pos] == 0 {
l1_offset: idx, let tail2_idx = find_tail(pstr_loc2 + pos);
};
} else if c2 == '\u{0}' { PStrSegmentCmpResult::Continue(
return PStrSegmentCmpResult::SecondMatch { pstr_loc_as_cell!(pstr_loc1 + pos),
pstr_loc1, heap_loc_as_cell!(tail2_idx),
pstr_loc2, )
l2_offset: idx, } else {
}; // Compute 7-byte chunks with the mismatching character at pos in the middle of
} else if c1 != c2 { // each. This way, the character of which the byte at pos is a part will be
return PStrSegmentCmpResult::Mismatch { c1, c2 }; // validated and reached eventually by the utf8_chunks() iterator.
let slice1_range = pos.saturating_sub(3)..(pos + 4).min(slice1.len());
let slice2_range = pos.saturating_sub(3)..(pos + 4).min(slice2.len());
let chars1_iter = slice1[slice1_range].utf8_chunks();
let chars2_iter = slice2[slice2_range].utf8_chunks();
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!() // PStrSegmentCmpResult::Match(std::cmp::min(str1.len(), str2.len())) unreachable!()
}
}
None => {
unreachable!()
}
} }
} }
@@ -833,43 +752,34 @@ impl Heap {
Range { start, end } Range { start, end }
} }
/* pub fn allocate_pstr(&mut self, src: &str) -> Result<HeapCellValue, usize> {
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(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],
}
}
*/
pub fn allocate_pstr(&mut self, src: &str) -> Result<Option<PStrWriteInfo>, usize> {
let size_in_heap = Self::compute_pstr_size(src); 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)?;
let HeapSectionWriteResult { result, .. } = 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) => cell,
});
Ok(result.map(|cell| PStrWriteInfo { cell })) Ok(result)
}
// 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 + 1)?;
let HeapSectionWriteResult { result, .. } =
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)
} }
pub const fn heap_cell_alignment() -> usize { pub const fn heap_cell_alignment() -> usize {
@@ -1007,7 +917,7 @@ impl Heap {
// by at least two null bytes so one of them may be used // by at least two null bytes so one of them may be used
// to mark partial strings e.g. during iteration // 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>(); byte_size += 2 * size_of::<HeapCellValue>();
} else { } else {
byte_size += size_of::<HeapCellValue>(); byte_size += size_of::<HeapCellValue>();
@@ -1107,27 +1017,6 @@ impl<'a> Iterator for PStrSegmentIter<'a> {
} }
} }
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> { pub trait SizedHeap: Index<usize, Output = HeapCellValue> {
// return the size of the instance in cells // return the size of the instance in cells
fn cell_len(&self) -> usize; fn cell_len(&self) -> usize;
@@ -1141,8 +1030,6 @@ pub trait SizedHeap: Index<usize, Output = HeapCellValue> {
// fn pstr_at(&self, cell_offset: usize) -> bool; // fn pstr_at(&self, cell_offset: usize) -> bool;
} }
pub trait SizedHeapMut: IndexMut<usize, Output = HeapCellValue> + SizedHeap {}
impl Index<usize> for Heap { impl Index<usize> for Heap {
type Output = HeapCellValue; type Output = HeapCellValue;
@@ -1183,8 +1070,6 @@ impl SizedHeap for Heap {
} }
} }
impl SizedHeapMut for Heap {}
// sometimes we need to dereference variables that are found only in // sometimes we need to dereference variables that are found only in
// the heap without access to the full WAM (e.g., while detecting // the heap without access to the full WAM (e.g., while detecting
// cycles in terms), and which therefore may only point other cells in // cycles in terms), and which therefore may only point other cells in

View File

@@ -1,15 +1,18 @@
use std::cmp::Ordering;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::rc::Rc;
use crate::atom_table; use crate::atom_table;
use crate::heap_iter::{stackful_post_order_iter, NonListElider}; use crate::heap_iter::{stackful_post_order_iter, NonListElider};
use crate::machine::machine_indices::VarKey;
use crate::machine::mock_wam::CompositeOpDir; use crate::machine::mock_wam::CompositeOpDir;
use crate::machine::{ use crate::machine::{
ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC, ArenaHeaderTag, F64Offset, F64Ptr, Fixnum, Number, BREAK_FROM_DISPATCH_LOOP_LOC,
LIB_QUERY_SUCCESS, LIB_QUERY_SUCCESS,
}; };
use crate::parser::ast::{TermWriteResult, Var}; use crate::parser::ast::{Var, VarPtr};
use crate::parser::lexer::LexerParser; use crate::parser::parser::{Parser, Tokens};
use crate::parser::parser::Tokens; use crate::read::{write_term_to_heap, TermWriteResult};
use crate::types::UntypedArenaPtr; use crate::types::UntypedArenaPtr;
use dashu::{Integer, Rational}; use dashu::{Integer, Rational};
@@ -169,7 +172,7 @@ impl Term {
pub(crate) fn from_heapcell( pub(crate) fn from_heapcell(
machine: &mut Machine, machine: &mut Machine,
heap_cell: HeapCellValue, heap_cell: HeapCellValue,
var_names: &mut IndexMap<HeapCellValue, Var>, var_names: &mut IndexMap<HeapCellValue, VarPtr>,
) -> Self { ) -> Self {
// Adapted from MachineState::read_term_from_heap // Adapted from MachineState::read_term_from_heap
let mut term_stack = vec![]; let mut term_stack = vec![];
@@ -183,6 +186,16 @@ impl Term {
); );
let mut anon_count: usize = 0; 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() { while let Some(addr) = iter.next() {
let addr = unmark_cell_bits!(addr); let addr = unmark_cell_bits!(addr);
@@ -233,33 +246,34 @@ impl Term {
term_stack.push(list); term_stack.push(list);
} }
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar) => { (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 { 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 { let anon_name = loop {
// Generate a name for the anonymous variable // 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 // 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 binary_result = var_names.binary_search_by(|_,a| {
let a: &String = a.as_ref(); let var_ptr = Var::Named(anon_name.clone());
a.cmp(&anon_name) var_ptr_cmp(a.borrow().clone(), var_ptr.clone())
}); });
match binary_result { match binary_result {
Ok(_) => anon_count += 1, // Name already used Ok(_) => anon_count += 1, // Name already used
Err(_) => { Err(_) => {
// Name not used, assign it to this variable // Name not used, assign it to this variable
let var = anon_name.clone(); let var_ptr = VarPtr::from(Var::Named(anon_name.clone()));
var_names.insert(addr, Var::from(var)); var_names.insert(addr, var_ptr);
break anon_name; break anon_name;
}, },
} }
}; };
term_stack.push(Term::Var(anon_name)); term_stack.push(Term::Var(anon_name.as_ref().to_owned()));
}, },
} }
} }
@@ -401,7 +415,7 @@ pub struct QueryState<'a> {
machine: &'a mut Machine, machine: &'a mut Machine,
term: TermWriteResult, term: TermWriteResult,
stub_b: usize, stub_b: usize,
var_names: IndexMap<HeapCellValue, Var>, var_names: IndexMap<HeapCellValue, VarPtr>,
called: bool, called: bool,
} }
@@ -465,7 +479,7 @@ impl Iterator for QueryState<'_> {
} }
if machine.machine_st.p == LIB_QUERY_SUCCESS { 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(); self.machine.machine_st.backtrack();
return Some(Ok(LeafAnswer::True)); return Some(Ok(LeafAnswer::True));
} }
@@ -474,39 +488,47 @@ impl Iterator for QueryState<'_> {
} }
let mut bindings: BTreeMap<String, Term> = BTreeMap::new(); 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('_') { 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 { if !should_print {
continue; continue;
} }
} }
let var_loc = *var_loc; let mut term =
let term = Term::from_heapcell(machine, *term_to_be_printed, &mut var_names.clone());
Term::from_heapcell(machine, heap_loc_as_cell!(var_loc), &mut var_names.clone());
if let Term::Var(ref term_str) = term { if let Term::Var(ref term_str) = term {
if *term_str == **var_name { if *term_str == var_name {
continue; continue;
} }
// inverse_var_locs is in the order things appear in // Var dict is in the order things appear in the query. If var_name appears
// the query. If var_name appears after term in the // after term in the query, switch their places.
// query, switch their places. let var_name_idx = var_dict
let var_cell = machine .get_index_of(&VarKey::VarPtr(Var::from(var_name.clone()).into()))
.machine_st .unwrap();
.store(machine.machine_st.deref(machine.machine_st.heap[var_loc])); let term_idx =
var_dict.get_index_of(&VarKey::VarPtr(Var::from(term_str.clone()).into()));
if (var_cell.get_value() as usize) < var_loc { if let Some(idx) = term_idx {
bindings.insert(term_str.clone(), Term::Var(var_name.to_string())); if idx < var_name_idx {
continue; 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 // NOTE: there are outstanding choicepoints, backtrack
@@ -530,9 +552,9 @@ impl Machine {
pub fn consult_module_string(&mut self, module_name: &str, program: impl Into<String>) { 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); 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[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, &self.machine_st.atom_tbl,
module_name, module_name
)); ));
self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2)); self.run_module_predicate(atom!("loader"), (atom!("consult_stream"), 2));
@@ -564,7 +586,7 @@ impl Machine {
/// Runs a query. /// Runs a query.
pub fn run_query(&mut self, query: impl Into<String>) -> QueryState { 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), Stream::from_owned_string(query.into(), &mut self.machine_st.arena),
&mut self.machine_st, &mut self.machine_st,
); );
@@ -575,10 +597,26 @@ impl Machine {
self.allocate_stub_choice_point(); self.allocate_stub_choice_point();
// Write term to heap // Write parsed term to heap
self.machine_st.registers[1] = self.machine_st.heap[term.focus]; let term_write_result = write_term_to_heap(&term, &mut self.machine_st.heap)
self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC; .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_write_result.heap_loc];
self.machine_st.cp = LIB_QUERY_SUCCESS; // BREAK_FROM_DISPATCH_LOOP_LOC;
let call_index_p = self let call_index_p = self
.indices .indices
.code_dir .code_dir
@@ -587,22 +625,12 @@ impl Machine {
.local() .local()
.unwrap(); .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); self.machine_st.execute_at_index(1, call_index_p);
let stub_b = self.machine_st.b; let stub_b = self.machine_st.b;
QueryState { QueryState {
machine: self, machine: self,
term, term: term_write_result,
stub_b, stub_b,
var_names, var_names,
called: false, called: false,

View File

@@ -1150,8 +1150,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut path_buf = PathBuf::from(&*filename.as_str()); let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl"); path_buf.set_extension("pl");
let file = File::open(&path_buf) let file = File::open(&path_buf)?;
.map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
( (
Stream::from_file_as_input( Stream::from_file_as_input(
@@ -1232,8 +1231,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
ModuleSource::File(filename) => { ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(&*filename.as_str()); let mut path_buf = PathBuf::from(&*filename.as_str());
path_buf.set_extension("pl"); path_buf.set_extension("pl");
let file = File::open(&path_buf) let file = File::open(&path_buf)?;
.map_err(|err| ParserError::IO(err, ParserErrorSrc::default()))?;
( (
Stream::from_file_as_input( Stream::from_file_as_input(

View File

@@ -15,28 +15,12 @@ use crate::types::*;
use indexmap::IndexSet; use indexmap::IndexSet;
use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::rc::Rc;
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,
})
}
}
/* /*
* The loader compiles Prolog terms read from a TermStream instance, * The loader compiles Prolog terms read from a TermStream instance,
@@ -194,18 +178,18 @@ impl CompilationTarget {
} }
pub struct PredicateQueue { pub struct PredicateQueue {
pub predicates: Vec<TermWriteResult>, pub(super) predicates: Vec<Term>,
pub compilation_target: CompilationTarget, pub(super) compilation_target: CompilationTarget,
} }
impl PredicateQueue { impl PredicateQueue {
#[inline] #[inline]
pub(super) fn push(&mut self, term_write_result: TermWriteResult) { pub(super) fn push(&mut self, clause: Term) {
self.predicates.push(term_write_result); self.predicates.push(clause);
} }
#[inline] #[inline]
pub(crate) fn first(&self) -> Option<&TermWriteResult> { pub(crate) fn first(&self) -> Option<&Term> {
self.predicates.first() self.predicates.first()
} }
@@ -416,7 +400,7 @@ impl<'a> LoadState<'a> for BootstrappingLoadState<'a> {
#[inline(always)] #[inline(always)]
fn machine_st(loader: &mut Self::LoaderFieldType) -> &mut MachineState { 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(always)]
@@ -508,9 +492,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
} }
} }
#[inline] pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term {
pub(super) fn machine_heap(&mut self) -> &mut Heap { let machine_st = LS::machine_st(&mut self.payload);
&mut LS::machine_st(&mut self.payload).heap let cell = machine_st[r];
machine_st.read_term_from_heap(cell)
} }
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> { pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
@@ -527,30 +513,18 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let compilation_target = &load_state.compilation_target; let compilation_target = &load_state.compilation_target;
let composite_op_dir = self.wam_prelude.composite_op_dir(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 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); if !term.is_consistent(&load_state.predicates) {
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());
if term_key_opt != predicate_key_opt {
self.compile_and_submit()?; self.compile_and_submit()?;
} }
}
if Some((atom!(":-"), 1)) == term_key_opt { let term = match term {
let machine_st = LS::machine_st(&mut self.payload); Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
term.focus = term_nth_arg(&machine_st.heap, term.focus, 1).unwrap(); return Ok(Some(setup_declaration(self, terms)?));
return Ok(Some(setup_declaration(self, term)?));
} }
term => term,
};
self.payload.predicates.push(term); self.payload.predicates.push(term);
} }
@@ -788,7 +762,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
) => { ) => {
remove_constant_indices( remove_constant_indices(
constant, constant,
&overlapping_constants, overlapping_constants,
indexing_code, indexing_code,
clause_loc - index_loc, // WAS: &inner_index_locs, clause_loc - index_loc, // WAS: &inner_index_locs,
); );
@@ -1071,73 +1045,30 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let machine_st = LS::machine_st(&mut self.payload); let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r]; let cell = machine_st[r];
let focus = machine_st.heap.cell_len(); let export_list = machine_st.read_term_from_heap(cell);
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 = setup_module_export_list(export_list)?; let export_list = setup_module_export_list(export_list)?;
Ok(export_list.into_iter().collect()) Ok(export_list.into_iter().collect())
} }
fn clause_clause(&mut self, cell: HeapCellValue) -> Result<TermWriteResult, CompilationError> { fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
let machine_st = LS::machine_st(&mut self.payload); match term {
let focus = machine_st.heap.cell_len(); Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => {
let body = terms.pop().unwrap();
let head = terms.pop().unwrap();
read_heap_cell!(cell, self.payload.clause_clauses.push((head, body));
(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()))?;
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")));
}
}
});
}
(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); return Err(CompilationError::InadmissibleFact);
} }
); }
Ok( Ok(())
TermWriteResult::from(&mut machine_st.heap, heap_loc_as_cell!(focus))
.map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?,
)
} }
fn add_extensible_predicate_declaration( fn add_extensible_predicate_declaration(
@@ -1355,11 +1286,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
) )
} }
fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> { fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
let machine_st = LS::machine_st(&mut self.payload); if let Some(predicate_name) = ClauseInfo::name(term) {
let key_opt = clause_predicate_key_from_heap(&machine_st.heap, value); let predicate_arity = ClauseInfo::arity(term);
if let Some((predicate_name, predicate_arity)) = key_opt {
let predicates_compilation_target = self.payload.predicates.compilation_target; let predicates_compilation_target = self.payload.predicates.compilation_target;
let is_dynamic = self let is_dynamic = self
@@ -1373,8 +1302,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.unwrap_or(false); .unwrap_or(false);
if is_dynamic { if is_dynamic {
let clause_clause_term = self.clause_clause(value)?; self.add_clause_clause(term.clone())?;
self.payload.clause_clauses.push(clause_clause_term);
} }
} }
@@ -1440,6 +1368,90 @@ impl<'a> MachinePreludeView<'a> {
} }
} }
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 { impl Machine {
pub(crate) fn use_module(&mut self) -> CallResult { pub(crate) fn use_module(&mut self) -> CallResult {
let subevacuable_addr = self let subevacuable_addr = self
@@ -1600,15 +1612,11 @@ impl Machine {
} }
pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult { 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 mut loader = self.loader_from_heap_evacuable(temp_v!(2));
let add_clause = || { let add_clause = || {
let term = loader.read_term_from_heap(temp_v!(1));
loader.incremental_compile_clause( loader.incremental_compile_clause(
(atom!("term_expansion"), 2), (atom!("term_expansion"), 2),
term, term,
@@ -1629,37 +1637,30 @@ impl Machine {
.machine_st .machine_st
.store(self.machine_st.deref(self.machine_st.registers[1]))); .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 { let compilation_target = match target_module_name {
atom!("user") => CompilationTarget::User, atom!("user") => CompilationTarget::User,
_ => CompilationTarget::Module(target_module_name), _ => 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 add_clause = || {
let indexing_arg_opt = match term_predicate_key(&self.machine_st.heap, term.focus) { let term = loader.read_term_from_heap(temp_v!(2));
Some((atom!(":-"), _)) => term_nth_arg(&self.machine_st.heap, term.focus, 1)
.and_then(|h| term_nth_arg(&self.machine_st.heap, h, 1)), let indexing_arg = match term.name() {
Some(_) => term_nth_arg(&self.machine_st.heap, term.focus, 1), Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
Some(_) => term.first_arg(),
None => None, None => None,
}; };
let key_opt = indexing_arg_opt.and_then(|indexing_term_loc| { if let Some(indexing_term) = indexing_arg {
term_predicate_key(&self.machine_st.heap, indexing_term_loc) if let Some(indexing_name) = indexing_term.name() {
});
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
if let Some((name, arity)) = key_opt {
loader loader
.wam_prelude .wam_prelude
.indices .indices
.goal_expansion_indices .goal_expansion_indices
.insert((name, arity)); .insert((indexing_name, indexing_term.arity()));
}
} }
loader.incremental_compile_clause( loader.incremental_compile_clause(
@@ -1964,21 +1965,29 @@ impl Machine {
}; };
let stub_gen = || functor_stub(key.0, key.1); let stub_gen = || functor_stub(key.0, key.1);
let assert_clause = self.machine_st.registers[2]; let head = self.deref_register(2);
let key_opt = clause_predicate_key_from_heap(&self.machine_st.heap, assert_clause);
let mut compile_assert = |assert_clause, key_opt| { 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 = || {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> = let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User)); Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target; loader.payload.compilation_target = compilation_target;
let (name, arity) = if let Some(key) = key_opt { let head =
key LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head);
let name = if let Some(name) = head.name() {
name
} else { } else {
return Err(SessionError::from(CompilationError::InvalidRuleHead)); return Err(SessionError::from(CompilationError::InvalidRuleHead));
}; };
let arity = head.arity();
let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity)); let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
let is_dynamic_predicate = loader let is_dynamic_predicate = loader
@@ -2010,39 +2019,39 @@ impl Machine {
return LiveLoadAndMachineState::evacuate(loader); return LiveLoadAndMachineState::evacuate(loader);
} }
let body = loader.read_term_from_heap(temp_v!(3));
let asserted_clause = Term::Clause(
Cell::default(),
atom!(":-"),
vec![head.clone(), body.clone()],
);
// if a new predicate was just created, make it dynamic. // if a new predicate was just created, make it dynamic.
loader.add_dynamic_predicate(compilation_target, name, arity)?; loader.add_dynamic_predicate(compilation_target, name, arity)?;
let machine_st = LiveLoadAndMachineState::machine_st(&mut loader.payload);
// let asserted_clause = loader.copy_term_from_heap(assert_clause);
let term = TermWriteResult::from(&mut machine_st.heap, assert_clause)
.map_err(|_err_loc| ParserError::ResourceError(ParserErrorSrc::default()))?;
loader.incremental_compile_clause( loader.incremental_compile_clause(
(name, arity), (name, arity),
term, asserted_clause,
compilation_target, compilation_target,
false, false,
append_or_prepend, append_or_prepend,
)?; )?;
let clause_clause_term = loader.clause_clause(assert_clause)?;
// the global clock is incremented after each assertion. // the global clock is incremented after each assertion.
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1; LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses( loader.compile_clause_clauses(
(name, arity), (name, arity),
compilation_target, compilation_target,
vec![clause_clause_term], std::iter::once((head, body)),
append_or_prepend, append_or_prepend,
)?; )?;
LiveLoadAndMachineState::evacuate(loader) LiveLoadAndMachineState::evacuate(loader)
}; };
match compile_assert(assert_clause, key_opt) { match compile_assert() {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(SessionError::CompilationError( Err(SessionError::CompilationError(
CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact, CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
@@ -2244,23 +2253,11 @@ impl Machine {
}; };
let mut loader = self.loader_from_heap_evacuable(temp_v!(4)); 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 = LiveLoadAndMachineState::machine_st(&mut loader.payload).fail =
(!loader.payload.predicates.is_empty() (!loader.payload.predicates.is_empty()
&& loader.payload.predicates.compilation_target != compilation_target) && loader.payload.predicates.compilation_target != compilation_target)
|| !is_consistent; || !key.is_consistent(&loader.payload.predicates);
let result = LiveLoadAndMachineState::evacuate(loader); let result = LiveLoadAndMachineState::evacuate(loader);
self.restore_load_state_payload(result) self.restore_load_state_payload(result)
@@ -2467,17 +2464,11 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
self.payload.predicates.compilation_target = compilation_target; self.payload.predicates.compilation_target = compilation_target;
} }
let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload); let term = self.read_term_from_heap(term_reg);
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()))?;
self.add_clause_clause_if_dynamic(&term)?;
self.payload.term_stream.term_queue.push_back(term); self.payload.term_stream.term_queue.push_back(term);
self.load() self.load()
} }
} }

View File

@@ -19,7 +19,7 @@ pub type MachineStubGen = Box<dyn Fn(&mut MachineState) -> MachineStub>;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct MachineError { pub(crate) struct MachineError {
stub: MachineStub, stub: MachineStub,
location: Option<ParserErrorSrc>, location: Option<(usize, usize)>, // line_num, col_num
} }
// from 7.12.2 b) of 13211-1:1995 // from 7.12.2 b) of 13211-1:1995
@@ -301,7 +301,7 @@ impl MachineState {
} }
} }
pub(super) fn resource_error(&mut self, err: ResourceError) -> MachineError { pub(super) fn resource_error(err: ResourceError) -> MachineError {
let stub = match err { let stub = match err {
ResourceError::FiniteMemory(size_requested) => { ResourceError::FiniteMemory(size_requested) => {
functor!( functor!(
@@ -466,10 +466,10 @@ impl MachineState {
fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError { fn arithmetic_error(&mut self, err: ArithmeticError) -> MachineError {
match err { match err {
ArithmeticError::NonEvaluableFunctor(cell, arity) => { 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) self.type_error(ValidType::Evaluable, culprit)
} }
ArithmeticError::UninstantiatedVar => self.instantiation_error(),
} }
} }
@@ -609,7 +609,7 @@ impl MachineState {
} }
pub(super) fn error_form(&mut self, err: MachineError, src: MachineStub) -> MachineStub { 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!( functor!(
atom!("error"), atom!("error"),
[ [
@@ -665,16 +665,17 @@ pub enum CompilationError {
InvalidRuleHead, InvalidRuleHead,
InvalidUseModuleDecl, InvalidUseModuleDecl,
InvalidModuleResolution(Atom), InvalidModuleResolution(Atom),
FiniteMemoryInHeap(usize),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum DirectiveError { pub enum DirectiveError {
ExpectedDirective(HeapCellValue), ExpectedDirective(Term),
InvalidDirective(Atom, usize /* arity */), InvalidDirective(Atom, usize /* arity */),
InvalidOpDeclNameType(HeapCellValue), InvalidOpDeclNameType(Term),
InvalidOpDeclSpecDomain(HeapCellValue), InvalidOpDeclSpecDomain(Term),
InvalidOpDeclSpecValue(Atom), InvalidOpDeclSpecValue(Atom),
InvalidOpDeclPrecType(HeapCellValue), InvalidOpDeclPrecType(Term),
InvalidOpDeclPrecDomain(Fixnum), InvalidOpDeclPrecDomain(Fixnum),
ShallNotCreate(Atom), ShallNotCreate(Atom),
ShallNotModify(Atom), ShallNotModify(Atom),
@@ -695,9 +696,9 @@ impl From<ParserError> for CompilationError {
} }
impl CompilationError { 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 { match self {
CompilationError::ParserError(err) => Some(err.err_src()), CompilationError::ParserError(err) => err.line_and_col_num(),
_ => None, _ => None,
} }
} }
@@ -740,6 +741,9 @@ impl CompilationError {
CompilationError::ParserError(ref err) => { CompilationError::ParserError(ref err) => {
functor!(err.as_atom()) functor!(err.as_atom())
} }
CompilationError::FiniteMemoryInHeap(h) => {
vec![FunctorElement::AbsoluteCell(str_loc_as_cell!(*h))]
}
} }
} }
} }
@@ -1015,6 +1019,13 @@ pub enum SessionError {
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey), 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 { impl From<ParserError> for SessionError {
#[inline] #[inline]
fn from(err: ParserError) -> Self { fn from(err: ParserError) -> Self {

View File

@@ -21,8 +21,6 @@ use std::collections::BTreeSet;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::types::*; use crate::types::*;
// #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
// pub(crate) struct OrderedOpDirKey(pub(crate) Atom, pub(crate) Fixity);
// 7.2 // 7.2
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
@@ -223,6 +221,30 @@ impl CodeIndex {
*/ */
} }
#[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 GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>; pub(crate) type StreamAliasDir = IndexMap<Atom, Stream, FxBuildHasher>;
@@ -279,9 +301,11 @@ impl IndexStore {
_ => self _ => self
.get_meta_predicate_spec(key.0, key.1, &compilation_target) .get_meta_predicate_spec(key.0, key.1, &compilation_target)
.map(|meta_specs| { .map(|meta_specs| {
meta_specs.iter().find(|meta_spec| match meta_spec { meta_specs.iter().find(|meta_spec| {
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_) => true, matches!(
_ => false, meta_spec,
MetaSpec::Colon | MetaSpec::RequiresExpansionWithArgument(_)
)
}) })
}) })
.map(|meta_spec_opt| meta_spec_opt.is_some()) .map(|meta_spec_opt| meta_spec_opt.is_some())

View File

@@ -13,6 +13,7 @@ use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::machine::Machine; use crate::machine::Machine;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::read::TermWriteResult;
use crate::types::*; use crate::types::*;
use crate::parser::dashu::Integer; use crate::parser::dashu::Integer;
@@ -22,7 +23,6 @@ use indexmap::IndexMap;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::ops::{Index, IndexMut, Range}; use std::ops::{Index, IndexMut, Range};
use std::rc::Rc;
use std::sync::Arc; use std::sync::Arc;
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1]; pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
@@ -72,7 +72,7 @@ pub struct MachineState {
pub(super) e: usize, pub(super) e: usize,
pub(super) num_of_args: usize, pub(super) num_of_args: usize,
pub(super) cp: usize, pub(super) cp: usize,
pub(crate) attr_var_init: AttrVarInitializer, pub(super) attr_var_init: AttrVarInitializer,
pub(super) fail: bool, pub(super) fail: bool,
pub heap: Heap, pub heap: Heap,
pub(super) mode: MachineMode, pub(super) mode: MachineMode,
@@ -203,26 +203,32 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
} }
*/ */
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, heap: &mut Heap,
size: usize, size: usize,
iter: impl Iterator<Item = (usize, Var)>, iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
atom_tbl: &AtomTable, atom_tbl: &AtomTable,
) -> Result<HeapCellValue, usize> { ) -> Result<HeapCellValue, usize> {
let src_h = heap.cell_len(); let src_h = heap.cell_len();
if size > 0 { let true_size = if size > 0 {
let mut writer = heap.reserve(1 + 5 * size)?; let mut writer = heap.reserve(2 + 5 * size)?;
writer.write_with(|section| { writer
for (var_loc, var) in iter { .write_with(|section| {
// (var, binding) in iter { let mut size = 0;
for (var, binding) in iter {
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string()); let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
let binding = heap_loc_as_cell!(var_loc);
section.push_cell(atom_as_cell!(atom!("="), 2)); section.push_cell(atom_as_cell!(atom!("="), 2));
section.push_cell(atom_as_cell!(var_atom)); section.push_cell(atom_as_cell!(var_atom));
section.push_cell(binding); section.push_cell(*binding);
size += 1;
} }
for idx in 0..size { for idx in 0..size {
@@ -230,25 +236,23 @@ fn push_var_eq_functors(
section.push_cell(str_loc_as_cell!(src_h + 3 * idx)); section.push_cell(str_loc_as_cell!(src_h + 3 * idx));
} }
if size > 0 {
section.push_cell(empty_list_as_cell!()); section.push_cell(empty_list_as_cell!());
});
Ok(heap_loc_as_cell!(src_h + 3 * size))
} else {
Ok(empty_list_as_cell!())
} }
}
/* size
pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>( })
iter: Iter, .result
boundary: i64, } else {
h: i64, size
) -> 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)] #[derive(Debug)]
pub struct Ball { pub struct Ball {
@@ -377,7 +381,7 @@ impl<'a> CopierTarget for CopyTerm<'a> {
} }
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct CopyBallTerm<'a> { pub(super) struct CopyBallTerm<'a> {
attr_var_queue: &'a mut Vec<usize>, attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack, stack: &'a mut Stack,
heap: &'a mut Heap, heap: &'a mut Heap,
@@ -385,7 +389,7 @@ pub(crate) struct CopyBallTerm<'a> {
} }
impl<'a> CopyBallTerm<'a> { impl<'a> CopyBallTerm<'a> {
pub(crate) fn new( pub(super) fn new(
attr_var_queue: &'a mut Vec<usize>, attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack, stack: &'a mut Stack,
heap: &'a mut Heap, heap: &'a mut Heap,
@@ -629,24 +633,13 @@ impl MachineState {
pub fn write_read_term_options( pub fn write_read_term_options(
&mut self, &mut self,
mut var_list: Vec<(Var, HeapCellValue, usize)>, mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
singletons_heap_list: HeapCellValue, singleton_heap_list: HeapCellValue,
) -> CallResult { ) -> CallResult {
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2)); 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]; 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 { if self.fail {
return Ok(()); return Ok(());
@@ -669,21 +662,18 @@ impl MachineState {
} }
let var_names_addr = self.registers[5]; 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!( let var_names_offset = resource_error_call_result!(
self, self,
push_var_eq_functors( push_var_eq_functors(
&mut self.heap, &mut self.heap,
var_list.len(), var_list.len(),
var_list var_list.iter().filter_map(|(var_name, var, _)| {
.iter() if var_name.is_anon() {
.map(|(var_name, var, _)| { (var.get_value() as usize, var_name.clone()) }), None
} else {
Some((var_name, var))
}
}),
&self.atom_tbl, &self.atom_tbl,
) )
); );
@@ -691,37 +681,22 @@ impl MachineState {
Ok(unify_fn!(*self, var_names_offset, var_names_addr)) Ok(unify_fn!(*self, var_names_offset, var_names_addr))
} }
pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult { pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
let heap_loc = self.heap[term.focus]; let heap_loc = heap_loc_as_cell!(term_write_result.heap_loc);
/*
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)
}
);
*/
unify_fn!(*self, heap_loc, self.registers[2]); unify_fn!(*self, heap_loc, self.registers[2]);
if self.fail { if self.fail {
return Ok(()); return Ok(());
} }
/*
for var in term_write_result.var_dict.values_mut() { for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var); *var = heap_bound_deref(&self.heap, *var);
} }
*/
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new(); let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
self.heap[0] = heap_loc;
for cell in for cell in stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0) {
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, term.focus)
{
let cell = unmark_cell_bits!(cell); let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.as_var() { if let Some(var) = cell.as_var() {
@@ -737,38 +712,36 @@ impl MachineState {
self, self,
push_var_eq_functors( push_var_eq_functors(
&mut self.heap, &mut self.heap,
singleton_var_set term_write_result.var_dict.len(),
term_write_result
.var_dict
.iter() .iter()
.filter(|(var, is_singleton)| { .filter(|(var_name, binding)| {
**is_singleton if var_name.is_anon() {
&& term return false;
.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);
if singleton_var_set.get(&r).cloned().unwrap_or(false) { if let Some(r) = binding.as_var() {
Some((*var_loc, var_name.clone())) *singleton_var_set.get(&r).unwrap_or(&false)
} else { } else {
None false
} }
}), }),
&self.atom_tbl, &self.atom_tbl,
) )
); );
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
let mut var_list = Vec::with_capacity(singleton_var_set.len()); let mut var_list = Vec::with_capacity(singleton_var_set.len());
for (var_loc, var_name) in term.inverse_var_locs { for (var_name, addr) in term_write_result.var_dict {
let r = Ref::heap_cell(var_loc); if let Some(var) = addr.as_var() {
let cell = self.heap[var_loc]; if let Some(idx) = singleton_var_set.get_index_of(&var) {
var_list.push((var_name, addr, idx));
if let Some(idx) = singleton_var_set.get_index_of(&r) { }
var_list.push((var_name, cell, idx));
} }
} }
@@ -851,8 +824,8 @@ impl MachineState {
} }
loop { loop {
match self.read_to_heap(stream, &indices.op_dir) { match self.read(stream, &indices.op_dir) {
Ok(term) => return self.read_term_body(term), Ok(term_write_result) => return self.read_term_body(term_write_result),
Err(err) => { Err(err) => {
match &err { match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => { CompilationError::ParserError(e) if e.is_unexpected_eof() => {
@@ -891,7 +864,7 @@ impl MachineState {
let printer = match self.try_from_list(self.registers[6], stub_gen) { let printer = match self.try_from_list(self.registers[6], stub_gen) {
Ok(addrs) => { Ok(addrs) => {
let mut var_names: IndexMap<HeapCellValue, Var> = IndexMap::new(); let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
for addr in addrs { for addr in addrs {
read_heap_cell!(addr, read_heap_cell!(addr,
@@ -910,14 +883,14 @@ impl MachineState {
read_heap_cell!(atom, read_heap_cell!(atom,
(HeapCellValueTag::Atom, (name, _arity)) => { (HeapCellValueTag::Atom, (name, _arity)) => {
debug_assert_eq!(_arity, 0); 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) => { (HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(self.heap[s]) let (name, arity) = cell_as_atom_cell!(self.heap[s])
.get_name_and_arity(); .get_name_and_arity();
debug_assert_eq!(arity, 0); 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!(); unreachable!();
@@ -996,18 +969,14 @@ impl MachineState {
} }
); );
let term_loc = self.heap.cell_len(); self.heap[0] = term_to_be_printed;
step_or_resource_error!(self, self.heap.push_cell(term_to_be_printed), {
return Ok(None);
});
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.heap, &mut self.heap,
&mut self.stack, &mut self.stack,
op_dir, op_dir,
PrinterOutputter::new(), PrinterOutputter::new(),
term_loc, 0,
); );
printer.ignore_ops = ignore_ops; printer.ignore_ops = ignore_ops;
@@ -1040,7 +1009,6 @@ impl MachineState {
} }
printer.var_names = var_names; printer.var_names = var_names;
printer printer
} }
Err(err) => { Err(err) => {

View File

@@ -621,10 +621,17 @@ impl MachineState {
(HeapCellValueTag::PStrLoc, l1) => { (HeapCellValueTag::PStrLoc, l1) => {
read_heap_cell!(v2, read_heap_cell!(v2,
(HeapCellValueTag::PStrLoc, l2) => { (HeapCellValueTag::PStrLoc, l2) => {
let cmp_result = self.heap.compare_pstr_segments(l1, l2); match self.heap.compare_pstr_segments(l1, l2) {
PStrSegmentCmpResult::Continue(v1, v2) => {
if let Some(ordering) = cmp_result.continue_pstr_compare(&mut self.pdl) { self.pdl.push(v1);
return Some(ordering); self.pdl.push(v2);
}
PStrSegmentCmpResult::Less => {
return Some(Ordering::Less);
}
PStrSegmentCmpResult::Greater => {
return Some(Ordering::Greater);
}
} }
} }
(HeapCellValueTag::Lis, l2) => { (HeapCellValueTag::Lis, l2) => {
@@ -747,38 +754,6 @@ impl MachineState {
Some(Ordering::Equal) 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( pub(crate) fn setup_call_n_init_goal_info(
&mut self, &mut self,
goal: HeapCellValue, goal: HeapCellValue,

View File

@@ -7,6 +7,7 @@ pub use crate::parser::ast::*;
#[cfg(test)] #[cfg(test)]
use crate::machine::copier::CopierTarget; use crate::machine::copier::CopierTarget;
use crate::read::TermWriteResult;
#[cfg(test)] #[cfg(test)]
use std::ops::{Deref, DerefMut, Index, IndexMut, Range}; use std::ops::{Deref, DerefMut, Index, IndexMut, Range};
@@ -34,7 +35,7 @@ impl MockWAM {
&mut self, &mut self,
input_stream: Stream, input_stream: Stream,
) -> Result<TermWriteResult, CompilationError> { ) -> 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( pub fn parse_and_write_parsed_term_to_heap(
@@ -50,24 +51,24 @@ impl MockWAM {
term_string: &'static str, term_string: &'static str,
) -> Result<String, CompilationError> { ) -> Result<String, CompilationError> {
let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?; let term_write_result = self.parse_and_write_parsed_term_to_heap(term_string)?;
print_heap_terms(&self.machine_st.heap, term_write_result.heap_loc);
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();
let mut printer = HCPrinter::new( let mut printer = HCPrinter::new(
&mut self.machine_st.heap, &mut self.machine_st.heap,
&mut self.machine_st.stack, &mut self.machine_st.stack,
&self.op_dir, &self.op_dir,
PrinterOutputter::new(), 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()) Ok(printer.print().result())
} }
@@ -238,7 +239,7 @@ pub(crate) fn write_parsed_term_to_heap(
input_stream: Stream, input_stream: Stream,
op_dir: &OpDir, op_dir: &OpDir,
) -> Result<TermWriteResult, CompilationError> { ) -> Result<TermWriteResult, CompilationError> {
machine_st.read_to_heap(input_stream, op_dir) machine_st.read(input_stream, op_dir)
} }
#[cfg(test)] #[cfg(test)]
@@ -298,7 +299,7 @@ mod tests {
unify!( unify!(
wam, wam,
str_loc_as_cell!(0), 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); assert!(wam.fail);
@@ -310,7 +311,6 @@ mod tests {
wam.heap.clear(); 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 = let term_write_result_2 =
@@ -318,8 +318,8 @@ mod tests {
unify!( unify!(
wam, wam,
heap_loc_as_cell!(term_write_result_1.focus), str_loc_as_cell!(1),
heap_loc_as_cell!(term_write_result_2.focus) heap_loc_as_cell!(term_write_result_2.heap_loc)
); );
assert!(!wam.fail); assert!(!wam.fail);
@@ -331,7 +331,6 @@ mod tests {
wam.heap.clear(); 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 = let term_write_result_2 =
@@ -339,8 +338,8 @@ mod tests {
unify!( unify!(
wam, wam,
heap_loc_as_cell!(term_write_result_1.focus), heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.focus) heap_loc_as_cell!(term_write_result_2.heap_loc)
); );
assert!(!wam.fail); assert!(!wam.fail);
@@ -352,7 +351,6 @@ mod tests {
wam.heap.clear(); 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 = let term_write_result_2 =
@@ -360,8 +358,8 @@ mod tests {
unify!( unify!(
wam, wam,
heap_loc_as_cell!(term_write_result_1.focus), heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.focus) heap_loc_as_cell!(term_write_result_2.heap_loc)
); );
assert!(!wam.fail); assert!(!wam.fail);
@@ -373,7 +371,6 @@ mod tests {
wam.heap.clear(); 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 = let term_write_result_2 =
@@ -381,8 +378,8 @@ mod tests {
unify!( unify!(
wam, wam,
heap_loc_as_cell!(term_write_result_1.focus), heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.focus) heap_loc_as_cell!(term_write_result_2.heap_loc)
); );
assert!(!wam.fail); assert!(!wam.fail);
@@ -394,7 +391,6 @@ mod tests {
wam.heap.clear(); 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 = let term_write_result_2 =
@@ -404,8 +400,8 @@ mod tests {
unify!( unify!(
wam, wam,
heap_loc_as_cell!(term_write_result_1.focus), heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.focus) heap_loc_as_cell!(term_write_result_2.heap_loc)
); );
assert!(!wam.fail); assert!(!wam.fail);
@@ -526,8 +522,21 @@ mod tests {
}); });
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5)); unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(!wam.fail); assert!(!wam.fail);
all_cells_unmarked(&wam.heap); 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] #[test]
@@ -550,8 +559,8 @@ mod tests {
unify_with_occurs_check!( unify_with_occurs_check!(
wam, wam,
heap_loc_as_cell!(0), str_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.focus) str_loc_as_cell!(term_write_result_2.heap_loc)
); );
assert!(wam.fail); assert!(wam.fail);
@@ -594,7 +603,7 @@ mod tests {
Some(Ordering::Equal) Some(Ordering::Equal)
); );
let cstr_cell = wam.allocate_cstr("string").unwrap(); let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!( assert_eq!(
compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell), compare_term_test!(wam, atom_as_cell!(atom!("atom")), cstr_cell),
@@ -693,7 +702,7 @@ mod tests {
Some(Ordering::Greater) Some(Ordering::Greater)
); );
let cstr_cell = wam.allocate_cstr("string").unwrap(); let cstr_cell = wam.heap.allocate_cstr("string").unwrap();
assert_eq!( assert_eq!(
compare_term_test!(wam, empty_list_as_cell!(), cstr_cell), compare_term_test!(wam, empty_list_as_cell!(), cstr_cell),
@@ -782,7 +791,7 @@ mod tests {
wam.heap.clear(); wam.heap.clear();
let h = wam.heap.cell_len(); 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)); assert!(!wam.is_cyclic_term(h));
} }

View File

@@ -1114,7 +1114,6 @@ impl Machine {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() { if let Some(idx) = self.indices.code_dir.get(&(name, arity)).cloned() {
self.try_execute(name, arity, idx.get()) self.try_execute(name, arity, idx.get())
} else { } else {
println!("aaand undefined!");
self.undefined_procedure(name, arity) self.undefined_procedure(name, arity)
} }
} else if let Some(module) = self.indices.modules.get(&module_name) { } else if let Some(module) = self.indices.modules.get(&module_name) {

View File

@@ -363,7 +363,7 @@ mod test {
fn pstr_iter_tests() { fn pstr_iter_tests() {
let mut wam = MockWAM::new(); 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 wam.machine_st
.heap .heap
.push_cell(empty_list_as_cell!()) .push_cell(empty_list_as_cell!())
@@ -391,7 +391,7 @@ mod test {
wam.machine_st.heap[2] = pstr_loc_as_cell!(heap_index!(3)); 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(); let h = wam.machine_st.heap.cell_len();
wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap(); wam.machine_st.heap.push_cell(heap_loc_as_cell!(h)).unwrap();
@@ -456,7 +456,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -484,7 +484,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -515,7 +515,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -534,7 +534,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -564,7 +564,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -602,7 +602,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -629,7 +629,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -653,7 +653,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -678,7 +678,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -706,7 +706,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -733,7 +733,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -764,7 +764,7 @@ mod test {
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();
@@ -791,7 +791,7 @@ mod test {
// #2293, test7. // #2293, test7.
wam.machine_st.heap.clear(); 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 start = wam.machine_st.heap.cell_len();
let mut writer = wam.machine_st.heap.reserve(16).unwrap(); let mut writer = wam.machine_st.heap.reserve(16).unwrap();

View File

@@ -3,17 +3,13 @@ use crate::codegen::CodeGenSettings;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::disjuncts::*; use crate::machine::disjuncts::*;
use crate::machine::heap::*;
use crate::machine::loader::*; use crate::machine::loader::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::CodeIndex;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::types::*;
use fxhash::FxBuildHasher;
use indexmap::IndexMap;
use indexmap::IndexSet; use indexmap::IndexSet;
use std::cell::Cell;
use std::convert::TryFrom; use std::convert::TryFrom;
pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl { pub(crate) fn to_op_decl(prec: u16, spec: OpDeclSpec, name: Atom) -> OpDecl {
OpDecl::new(OpDesc::build_with(prec, spec), name) OpDecl::new(OpDesc::build_with(prec, spec), name)
@@ -25,47 +21,43 @@ pub(crate) fn to_op_decl_spec(spec: Atom) -> Result<OpDeclSpec, CompilationError
}) })
} }
fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> { fn setup_op_decl(mut terms: Vec<Term>) -> Result<OpDecl, CompilationError> {
let (focus, _cell) = subterm_index(term.heap, term.focus); // should allow non-partial lists?
let name = match terms.pop().unwrap() {
let name = match term_predicate_key(term.heap, focus + 3) { Term::Literal(_, Literal::Atom(name)) => name,
Some((name, 0)) => name, other => {
_ => {
return Err(CompilationError::InvalidDirective( return Err(CompilationError::InvalidDirective(
DirectiveError::InvalidOpDeclNameType(term.heap[focus + 3]), DirectiveError::InvalidOpDeclNameType(other),
)); ));
} }
}; };
let spec = match term_predicate_key(term.heap, focus + 2) { let spec = match terms.pop().unwrap() {
Some((name, _)) => name, Term::Literal(_, Literal::Atom(name)) => name,
None => { other => {
return Err(CompilationError::InvalidDirective( return Err(CompilationError::InvalidDirective(
DirectiveError::InvalidOpDeclSpecDomain(term.heap[focus + 2]), DirectiveError::InvalidOpDeclSpecDomain(other),
)); ))
} }
}; };
let spec = to_op_decl_spec(spec)?; let spec = to_op_decl_spec(spec)?;
let prec = term.deref_loc(focus + 1);
let prec = read_heap_cell!(prec, let prec = match terms.pop().unwrap() {
(HeapCellValueTag::Fixnum, n) => { Term::Literal(_, Literal::Fixnum(bi)) => match u16::try_from(bi.get_num()) {
match u16::try_from(n.get_num()) {
Ok(n) if n <= 1200 => n, Ok(n) if n <= 1200 => n,
_ => { _ => {
return Err(CompilationError::InvalidDirective( return Err(CompilationError::InvalidDirective(
DirectiveError::InvalidOpDeclPrecDomain(n), DirectiveError::InvalidOpDeclPrecDomain(bi),
)); ));
} }
} },
} other => {
_ => {
return Err(CompilationError::InvalidDirective( return Err(CompilationError::InvalidDirective(
DirectiveError::InvalidOpDeclPrecType(prec), DirectiveError::InvalidOpDeclPrecType(other),
)); ));
} }
); };
if name == "[]" || name == "{}" { if name == "[]" || name == "{}" {
return Err(CompilationError::InvalidDirective( return Err(CompilationError::InvalidDirective(
@@ -88,162 +80,129 @@ fn setup_op_decl(term: &FocusedHeapRefMut) -> Result<OpDecl, CompilationError> {
Ok(to_op_decl(prec, spec, name)) Ok(to_op_decl(prec, spec, name))
} }
fn setup_predicate_indicator(term: &FocusedHeapRefMut) -> Result<PredicateKey, CompilationError> { fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError> {
let key_opt = term_predicate_key(term.heap, term.focus); 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();
if let Some((atom!("/") | atom!("//"), 2)) = key_opt { let arity = match arity {
let arity_loc = term.nth_arg(term.focus, 2).unwrap(); Term::Literal(_, Literal::Integer(n)) => (&*n).try_into().ok(),
Term::Literal(_, Literal::Fixnum(n)) => usize::try_from(n.get_num()).ok(),
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, _ => None,
} }
.ok_or(CompilationError::InvalidModuleExport)?; .ok_or(CompilationError::InvalidModuleExport)?;
let name_loc = term.nth_arg(term.focus, 1).unwrap(); let name = match name {
let name = term_predicate_key(term.heap, name_loc) Term::Literal(_, Literal::Atom(name)) => Some(name),
.map(|(name, _)| name) _ => None,
}
.ok_or(CompilationError::InvalidModuleExport)?; .ok_or(CompilationError::InvalidModuleExport)?;
if matches!(key_opt, Some((atom!("/"), _))) { if *slash == atom!("/") {
Ok((name, arity)) Ok((name, arity))
} else { } else {
Ok((name, arity + 2)) Ok((name, arity + 2))
} }
} else { }
Err(CompilationError::InvalidModuleExport) _ => Err(CompilationError::InvalidModuleExport),
} }
} }
fn setup_module_export(term: &FocusedHeapRefMut) -> Result<ModuleExport, CompilationError> { fn setup_module_export(mut term: Term) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(term) setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey) .map(ModuleExport::PredicateKey)
.or_else(|_| { .or_else(|_| {
let key_opt = term_predicate_key(term.heap, term.focus); if let Term::Clause(_, name, terms) = term {
if terms.len() == 3 && name == atom!("op") {
if let Some((atom!("op"), 3)) = key_opt { Ok(ModuleExport::OpDecl(setup_op_decl(terms)?))
Ok(ModuleExport::OpDecl(setup_op_decl(term)?)) } else {
Err(CompilationError::InvalidModuleDecl)
}
} else { } else {
Err(CompilationError::InvalidModuleDecl) Err(CompilationError::InvalidModuleDecl)
} }
}) })
} }
/* TODO: should be unnecessary now.
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term { pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec()); let head_term = Term::Clause(Cell::default(), atom!(""), vars.to_vec());
let rule = vec![head_term, body_term]; let rule = vec![head_term, body_term];
Term::Clause(Cell::default(), atom!(":-"), rule) Term::Clause(Cell::default(), atom!(":-"), rule)
} }
*/
pub(super) fn setup_module_export_list( pub(super) fn setup_module_export_list(
term: FocusedHeapRefMut, mut export_list: Term,
) -> Result<Vec<ModuleExport>, CompilationError> { ) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![]; let mut exports = vec![];
let mut focus = term.focus;
loop { while let Term::Cons(_, t1, t2) = export_list {
read_heap_cell!(term.heap[focus], let module_export = setup_module_export(*t1)?;
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if h == focus { exports.push(module_export);
break; export_list = *t2;
}
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok(exports)
} else { } 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;
}
);
}
Err(CompilationError::InvalidModuleDecl) Err(CompilationError::InvalidModuleDecl)
}
} }
fn setup_module_decl(mut term: FocusedHeapRefMut) -> Result<ModuleDecl, CompilationError> { fn setup_module_decl(mut terms: Vec<Term>) -> Result<ModuleDecl, CompilationError> {
let name = term_predicate_key(term.heap, term.focus + 1) let export_list = terms.pop().unwrap();
.map(|(name, _)| name) let name = terms.pop().unwrap();
let name = match name {
Term::Literal(_, Literal::Atom(name)) => Some(name),
_ => None,
}
.ok_or(CompilationError::InvalidModuleDecl)?; .ok_or(CompilationError::InvalidModuleDecl)?;
term.focus = term.focus + 2; let exports = setup_module_export_list(export_list)?;
let exports = setup_module_export_list(term)?;
Ok(ModuleDecl { name, exports }) Ok(ModuleDecl { name, exports })
} }
fn setup_use_module_decl(term: &FocusedHeapRefMut) -> Result<ModuleSource, CompilationError> { fn setup_use_module_decl(mut terms: Vec<Term>) -> Result<ModuleSource, CompilationError> {
read_heap_cell!(term.deref_loc(term.focus+1), match terms.pop().unwrap() {
(HeapCellValueTag::Str, s) => { Term::Clause(_, name, mut terms) if name == atom!("library") && terms.len() == 1 => {
let (name, arity) = cell_as_atom_cell!(term.heap[s]).get_name_and_arity(); match terms.pop().unwrap() {
Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::Library(name)),
if (name, arity) == (atom!("library"), 1) { _ => Err(CompilationError::InvalidModuleDecl),
read_heap_cell!(term.deref_loc(s+1),
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
return Ok(ModuleSource::Library(name));
} }
} }
_ => { Term::Literal(_, Literal::Atom(name)) => Ok(ModuleSource::File(name)),
_ => Err(CompilationError::InvalidUseModuleDecl),
} }
)
}
return Err(CompilationError::InvalidModuleDecl);
}
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
Ok(ModuleSource::File(name))
} else {
Err(CompilationError::InvalidUseModuleDecl)
}
}
_ => {
Err(CompilationError::InvalidUseModuleDecl)
}
)
} }
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>); type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, CompilationError> { fn setup_qualified_import(mut terms: Vec<Term>) -> Result<UseModuleExport, CompilationError> {
let module_src = setup_use_module_decl(&term)?; 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 mut exports = IndexSet::new(); let mut exports = IndexSet::new();
let mut focus = term.focus + 2; while let Term::Cons(_, t1, t2) = export_list {
exports.insert(setup_module_export(*t1)?);
while let HeapCellValueTag::Lis = term.heap[focus].get_tag() { export_list = *t2;
focus = term.heap[focus].get_value() as usize;
let term = FocusedHeapRefMut {
heap: term.heap,
focus,
};
exports.insert(setup_module_export(&term)?);
focus = focus + 1;
} }
if term.heap[focus] == empty_list_as_cell!() { if let Term::Literal(_, Literal::Atom(atom!("[]"))) = export_list {
Ok((module_src, exports)) Ok((module_src, exports))
} else { } else {
Err(CompilationError::InvalidModuleDecl) Err(CompilationError::InvalidModuleDecl)
@@ -290,20 +249,18 @@ fn setup_qualified_import(term: FocusedHeapRefMut) -> Result<UseModuleExport, Co
*/ */
fn setup_meta_predicate<'a, LS: LoadState<'a>>( fn setup_meta_predicate<'a, LS: LoadState<'a>>(
term: TermWriteResult, mut terms: Vec<Term>,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> { ) -> Result<(Atom, Atom, Vec<MetaSpec>), CompilationError> {
fn get_meta_specs( fn get_name_and_meta_specs(
term: FocusedHeapRefMut, name: Atom,
arity: usize, terms: &mut [Term],
) -> Result<Vec<MetaSpec>, CompilationError> { ) -> Result<(Atom, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![]; let mut meta_specs = vec![];
for meta_spec_loc in term.focus + 1..term.focus + arity + 1 { for meta_spec in terms.iter_mut() {
read_heap_cell!(term.deref_loc(meta_spec_loc), match meta_spec {
(HeapCellValueTag::Atom, (meta_spec, arity)) => { Term::Literal(_, Literal::Atom(meta_spec)) => {
debug_assert_eq!(arity, 0);
let meta_spec = match meta_spec { let meta_spec = match meta_spec {
atom!("+") => MetaSpec::Plus, atom!("+") => MetaSpec::Plus,
atom!("-") => MetaSpec::Minus, atom!("-") => MetaSpec::Minus,
@@ -314,322 +271,263 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
meta_specs.push(meta_spec); meta_specs.push(meta_spec);
} }
(HeapCellValueTag::Fixnum, n) => { Term::Literal(_, Literal::Fixnum(n)) => match usize::try_from(n.get_num()) {
match usize::try_from(n.get_num()) {
Ok(n) if n <= MAX_ARITY => { Ok(n) if n <= MAX_ARITY => {
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n)); meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
} }
_ => { _ => {
return Err(CompilationError::InvalidMetaPredicateDecl); return Err(CompilationError::InvalidMetaPredicateDecl);
} }
} },
}
_ => { _ => {
return Err(CompilationError::InvalidMetaPredicateDecl); return Err(CompilationError::InvalidMetaPredicateDecl);
} }
);
}
Ok(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();
return Ok((module_name, name, specs));
} }
} }
Err(CompilationError::InvalidMetaPredicateDecl) Ok((name, meta_specs))
} }
_ => {
Err(CompilationError::InvalidMetaPredicateDecl) 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();
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),
}
}
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>>( pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
mut term: TermWriteResult, mut terms: Vec<Term>,
) -> Result<Declaration, CompilationError> { ) -> Result<Declaration, CompilationError> {
let mut focus = term.focus; let term = terms.pop().unwrap();
let machine_st = LS::machine_st(&mut loader.payload);
loop { match term {
let decl = machine_st.heap[focus]; Term::Clause(_, name, mut terms) => match (name, terms.len()) {
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) => { (atom!("dynamic"), 1) => {
let (name, arity) = setup_predicate_indicator(&focused)?; let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity)) Ok(Declaration::Dynamic(name, arity))
} }
(atom!("module"), 2) => { (atom!("module"), 2) => Ok(Declaration::Module(setup_module_decl(terms)?)),
Ok(Declaration::Module(setup_module_decl(focused)?)) (atom!("op"), 3) => Ok(Declaration::Op(setup_op_decl(terms)?)),
}
(atom!("op"), 3) => {
Ok(Declaration::Op(setup_op_decl(&focused)?))
}
(atom!("non_counted_backtracking"), 1) => { (atom!("non_counted_backtracking"), 1) => {
focused.focus = focused.nth_arg(focused.focus, 1).unwrap(); let (name, arity) = setup_predicate_indicator(&mut terms.pop().unwrap())?;
let (name, arity) = setup_predicate_indicator(&focused)?;
Ok(Declaration::NonCountedBacktracking(name, arity)) Ok(Declaration::NonCountedBacktracking(name, arity))
} }
(atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(&focused)?)), (atom!("use_module"), 1) => Ok(Declaration::UseModule(setup_use_module_decl(terms)?)),
(atom!("use_module"), 2) => { (atom!("use_module"), 2) => {
let (name, exports) = setup_qualified_import(focused)?; let (name, exports) = setup_qualified_import(terms)?;
Ok(Declaration::UseQualifiedModule(name, exports)) Ok(Declaration::UseQualifiedModule(name, exports))
} }
(atom!("meta_predicate"), 1) => { (atom!("meta_predicate"), 1) => {
term.focus = focus; let (module_name, name, meta_specs) = setup_meta_predicate(terms, loader)?;
let (module_name, name, meta_specs) = setup_meta_predicate(term, loader)?;
Ok(Declaration::MetaPredicate(module_name, name, meta_specs)) Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
} }
_ => Err(CompilationError::InvalidDirective( _ => Err(CompilationError::InvalidDirective(
DirectiveError::InvalidDirective(name, arity) DirectiveError::InvalidDirective(name, terms.len()),
)) )),
}; },
} other => Err(CompilationError::InvalidDirective(
(HeapCellValueTag::Str, s) => { DirectiveError::ExpectedDirective(other),
focus = s; )),
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if focus != h {
focus = h;
} else {
return Err(CompilationError::InvalidDirective(
DirectiveError::ExpectedDirective(decl),
));
}
}
_ => {
return Err(CompilationError::InvalidDirective(
DirectiveError::ExpectedDirective(decl),
));
}
);
} }
} }
fn build_meta_predicate_clause<'a, LS: LoadState<'a>>( fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
module_name: Atom, module_name: Atom,
arity: usize, terms: Vec<Term>,
term: &TermWriteResult,
meta_specs: Vec<MetaSpec>, meta_specs: Vec<MetaSpec>,
) -> IndexMap<usize, CodeIndex, FxBuildHasher> { ) -> Vec<Term> {
use crate::machine::heap::Heap; let mut arg_terms = Vec::with_capacity(terms.len());
let mut index_ptrs = IndexMap::with_hasher(FxBuildHasher::default());
let focus = { for (term, meta_spec) in terms.into_iter().zip(meta_specs.iter()) {
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;
}
};
for (subterm_loc, meta_spec) in (focus + 1..focus + arity + 1).zip(meta_specs) {
if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec { if let MetaSpec::RequiresExpansionWithArgument(supp_args) = meta_spec {
let predicate_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); if let Some(name) = term.name() {
if let Some((name, arity)) = predicate_key_opt {
if name == atom!("$call") { if name == atom!("$call") {
arg_terms.push(term);
continue; continue;
} }
struct QualifiedNameInfo { let arity = term.arity();
module_name: Atom,
name: Atom,
arity: usize,
qualified_term_loc: usize,
}
fn get_qualified_name( fn get_qualified_name(
heap: &Heap, module_term: &Term,
module_term_loc: usize, qualified_term: &Term,
qualified_term_loc: usize, ) -> Option<(Atom, Atom)> {
) -> Option<QualifiedNameInfo> { if let Term::Literal(_, Literal::Atom(module_name)) = module_term {
let (module_term_loc, _) = subterm_index(heap, module_term_loc); if let Some(name) = qualified_term.name() {
let (qualified_term_loc, _) = subterm_index(heap, qualified_term_loc); return Some((*module_name, name));
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,
});
} }
} }
}
_ => {}
);
None None
} }
let (subterm_loc, _) = subterm_index(loader.machine_heap(), subterm_loc); fn identity_fn(_module_name: Atom, term: Term) -> Term {
let subterm_key_opt = term_predicate_key(loader.machine_heap(), subterm_loc); term
}
let (module_name, key, term_loc) = if subterm_key_opt == Some((atom!(":"), 2)) { fn tag_with_module_name(module_name: Atom, term: Term) -> Term {
match get_qualified_name( Term::Clause(
loader.machine_heap(), Cell::default(),
subterm_loc + 1, atom!(":"),
subterm_loc + 2, vec![
) { Term::Literal(Cell::default(), Literal::Atom(module_name)),
Some(QualifiedNameInfo { 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, module_name,
name, (name, terms[1].arity() + supp_args),
arity, terms.pop().unwrap(),
qualified_term_loc, )
}) => (module_name, (name, arity + supp_args), qualified_term_loc), } else {
None => { arg_terms.push(Term::Clause(cell, atom!(":"), terms));
continue; continue;
} }
} }
} else { term => {
(module_name, (name, arity + supp_args), subterm_loc) process_term = identity_fn;
(module_name, (name, arity + supp_args), term)
}
}; };
if let Some(index_ptr) = fetch_index_ptr(loader.machine_heap(), term_loc) { let term = match term {
index_ptrs.insert(term_loc, index_ptr); 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; continue;
} }
index_ptrs.insert( let idx = loader.get_or_insert_qualified_code_index(module_name, key);
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;
} }
} }
index_ptrs arg_terms.push(term);
}
arg_terms
} }
#[inline] #[inline]
pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>( pub(super) fn clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
key: PredicateKey, name: Atom,
terms: &TermWriteResult, mut terms: Vec<Term>,
term: HeapCellValue,
call_policy: CallPolicy, call_policy: CallPolicy,
) -> QueryClause { ) -> QueryTerm {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
// supplementary code vector indices are unnecessary for // supplementary code vector indices are unnecessary for
// root-level clauses. // root-level clauses.
blunt_index_ptr(loader.machine_heap(), key, terms.focus); 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 ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let module_name = loader.payload.compilation_target.module_name(); let module_name = loader.payload.compilation_target.module_name();
let code_indices = let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
build_meta_predicate_clause(loader, module_name, arity, terms, meta_specs);
return QueryClause { return QueryTerm::Clause(
ct: ClauseType::Named(key.1, key.0, idx), Cell::default(),
term, ClauseType::Named(arity, name, idx),
code_indices, terms,
call_policy, call_policy,
}; );
} }
ct = ClauseType::Named(key.1, key.0, idx); ct = ClauseType::Named(arity, name, idx);
} }
QueryClause { QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
ct,
term,
code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
call_policy,
}
} }
#[inline] #[inline]
pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>( pub(super) fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
key: PredicateKey,
module_name: Atom, module_name: Atom,
terms: &TermWriteResult, name: Atom,
term: HeapCellValue, mut terms: Vec<Term>,
call_policy: CallPolicy, call_policy: CallPolicy,
) -> QueryClause { ) -> QueryTerm {
if let Some(Term::Literal(_, Literal::CodeIndex(_))) = terms.last() {
// supplementary code vector indices are unnecessary for // supplementary code vector indices are unnecessary for
// root-level clauses. // root-level clauses.
blunt_index_ptr(loader.machine_heap(), key, terms.focus); 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 ClauseType::Named(arity, name, idx) = ct {
if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() { if let Some(meta_specs) = loader.get_meta_specs(name, arity).cloned() {
let code_indices = let terms = build_meta_predicate_clause(loader, module_name, terms, meta_specs);
build_meta_predicate_clause(loader, module_name, arity, &terms, meta_specs);
return QueryClause { return QueryTerm::Clause(
ct: ClauseType::Named(key.1, key.0, idx), Cell::default(),
term, ClauseType::Named(arity, name, idx),
code_indices, terms,
call_policy, call_policy,
}; );
} }
ct = ClauseType::Named(key.1, key.0, idx); ct = ClauseType::Named(arity, name, idx);
} }
QueryClause { QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
ct,
term,
code_indices: IndexMap::with_hasher(FxBuildHasher::default()),
call_policy,
}
} }
#[derive(Debug)] #[derive(Debug)]
@@ -642,66 +540,70 @@ impl Preprocessor {
Preprocessor { settings } Preprocessor { settings }
} }
pub fn setup_fact<'a, LS: LoadState<'a>>( fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
&mut self, match term {
loader: &mut Loader<'a, LS>, Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
term: TermWriteResult,
) -> Result<(Fact, VarData), CompilationError> {
let heap = loader.machine_heap();
if term_predicate_key(heap, term.focus).is_some() {
let classifier = VariableClassifier::new(self.settings.default_call_policy()); let classifier = VariableClassifier::new(self.settings.default_call_policy());
let var_data = classifier.classify_fact(loader, &term)?;
Ok(( let (head, var_data) = classifier.classify_fact(term)?;
Fact { Ok((Fact { head }, var_data))
term_loc: term.focus, }
}, _ => Err(CompilationError::InadmissibleFact),
var_data,
))
} else {
Err(CompilationError::InadmissibleFact)
} }
} }
fn setup_rule<'a, LS: LoadState<'a>>( fn setup_rule<'a, LS: LoadState<'a>>(
&mut self, &mut self,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
term: TermWriteResult, head: Term,
body: Term,
) -> Result<(Rule, VarData), CompilationError> { ) -> Result<(Rule, VarData), CompilationError> {
let classifier = VariableClassifier::new(self.settings.default_call_policy()); 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, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
let head_loc = term_nth_arg(heap, term.focus, 1).unwrap();
if term_predicate_key(heap, head_loc).is_some() { match head {
Ok(( Term::Clause(_, name, terms) => Ok((
Rule { Rule {
term_loc: term.focus, head: (name, terms),
clauses, clauses,
}, },
var_data, var_data,
)) )),
} else { Term::Literal(_, Literal::Atom(name)) => Ok((
Err(CompilationError::InvalidRuleHead) Rule {
head: (name, vec![]),
clauses,
},
var_data,
)),
_ => Err(CompilationError::InvalidRuleHead),
} }
} }
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>( pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
&mut self, &mut self,
loader: &mut Loader<'a, LS>, loader: &mut Loader<'a, LS>,
term: TermWriteResult, term: Term,
) -> Result<PredicateClause, CompilationError> { ) -> 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) { if is_rule {
Some((atom!(":-"), 2)) => { let tail = terms.pop().unwrap();
let (rule, var_data) = self.setup_rule(loader, term)?; let head = terms.pop().unwrap();
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
Ok(PredicateClause::Rule(rule, var_data)) 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)) Ok(PredicateClause::Fact(fact, var_data))
} }
} }

View File

@@ -24,7 +24,12 @@ pub(crate) struct RawBlock<T: RawBlockTraits> {
impl<T: RawBlockTraits> RawBlock<T> { impl<T: RawBlockTraits> RawBlock<T> {
pub(crate) fn new() -> Self { 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 { unsafe {
block.grow(); block.grow();
@@ -33,15 +38,6 @@ impl<T: RawBlockTraits> RawBlock<T> {
block 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) { unsafe fn init_at_size(&mut self, cap: usize) {
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align()); let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());

View File

@@ -168,13 +168,6 @@ impl Stack {
} }
} }
pub(crate) fn uninitialized() -> Self {
Stack {
buf: RawBlock::empty_block(),
_marker: PhantomData,
}
}
#[inline(always)] #[inline(always)]
unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 { unsafe fn alloc(&mut self, frame_size: usize) -> *mut u8 {
loop { loop {

View File

@@ -1844,10 +1844,11 @@ impl MachineState {
(HeapCellValueTag::Cons, ptr) => { (HeapCellValueTag::Cons, ptr) => {
match_untyped_arena_ptr!(ptr, match_untyped_arena_ptr!(ptr,
(ArenaHeaderTag::Stream, stream) => { (ArenaHeaderTag::Stream, stream) => {
if stream.is_null_stream() { return if stream.is_null_stream() {
unreachable!("Null streams have no Cons representation"); Err(self.open_permission_error(stream_as_cell!(stream), caller, arity))
} } else {
return Ok(stream); Ok(stream)
};
} }
(ArenaHeaderTag::Dropped, _value) => { (ArenaHeaderTag::Dropped, _value) => {
let stub = functor_stub(caller, arity); let stub = functor_stub(caller, arity);
@@ -1880,7 +1881,7 @@ impl MachineState {
) -> Result<Stream, ParserError> { ) -> Result<Stream, ParserError> {
match stream.peek_char() { match stream.peek_char() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof 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)) => { Some(Ok(c)) => {
if c == '\u{feff}' { if c == '\u{feff}' {
// skip UTF-8 BOM // skip UTF-8 BOM
@@ -2086,7 +2087,7 @@ impl MachineState {
_ => { _ => {
// assume the OS is out of file descriptors. // assume the OS is out of file descriptors.
let stub = functor_stub(atom!("open"), 4); 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)); return Err(self.error_form(err, stub));
} }

View File

@@ -1,7 +1,3 @@
use crate::parser::ast::*;
use crate::parser::lexer::LexerParser;
use crate::parser::parser::*;
use base64::Engine; use base64::Engine;
use dashu::integer::{Sign, UBig}; use dashu::integer::{Sign, UBig};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@@ -29,8 +25,10 @@ use crate::machine::partial_string::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC}; use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
use crate::parser::ast::*;
use crate::parser::char_reader::*; 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::read::*;
use crate::types::*; use crate::types::*;
use rand::rngs::StdRng; use rand::rngs::StdRng;
@@ -41,6 +39,7 @@ use ordered_float::OrderedFloat;
use fxhash::{FxBuildHasher, FxHasher}; use fxhash::{FxBuildHasher, FxHasher};
use indexmap::IndexSet; use indexmap::IndexSet;
use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::env; use std::env;
@@ -851,12 +850,10 @@ impl MachineState {
) { ) {
let mut seen_set = IndexSet::new(); let mut seen_set = IndexSet::new();
if term.is_ref() { {
let mut iter = stackful_post_order_iter::<NonListElider>( self.heap[0] = term;
&mut self.heap, let mut iter =
&mut self.stack, stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, 0);
term.get_value() as usize,
);
while let Some(value) = iter.next() { while let Some(value) = iter.next() {
if iter.parent_stack_len() >= max_depth { if iter.parent_stack_len() >= max_depth {
@@ -874,9 +871,8 @@ impl MachineState {
let outcome = step_or_resource_error!( let outcome = step_or_resource_error!(
self, 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); unify_fn!(*self, list_of_vars, outcome);
} }
@@ -959,7 +955,7 @@ impl MachineState {
let nx = self.store(self.deref(self.registers[2])); let nx = self.store(self.deref(self.registers[2]));
let iter = std::io::Cursor::new(string); let iter = std::io::Cursor::new(string);
let mut lexer_parser = LexerParser::new(CharReader::new(iter), self); let mut lexer = Lexer::new(CharReader::new(iter), self);
let mut tokens = vec![]; let mut tokens = vec![];
match lexer.next_number_token() { match lexer.next_number_token() {
@@ -980,58 +976,35 @@ impl MachineState {
} }
loop { loop {
match lexer_parser.lookahead_char() { match lexer.lookahead_char() {
Err(e) if e.is_unexpected_eof() => { Err(e) if e.is_unexpected_eof() => {
let mut parser = Parser::from_lexer(lexer);
let op_dir = CompositeOpDir::new(&indices.op_dir, None); let op_dir = CompositeOpDir::new(&indices.op_dir, None);
tokens.reverse(); tokens.reverse();
let byte_size = heap_index!(tokens.len());
match lexer_parser.read_term(&op_dir, Tokens::Provided(tokens, byte_size)) { match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
Ok(term) => { Err(err) => {
read_heap_cell!(lexer_parser.machine_st.heap[term.focus], let err = self.syntax_error(err);
(HeapCellValueTag::Cons, c) => { return Err(self.error_form(err, stub_gen()));
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Rational, n) => {
self.unify_rational(n, nx);
} }
(ArenaHeaderTag::Integer, n) => { Ok(Term::Literal(_, cell)) => {
self.unify_big_int(n, nx); unify!(self, nx, HeapCellValue::from(cell));
} }
_ => { _ => {
let e = ParserError::ParseBigInt(lexer_parser.loc_to_err_src()); let err = ParserError::ParseBigInt(0, 0);
let e = self.syntax_error(e); let err = self.syntax_error(err);
return Err(self.error_form(e, stub_gen())); return Err(self.error_form(err, 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(()); return Ok(());
} }
Err(e) => {
let e = self.syntax_error(e);
return Err(self.error_form(e, stub_gen()));
}
}
}
Ok(c) => { 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); let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen())); return Err(self.error_form(err, stub_gen()));
@@ -1645,12 +1618,12 @@ impl Machine {
let vars: Vec<_> = vars let vars: Vec<_> = vars
.union(&result.supp_vars) // difference + union does not cancel. .union(&result.supp_vars) // difference + union does not cancel.
.cloned() .map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
.collect(); .collect();
let helper_clause_loc = self.code.len(); 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) => { Err(e) => {
let err = self.machine_st.session_error(e); let err = self.machine_st.session_error(e);
let stub = functor_stub(atom!("call"), result.key.1); let stub = functor_stub(atom!("call"), result.key.1);
@@ -1996,7 +1969,7 @@ impl Machine {
if let Some(name) = entry.file_name().to_str() { if let Some(name) = entry.file_name().to_str() {
let file_string_cell = resource_error_call_result!( let file_string_cell = resource_error_call_result!(
self.machine_st, self.machine_st,
self.machine_st.allocate_cstr(name) self.machine_st.heap.allocate_cstr(name)
); );
files.push(file_string_cell); files.push(file_string_cell);
@@ -2115,7 +2088,7 @@ impl Machine {
let cstr_cell = step_or_resource_error!( let cstr_cell = step_or_resource_error!(
self.machine_st, 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]); unify!(self.machine_st, cstr_cell, self.machine_st.registers[3]);
@@ -2251,7 +2224,7 @@ impl Machine {
let current_string = resource_error_call_result!( let current_string = resource_error_call_result!(
self.machine_st, self.machine_st,
self.machine_st.allocate_cstr(current) self.machine_st.heap.allocate_cstr(current)
); );
unify!( unify!(
@@ -2295,8 +2268,10 @@ impl Machine {
} }
}; };
let canonical_string = let canonical_string = resource_error_call_result!(
resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(cs)); self.machine_st,
self.machine_st.heap.allocate_cstr(cs)
);
unify!( unify!(
self.machine_st, self.machine_st,
@@ -2321,7 +2296,7 @@ impl Machine {
let cell = step_or_resource_error!( let cell = step_or_resource_error!(
self.machine_st, 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); unify!(self.machine_st, self.machine_st.registers[2], cell);
@@ -2522,7 +2497,7 @@ impl Machine {
let pstr_loc_cell = step_or_resource_error!( let pstr_loc_cell = step_or_resource_error!(
self.machine_st, 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 tail_loc = Heap::pstr_tail_idx(atom.as_str().len() + heap_index!(pstr_h));
@@ -2897,7 +2872,7 @@ impl Machine {
let cstr_cell = step_or_resource_error!( let cstr_cell = step_or_resource_error!(
self.machine_st, 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); unify!(self.machine_st, cstr_cell, chs);
@@ -3137,7 +3112,7 @@ impl Machine {
let reg = self.machine_st.deref(self.machine_st.heap[s+1]); let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
let upper_str = step_or_resource_error!( let upper_str = step_or_resource_error!(
self.machine_st, 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); unify!(self.machine_st, reg, upper_str);
} }
@@ -3145,7 +3120,7 @@ impl Machine {
let reg = self.machine_st.deref(self.machine_st.heap[s+1]); let reg = self.machine_st.deref(self.machine_st.heap[s+1]);
let lower_str = step_or_resource_error!( let lower_str = step_or_resource_error!(
self.machine_st, 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); unify!(self.machine_st, reg, lower_str);
@@ -3660,12 +3635,7 @@ impl Machine {
} }
Some(Err(e)) => { Some(Err(e)) => {
let stub = functor_stub(atom!("$get_n_chars"), 3); let stub = functor_stub(atom!("$get_n_chars"), 3);
let err = let err = self.machine_st.session_error(SessionError::from(e));
self.machine_st
.session_error(SessionError::from(ParserError::IO(
e,
ParserErrorSrc::default(),
)));
return Err(self.machine_st.error_form(err, stub)); return Err(self.machine_st.error_form(err, stub));
} }
@@ -3677,8 +3647,10 @@ impl Machine {
}; };
let output = self.deref_register(3); let output = self.deref_register(3);
let cstr_cell = let cstr_cell = resource_error_call_result!(
resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&string)); self.machine_st,
self.machine_st.heap.allocate_cstr(&string)
);
unify!(self.machine_st, cstr_cell, output); unify!(self.machine_st, cstr_cell, output);
Ok(()) Ok(())
@@ -4403,9 +4375,7 @@ impl Machine {
Ok(Number::Integer(n)) => match (&*n).try_into() as Result<usize, _> { Ok(Number::Integer(n)) => match (&*n).try_into() as Result<usize, _> {
Ok(n) => n, Ok(n) => n,
Err(_) => { Err(_) => {
let err = self let err = MachineState::resource_error(ResourceError::FiniteMemory(len));
.machine_st
.resource_error(ResourceError::FiniteMemory(len));
return Err(self.machine_st.error_form(err, stub_gen())); return Err(self.machine_st.error_form(err, stub_gen()));
} }
}, },
@@ -4508,6 +4478,7 @@ impl Machine {
let string_cell = resource_error_call_result!( let string_cell = resource_error_call_result!(
self.machine_st, self.machine_st,
self.machine_st self.machine_st
.heap
.allocate_cstr(header_value.to_str().unwrap()) .allocate_cstr(header_value.to_str().unwrap())
); );
@@ -4568,7 +4539,7 @@ impl Machine {
} }
} }
Ok(()) Ok::<(), _>(())
})?; })?;
} else { } else {
let err = self let err = self
@@ -4758,7 +4729,7 @@ impl Machine {
let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path); let path_atom = AtomTable::build_with(&self.machine_st.atom_tbl, &request.request_data.path);
let path_cell = resource_error_call_result!( let path_cell = resource_error_call_result!(
self.machine_st, 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![]; let mut headers = vec![];
@@ -4766,7 +4737,7 @@ impl Machine {
for (header_name, header_value) in request.request_data.headers { for (header_name, header_value) in request.request_data.headers {
let header_value = resource_error_call_result!( let header_value = resource_error_call_result!(
self.machine_st, 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 header_term = functor!(
@@ -4796,7 +4767,7 @@ impl Machine {
let query_str = request.request_data.query; let query_str = request.request_data.query;
let query_cell = resource_error_call_result!( let query_cell = resource_error_call_result!(
self.machine_st, 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( let mut stream = Stream::from_http_stream(
@@ -5064,7 +5035,7 @@ impl Machine {
Value::CString(cstr) => { Value::CString(cstr) => {
let str_cell = resource_error_call_result!( let str_cell = resource_error_call_result!(
self.machine_st, 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); unify!(self.machine_st, str_cell, return_value);
@@ -5208,8 +5179,10 @@ impl Machine {
let mut args_pstrs = vec![]; let mut args_pstrs = vec![];
for arg in env::args() { for arg in env::args() {
let pstr_cell = let pstr_cell = resource_error_call_result!(
resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&arg)); self.machine_st,
self.machine_st.heap.allocate_cstr(&arg)
);
args_pstrs.push(pstr_cell); args_pstrs.push(pstr_cell);
} }
@@ -5230,8 +5203,10 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn current_time(&mut self) { pub(crate) fn current_time(&mut self) {
let timestamp = self.systemtime_to_timestamp(SystemTime::now()); let timestamp = self.systemtime_to_timestamp(SystemTime::now());
let cstr_cell = let cstr_cell = step_or_resource_error!(
step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(&timestamp)); self.machine_st,
self.machine_st.heap.allocate_cstr(&timestamp)
);
unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]); unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
} }
@@ -6494,7 +6469,7 @@ impl Machine {
} }
#[inline(always)] #[inline(always)]
fn read_term_from_atom( fn read_term_and_write_to_heap(
&mut self, &mut self,
atom_or_string: AtomOrString, atom_or_string: AtomOrString,
) -> Result<Option<TermWriteResult>, MachineStub> { ) -> Result<Option<TermWriteResult>, MachineStub> {
@@ -6504,15 +6479,16 @@ impl Machine {
}; };
let chars = CharReader::new(ByteStream::from_string(string)); 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 op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
let term = parser let term_write_result = parser
.read_term(&op_dir, Tokens::Default) .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 { match term_write_result {
Ok(term) => Ok(Some(term)), Ok(term_write_result) => Ok(Some(term_write_result)),
Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => { Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
let value = self.machine_st.registers[2]; let value = self.machine_st.registers[2];
self.machine_st.unify_atom(atom!("end_of_file"), value); self.machine_st.unify_atom(atom!("end_of_file"), value);
@@ -6530,46 +6506,43 @@ impl Machine {
#[inline(always)] #[inline(always)]
pub(crate) fn read_from_chars(&mut self) -> CallResult { pub(crate) fn read_from_chars(&mut self) -> CallResult {
let atom_or_string = self if let Some(atom_or_string) = self
.machine_st .machine_st
.value_to_str_like(self.machine_st.registers[1]) .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)? {
if let Some(term) = self.read_term_from_atom(atom_or_string)? { let result = heap_loc_as_cell!(term_write_result.heap_loc);
let result = self.machine_st.heap[term.focus];
let var = self.deref_register(2).as_var().unwrap(); let var = self.deref_register(2).as_var().unwrap();
self.machine_st.bind(var, result); self.machine_st.bind(var, result);
} }
Ok(()) Ok(())
} else {
unreachable!()
}
} }
#[inline(always)] #[inline(always)]
pub(crate) fn read_term_from_chars(&mut self) -> CallResult { pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
let atom_or_string = self if let Some(atom_or_string) = self
.machine_st .machine_st
.value_to_str_like(self.machine_st.registers[1]) .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)? {
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!())?;
}
let string = match atom_or_string { Ok(())
AtomOrString::Atom(atom!("[]")) => "".to_owned(), }
_ => atom_or_string.into(), } else {
}; unreachable!()
}
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)
})?;
self.machine_st.read_term_body(term)
} }
#[inline(always)] #[inline(always)]
@@ -7542,8 +7515,10 @@ impl Machine {
}; };
let result = printer.print().result(); let result = printer.print().result();
let chars = let chars = resource_error_call_result!(
resource_error_call_result!(self.machine_st, self.machine_st.allocate_cstr(&result)); self.machine_st,
self.machine_st.heap.allocate_cstr(&result)
);
let result_addr = self.deref_register(1); let result_addr = self.deref_register(1);
let var = result_addr.as_var().unwrap(); let var = result_addr.as_var().unwrap();
@@ -7559,7 +7534,7 @@ impl Machine {
let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown"); let buffer = git_version!(cargo_prefix = "cargo:", fallback = "unknown");
let cstr_cell = 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]); unify!(self.machine_st, cstr_cell, self.machine_st.registers[1]);
} }
@@ -8010,7 +7985,10 @@ impl Machine {
if buffer.is_empty() { if buffer.is_empty() {
empty_list_as_cell!() empty_list_as_cell!()
} else { } 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)
)
} }
}; };
@@ -8197,7 +8175,7 @@ impl Machine {
Ok(value) => { Ok(value) => {
let cstr = step_or_resource_error!( let cstr = step_or_resource_error!(
self.machine_st, 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); unify!(self.machine_st, self.machine_st.registers[2], cstr);
@@ -8410,20 +8388,15 @@ impl Machine {
1, 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) => { Ok(false) => {
// not at EOF ... // not at EOF.
stream.add_lines_read(lexer_parser.line_num()); stream.add_lines_read(parser.lines_read());
// ... unless we are.
if stream.at_end_of_stream() {
self.machine_st.fail = true;
}
} }
Ok(true) => { Ok(true) => {
stream.add_lines_read(lexer_parser.line_num()); stream.add_lines_read(parser.lexer.line_num);
self.machine_st.fail = true; self.machine_st.fail = true;
} }
Err(err) => { Err(err) => {
@@ -8483,8 +8456,10 @@ impl Machine {
if path.is_dir() { if path.is_dir() {
if let Some(path) = path.to_str() { if let Some(path) = path.to_str() {
let path_string = let path_string = step_or_resource_error!(
step_or_resource_error!(self.machine_st, self.machine_st.allocate_cstr(path)); self.machine_st,
self.machine_st.heap.allocate_cstr(path)
);
unify!(self.machine_st, self.machine_st.registers[1], path_string); unify!(self.machine_st, self.machine_st.registers[1], path_string);
return; return;
@@ -8557,13 +8532,13 @@ impl Machine {
node: roxmltree::Node, node: roxmltree::Node,
) -> Result<HeapCellValue, usize> { ) -> Result<HeapCellValue, usize> {
if node.is_text() { if node.is_text() {
self.machine_st.allocate_cstr(node.text().unwrap()) self.machine_st.heap.allocate_cstr(node.text().unwrap())
} else { } else {
let mut avec = Vec::new(); let mut avec = Vec::new();
for attr in node.attributes() { for attr in node.attributes() {
let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.name()); 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())); avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
@@ -8610,13 +8585,14 @@ impl Machine {
match node.value().as_element() { match node.value().as_element() {
None => self None => self
.machine_st .machine_st
.heap
.allocate_cstr(&node.value().as_text().unwrap().text), .allocate_cstr(&node.value().as_text().unwrap().text),
Some(element) => { Some(element) => {
let mut avec = Vec::new(); let mut avec = Vec::new();
for attr in element.attrs() { for attr in element.attrs() {
let name = AtomTable::build_with(&self.machine_st.atom_tbl, attr.0); 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())); avec.push(str_loc_as_cell!(self.machine_st.heap.cell_len()));
@@ -8669,7 +8645,7 @@ impl Machine {
if buffer.is_empty() { if buffer.is_empty() {
Ok(empty_list_as_cell!()) Ok(empty_list_as_cell!())
} else { } else {
self.machine_st.allocate_cstr(&buffer) self.machine_st.heap.allocate_cstr(&buffer)
} }
} }
} }

View File

@@ -21,11 +21,11 @@ pub struct LoadStatePayload<TS> {
pub(super) module_op_exports: ModuleOpExports, pub(super) module_op_exports: ModuleOpExports,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>, pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>,
pub(super) predicates: PredicateQueue, pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<TermWriteResult>, pub(super) clause_clauses: Vec<(Term, Term)>,
} }
pub trait TermStream: Sized { 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 eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource; fn listing_src(&self) -> &ListingSource;
} }
@@ -33,7 +33,7 @@ pub trait TermStream: Sized {
#[derive(Debug)] #[derive(Debug)]
pub struct BootstrappingTermStream<'a> { pub struct BootstrappingTermStream<'a> {
listing_src: ListingSource, listing_src: ListingSource,
pub(super) lexer_parser: LexerParser<'a, Stream>, pub(super) parser: Parser<'a, Stream>,
} }
impl<'a> BootstrappingTermStream<'a> { impl<'a> BootstrappingTermStream<'a> {
@@ -43,9 +43,9 @@ impl<'a> BootstrappingTermStream<'a> {
machine_st: &'a mut MachineState, machine_st: &'a mut MachineState,
listing_src: ListingSource, listing_src: ListingSource,
) -> Self { ) -> Self {
let lexer_parser = LexerParser::new(stream, machine_st); let parser = Parser::new(stream, machine_st);
Self { Self {
lexer_parser, parser,
listing_src, listing_src,
} }
} }
@@ -53,18 +53,16 @@ impl<'a> BootstrappingTermStream<'a> {
impl<'a> TermStream for BootstrappingTermStream<'a> { impl<'a> TermStream for BootstrappingTermStream<'a> {
#[inline] #[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> { fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
let result = self self.parser.reset();
.lexer_parser self.parser
.read_term(op_dir, Tokens::Default) .read_term(op_dir, Tokens::Default)
.map_err(CompilationError::from); .map_err(CompilationError::from)
result
} }
#[inline] #[inline]
fn eof(&mut self) -> Result<bool, CompilationError> { 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) .map_err(CompilationError::from)
} }
@@ -75,7 +73,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
} }
pub struct LiveTermStream { pub struct LiveTermStream {
pub(super) term_queue: VecDeque<TermWriteResult>, pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource, pub(super) listing_src: ListingSource,
} }
@@ -111,7 +109,7 @@ impl<TS> LoadStatePayload<TS> {
impl TermStream for LiveTermStream { impl TermStream for LiveTermStream {
#[inline] #[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> { fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap()) Ok(self.term_queue.pop_front().unwrap())
} }
@@ -129,10 +127,8 @@ impl TermStream for LiveTermStream {
pub struct InlineTermStream {} pub struct InlineTermStream {}
impl TermStream for InlineTermStream { impl TermStream for InlineTermStream {
fn next(&mut self, _: &CompositeOpDir) -> Result<TermWriteResult, CompilationError> { fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Err(CompilationError::from(ParserError::unexpected_eof( Err(CompilationError::from(ParserError::unexpected_eof()))
ParserErrorSrc::default(),
)))
} }
fn eof(&mut self) -> Result<bool, CompilationError> { fn eof(&mut self) -> Result<bool, CompilationError> {

View File

@@ -133,13 +133,16 @@ pub(crate) trait Unifier: DerefMut<Target = MachineState> {
machine_st.partial_string_to_pdl(pstr_loc, l); machine_st.partial_string_to_pdl(pstr_loc, l);
} }
(HeapCellValueTag::PStrLoc, other_pstr_loc) => { (HeapCellValueTag::PStrLoc, other_pstr_loc) => {
let cmp_result = machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc); match machine_st.heap.compare_pstr_segments(pstr_loc, other_pstr_loc) {
PStrSegmentCmpResult::Continue(v1, v2) => {
if cmp_result.continue_pstr_compare(&mut machine_st.pdl).is_some() { machine_st.pdl.push(v1);
debug_assert!(matches!(cmp_result, PStrSegmentCmpResult::Mismatch { .. })); machine_st.pdl.push(v2);
}
_ => {
machine_st.fail = true; machine_st.fail = true;
} }
} }
}
_ => { _ => {
machine_st.fail = true; machine_st.fail = true;
} }
@@ -501,10 +504,8 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
let mut occurs_triggered = false; let mut occurs_triggered = false;
if !value.is_constant() {
let machine_st: &mut MachineState = unifier.deref_mut(); 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() {
machine_st.heap[0] = value; machine_st.heap[0] = value;
for cell in for cell in

View File

@@ -287,12 +287,6 @@ macro_rules! read_heap_cell_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $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) => {{ ($cell:ident, PStr, $atom:ident, $code:expr) => {{
let $atom = cell_as_atom!($cell); let $atom = cell_as_atom!($cell);
#[allow(unused_braces)] #[allow(unused_braces)]
@@ -313,7 +307,6 @@ macro_rules! read_heap_cell_pat_body {
#[allow(unused_braces)] #[allow(unused_braces)]
$code $code
}}; }};
*/
($cell:ident, Fixnum, $value:ident, $code:expr) => {{ ($cell:ident, Fixnum, $value:ident, $code:expr) => {{
let $value = Fixnum::from_bytes($cell.into_bytes()); let $value = Fixnum::from_bytes($cell.into_bytes());
#[allow(unused_braces)] #[allow(unused_braces)]
@@ -489,7 +482,7 @@ macro_rules! step_or_resource_error {
macro_rules! resource_error_call_result { macro_rules! resource_error_call_result {
($machine_st:expr, $val:expr) => { ($machine_st:expr, $val:expr) => {
step_or_resource_error!($machine_st, $val, { step_or_resource_error!($machine_st, $val, {
return Err(vec![]); // TODO: return Ok(()); return Err(vec![]);
}) })
}; };
} }

View File

@@ -2,18 +2,22 @@
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::PredicateKey; use crate::machine::machine_indices::CodeIndex;
use crate::machine::heap::*; use crate::parser::char_reader::*;
use crate::machine::machine_indices::*; use crate::types::HeapCellValueTag;
use crate::types::*;
use std::cell::{Cell, Ref, RefCell, RefMut};
use std::fmt; use std::fmt;
use std::hash::Hash; use std::hash::Hash;
use std::hash::Hasher;
use std::io::{Error as IOError, ErrorKind}; use std::io::{Error as IOError, ErrorKind};
use std::ops::Neg; use std::ops::{Deref, Neg};
use std::rc::Rc; use std::rc::Rc;
use std::sync::Arc;
use std::vec::Vec; use std::vec::Vec;
use dashu::Integer;
use dashu::Rational;
use fxhash::FxBuildHasher; use fxhash::FxBuildHasher;
use indexmap::IndexMap; use indexmap::IndexMap;
use scryer_modular_bitfield::error::OutOfBounds; use scryer_modular_bitfield::error::OutOfBounds;
@@ -138,16 +142,7 @@ pub const BTERM: u32 = 0x11000;
pub const NEGATIVE_SIGN: u32 = 0x0200; pub const NEGATIVE_SIGN: u32 = 0x0200;
macro_rules! fixnum { macro_rules! fixnum {
($n:expr, $arena:expr) => { ($wrapper:tt, $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) => {
Fixnum::build_with_checked($n) Fixnum::build_with_checked($n)
.map(<$wrapper>::Fixnum) .map(<$wrapper>::Fixnum)
.unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena))) .unwrap_or_else(|_| <$wrapper>::Integer(arena_alloc!(Integer::from($n), $arena)))
@@ -276,6 +271,37 @@ impl fmt::Display for RegType {
} }
} }
#[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 { macro_rules! temp_v {
($x:expr) => { ($x:expr) => {
$crate::parser::ast::RegType::Temp($x) $crate::parser::ast::RegType::Temp($x)
@@ -373,49 +399,41 @@ pub fn default_op_dir() -> OpDir {
op_dir op_dir
} }
#[derive(Debug, Clone)] #[derive(Debug, Copy, Clone)]
pub enum ArithmeticError { pub enum ArithmeticError {
NonEvaluableFunctor(HeapCellValue, usize), NonEvaluableFunctor(Literal, usize),
} UninstantiatedVar,
#[derive(Debug, Copy, Clone, Default)]
pub struct ParserErrorSrc {
pub col_num: usize,
pub line_num: usize,
} }
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub enum ParserError { pub enum ParserError {
BackQuotedString(ParserErrorSrc), BackQuotedString(usize, usize),
IO(IOError, ParserErrorSrc), IO(IOError),
IncompleteReduction(ParserErrorSrc), IncompleteReduction(usize, usize),
InfiniteFloat(ParserErrorSrc), InfiniteFloat(usize, usize),
InvalidSingleQuotedCharacter(char, ParserErrorSrc), InvalidSingleQuotedCharacter(char),
LexicalError(lexical::Error, ParserErrorSrc), LexicalError(lexical::Error),
MissingQuote(ParserErrorSrc), MissingQuote(usize, usize),
NonPrologChar(ParserErrorSrc), NonPrologChar(usize, usize),
ParseBigInt(ParserErrorSrc), ParseBigInt(usize, usize),
ResourceError(ParserErrorSrc), UnexpectedChar(char, usize, usize),
UnexpectedChar(char, ParserErrorSrc),
// UnexpectedEOF, // UnexpectedEOF,
Utf8Error(ParserErrorSrc), Utf8Error(usize, usize),
} }
impl ParserError { impl ParserError {
pub fn err_src(&self) -> ParserErrorSrc { pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self { match self {
&ParserError::BackQuotedString(err_src) &ParserError::BackQuotedString(line_num, col_num)
| &ParserError::IO(_, err_src) | &ParserError::IncompleteReduction(line_num, col_num)
| &ParserError::IncompleteReduction(err_src) | &ParserError::InfiniteFloat(line_num, col_num)
| &ParserError::InfiniteFloat(err_src) | &ParserError::MissingQuote(line_num, col_num)
| &ParserError::InvalidSingleQuotedCharacter(_, err_src) | &ParserError::NonPrologChar(line_num, col_num)
| &ParserError::LexicalError(_, err_src) | &ParserError::ParseBigInt(line_num, col_num)
| &ParserError::MissingQuote(err_src) | &ParserError::UnexpectedChar(_, line_num, col_num)
| &ParserError::NonPrologChar(err_src) | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)),
| &ParserError::ParseBigInt(err_src) _ => None,
| &ParserError::ResourceError(err_src)
| &ParserError::UnexpectedChar(_, err_src)
| &ParserError::Utf8Error(err_src) => err_src,
} }
} }
@@ -429,31 +447,30 @@ impl ParserError {
ParserError::InfiniteFloat(..) => { ParserError::InfiniteFloat(..) => {
atom!("infinite_float") atom!("infinite_float")
} }
ParserError::IO(e, _) if e.kind() == ErrorKind::UnexpectedEof => { ParserError::IO(e) if e.kind() == ErrorKind::UnexpectedEof => {
atom!("unexpected_end_of_file") atom!("unexpected_end_of_file")
} }
ParserError::IO(e, _) if e.kind() == ErrorKind::InvalidData => { ParserError::IO(e) if e.kind() == ErrorKind::InvalidData => {
atom!("invalid_data") atom!("invalid_data")
} }
ParserError::IO(..) => atom!("input_output_error"), ParserError::IO(_) => atom!("input_output_error"),
ParserError::LexicalError(..) => atom!("lexical_error"), ParserError::LexicalError(_) => atom!("lexical_error"),
ParserError::MissingQuote(..) => atom!("missing_quote"), ParserError::MissingQuote(..) => atom!("missing_quote"),
ParserError::NonPrologChar(..) => atom!("non_prolog_character"), ParserError::NonPrologChar(..) => atom!("non_prolog_character"),
ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"), ParserError::ParseBigInt(..) => atom!("cannot_parse_big_int"),
ParserError::UnexpectedChar(..) => atom!("unexpected_char"), ParserError::UnexpectedChar(..) => atom!("unexpected_char"),
ParserError::Utf8Error(..) => atom!("utf8_conversion_error"), ParserError::Utf8Error(..) => atom!("utf8_conversion_error"),
ParserError::ResourceError(..) => atom!("resource_error"),
} }
} }
#[inline] #[inline]
pub fn unexpected_eof(err_src: ParserErrorSrc) -> Self { pub fn unexpected_eof() -> Self {
ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof), err_src) ParserError::IO(std::io::Error::from(ErrorKind::UnexpectedEof))
} }
#[inline] #[inline]
pub fn is_unexpected_eof(&self) -> bool { pub fn is_unexpected_eof(&self) -> bool {
if let ParserError::IO(e, _) = self { if let ParserError::IO(e) = self {
e.kind() == ErrorKind::UnexpectedEof e.kind() == ErrorKind::UnexpectedEof
} else { } else {
false false
@@ -461,9 +478,25 @@ impl ParserError {
} }
} }
impl From<ParserErrorSrc> for ParserError { impl From<lexical::Error> for ParserError {
fn from(err_src: ParserErrorSrc) -> ParserError { fn from(e: lexical::Error) -> ParserError {
ParserError::LexicalError(err_src) 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())
}
} }
} }
@@ -575,8 +608,7 @@ impl Neg for Fixnum {
} }
} }
/* #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Literal { pub enum Literal {
Atom(Atom), Atom(Atom),
CodeIndex(CodeIndex), CodeIndex(CodeIndex),
@@ -584,7 +616,6 @@ pub enum Literal {
Integer(TypedArenaPtr<Integer>), Integer(TypedArenaPtr<Integer>),
Rational(TypedArenaPtr<Rational>), Rational(TypedArenaPtr<Rational>),
Float(F64Offset), Float(F64Offset),
String(Rc<String>),
} }
impl From<F64Ptr> for Literal { impl From<F64Ptr> for Literal {
@@ -606,7 +637,6 @@ impl fmt::Display for Literal {
Literal::Integer(ref n) => write!(f, "{}", n), Literal::Integer(ref n) => write!(f, "{}", n),
Literal::Rational(ref n) => write!(f, "{}", n), Literal::Rational(ref n) => write!(f, "{}", n),
Literal::Float(ref n) => write!(f, "{}", *n), Literal::Float(ref n) => write!(f, "{}", *n),
Literal::String(ref s) => write!(f, "\"{}\"", s.as_str()),
} }
} }
} }
@@ -619,38 +649,109 @@ impl Literal {
} }
} }
} }
*/
pub type Var = Rc<String>; #[derive(Debug, Clone, PartialEq, Eq)]
pub struct VarPtr(Rc<RefCell<Var>>);
pub(crate) fn subterm_index(heap: &impl SizedHeap, subterm_loc: usize) -> (usize, HeapCellValue) { impl Hash for VarPtr {
let subterm = heap[subterm_loc]; #[inline(always)]
fn hash<H: Hasher>(&self, hasher: &mut H) {
if subterm.is_ref() { self.borrow().hash(hasher)
let subterm = heap_bound_deref(heap, subterm); }
let subterm_loc = subterm.get_value() as usize; }
let subterm = heap_bound_store(heap, subterm);
impl Deref for VarPtr {
let subterm_loc = if subterm.is_ref() { type Target = RefCell<Var>;
subterm.get_value() as usize
} else { #[inline(always)]
subterm_loc fn deref(&self) -> &Self::Target {
}; self.0.deref()
}
(subterm_loc, subterm) }
} else {
(subterm_loc, subterm) impl VarPtr {
#[inline(always)]
pub(crate) fn borrow(&self) -> Ref<'_, Var> {
self.0.borrow()
}
#[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)] #[derive(Debug, Clone)]
pub enum Term { pub enum Term {
AnonVar, AnonVar,
Clause(Cell<RegType>, Atom, Vec<Term>), Clause(Cell<RegType>, Atom, Vec<Term>),
Cons(Cell<RegType>, Box<Term>, Box<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 // PartialString wraps a String in anticipation of it absorbing
// other PartialString variants in as_partial_string. // other PartialString variants in as_partial_string.
PartialString(Cell<RegType>, Rc<String>, Box<Term>), PartialString(Cell<RegType>, Rc<String>, Box<Term>),
@@ -668,12 +769,8 @@ impl Term {
pub fn name(&self) -> Option<Atom> { pub fn name(&self) -> Option<Atom> {
match self { match self {
Term::Literal(_, cell) => { &Term::Literal(_, Literal::Atom(atom)) => Some(atom),
cell.to_atom() &Term::Clause(_, atom, ..) => Some(atom),
}
&Term::Clause(_, atom, ..) => {
Some(atom)
}
_ => None, _ => None,
} }
} }
@@ -714,281 +811,3 @@ pub fn unfold_by_str(mut term: Term, s: Atom) -> Vec<Term> {
terms.push(term); terms.push(term);
terms 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 }
}
*/
}

View File

@@ -1,15 +1,12 @@
use crate::arena::F64Ptr; use crate::arena::F64Ptr;
use crate::arena::TypedArenaPtr; use crate::arena::TypedArenaPtr;
use lexical::{FromLexical, parse};
use crate::arena::*; use crate::arena::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::machine::heap::*;
pub use crate::machine::machine_state::*; pub use crate::machine::machine_state::*;
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::dashu::Integer; use crate::parser::dashu::Integer;
use crate::types::*;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
@@ -35,7 +32,7 @@ struct LayoutInfo {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Token { pub enum Token {
Literal(HeapCellValue), Literal(Literal),
Var(String), Var(String),
String(String), String(String),
Open, // '(' Open, // '('
@@ -51,26 +48,6 @@ pub enum Token {
} }
impl Token { 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] #[inline]
pub(super) fn is_end(&self) -> bool { pub(super) fn is_end(&self) -> bool {
matches!(self, Token::End) matches!(self, Token::End)
@@ -126,14 +103,14 @@ macro_rules! try_nt {
}}; }};
} }
pub(crate) struct LexerParser<'a, R> { pub(crate) struct Lexer<'a, R> {
pub(crate) reader: R, pub(crate) reader: R,
pub(crate) machine_st: &'a mut MachineState, pub(crate) machine_st: &'a mut MachineState,
pub(crate) line_num: usize, pub(crate) line_num: usize,
pub(crate) col_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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("LexerParser") f.debug_struct("LexerParser")
.field("reader", &"&'a mut R") // Hacky solution. .field("reader", &"&'a mut R") // Hacky solution.
@@ -143,9 +120,9 @@ impl<'a, R: fmt::Debug> fmt::Debug for LexerParser<'a, R> {
} }
} }
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 { pub fn new(src: R, machine_st: &'a mut MachineState) -> Self {
LexerParser { Self {
reader: src, reader: src,
machine_st, machine_st,
line_num: 0, line_num: 0,
@@ -156,14 +133,14 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
pub fn lookahead_char(&mut self) -> Result<char, ParserError> { pub fn lookahead_char(&mut self) -> Result<char, ParserError> {
match self.reader.peek_char() { match self.reader.peek_char() {
Some(Ok(c)) => Ok(c), 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> { pub fn read_char(&mut self) -> Result<char, ParserError> {
match self.reader.read_char() { match self.reader.read_char() {
Some(Ok(c)) => Ok(c), Some(Ok(c)) => Ok(c),
_ => Err(ParserError::unexpected_eof(self.loc_to_err_src())), _ => Err(ParserError::unexpected_eof()),
} }
} }
@@ -238,7 +215,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
match comment_loop() { match comment_loop() {
Err(e) if e.is_unexpected_eof() => { 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) => { Err(e) => {
return Err(e); return Err(e);
@@ -250,7 +230,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
self.skip_char(c); self.skip_char(c);
Ok(true) Ok(true)
} else { } else {
Err(ParserError::NonPrologChar(self.loc_to_err_src())) Err(ParserError::NonPrologChar(self.line_num, self.col_num))
} }
} else { } else {
self.return_char('/'); self.return_char('/');
@@ -267,7 +247,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if !back_quote_char!(c2) { if !back_quote_char!(c2) {
self.return_char(c); self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else { } else {
self.skip_char(c2); self.skip_char(c2);
Ok(c2) Ok(c2)
@@ -292,7 +272,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
Ok(None) Ok(None)
} else { } else {
self.return_char(c); self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} }
} else { } else {
self.get_back_quoted_char().map(Some) self.get_back_quoted_char().map(Some)
@@ -314,10 +294,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
self.skip_char(c); self.skip_char(c);
Ok(token) Ok(token)
} else { } else {
Err(ParserError::MissingQuote(self.loc_to_err_src())) Err(ParserError::MissingQuote(self.line_num, self.col_num))
} }
} else { } else {
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} }
} }
@@ -348,7 +328,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if !single_quote_char!(c2) { if !single_quote_char!(c2) {
self.return_char(c); self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else { } else {
self.skip_char(c2); self.skip_char(c2);
Ok(c2) Ok(c2)
@@ -389,7 +369,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if !double_quote_char!(c2) { if !double_quote_char!(c2) {
self.return_char(c); self.return_char(c);
Err(ParserError::UnexpectedChar(c, self.loc_to_err_src())) Err(ParserError::UnexpectedChar(c, self.line_num, self.col_num))
} else { } else {
self.skip_char(c2); self.skip_char(c2);
Ok(c2) Ok(c2)
@@ -413,7 +393,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
't' => '\t', 't' => '\t',
'n' => '\n', 'n' => '\n',
'r' => '\r', '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); self.skip_char(c);
@@ -431,7 +411,10 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if hexadecimal_digit_char!(c) { if hexadecimal_digit_char!(c) {
self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16) self.escape_sequence_to_char(|c| hexadecimal_digit_char!(c), 16)
} else { } else {
Err(ParserError::IncompleteReduction(self.loc_to_err_src())) Err(ParserError::IncompleteReduction(
self.line_num,
self.col_num,
))
} }
} }
@@ -457,11 +440,17 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if backslash_char!(c) { if backslash_char!(c) {
self.skip_char(c); self.skip_char(c);
u32::from_str_radix(&token, radix).map_or_else( u32::from_str_radix(&token, radix).map_or_else(
|_| Err(ParserError::ParseBigInt(self.loc_to_err_src())), |_| Err(ParserError::ParseBigInt(self.line_num, self.col_num)),
|n| char::try_from(n).map_err(|_| ParserError::Utf8Error(self.loc_to_err_src())), |n| {
char::try_from(n)
.map_err(|_| ParserError::Utf8Error(self.line_num, self.col_num))
},
) )
} else { } else {
Err(ParserError::IncompleteReduction(self.loc_to_err_src())) Err(ParserError::IncompleteReduction(
self.line_num,
self.col_num,
))
} }
} }
@@ -473,7 +462,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
Ok(c) Ok(c)
} else { } else {
if !backslash_char!(c) { 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);
@@ -504,7 +493,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
self.skip_char(c); self.skip_char(c);
Ok(token) Ok(token)
} else { } else {
Err(ParserError::MissingQuote(self.loc_to_err_src())) Err(ParserError::MissingQuote(self.line_num, self.col_num))
} }
} }
@@ -529,7 +518,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
.map(NumberToken::Number) .map(NumberToken::Number)
} else { } else {
self.return_char(start); self.return_char(start);
Err(ParserError::ParseBigInt(self.loc_to_err_src())) Err(ParserError::ParseBigInt(self.line_num, self.col_num))
} }
} }
@@ -554,7 +543,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
.map(NumberToken::Number) .map(NumberToken::Number)
} else { } else {
self.return_char(start); self.return_char(start);
Err(ParserError::ParseBigInt(self.loc_to_err_src())) Err(ParserError::ParseBigInt(self.line_num, self.col_num))
} }
} }
@@ -579,7 +568,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
.map(NumberToken::Number) .map(NumberToken::Number)
} else { } else {
self.return_char(start); self.return_char(start);
Err(ParserError::ParseBigInt(self.loc_to_err_src())) Err(ParserError::ParseBigInt(self.line_num, self.col_num))
} }
} }
@@ -646,42 +635,37 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if !token.is_empty() && token.chars().nth(1).is_none() { if !token.is_empty() && token.chars().nth(1).is_none() {
if let Some(c) = token.chars().next() { 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 { } else {
return Err(ParserError::InvalidSingleQuotedCharacter( return Err(ParserError::InvalidSingleQuotedCharacter(c));
self.loc_to_err_src(),
));
} }
} else { } else {
match self.get_back_quoted_string() { 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), Err(e) => return Err(e),
} }
} }
if token.as_str() == "[]" { if token.as_str() == "[]" {
Ok(Token::Literal(empty_list_as_cell!())) Ok(Token::Literal(Literal::Atom(atom!("[]"))))
} else { } else {
Ok(Token::Literal(atom_as_cell!(AtomTable::build_with( Ok(Token::Literal(Literal::Atom(AtomTable::build_with(
&self.machine_st.atom_tbl, &self.machine_st.atom_tbl,
&token, &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> { fn vacate_with_float(&mut self, mut token: String) -> Result<Token, ParserError> {
self.return_char(token.pop().unwrap()); 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, n,
self.machine_st.arena self.machine_st.arena
)))) ))))
@@ -698,7 +682,7 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
if decimal_digit_char!(c) { if decimal_digit_char!(c) {
Ok(c) Ok(c)
} else { } else {
Err(ParserError::ParseBigInt(self.loc_to_err_src())) Err(ParserError::ParseBigInt(self.line_num, self.col_num))
} }
} else { } else {
Ok(c) Ok(c)
@@ -810,8 +794,8 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
} }
} }
let n = self.parse_lossy_wrapper::<f64>(&token)?; let n = parse_float_lossy(&token)?;
Ok(Token::Literal(HeapCellValue::from(float_alloc!( Ok(Token::Literal(Literal::from(float_alloc!(
n, n,
self.machine_st.arena self.machine_st.arena
)))) ))))
@@ -819,8 +803,8 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
return self.vacate_with_float(token).map(NumberToken::Number); return self.vacate_with_float(token).map(NumberToken::Number);
} }
} else { } else {
let n = self.parse_lossy_wrapper::<f64>(&token)?; let n = parse_float_lossy(&token)?;
Ok(Token::Literal(HeapCellValue::from(float_alloc!( Ok(Token::Literal(Literal::from(float_alloc!(
n, n,
self.machine_st.arena self.machine_st.arena
)))) ))))
@@ -1057,14 +1041,14 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes { return if let DoubleQuotes::Atom = self.machine_st.flags.double_quotes {
let atom = AtomTable::build_with(&self.machine_st.atom_tbl, &s); 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 { } else {
Ok(Token::String(s)) Ok(Token::String(s))
}; };
} }
if c == '\u{0}' { if c == '\u{0}' {
return Err(ParserError::unexpected_eof(self.loc_to_err_src())); return Err(ParserError::unexpected_eof());
} }
self.name_token(c) self.name_token(c)
@@ -1073,3 +1057,13 @@ impl<'a, R: CharRead> LexerParser<'a, R> {
} }
} }
} }
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)
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@ pub struct RawBlock<T: RawBlockTraits> {
impl<T: RawBlockTraits> RawBlock<T> { impl<T: RawBlockTraits> RawBlock<T> {
#[inline] #[inline]
pub(crate) fn empty_block() -> Self { fn empty_block() -> Self {
RawBlock { RawBlock {
base: ptr::null(), base: ptr::null(),
top: ptr::null(), top: ptr::null(),

View File

@@ -1,14 +1,21 @@
use crate::parser::ast::*; use crate::parser::ast::*;
use crate::parser::lexer::Lexer;
use crate::parser::parser::*; use crate::parser::parser::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*;
use crate::iterators::*;
use crate::machine::heap::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::MachineState; use crate::machine::machine_state::MachineState;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::parser::char_reader::*; use crate::parser::char_reader::*;
use crate::parser::lexer::LexerParser;
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
use crate::repl_helper::Helper; use crate::repl_helper::Helper;
use crate::types::*;
use fxhash::FxBuildHasher;
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
use rustyline::error::ReadlineError; use rustyline::error::ReadlineError;
@@ -17,13 +24,16 @@ use rustyline::history::DefaultHistory;
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
use rustyline::{Config, Editor}; use rustyline::{Config, Editor};
use std::collections::VecDeque;
use std::io::{Cursor, Read}; use std::io::{Cursor, Read};
#[cfg(feature = "repl")] #[cfg(feature = "repl")]
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use std::sync::Arc; use std::sync::Arc;
type SubtermDeque = VecDeque<(usize, usize)>;
pub(crate) fn devour_whitespace<R: CharRead>( pub(crate) fn devour_whitespace<R: CharRead>(
lexer: &mut LexerParser<'_, R>, lexer: &mut Lexer<'_, R>,
) -> Result<bool, ParserError> { ) -> Result<bool, ParserError> {
match lexer.scan_for_layout() { match lexer.scan_for_layout() {
Err(e) if e.is_unexpected_eof() => Ok(true), Err(e) if e.is_unexpected_eof() => Ok(true),
@@ -32,16 +42,18 @@ pub(crate) fn devour_whitespace<R: CharRead>(
} }
} }
pub(crate) fn error_after_read_term( pub(crate) fn error_after_read_term<R>(
err: ParserError, err: ParserError,
prior_num_lines_read: usize, prior_num_lines_read: usize,
parser: &Parser<R>,
) -> CompilationError { ) -> CompilationError {
if err.is_unexpected_eof() { 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 // 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) { 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));
} }
} }
@@ -49,37 +61,27 @@ pub(crate) fn error_after_read_term(
} }
impl MachineState { impl MachineState {
pub(crate) fn read<R: CharRead>( pub(crate) fn read(
&mut self,
inner: R,
op_dir: &OpDir,
) -> Result<(TermWriteResult, usize), ParserError> {
let mut lexer_parser = LexerParser::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();
term_result.map(|term| (term, lines_read))
}
pub(crate) fn read_to_heap(
&mut self, &mut self,
mut inner: Stream, mut inner: Stream,
op_dir: &OpDir, op_dir: &OpDir,
) -> Result<TermWriteResult, CompilationError> { ) -> Result<TermWriteResult, CompilationError> {
let (term, num_lines_read) = {
let prior_num_lines_read = inner.lines_read(); let prior_num_lines_read = inner.lines_read();
let term = match self.read(inner, op_dir) { let mut parser = Parser::new(inner, self);
Ok((term, num_lines_read)) => { let op_dir = CompositeOpDir::new(op_dir, None);
inner.add_lines_read(num_lines_read);
term parser.add_lines_read(prior_num_lines_read);
}
Err(e) => { let term = parser
return Err(error_after_read_term(e, prior_num_lines_read)); .read_term(&op_dir, Tokens::Default)
} .map_err(|err| error_after_read_term(err, prior_num_lines_read, &parser))?; // CompilationError::from
(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)
} }
} }
@@ -278,6 +280,7 @@ impl CharRead for ReadlineStream {
} }
} }
} }
#[inline] #[inline]
fn consume(&mut self, nread: usize) { fn consume(&mut self, nread: usize) {
self.pending_input.consume(nread); self.pending_input.consume(nread);
@@ -288,3 +291,217 @@ impl CharRead for ReadlineStream {
self.pending_input.put_back_char(c); 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,
})
}
}

View File

@@ -3,6 +3,7 @@ use crate::parser::ast::*;
use crate::atom_table::*; use crate::atom_table::*;
use crate::forms::*; use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*;
use crate::types::*; use crate::types::*;
use std::rc::Rc; use std::rc::Rc;
@@ -11,7 +12,11 @@ pub(crate) struct FactInstruction;
pub(crate) struct QueryInstruction; pub(crate) struct QueryInstruction;
pub(crate) trait CompilationTarget<'a> { 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_list(lvl: Level, r: RegType) -> Instruction;
fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction; fn to_structure(lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction;
@@ -22,7 +27,7 @@ pub(crate) trait CompilationTarget<'a> {
fn incr_void_instr(instr: &mut 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_variable(r: RegType, r: usize) -> Instruction;
fn argument_to_value(r: RegType, val: usize) -> Instruction; fn argument_to_value(r: RegType, val: usize) -> Instruction;
@@ -38,8 +43,14 @@ pub(crate) trait CompilationTarget<'a> {
} }
impl<'a> CompilationTarget<'a> for FactInstruction { impl<'a> CompilationTarget<'a> for FactInstruction {
fn to_constant(lvl: Level, cell: HeapCellValue, reg: RegType) -> Instruction { type Iterator = FactIterator<'a>;
Instruction::GetConstant(lvl, cell, reg)
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 to_structure(lvl: Level, name: Atom, arity: usize, reg: RegType) -> Instruction {
@@ -68,8 +79,8 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
} }
} }
fn constant_subterm(constant: HeapCellValue) -> Instruction { fn constant_subterm(constant: Literal) -> Instruction {
Instruction::UnifyConstant(constant) Instruction::UnifyConstant(HeapCellValue::from(constant))
} }
fn argument_to_variable(arg: RegType, val: usize) -> Instruction { fn argument_to_variable(arg: RegType, val: usize) -> Instruction {
@@ -106,8 +117,10 @@ impl<'a> CompilationTarget<'a> for FactInstruction {
} }
impl<'a> CompilationTarget<'a> for QueryInstruction { impl<'a> CompilationTarget<'a> for QueryInstruction {
fn to_constant(lvl: Level, constant: HeapCellValue, reg: RegType) -> Instruction { type Iterator = QueryIterator<'a>;
Instruction::PutConstant(lvl, constant, reg)
fn iter(term: &'a Term) -> Self::Iterator {
post_order_iter(term)
} }
fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction { fn to_structure(_lvl: Level, name: Atom, arity: usize, r: RegType) -> Instruction {
@@ -136,8 +149,12 @@ impl<'a> CompilationTarget<'a> for QueryInstruction {
} }
} }
fn constant_subterm(constant: HeapCellValue) -> Instruction { fn constant_subterm(constant: Literal) -> Instruction {
Instruction::SetConstant(constant) 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 { fn argument_to_variable(arg: RegType, val: usize) -> Instruction {

View File

@@ -46,7 +46,7 @@ test_queries_on_builtins :-
\+ float([1,2,_]), \+ float([1,2,_]),
\+ (X is 3 rdiv 4, float(X)), \+ (X is 3 rdiv 4, float(X)),
\+ \+ (X is 3 rdiv 4, rational(X)), \+ \+ (X is 3 rdiv 4, rational(X)),
rational(3), \+ rational(3),
\+ rational(f(_)), \+ rational(f(_)),
\+ rational("sdfa"), \+ rational("sdfa"),
\+ rational(atom), \+ rational(atom),

View File

@@ -30,7 +30,7 @@ test_queries_on_call_with_inference_limit :-
[true, 4], [true, 4],
[!, 5]]), [!, 5]]),
findall([R,X], 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, 1],
[true, 2], [true, 2],
[inference_limit_exceeded, _]]), [inference_limit_exceeded, _]]),

View File

@@ -7,6 +7,7 @@ use crate::machine::heap::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::parser::ast::Fixnum; use crate::parser::ast::Fixnum;
use crate::parser::ast::Literal;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -14,6 +15,8 @@ use std::fmt;
use std::mem; use std::mem;
use std::ops::{Add, Sub, SubAssign}; use std::ops::{Add, Sub, SubAssign};
use dashu::{Integer, Rational};
#[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] #[derive(BitfieldSpecifier, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
#[repr(u8)] #[repr(u8)]
#[bits = 6] #[bits = 6]
@@ -307,6 +310,67 @@ impl fmt::Debug for HeapCellValue {
} }
} }
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 impl<T: ArenaAllocated> From<TypedArenaPtr<T>> for HeapCellValue
where where
T::Payload: Sized, T::Payload: Sized,

View File

@@ -88,10 +88,7 @@ pub enum VarAlloc {
safety: VarSafetyStatus, safety: VarSafetyStatus,
to_perm_var_num: Option<usize>, to_perm_var_num: Option<usize>,
}, },
Perm { Perm(usize, PermVarAllocation), // stack offset, allocation info
reg: usize,
allocation: PermVarAllocation,
}, // stack offset, allocation info
} }
impl VarAlloc { impl VarAlloc {
@@ -99,14 +96,14 @@ impl VarAlloc {
pub(crate) fn as_reg_type(&self) -> RegType { pub(crate) fn as_reg_type(&self) -> RegType {
match *self { match *self {
VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg), VarAlloc::Temp { temp_reg, .. } => RegType::Temp(temp_reg),
VarAlloc::Perm { reg, .. } => RegType::Perm(reg), VarAlloc::Perm(r, _) => RegType::Perm(r),
} }
} }
#[inline] #[inline]
pub(crate) fn set_register(&mut self, reg_num: usize) { pub(crate) fn set_register(&mut self, reg_num: usize) {
match self { match self {
VarAlloc::Perm { ref mut reg, .. } => *reg = reg_num, VarAlloc::Perm(ref mut p, _) => *p = reg_num,
VarAlloc::Temp { VarAlloc::Temp {
ref mut temp_reg, .. ref mut temp_reg, ..
} => *temp_reg = reg_num, } => *temp_reg = reg_num,
@@ -155,10 +152,7 @@ pub struct VariableRecord {
impl Default for VariableRecord { impl Default for VariableRecord {
fn default() -> Self { fn default() -> Self {
VariableRecord { VariableRecord {
allocation: VarAlloc::Perm { allocation: VarAlloc::Perm(0, PermVarAllocation::Pending),
reg: 0,
allocation: PermVarAllocation::Pending,
},
num_occurrences: 0, num_occurrences: 0,
running_count: 0, running_count: 0,
} }

View File

@@ -761,7 +761,8 @@ test_171 :- writeq_term_to_chars("a", C),
test_229 :- test_syntax_error("\"\\z.\"", syntax_error(missing_quote)). 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\\']". C == "['\\x0\\']".
test_172 :- X is 10.0** -323, test_172 :- X is 10.0** -323,

View File

@@ -35,7 +35,7 @@ fn hello_world() {
fn syntax_error() { fn syntax_error() {
load_module_test( load_module_test(
"tests-pl/syntax_error.pl", "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",
); );
} }