Merge branch 'compiling_disj'
This commit is contained in:
@@ -23,13 +23,9 @@ fn capture_offset(line: &Instruction, index: usize, stack: &mut Vec<usize>) -> b
|
||||
{
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Instruction::JmpByCall(_, offset, _) => {
|
||||
&Instruction::JmpByCall(offset) => {
|
||||
stack.push(index + offset);
|
||||
}
|
||||
&Instruction::JmpByExecute(_, offset, _) => {
|
||||
stack.push(index + offset);
|
||||
return true;
|
||||
}
|
||||
&Instruction::Proceed => {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -44,60 +44,6 @@ pub(super) fn bootstrapping_compile(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// throw errors if declaration or query found.
|
||||
pub(super) fn compile_relation(
|
||||
cg: &mut CodeGenerator,
|
||||
tl: &TopLevel,
|
||||
) -> Result<Code, CompilationError> {
|
||||
match tl {
|
||||
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
|
||||
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
|
||||
&TopLevel::Fact(ref fact, ..) => cg.compile_fact(fact),
|
||||
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn compile_appendix(
|
||||
code: &mut Code,
|
||||
mut queue: VecDeque<TopLevel>,
|
||||
jmp_by_locs: Vec<usize>,
|
||||
non_counted_bt: bool,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Result<(), CompilationError> {
|
||||
let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
|
||||
|
||||
while let Some(jmp_by_offset) = jmp_by_locs.pop_front() {
|
||||
let code_len = code.len();
|
||||
|
||||
match &mut code[jmp_by_offset] {
|
||||
&mut Instruction::JmpByCall(_, ref mut offset, ..) |
|
||||
&mut Instruction::JmpByExecute(_, ref mut offset, ..) => {
|
||||
*offset = code_len - jmp_by_offset;
|
||||
}
|
||||
_ => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
// false because the inner predicate is a one-off, hence not extensible.
|
||||
let settings = CodeGenSettings {
|
||||
global_clock_tick: None,
|
||||
is_extensible: false,
|
||||
non_counted_bt,
|
||||
};
|
||||
|
||||
let mut cg = CodeGenerator::new(atom_tbl, settings);
|
||||
|
||||
let tl = queue.pop_front().unwrap();
|
||||
let decl_code = compile_relation(&mut cg, &tl)?;
|
||||
|
||||
jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len()));
|
||||
code.extend(decl_code.into_iter());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize {
|
||||
if target_pos == 0 {
|
||||
return 0;
|
||||
@@ -1342,22 +1288,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
let mut preprocessor = Preprocessor::new(settings);
|
||||
|
||||
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
|
||||
let queue = preprocessor.parse_queue(self)?;
|
||||
// let queue = preprocessor.parse_queue(self)?;
|
||||
|
||||
let mut cg = CodeGenerator::new(
|
||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||
settings,
|
||||
);
|
||||
|
||||
let mut clause_code = cg.compile_predicate(&vec![clause])?;
|
||||
|
||||
compile_appendix(
|
||||
&mut clause_code,
|
||||
queue,
|
||||
cg.jmp_by_locs,
|
||||
settings.non_counted_bt,
|
||||
cg.atom_tbl,
|
||||
)?;
|
||||
let clause_code = cg.compile_predicate(vec![clause])?;
|
||||
|
||||
Ok(StandaloneCompileResult {
|
||||
clause_code,
|
||||
@@ -1385,22 +1323,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
|
||||
}
|
||||
|
||||
let queue = preprocessor.parse_queue(self)?;
|
||||
|
||||
let mut cg = CodeGenerator::new(
|
||||
&mut LS::machine_st(&mut self.payload).atom_tbl,
|
||||
settings,
|
||||
);
|
||||
|
||||
let mut code = cg.compile_predicate(&clauses)?;
|
||||
|
||||
compile_appendix(
|
||||
&mut code,
|
||||
queue,
|
||||
cg.jmp_by_locs,
|
||||
settings.non_counted_bt,
|
||||
cg.atom_tbl,
|
||||
)?;
|
||||
let mut code = cg.compile_predicate(clauses)?;
|
||||
|
||||
if settings.is_extensible {
|
||||
let mut clause_clause_locs = VecDeque::new();
|
||||
|
||||
829
src/machine/disjuncts.rs
Normal file
829
src/machine/disjuncts.rs
Normal file
@@ -0,0 +1,829 @@
|
||||
use crate::atom_table::*;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::CompilationError;
|
||||
use crate::machine::preprocessor::*;
|
||||
use crate::parser::ast::*;
|
||||
use crate::parser::rug::Rational;
|
||||
use crate::variable_records::*;
|
||||
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::VecDeque;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
#[derive(Debug, Clone)] //, PartialOrd, PartialEq, Eq, Hash)]
|
||||
pub struct BranchNumber {
|
||||
branch_num: Rational,
|
||||
delta: Rational,
|
||||
}
|
||||
|
||||
impl Default for BranchNumber {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
branch_num: Rational::from(1usize << 63),
|
||||
delta: Rational::from(1),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<BranchNumber> for BranchNumber {
|
||||
#[inline]
|
||||
fn eq(&self, rhs: &BranchNumber) -> bool {
|
||||
self.branch_num == rhs.branch_num
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BranchNumber {}
|
||||
|
||||
impl Hash for BranchNumber {
|
||||
#[inline(always)]
|
||||
fn hash<H: Hasher>(&self, hasher: &mut H) {
|
||||
self.branch_num.hash(hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<BranchNumber> for BranchNumber {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, rhs: &BranchNumber) -> Option<Ordering> {
|
||||
self.branch_num.partial_cmp(&rhs.branch_num)
|
||||
}
|
||||
}
|
||||
|
||||
impl BranchNumber {
|
||||
fn split(&self) -> BranchNumber {
|
||||
BranchNumber {
|
||||
branch_num: self.branch_num.clone() + &self.delta / Rational::from(2),
|
||||
delta: &self.delta / Rational::from(4),
|
||||
}
|
||||
}
|
||||
|
||||
fn incr_by_delta(&self) -> BranchNumber {
|
||||
BranchNumber {
|
||||
branch_num: self.branch_num.clone() + &self.delta,
|
||||
delta: self.delta.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
fn halve_delta(&self) -> BranchNumber {
|
||||
BranchNumber {
|
||||
branch_num: self.branch_num.clone(),
|
||||
delta : &self.delta / Rational::from(2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VarInfo {
|
||||
var_ptr: VarPtr,
|
||||
chunk_type: ChunkType,
|
||||
classify_info: ClassifyInfo,
|
||||
lvl: Level,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ChunkInfo {
|
||||
chunk_num: usize,
|
||||
term_loc: GenContext,
|
||||
// pointer to incidence, term occurrence arity.
|
||||
vars: Vec<VarInfo>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BranchArm {
|
||||
pub arm_terms: Vec<QueryTerm>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct BranchInfo {
|
||||
branch_num: BranchNumber,
|
||||
chunks: Vec<ChunkInfo>,
|
||||
}
|
||||
|
||||
impl BranchInfo {
|
||||
fn new(branch_num: BranchNumber) -> Self {
|
||||
Self { branch_num, chunks: vec![] }
|
||||
}
|
||||
}
|
||||
|
||||
type BranchMapInt = IndexMap<VarPtr, Vec<BranchInfo>>;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct BranchMap(BranchMapInt);
|
||||
|
||||
impl Deref for BranchMap {
|
||||
type Target = BranchMapInt;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &BranchMapInt {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for BranchMap {
|
||||
#[inline(always)]
|
||||
fn deref_mut(&mut self) -> &mut BranchMapInt {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
|
||||
type RootSet = IndexSet<BranchNumber>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct ClassifyInfo {
|
||||
arg_c: usize,
|
||||
arity: usize,
|
||||
}
|
||||
|
||||
enum TraversalState {
|
||||
// construct a QueryTerm::Branch with number of disjuncts, reset
|
||||
// the chunk type to that of the chunk preceding the disjunct and the chunk_num.
|
||||
BuildDisjunct(usize),
|
||||
// add the last disjunct to a QueryTerm::Branch, continuing from
|
||||
// where it leaves off.
|
||||
BuildFinalDisjunct(usize),
|
||||
Fail,
|
||||
GetCutPoint{ var_num: usize, prev_b: bool },
|
||||
Cut { var_num: usize, is_global: bool },
|
||||
ResetCallPolicy(CallPolicy),
|
||||
Term(Term),
|
||||
RemoveBranchNum, // pop the current_branch_num and from the root set.
|
||||
AddBranchNum(BranchNumber), // set current_branch_num, add it to the root set
|
||||
RepBranchNum(BranchNumber), // replace current_branch_num and the latest in the root set
|
||||
// SetChunkType(ChunkType), // consider remaining terms as belonging to a last chunk
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct VariableClassifier {
|
||||
call_policy: CallPolicy,
|
||||
current_branch_num: BranchNumber,
|
||||
current_chunk_num: usize,
|
||||
current_chunk_type: ChunkType,
|
||||
branch_map: BranchMap,
|
||||
var_num: usize,
|
||||
root_set: RootSet,
|
||||
global_cut_var_num: Option<usize>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct VarData {
|
||||
pub records: VariableRecords,
|
||||
pub global_cut_var_num: Option<usize>,
|
||||
pub allocates: bool,
|
||||
}
|
||||
|
||||
impl VarData {
|
||||
fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
|
||||
let global_cut_var_num =
|
||||
if let &Some(global_cut_var_num) = &self.global_cut_var_num {
|
||||
match &self.records[global_cut_var_num].allocation {
|
||||
VarAlloc::Perm(..) => Some(global_cut_var_num),
|
||||
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
|
||||
Some(global_cut_var_num)
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(global_cut_var_num) = global_cut_var_num {
|
||||
let term = QueryTerm::GetLevel(global_cut_var_num);
|
||||
self.records[global_cut_var_num].allocation = VarAlloc::Perm(0, PermVarAllocation::Pending);
|
||||
|
||||
match build_stack.front_mut() {
|
||||
Some(ChunkedTerms::Branch(_)) => {
|
||||
build_stack.push_front(ChunkedTerms::Chunk(VecDeque::from(vec![term])));
|
||||
}
|
||||
Some(ChunkedTerms::Chunk(chunk)) => {
|
||||
chunk.push_front(term);
|
||||
}
|
||||
None => {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type ClassifyFactResult = (Term, VarData);
|
||||
pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
|
||||
|
||||
fn merge_branch_seq<Iter: Iterator<Item = BranchInfo>>(branches: Iter) -> BranchInfo {
|
||||
let mut branch_info = BranchInfo::new(BranchNumber::default());
|
||||
|
||||
for mut branch in branches {
|
||||
branch_info.branch_num = branch.branch_num;
|
||||
|
||||
/*
|
||||
if let Some(last_chunk) = branch_info.chunks.last_mut() {
|
||||
if let Some(first_moved_chunk) = branch.chunks.first_mut() {
|
||||
if last_chunk.chunk_num == first_moved_chunk.chunk_num {
|
||||
last_chunk.vars.extend(first_moved_chunk.vars.drain(..));
|
||||
branch_info.chunks.extend(branch.chunks.drain(1 ..));
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
branch_info.chunks.extend(branch.chunks.drain(..));
|
||||
}
|
||||
|
||||
branch_info.branch_num.delta *= 2;
|
||||
branch_info.branch_num.branch_num -= &branch_info.branch_num.delta;
|
||||
|
||||
branch_info
|
||||
}
|
||||
|
||||
fn flatten_into_disjunct(build_stack: &mut ChunkedTermVec, preceding_len: usize) {
|
||||
let branch_vec = build_stack.drain(preceding_len + 1 ..).collect();
|
||||
|
||||
if let ChunkedTerms::Branch(ref mut disjuncts) = &mut build_stack[preceding_len] {
|
||||
disjuncts.push(branch_vec);
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
impl VariableClassifier {
|
||||
pub fn new(call_policy: CallPolicy) -> Self {
|
||||
Self {
|
||||
call_policy,
|
||||
current_branch_num: BranchNumber::default(),
|
||||
current_chunk_num: 0,
|
||||
current_chunk_type: ChunkType::Head,
|
||||
branch_map: BranchMap(BranchMapInt::new()),
|
||||
root_set: RootSet::new(),
|
||||
var_num: 0,
|
||||
global_cut_var_num: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn classify_fact(mut self, term: Term) -> Result<ClassifyFactResult, CompilationError> {
|
||||
self.classify_head_variables(&term)?;
|
||||
Ok((term, self.branch_map.separate_and_classify_variables(
|
||||
self.var_num,
|
||||
self.global_cut_var_num,
|
||||
self.current_chunk_num,
|
||||
)))
|
||||
}
|
||||
|
||||
pub fn classify_rule<'a, LS: LoadState<'a>>(
|
||||
mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
head: Term,
|
||||
body: Term,
|
||||
) -> Result<ClassifyRuleResult, CompilationError> {
|
||||
self.classify_head_variables(&head)?;
|
||||
self.root_set.insert(self.current_branch_num.clone());
|
||||
|
||||
let mut query_terms = self.classify_body_variables(loader, body)?;
|
||||
|
||||
self.merge_branches();
|
||||
|
||||
let mut var_data = self.branch_map.separate_and_classify_variables(
|
||||
self.var_num,
|
||||
self.global_cut_var_num,
|
||||
self.current_chunk_num,
|
||||
);
|
||||
|
||||
var_data.emit_initial_get_level(&mut query_terms);
|
||||
|
||||
Ok((head, query_terms, var_data))
|
||||
}
|
||||
|
||||
fn merge_branches(&mut self) {
|
||||
for branches in self.branch_map.values_mut() {
|
||||
let mut old_branches = std::mem::replace(branches, vec![]);
|
||||
|
||||
while let Some(last_branch_num) = old_branches.last().map(|bi| &bi.branch_num) {
|
||||
let mut old_branches_len = old_branches.len();
|
||||
|
||||
for (rev_idx, bi) in old_branches.iter().rev().enumerate() {
|
||||
if &bi.branch_num > last_branch_num {
|
||||
old_branches_len = old_branches.len() - rev_idx;
|
||||
}
|
||||
}
|
||||
|
||||
let iter = old_branches.drain(old_branches_len - 1 ..);
|
||||
branches.push(merge_branch_seq(iter));
|
||||
}
|
||||
|
||||
branches.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
|
||||
let classify_info = ClassifyInfo { arg_c, arity };
|
||||
|
||||
// second arg is true to iterate the root, which may be a variable
|
||||
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
|
||||
// root terms are shallow here (since we're iterating a
|
||||
// body term) so take the child level.
|
||||
let lvl = lvl.child_level();
|
||||
self.probe_body_var(VarInfo {
|
||||
var_ptr,
|
||||
lvl,
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn probe_body_var(&mut self, var_info: VarInfo) {
|
||||
let term_loc = self.current_chunk_type.to_gen_context(self.current_chunk_num);
|
||||
|
||||
let branch_info_v = self.branch_map.entry(var_info.var_ptr.clone())
|
||||
.or_insert_with(|| vec![]);
|
||||
|
||||
let needs_new_branch = if let Some(last_bi) = branch_info_v.last() {
|
||||
!self.root_set.contains(&last_bi.branch_num)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if needs_new_branch {
|
||||
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
|
||||
}
|
||||
|
||||
let branch_info = branch_info_v.last_mut().unwrap();
|
||||
|
||||
let needs_new_chunk = if let Some(last_ci) = branch_info.chunks.last() {
|
||||
last_ci.chunk_num != self.current_chunk_num
|
||||
} else {
|
||||
true
|
||||
};
|
||||
|
||||
if needs_new_chunk {
|
||||
branch_info.chunks.push(ChunkInfo {
|
||||
chunk_num: self.current_chunk_num,
|
||||
term_loc,
|
||||
vars: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
let chunk_info = branch_info.chunks.last_mut().unwrap();
|
||||
chunk_info.vars.push(var_info);
|
||||
}
|
||||
|
||||
fn probe_in_situ_var(&mut self, var_num: usize) {
|
||||
let classify_info = ClassifyInfo { arg_c: 1, arity: 1 };
|
||||
|
||||
let var_info = VarInfo {
|
||||
var_ptr: VarPtr::from(Var::InSitu(var_num)),
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
lvl: Level::Shallow,
|
||||
};
|
||||
|
||||
self.probe_body_var(var_info);
|
||||
}
|
||||
|
||||
fn classify_head_variables(&mut self, term: &Term) -> Result<(), CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(_)) => {
|
||||
}
|
||||
_ => return Err(CompilationError::InvalidRuleHead),
|
||||
}
|
||||
|
||||
let mut classify_info = ClassifyInfo { arg_c: 1, arity: term.arity() };
|
||||
|
||||
match term {
|
||||
Term::Clause(_, _, terms) => {
|
||||
for term in terms.into_iter() {
|
||||
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
|
||||
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
|
||||
// a body term, so we need the child level here.
|
||||
let lvl = lvl.child_level();
|
||||
|
||||
// the body of the if let here is an inlined
|
||||
// "probe_head_var". note the difference between it
|
||||
// and "probe_body_var".
|
||||
let branch_info_v = self.branch_map.entry(var_ptr.clone())
|
||||
.or_insert_with(|| vec![]);
|
||||
|
||||
let needs_new_branch = branch_info_v.is_empty();
|
||||
|
||||
if needs_new_branch {
|
||||
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
|
||||
}
|
||||
|
||||
let branch_info = branch_info_v.last_mut().unwrap();
|
||||
let needs_new_chunk = branch_info.chunks.is_empty();
|
||||
|
||||
if needs_new_chunk {
|
||||
branch_info.chunks.push(ChunkInfo {
|
||||
chunk_num: self.current_chunk_num,
|
||||
term_loc: GenContext::Head,
|
||||
vars: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
let chunk_info = branch_info.chunks.last_mut().unwrap();
|
||||
let var_info = VarInfo {
|
||||
var_ptr,
|
||||
classify_info,
|
||||
chunk_type: self.current_chunk_type,
|
||||
lvl,
|
||||
};
|
||||
|
||||
chunk_info.vars.push(var_info);
|
||||
}
|
||||
}
|
||||
|
||||
classify_info.arg_c += 1;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn classify_body_variables<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
) -> Result<ChunkedTermVec, CompilationError> {
|
||||
let mut state_stack = vec![TraversalState::Term(term)];
|
||||
let mut build_stack = ChunkedTermVec::new();
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
|
||||
while let Some(traversal_st) = state_stack.pop() {
|
||||
match traversal_st {
|
||||
TraversalState::AddBranchNum(branch_num) => {
|
||||
self.root_set.insert(branch_num.clone());
|
||||
self.current_branch_num = branch_num;
|
||||
}
|
||||
TraversalState::RemoveBranchNum => {
|
||||
self.root_set.pop();
|
||||
}
|
||||
TraversalState::RepBranchNum(branch_num) => {
|
||||
self.root_set.pop();
|
||||
self.root_set.insert(branch_num.clone());
|
||||
self.current_branch_num = branch_num;
|
||||
}
|
||||
TraversalState::ResetCallPolicy(call_policy) => {
|
||||
self.call_policy = call_policy;
|
||||
}
|
||||
TraversalState::BuildDisjunct(preceding_len) => {
|
||||
flatten_into_disjunct(&mut build_stack, preceding_len);
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
}
|
||||
TraversalState::BuildFinalDisjunct(preceding_len) => {
|
||||
flatten_into_disjunct(&mut build_stack, preceding_len);
|
||||
|
||||
self.current_chunk_type = ChunkType::Mid;
|
||||
self.current_chunk_num += 1;
|
||||
}
|
||||
TraversalState::GetCutPoint { var_num, prev_b } => {
|
||||
if self.try_set_chunk_at_inlined_boundary() {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
build_stack.push_chunk_term(QueryTerm::GetCutPoint { var_num, prev_b });
|
||||
}
|
||||
TraversalState::Cut { var_num, is_global } => {
|
||||
if self.try_set_chunk_at_inlined_boundary() {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_in_situ_var(var_num);
|
||||
|
||||
build_stack.push_chunk_term(
|
||||
if is_global {
|
||||
QueryTerm::GlobalCut(var_num)
|
||||
} else {
|
||||
QueryTerm::LocalCut(var_num)
|
||||
}
|
||||
);
|
||||
}
|
||||
TraversalState::Fail => {
|
||||
build_stack.push_chunk_term(QueryTerm::Fail);
|
||||
}
|
||||
TraversalState::Term(term) => {
|
||||
// return true iff new chunk should be added.
|
||||
let update_chunk_data = |classifier: &mut Self, predicate_name, arity| {
|
||||
if ClauseType::is_inlined(predicate_name, arity) {
|
||||
classifier.try_set_chunk_at_inlined_boundary()
|
||||
} else {
|
||||
classifier.try_set_chunk_at_call_boundary()
|
||||
}
|
||||
};
|
||||
|
||||
match term {
|
||||
Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
|
||||
let tail = terms.pop().unwrap();
|
||||
let head = terms.pop().unwrap();
|
||||
|
||||
let iter = unfold_by_str(tail, atom!(","))
|
||||
.into_iter()
|
||||
.rev()
|
||||
.chain(std::iter::once(head))
|
||||
.map(TraversalState::Term);
|
||||
|
||||
state_stack.extend(iter);
|
||||
}
|
||||
Term::Clause(_, atom!(";"), mut terms) if terms.len() == 2 => {
|
||||
let tail = terms.pop().unwrap();
|
||||
let head = terms.pop().unwrap();
|
||||
|
||||
let first_branch_num = self.current_branch_num.split();
|
||||
let branches: Vec<_> = std::iter::once(head)
|
||||
.chain(unfold_by_str(tail, atom!(";")).into_iter())
|
||||
.collect();
|
||||
|
||||
let mut branch_numbers = vec![first_branch_num];
|
||||
|
||||
for idx in 1 .. branches.len() {
|
||||
let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
|
||||
|
||||
branch_numbers.push(if idx + 1 < branches.len() {
|
||||
succ_branch_number.split()
|
||||
} else {
|
||||
succ_branch_number
|
||||
});
|
||||
}
|
||||
|
||||
let build_stack_len = build_stack.len();
|
||||
build_stack.reserve_branch(branches.len());
|
||||
|
||||
state_stack.push(TraversalState::RepBranchNum(
|
||||
self.current_branch_num.halve_delta(),
|
||||
));
|
||||
|
||||
let iter = branches.into_iter().zip(branch_numbers.into_iter());
|
||||
let final_disjunct_loc = state_stack.len();
|
||||
|
||||
for (term, branch_num) in iter.rev() {
|
||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::RemoveBranchNum);
|
||||
state_stack.push(TraversalState::Term(term));
|
||||
state_stack.push(TraversalState::AddBranchNum(branch_num));
|
||||
}
|
||||
|
||||
if let TraversalState::BuildDisjunct(build_stack_len) = state_stack[final_disjunct_loc] {
|
||||
state_stack[final_disjunct_loc] = TraversalState::BuildFinalDisjunct(build_stack_len);
|
||||
}
|
||||
}
|
||||
Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
|
||||
let then_term = terms.pop().unwrap();
|
||||
let if_term = terms.pop().unwrap();
|
||||
|
||||
let prev_b = if matches!(state_stack.last(), Some(TraversalState::RemoveBranchNum)) {
|
||||
// check if the second-to-last element is a regular BuildDisjunct, as we don't
|
||||
// want to add GetPrevLevel in case of a TrustMe.
|
||||
matches!(state_stack.iter().rev().nth(1), Some(TraversalState::BuildDisjunct(..)))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
state_stack.push(TraversalState::Term(then_term));
|
||||
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
|
||||
state_stack.push(TraversalState::Term(if_term));
|
||||
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b });
|
||||
|
||||
self.var_num += 1;
|
||||
}
|
||||
Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
|
||||
let not_term = terms.pop().unwrap();
|
||||
let build_stack_len = build_stack.len();
|
||||
|
||||
build_stack.reserve_branch(2);
|
||||
|
||||
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::Term(Term::Clause(Cell::default(), atom!("$succeed"), vec![])));
|
||||
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
|
||||
state_stack.push(TraversalState::Fail);
|
||||
state_stack.push(TraversalState::Cut { var_num: self.var_num, is_global: false });
|
||||
state_stack.push(TraversalState::Term(not_term));
|
||||
state_stack.push(TraversalState::GetCutPoint { var_num: self.var_num, prev_b: true });
|
||||
|
||||
self.var_num += 1;
|
||||
}
|
||||
Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
|
||||
let predicate_name = terms.pop().unwrap();
|
||||
let module_name = terms.pop().unwrap();
|
||||
|
||||
match (module_name, predicate_name) {
|
||||
(
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
Term::Literal(_, Literal::Atom(predicate_name)),
|
||||
) => {
|
||||
if update_chunk_data(self, predicate_name, 0) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(
|
||||
qualified_clause_to_query_term(
|
||||
loader,
|
||||
module_name,
|
||||
predicate_name,
|
||||
vec![],
|
||||
self.call_policy,
|
||||
),
|
||||
);
|
||||
}
|
||||
(
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
Term::Clause(_, name, terms),
|
||||
) => {
|
||||
if update_chunk_data(self, name, terms.len()) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
for (arg_c, term) in terms.iter().enumerate() {
|
||||
self.probe_body_term(arg_c + 1, terms.len(), term);
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(
|
||||
qualified_clause_to_query_term(
|
||||
loader,
|
||||
module_name,
|
||||
name,
|
||||
terms,
|
||||
self.call_policy,
|
||||
),
|
||||
);
|
||||
}
|
||||
(module_name, predicate_name) => {
|
||||
if update_chunk_data(self, atom!("call"), 2) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
self.probe_body_term(1, 0, &module_name);
|
||||
self.probe_body_term(2, 0, &predicate_name);
|
||||
|
||||
terms.push(module_name);
|
||||
terms.push(predicate_name);
|
||||
|
||||
build_stack.push_chunk_term(
|
||||
clause_to_query_term(
|
||||
loader,
|
||||
atom!("call"),
|
||||
vec![Term::Clause(Cell::default(), atom!(":"), terms)],
|
||||
self.call_policy,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Term::Clause(_, atom!("$call_with_inference_counting"), mut terms) if terms.len() == 1 => {
|
||||
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
|
||||
state_stack.push(TraversalState::Term(terms.pop().unwrap()));
|
||||
|
||||
self.call_policy = CallPolicy::Counted;
|
||||
}
|
||||
Term::Clause(_, name, terms) => {
|
||||
if update_chunk_data(self, name, terms.len()) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
for (arg_c, term) in terms.iter().enumerate() {
|
||||
self.probe_body_term(arg_c + 1, terms.len(), term);
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(
|
||||
clause_to_query_term(
|
||||
loader,
|
||||
name,
|
||||
terms,
|
||||
self.call_policy,
|
||||
),
|
||||
);
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
|
||||
if self.global_cut_var_num.is_none() {
|
||||
self.global_cut_var_num = Some(self.var_num);
|
||||
self.var_num += 1;
|
||||
}
|
||||
|
||||
self.probe_in_situ_var(self.global_cut_var_num.unwrap());
|
||||
|
||||
state_stack.push(TraversalState::Cut {
|
||||
var_num: self.global_cut_var_num.unwrap(),
|
||||
is_global: true,
|
||||
});
|
||||
}
|
||||
Term::Literal(_, Literal::Atom(name)) => {
|
||||
if update_chunk_data(self, name, 0) {
|
||||
build_stack.add_chunk();
|
||||
}
|
||||
|
||||
build_stack.push_chunk_term(
|
||||
clause_to_query_term(
|
||||
loader,
|
||||
name,
|
||||
vec![],
|
||||
self.call_policy,
|
||||
),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
return Err(CompilationError::InadmissibleQueryTerm);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(build_stack)
|
||||
}
|
||||
}
|
||||
|
||||
impl BranchMap {
|
||||
pub fn separate_and_classify_variables(
|
||||
&mut self,
|
||||
var_num: usize,
|
||||
global_cut_var_num: Option<usize>,
|
||||
current_chunk_num: usize,
|
||||
) -> VarData {
|
||||
let mut var_data = VarData {
|
||||
records: VariableRecords::new(var_num),
|
||||
global_cut_var_num,
|
||||
allocates: current_chunk_num > 0,
|
||||
};
|
||||
|
||||
for (var, branches) in self.iter_mut() {
|
||||
let (mut var_num, var_num_incr) =
|
||||
if let Var::InSitu(var_num) = *var.borrow() {
|
||||
(var_num, false)
|
||||
} else {
|
||||
(var_data.records.len(), true)
|
||||
};
|
||||
|
||||
for branch in branches.iter_mut() {
|
||||
if var_num_incr {
|
||||
var_num = var_data.records.len();
|
||||
var_data.records.push(VariableRecord::default());
|
||||
}
|
||||
|
||||
if branch.chunks.len() <= 1 { // true iff var is a temporary variable.
|
||||
debug_assert_eq!(branch.chunks.len(), 1);
|
||||
|
||||
let chunk = &mut branch.chunks[0];
|
||||
let mut temp_var_data = TempVarData::new();
|
||||
|
||||
for var_info in chunk.vars.iter_mut() {
|
||||
if var_info.lvl == Level::Shallow {
|
||||
let term_loc = var_info.chunk_type.to_gen_context(chunk.chunk_num);
|
||||
temp_var_data.use_set.insert((term_loc, var_info.classify_info.arg_c));
|
||||
}
|
||||
}
|
||||
|
||||
var_data.records[var_num].allocation = VarAlloc::Temp {
|
||||
term_loc: chunk.term_loc,
|
||||
temp_reg: 0,
|
||||
temp_var_data,
|
||||
safety: VarSafetyStatus::Needed,
|
||||
to_perm_var_num: None,
|
||||
};
|
||||
} // else VarAlloc is already a Perm variant, as it's the default.
|
||||
|
||||
for chunk in branch.chunks.iter_mut() {
|
||||
var_data.records[var_num].num_occurrences += chunk.vars.len();
|
||||
|
||||
for var_info in chunk.vars.iter_mut() {
|
||||
var_info.var_ptr.set(Var::Generated(var_num));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var_data.records.populate_restricting_sets();
|
||||
var_data
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -441,13 +441,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
term: Term,
|
||||
preprocessor: &mut Preprocessor,
|
||||
) -> Result<PredicateClause, SessionError> {
|
||||
let tl = preprocessor.try_term_to_tl(self, term, CutContext::BlocksCuts)?;
|
||||
let tl = preprocessor.try_term_to_tl(self, term)?;
|
||||
|
||||
Ok(match tl {
|
||||
TopLevel::Fact(fact) => PredicateClause::Fact(fact),
|
||||
TopLevel::Rule(rule) => PredicateClause::Rule(rule),
|
||||
TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact),
|
||||
_ => unreachable!(),
|
||||
TopLevel::Fact(fact, var_data) => PredicateClause::Fact(fact, var_data),
|
||||
TopLevel::Rule(rule, var_data) => PredicateClause::Rule(rule, var_data),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
/*
|
||||
* The loader compiles Prolog terms read from a TermStream instance,
|
||||
@@ -465,6 +464,11 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Result<Term, SessionError> {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
machine_st.read_term_from_heap(r)
|
||||
}
|
||||
|
||||
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
|
||||
while let Some(decl) = self.dequeue_terms()? {
|
||||
self.load_decl(decl)?;
|
||||
@@ -531,106 +535,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(super) fn read_term_from_heap(&mut self, heap_term_loc: RegType) -> Result<Term, SessionError> {
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
let term_addr = machine_st[heap_term_loc];
|
||||
|
||||
let mut term_stack = vec![];
|
||||
let mut iter = stackful_post_order_iter(&mut machine_st.heap, &mut machine_st.stack, term_addr);
|
||||
|
||||
while let Some(addr) = iter.next() {
|
||||
let addr = unmark_cell_bits!(addr);
|
||||
|
||||
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(), string, tail));
|
||||
}
|
||||
Ok((string, None)) => {
|
||||
let atom = machine_st.atom_tbl.build_with(&string);
|
||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||
}
|
||||
Err(cons_term) => term_stack.push(cons_term),
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
|
||||
let offset_string = format!("_{}", h);
|
||||
term_stack.push(Term::Var(Cell::default(), Rc::new(offset_string)));
|
||||
}
|
||||
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
|
||||
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
|
||||
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
let h = iter.focus().value() as usize;
|
||||
let mut arity = arity;
|
||||
|
||||
if iter.heap.len() > h + arity + 1 {
|
||||
let value = iter.heap[h + arity + 1];
|
||||
|
||||
if let Some(idx) = get_structure_index(value) {
|
||||
// in the second condition, arity == 0,
|
||||
// meaning idx cannot pertain to this atom
|
||||
// if it is the direct subterm of a larger
|
||||
// structure.
|
||||
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
||||
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::PStr, atom) => {
|
||||
let tail = term_stack.pop().unwrap();
|
||||
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||
} else {
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
atom.as_str().to_owned(),
|
||||
Box::new(tail),
|
||||
));
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::PStrLoc, h) => {
|
||||
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
||||
let tail = term_stack.pop().unwrap();
|
||||
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
atom.as_str().to_owned(),
|
||||
Box::new(tail),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
debug_assert!(term_stack.len() == 1);
|
||||
Ok(term_stack.pop().unwrap())
|
||||
}
|
||||
|
||||
fn reset_machine(&mut self) {
|
||||
while let Some(record) = self.payload.retraction_info.records.pop() {
|
||||
match record {
|
||||
@@ -1143,7 +1047,9 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
|
||||
&mut self,
|
||||
r: RegType,
|
||||
) -> Result<IndexSet<ModuleExport>, SessionError> {
|
||||
let export_list = self.read_term_from_heap(r)?;
|
||||
let machine_st = LS::machine_st(&mut self.payload);
|
||||
|
||||
let export_list = machine_st.read_term_from_heap(r)?;
|
||||
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
|
||||
let export_list = setup_module_export_list(export_list, atom_tbl)?;
|
||||
|
||||
@@ -1493,6 +1399,106 @@ impl<'a> MachinePreludeView<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl MachineState {
|
||||
pub(super) fn read_term_from_heap(&mut self, r: RegType) -> Result<Term, SessionError> {
|
||||
let term_addr = self[r];
|
||||
|
||||
let mut term_stack = vec![];
|
||||
let mut iter = stackful_post_order_iter(&mut self.heap, &mut self.stack, term_addr);
|
||||
|
||||
while let Some(addr) = iter.next() {
|
||||
let addr = unmark_cell_bits!(addr);
|
||||
|
||||
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(), string, tail));
|
||||
}
|
||||
Ok((string, None)) => {
|
||||
let atom = self.atom_tbl.build_with(&string);
|
||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||
}
|
||||
Err(cons_term) => term_stack.push(cons_term),
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::Var | HeapCellValueTag::AttrVar | HeapCellValueTag::StackVar, h) => {
|
||||
term_stack.push(Term::Var(Cell::default(), VarPtr::from(format!("_{}", h))));
|
||||
}
|
||||
(HeapCellValueTag::Cons | HeapCellValueTag::CStr | HeapCellValueTag::Fixnum |
|
||||
HeapCellValueTag::Char | HeapCellValueTag::F64) => {
|
||||
term_stack.push(Term::Literal(Cell::default(), Literal::try_from(addr).unwrap()));
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, arity)) => {
|
||||
let h = iter.focus().value() as usize;
|
||||
let mut arity = arity;
|
||||
|
||||
if iter.heap.len() > h + arity + 1 {
|
||||
let value = iter.heap[h + arity + 1];
|
||||
|
||||
if let Some(idx) = get_structure_index(value) {
|
||||
// in the second condition, arity == 0,
|
||||
// meaning idx cannot pertain to this atom
|
||||
// if it is the direct subterm of a larger
|
||||
// structure.
|
||||
if arity > 0 || !iter.direct_subterm_of_str(h) {
|
||||
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::PStr, atom) => {
|
||||
let tail = term_stack.pop().unwrap();
|
||||
|
||||
if let Term::Literal(_, Literal::Atom(atom!("[]"))) = &tail {
|
||||
term_stack.push(Term::CompleteString(Cell::default(), atom));
|
||||
} else {
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
atom.as_str().to_owned(),
|
||||
Box::new(tail),
|
||||
));
|
||||
}
|
||||
}
|
||||
(HeapCellValueTag::PStrLoc, h) => {
|
||||
let atom = cell_as_atom_cell!(iter.heap[h]).get_name();
|
||||
let tail = term_stack.pop().unwrap();
|
||||
|
||||
term_stack.push(Term::PartialString(
|
||||
Cell::default(),
|
||||
atom.as_str().to_owned(),
|
||||
Box::new(tail),
|
||||
));
|
||||
}
|
||||
_ => {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
debug_assert!(term_stack.len() == 1);
|
||||
Ok(term_stack.pop().unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl Machine {
|
||||
pub(crate) fn use_module(&mut self) -> CallResult {
|
||||
let subevacuable_addr = self
|
||||
|
||||
@@ -2,7 +2,6 @@ use crate::parser::ast::*;
|
||||
|
||||
use crate::arena::*;
|
||||
use crate::atom_table::*;
|
||||
use crate::fixtures::*;
|
||||
use crate::forms::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_state::*;
|
||||
@@ -16,7 +15,6 @@ use modular_bitfield::specifiers::*;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::BTreeSet;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::types::*;
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@@ -228,8 +226,8 @@ impl CodeIndex {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type HeapVarDict = IndexMap<Rc<String>, HeapCellValue, FxBuildHasher>;
|
||||
pub(crate) type AllocVarDict = IndexMap<Rc<String>, VarData, FxBuildHasher>;
|
||||
pub(crate) type HeapVarDict = IndexMap<VarPtr, HeapCellValue, FxBuildHasher>;
|
||||
// pub(crate) type AllocVarDict = IndexMap<Var, VarAlloc, FxBuildHasher>;
|
||||
|
||||
pub(crate) type GlobalVarDir = IndexMap<Atom, (Ball, Option<HeapCellValue>), FxBuildHasher>;
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ use indexmap::IndexMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt;
|
||||
use std::ops::{Index, IndexMut};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub(crate) type Registers = [HeapCellValue; MAX_ARITY + 1];
|
||||
|
||||
@@ -501,13 +500,13 @@ impl MachineState {
|
||||
pub fn read_term(&mut self, stream: Stream, indices: &mut IndexStore) -> CallResult {
|
||||
fn push_var_eq_functors<'a>(
|
||||
heap: &mut Heap,
|
||||
iter: impl Iterator<Item = (&'a Rc<String>, &'a HeapCellValue)>,
|
||||
iter: impl Iterator<Item = (&'a VarPtr, &'a HeapCellValue)>,
|
||||
atom_tbl: &mut AtomTable,
|
||||
) -> Vec<HeapCellValue> {
|
||||
let mut list_of_var_eqs = vec![];
|
||||
|
||||
for (var, binding) in iter {
|
||||
let var_atom = atom_tbl.build_with(&var);
|
||||
let var_atom = atom_tbl.build_with(&var.borrow().to_string());
|
||||
let h = heap.len();
|
||||
|
||||
heap.push(atom_as_cell!(atom!("="), 2));
|
||||
@@ -673,7 +672,7 @@ impl MachineState {
|
||||
|
||||
let printer = match self.try_from_list(self.registers[6], stub_gen) {
|
||||
Ok(addrs) => {
|
||||
let mut var_names: IndexMap<HeapCellValue, Rc<String>> = IndexMap::new();
|
||||
let mut var_names: IndexMap<HeapCellValue, VarPtr> = IndexMap::new();
|
||||
|
||||
for addr in addrs {
|
||||
read_heap_cell!(addr,
|
||||
@@ -691,18 +690,18 @@ impl MachineState {
|
||||
|
||||
read_heap_cell!(atom,
|
||||
(HeapCellValueTag::Char, c) => {
|
||||
var_names.insert(var, Rc::new(c.to_string()));
|
||||
var_names.insert(var, VarPtr::from(c.to_string()));
|
||||
}
|
||||
(HeapCellValueTag::Atom, (name, _arity)) => {
|
||||
debug_assert_eq!(_arity, 0);
|
||||
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
||||
var_names.insert(var, VarPtr::from(name.as_str()));
|
||||
}
|
||||
(HeapCellValueTag::Str, s) => {
|
||||
let (name, arity) = cell_as_atom_cell!(self.heap[s])
|
||||
.get_name_and_arity();
|
||||
|
||||
debug_assert_eq!(arity, 0);
|
||||
var_names.insert(var, Rc::new(name.as_str().to_owned()));
|
||||
var_names.insert(var, VarPtr::from(name.as_str()));
|
||||
}
|
||||
_ => {
|
||||
unreachable!();
|
||||
|
||||
@@ -16,6 +16,7 @@ pub mod machine_state;
|
||||
pub mod machine_state_impl;
|
||||
pub mod mock_wam;
|
||||
pub mod partial_string;
|
||||
pub mod disjuncts;
|
||||
pub mod preprocessor;
|
||||
pub mod stack;
|
||||
pub mod streams;
|
||||
@@ -67,7 +68,7 @@ pub struct Machine {
|
||||
pub(super) user_error: Stream,
|
||||
pub(super) load_contexts: Vec<LoadContext>,
|
||||
pub(super) runtime: Runtime,
|
||||
pub(super) foreign_function_table: ForeignFunctionTable,
|
||||
pub(super) foreign_function_table: ForeignFunctionTable,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -364,46 +365,46 @@ impl Machine {
|
||||
Instruction::BreakFromDispatchLoop,
|
||||
Instruction::InstallVerifyAttr,
|
||||
Instruction::VerifyAttrInterrupt,
|
||||
Instruction::ExecuteTermGreaterThan(0),
|
||||
Instruction::ExecuteTermLessThan(0),
|
||||
Instruction::ExecuteTermGreaterThanOrEqual(0),
|
||||
Instruction::ExecuteTermLessThanOrEqual(0),
|
||||
Instruction::ExecuteTermEqual(0),
|
||||
Instruction::ExecuteTermNotEqual(0),
|
||||
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2)), 0),
|
||||
Instruction::ExecuteAcyclicTerm(0),
|
||||
Instruction::ExecuteArg(0),
|
||||
Instruction::ExecuteCompare(0),
|
||||
Instruction::ExecuteCopyTerm(0),
|
||||
Instruction::ExecuteFunctor(0),
|
||||
Instruction::ExecuteGround(0),
|
||||
Instruction::ExecuteKeySort(0),
|
||||
Instruction::ExecuteRead(0),
|
||||
Instruction::ExecuteSort(0),
|
||||
Instruction::ExecuteN(1, 0),
|
||||
Instruction::ExecuteN(2, 0),
|
||||
Instruction::ExecuteN(3, 0),
|
||||
Instruction::ExecuteN(4, 0),
|
||||
Instruction::ExecuteN(5, 0),
|
||||
Instruction::ExecuteN(6, 0),
|
||||
Instruction::ExecuteN(7, 0),
|
||||
Instruction::ExecuteN(8, 0),
|
||||
Instruction::ExecuteN(9, 0),
|
||||
Instruction::ExecuteIsAtom(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsAtomic(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsCompound(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsInteger(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsNumber(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsRational(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsFloat(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsNonVar(temp_v!(1), 0),
|
||||
Instruction::ExecuteIsVar(temp_v!(1), 0)
|
||||
Instruction::ExecuteTermGreaterThan,
|
||||
Instruction::ExecuteTermLessThan,
|
||||
Instruction::ExecuteTermGreaterThanOrEqual,
|
||||
Instruction::ExecuteTermLessThanOrEqual,
|
||||
Instruction::ExecuteTermEqual,
|
||||
Instruction::ExecuteTermNotEqual,
|
||||
Instruction::ExecuteNumberGreaterThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteNumberLessThan(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteNumberGreaterThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteNumberLessThanOrEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteNumberEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteNumberNotEqual(ar_reg!(temp_v!(1)), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteIs(temp_v!(1), ar_reg!(temp_v!(2))),
|
||||
Instruction::ExecuteAcyclicTerm,
|
||||
Instruction::ExecuteArg,
|
||||
Instruction::ExecuteCompare,
|
||||
Instruction::ExecuteCopyTerm,
|
||||
Instruction::ExecuteFunctor,
|
||||
Instruction::ExecuteGround,
|
||||
Instruction::ExecuteKeySort,
|
||||
Instruction::ExecuteRead,
|
||||
Instruction::ExecuteSort,
|
||||
Instruction::ExecuteN(1),
|
||||
Instruction::ExecuteN(2),
|
||||
Instruction::ExecuteN(3),
|
||||
Instruction::ExecuteN(4),
|
||||
Instruction::ExecuteN(5),
|
||||
Instruction::ExecuteN(6),
|
||||
Instruction::ExecuteN(7),
|
||||
Instruction::ExecuteN(8),
|
||||
Instruction::ExecuteN(9),
|
||||
Instruction::ExecuteIsAtom(temp_v!(1)),
|
||||
Instruction::ExecuteIsAtomic(temp_v!(1)),
|
||||
Instruction::ExecuteIsCompound(temp_v!(1)),
|
||||
Instruction::ExecuteIsInteger(temp_v!(1)),
|
||||
Instruction::ExecuteIsNumber(temp_v!(1)),
|
||||
Instruction::ExecuteIsRational(temp_v!(1)),
|
||||
Instruction::ExecuteIsFloat(temp_v!(1)),
|
||||
Instruction::ExecuteIsNonVar(temp_v!(1)),
|
||||
Instruction::ExecuteIsVar(temp_v!(1))
|
||||
].into_iter());
|
||||
|
||||
for (p, instr) in self.code[impls_offset ..].iter().enumerate() {
|
||||
@@ -689,6 +690,8 @@ impl Machine {
|
||||
fn try_call(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||
let compiled_tl_index = idx.p() as usize;
|
||||
|
||||
// println!("calling {}/{}", name.as_str(), arity);
|
||||
|
||||
match idx.tag() {
|
||||
IndexPtrTag::DynamicUndefined => {
|
||||
self.machine_st.fail = true;
|
||||
@@ -712,6 +715,8 @@ impl Machine {
|
||||
fn try_execute(&mut self, name: Atom, arity: usize, idx: IndexPtr) -> CallResult {
|
||||
let compiled_tl_index = idx.p() as usize;
|
||||
|
||||
// println!("executing {}/{}", name.as_str(), arity);
|
||||
|
||||
match idx.tag() {
|
||||
IndexPtrTag::DynamicUndefined => {
|
||||
self.machine_st.fail = true;
|
||||
|
||||
@@ -2,7 +2,7 @@ use crate::atom_table::*;
|
||||
use crate::codegen::CodeGenSettings;
|
||||
use crate::forms::*;
|
||||
use crate::instructions::*;
|
||||
use crate::iterators::*;
|
||||
use crate::machine::disjuncts::*;
|
||||
use crate::machine::loader::*;
|
||||
use crate::machine::machine_errors::*;
|
||||
use crate::parser::ast::*;
|
||||
@@ -10,35 +10,7 @@ use crate::parser::ast::*;
|
||||
use indexmap::IndexSet;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::rc::Rc;
|
||||
|
||||
/*
|
||||
* The preprocessor fabricates if-then-else ( .. -> ... ; ...)
|
||||
* clauses into nameless standalone predicates, which it queues for
|
||||
* later preprocessing and compilation. Fabricated predicates inherit
|
||||
* explicit "cut variables" from the handwritten predicate
|
||||
* surrounding their source if-then-else. They must be specially
|
||||
* handled.
|
||||
*/
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) enum CutContext {
|
||||
BlocksCuts,
|
||||
HasCutVariable,
|
||||
}
|
||||
|
||||
pub(crate) fn fold_by_str<I>(terms: I, mut term: Term, sym: Atom) -> Term
|
||||
where
|
||||
I: DoubleEndedIterator<Item = Term>,
|
||||
{
|
||||
for prec in terms.rev() {
|
||||
term = Term::Clause(Cell::default(), sym, vec![prec, term]);
|
||||
}
|
||||
|
||||
term
|
||||
}
|
||||
|
||||
pub(crate) fn to_op_decl(
|
||||
prec: u16,
|
||||
@@ -132,6 +104,13 @@ fn setup_module_export(
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
|
||||
let rule = vec![head_term, body_term];
|
||||
|
||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||
}
|
||||
|
||||
pub(super) fn setup_module_export_list(
|
||||
mut export_list: Term,
|
||||
atom_tbl: &mut AtomTable,
|
||||
@@ -325,110 +304,6 @@ fn setup_meta_predicate<'a, LS: LoadState<'a>>(
|
||||
}
|
||||
}
|
||||
|
||||
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationError> {
|
||||
let mut clauses = vec![];
|
||||
|
||||
while let Some(tl) = tls.pop_front() {
|
||||
match tl {
|
||||
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
|
||||
return Ok(tl);
|
||||
}
|
||||
TopLevel::Query(_) => {
|
||||
return Err(CompilationError::InconsistentEntry);
|
||||
}
|
||||
TopLevel::Fact(fact) => {
|
||||
let clause = PredicateClause::Fact(fact);
|
||||
clauses.push(clause);
|
||||
}
|
||||
TopLevel::Rule(rule) => {
|
||||
let clause = PredicateClause::Rule(rule);
|
||||
clauses.push(clause);
|
||||
}
|
||||
TopLevel::Predicate(predicate) => clauses.extend(predicate.into_iter()),
|
||||
}
|
||||
}
|
||||
|
||||
if clauses.is_empty() {
|
||||
Err(CompilationError::InconsistentEntry)
|
||||
} else {
|
||||
Ok(TopLevel::Predicate(clauses))
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: Atom) {
|
||||
for term in terms.iter_mut() {
|
||||
match term {
|
||||
&mut Term::Literal(_, Literal::Atom(ref mut var)) if *var == atom!("!") => {
|
||||
*var = name;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_cut_variable(term: &mut Term) -> bool {
|
||||
let cut_var_found = match term {
|
||||
&mut Term::Literal(_, Literal::Atom(ref var)) if *var == atom!("!") => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if cut_var_found {
|
||||
*term = Term::Var(Cell::default(), Rc::new(String::from("!")));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
|
||||
let mut found_cut_var = false;
|
||||
|
||||
for item in terms.iter_mut() {
|
||||
found_cut_var = mark_cut_variable(item) || found_cut_var;
|
||||
}
|
||||
|
||||
found_cut_var
|
||||
}
|
||||
|
||||
// terms is a list of goals composing one clause in a (;) functor. it
|
||||
// checks that the first (and only) of these clauses is a ->. if so,
|
||||
// it expands its terms using a blocked_!.
|
||||
fn check_for_internal_if_then(terms: &mut Vec<Term>) {
|
||||
if terms.len() != 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(Term::Clause(_, name, ref subterms)) = terms.last() {
|
||||
if *name != atom!("->") || source_arity(subterms) != 2 {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(Term::Clause(_, _, mut subterms)) = terms.pop() {
|
||||
let mut conq_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
|
||||
let mut pre_cut_terms = VecDeque::from(unfold_by_str(subterms.pop().unwrap(), atom!(",")));
|
||||
|
||||
conq_terms.push_front(Term::Literal(
|
||||
Cell::default(),
|
||||
Literal::Atom(atom!("blocked_!")),
|
||||
));
|
||||
|
||||
while let Some(term) = pre_cut_terms.pop_back() {
|
||||
conq_terms.push_front(term);
|
||||
}
|
||||
|
||||
let tail_term = conq_terms.pop_back().unwrap();
|
||||
|
||||
terms.push(fold_by_str(
|
||||
conq_terms.into_iter(),
|
||||
tail_term,
|
||||
atom!(","),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn setup_declaration<'a, LS: LoadState<'a>>(
|
||||
loader: &mut Loader<'a, LS>,
|
||||
mut terms: Vec<Term>,
|
||||
@@ -570,7 +445,7 @@ fn build_meta_predicate_clause<'a, LS: LoadState<'a>>(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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>,
|
||||
name: Atom,
|
||||
mut terms: Vec<Term>,
|
||||
@@ -609,7 +484,7 @@ fn clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
}
|
||||
|
||||
#[inline]
|
||||
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>,
|
||||
module_name: Atom,
|
||||
name: Atom,
|
||||
@@ -647,308 +522,58 @@ fn qualified_clause_to_query_term<'a, LS: LoadState<'a>>(
|
||||
QueryTerm::Clause(Cell::default(), ct, terms, call_policy)
|
||||
}
|
||||
|
||||
fn compute_head(term: &Term) -> Vec<Term> {
|
||||
let mut vars = IndexSet::new();
|
||||
|
||||
for term in post_order_iter(term) {
|
||||
if let TermRef::Var(_, _, v) = term {
|
||||
vars.insert(v.clone());
|
||||
}
|
||||
}
|
||||
|
||||
vars.insert(Rc::new(String::from("!")));
|
||||
vars.into_iter()
|
||||
.map(|v| Term::Var(Cell::default(), v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub(crate) fn build_rule_body(vars: &[Term], body_term: Term) -> Term {
|
||||
let head_term = Term::Clause(Cell::default(), atom!(""), vars.iter().cloned().collect());
|
||||
let rule = vec![head_term, body_term];
|
||||
|
||||
Term::Clause(Cell::default(), atom!(":-"), rule)
|
||||
}
|
||||
|
||||
// the terms form the body of the rule. We create a head, by
|
||||
// gathering variables from the body of terms and recording them
|
||||
// in the head clause.
|
||||
fn build_rule(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
// collect the vars of body_term into a head, return the num_vars
|
||||
// (the arity) as well.
|
||||
let vars = compute_head(&body_term);
|
||||
let rule = build_rule_body(&vars, body_term);
|
||||
|
||||
(vars, VecDeque::from(vec![rule]))
|
||||
}
|
||||
|
||||
fn build_disjunct(body_term: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
let vars = compute_head(&body_term);
|
||||
let results = unfold_by_str(body_term, atom!(";"))
|
||||
.into_iter()
|
||||
.map(|term| {
|
||||
let mut subterms = unfold_by_str(term, atom!(","));
|
||||
mark_cut_variables(&mut subterms);
|
||||
|
||||
check_for_internal_if_then(&mut subterms);
|
||||
|
||||
let term = subterms.pop().unwrap();
|
||||
let clause = fold_by_str(subterms.into_iter(), term, atom!(","));
|
||||
|
||||
build_rule_body(&vars, clause)
|
||||
})
|
||||
.collect();
|
||||
|
||||
(vars, results)
|
||||
}
|
||||
|
||||
fn build_if_then(prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
|
||||
let mut prec_seq = unfold_by_str(prec, atom!(","));
|
||||
let comma_sym = atom!(",");
|
||||
let cut_sym = Literal::Atom(atom!("!"));
|
||||
|
||||
prec_seq.push(Term::Literal(Cell::default(), cut_sym));
|
||||
|
||||
mark_cut_variables_as(&mut prec_seq, atom!("blocked_!"));
|
||||
|
||||
let mut conq_seq = unfold_by_str(conq, atom!(","));
|
||||
|
||||
mark_cut_variables(&mut conq_seq);
|
||||
prec_seq.extend(conq_seq.into_iter());
|
||||
|
||||
let back_term = prec_seq.pop().unwrap();
|
||||
let front_term = prec_seq.pop().unwrap();
|
||||
|
||||
let body_term = Term::Clause(
|
||||
Cell::default(),
|
||||
comma_sym,
|
||||
vec![front_term, back_term],
|
||||
);
|
||||
|
||||
build_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct Preprocessor {
|
||||
queue: VecDeque<VecDeque<Term>>,
|
||||
settings: CodeGenSettings,
|
||||
}
|
||||
|
||||
impl Preprocessor {
|
||||
pub(super) fn new(settings: CodeGenSettings) -> Self {
|
||||
Preprocessor {
|
||||
queue: VecDeque::new(),
|
||||
settings,
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
|
||||
fn setup_fact(&mut self, term: Term) -> Result<(Fact, VarData), CompilationError> {
|
||||
match term {
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => Ok(term),
|
||||
Term::Clause(..) | Term::Literal(_, Literal::Atom(..)) => {
|
||||
let classifier = VariableClassifier::new(
|
||||
self.settings.default_call_policy(),
|
||||
);
|
||||
|
||||
let (head, var_data) = classifier.classify_fact(term)?;
|
||||
Ok((Fact { head }, var_data))
|
||||
}
|
||||
_ => Err(CompilationError::InadmissibleFact),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_query_term<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
) -> Result<QueryTerm, CompilationError> {
|
||||
match term {
|
||||
Term::Literal(_, Literal::Atom(name)) => {
|
||||
if name == atom!("!") || name == atom!("blocked_!") {
|
||||
Ok(QueryTerm::BlockedCut)
|
||||
} else {
|
||||
Ok(clause_to_query_term(
|
||||
loader,
|
||||
name,
|
||||
vec![],
|
||||
self.settings.default_call_policy(),
|
||||
))
|
||||
}
|
||||
}
|
||||
Term::Literal(_, Literal::Char('!')) => Ok(QueryTerm::BlockedCut),
|
||||
Term::Var(_, ref v) if v.as_str() == "!" => {
|
||||
Ok(QueryTerm::UnblockedCut(Cell::default()))
|
||||
}
|
||||
Term::Clause(r, name, mut terms) => match (name, source_arity(&terms)) {
|
||||
(atom!(";"), 2) => {
|
||||
let term = Term::Clause(r, name, terms);
|
||||
|
||||
let (stub, clauses) = build_disjunct(term);
|
||||
self.queue.push_back(clauses);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
(atom!("->"), 2) => {
|
||||
let conq = terms.pop().unwrap();
|
||||
let prec = terms.pop().unwrap();
|
||||
|
||||
let (stub, clauses) = build_if_then(prec, conq);
|
||||
self.queue.push_back(clauses);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
(atom!("\\+"), 1) => {
|
||||
terms.push(Term::Literal(
|
||||
Cell::default(),
|
||||
Literal::Atom(atom!("$fail")),
|
||||
));
|
||||
|
||||
let conq = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
|
||||
|
||||
let prec = Term::Clause(Cell::default(), atom!("->"), terms);
|
||||
let terms = vec![prec, conq];
|
||||
|
||||
let term = Term::Clause(Cell::default(), atom!(";"), terms);
|
||||
let (stub, clauses) = build_disjunct(term);
|
||||
|
||||
debug_assert!(clauses.len() > 0);
|
||||
self.queue.push_back(clauses);
|
||||
|
||||
Ok(QueryTerm::Jump(stub))
|
||||
}
|
||||
(atom!("$get_level"), 1) => {
|
||||
if let Term::Var(_, ref var) = &terms[0] {
|
||||
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
|
||||
} else {
|
||||
Err(CompilationError::InadmissibleQueryTerm)
|
||||
}
|
||||
}
|
||||
(atom!(":"), 2) => {
|
||||
let predicate_name = terms.pop().unwrap();
|
||||
let module_name = terms.pop().unwrap();
|
||||
|
||||
match (module_name, predicate_name) {
|
||||
(
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
Term::Literal(_, Literal::Atom(predicate_name)),
|
||||
) => Ok(qualified_clause_to_query_term(
|
||||
loader,
|
||||
module_name,
|
||||
predicate_name,
|
||||
vec![],
|
||||
self.settings.default_call_policy(),
|
||||
)),
|
||||
(
|
||||
Term::Literal(_, Literal::Atom(module_name)),
|
||||
Term::Clause(_, name, terms),
|
||||
) => Ok(qualified_clause_to_query_term(
|
||||
loader,
|
||||
module_name,
|
||||
name,
|
||||
terms,
|
||||
self.settings.default_call_policy()
|
||||
)),
|
||||
(module_name, predicate_name) => {
|
||||
terms.push(module_name);
|
||||
terms.push(predicate_name);
|
||||
|
||||
Ok(clause_to_query_term(
|
||||
loader,
|
||||
atom!("call"),
|
||||
vec![Term::Clause(r, name, terms)],
|
||||
self.settings.default_call_policy(),
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => Ok(clause_to_query_term(loader, name, terms,
|
||||
self.settings.default_call_policy())),
|
||||
},
|
||||
Term::Var(..) => Ok(QueryTerm::Clause(
|
||||
Cell::default(),
|
||||
ClauseType::CallN(1),
|
||||
vec![term],
|
||||
self.settings.default_call_policy(),
|
||||
)),
|
||||
_ => Err(CompilationError::InadmissibleQueryTerm),
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_query_term<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
) -> Result<QueryTerm, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(r, name, mut subterms) => {
|
||||
if subterms.len() == 1 && name == atom!("$call_with_inference_counting") {
|
||||
self.to_query_term(loader, subterms.pop().unwrap())
|
||||
.map(|mut query_term| {
|
||||
query_term.set_call_policy(CallPolicy::Counted);
|
||||
query_term
|
||||
})
|
||||
} else {
|
||||
let clause = Term::Clause(r, name, subterms);
|
||||
self.to_query_term(loader, clause)
|
||||
}
|
||||
}
|
||||
_ => self.to_query_term(loader, term),
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_query<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
terms: Vec<Term>,
|
||||
cut_context: CutContext,
|
||||
) -> Result<Vec<QueryTerm>, CompilationError> {
|
||||
let mut query_terms = vec![];
|
||||
let mut work_queue = VecDeque::from(terms);
|
||||
|
||||
while let Some(term) = work_queue.pop_front() {
|
||||
let mut term = term;
|
||||
|
||||
if let Term::Clause(cell, name, terms) = term {
|
||||
if name == atom!(",") && source_arity(&terms) == 2 {
|
||||
let term = Term::Clause(cell, name, terms);
|
||||
let mut subterms = unfold_by_str(term, atom!(","));
|
||||
|
||||
while let Some(subterm) = subterms.pop() {
|
||||
work_queue.push_front(subterm);
|
||||
}
|
||||
|
||||
continue;
|
||||
} else {
|
||||
term = Term::Clause(cell, name, terms);
|
||||
}
|
||||
}
|
||||
|
||||
if let CutContext::HasCutVariable = cut_context {
|
||||
mark_cut_variable(&mut term);
|
||||
}
|
||||
|
||||
query_terms.push(self.pre_query_term(loader, term)?);
|
||||
}
|
||||
|
||||
Ok(query_terms)
|
||||
}
|
||||
|
||||
fn setup_rule<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
mut terms: Vec<Term>,
|
||||
cut_context: CutContext,
|
||||
) -> Result<Rule, CompilationError> {
|
||||
let post_head_terms: Vec<_> = terms.drain(1..).collect();
|
||||
let mut query_terms = self.setup_query(loader, post_head_terms, cut_context)?;
|
||||
head: Term,
|
||||
body: Term,
|
||||
) -> Result<(Rule, VarData), CompilationError> {
|
||||
let classifier = VariableClassifier::new(
|
||||
self.settings.default_call_policy(),
|
||||
);
|
||||
|
||||
let clauses = query_terms.drain(1..).collect();
|
||||
let qt = query_terms.pop().unwrap();
|
||||
let (head, clauses, var_data) = classifier.classify_rule(loader, head, body)?;
|
||||
|
||||
match terms.pop().unwrap() {
|
||||
Term::Clause(_, name, terms) => Ok(Rule {
|
||||
head: (name, terms, qt),
|
||||
match head {
|
||||
Term::Clause(_, name, terms) => Ok((Rule {
|
||||
head: (name, terms),
|
||||
clauses,
|
||||
}),
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok(Rule {
|
||||
head: (name, vec![], qt),
|
||||
}, var_data)),
|
||||
Term::Literal(_, Literal::Atom(name)) => Ok((Rule {
|
||||
head: (name, vec![]),
|
||||
clauses,
|
||||
}),
|
||||
}, var_data)),
|
||||
_ => Err(CompilationError::InvalidRuleHead),
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn try_term_to_query<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
@@ -961,63 +586,49 @@ impl Preprocessor {
|
||||
cut_context,
|
||||
)?))
|
||||
}
|
||||
*/
|
||||
|
||||
pub(super) fn try_term_to_tl<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
term: Term,
|
||||
cut_context: CutContext,
|
||||
) -> Result<TopLevel, CompilationError> {
|
||||
match term {
|
||||
Term::Clause(r, name, terms) => {
|
||||
if name == atom!("?-") {
|
||||
self.try_term_to_query(loader, terms, cut_context)
|
||||
} else if name == atom!(":-") && terms.len() == 2 {
|
||||
Ok(TopLevel::Rule(self.setup_rule(
|
||||
loader,
|
||||
terms,
|
||||
cut_context,
|
||||
)?))
|
||||
Term::Clause(r, name, mut terms) => {
|
||||
let is_rule = name == atom!(":-") && terms.len() == 2;
|
||||
|
||||
if is_rule {
|
||||
let tail = terms.pop().unwrap();
|
||||
let head = terms.pop().unwrap();
|
||||
|
||||
let (rule, var_data) = self.setup_rule(loader, head, tail)?;
|
||||
Ok(TopLevel::Rule(rule, var_data))
|
||||
} else {
|
||||
let term = Term::Clause(r, name, terms);
|
||||
Ok(TopLevel::Fact(self.setup_fact(term)?))
|
||||
let (fact, var_data) = self.setup_fact(term)?;
|
||||
Ok(TopLevel::Fact(fact, var_data))
|
||||
}
|
||||
}
|
||||
term => Ok(TopLevel::Fact(self.setup_fact(term)?)),
|
||||
term => {
|
||||
let (fact, var_data) = self.setup_fact(term)?;
|
||||
Ok(TopLevel::Fact(fact, var_data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
terms: I,
|
||||
cut_context: CutContext,
|
||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
||||
let mut results = VecDeque::new();
|
||||
|
||||
for term in terms.into_iter() {
|
||||
results.push_back(self.try_term_to_tl(loader, term, cut_context)?);
|
||||
results.push_back(self.try_term_to_tl(loader, term)?);
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub(super) fn parse_queue<'a, LS: LoadState<'a>>(
|
||||
&mut self,
|
||||
loader: &mut Loader<'a, LS>,
|
||||
) -> Result<VecDeque<TopLevel>, CompilationError> {
|
||||
let mut queue = VecDeque::new();
|
||||
|
||||
while let Some(terms) = self.queue.pop_front() {
|
||||
let clauses = merge_clauses(&mut self.try_terms_to_tls(
|
||||
loader,
|
||||
terms,
|
||||
CutContext::HasCutVariable,
|
||||
)?)?;
|
||||
|
||||
queue.push_back(clauses);
|
||||
}
|
||||
|
||||
Ok(queue)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@@ -51,7 +51,6 @@ use std::net::{TcpListener, TcpStream, SocketAddr, ToSocketAddrs};
|
||||
use std::num::NonZeroU32;
|
||||
use std::ops::Sub;
|
||||
use std::process;
|
||||
use std::rc::Rc;
|
||||
use std::str::FromStr;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -1445,7 +1444,7 @@ impl Machine {
|
||||
|
||||
let vars: Vec<_> = vars
|
||||
.union(&result.supp_vars) // difference + union does not cancel.
|
||||
.map(|v| Term::Var(Cell::default(), Rc::new(format!("_{}", v.get_value()))))
|
||||
.map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
|
||||
.collect();
|
||||
|
||||
let helper_clause_loc = self.code.len();
|
||||
@@ -1655,8 +1654,8 @@ impl Machine {
|
||||
#[inline(always)]
|
||||
pub(crate) fn is_reset_cont_marker(&self, p: usize) -> bool {
|
||||
match &self.code[p] {
|
||||
&Instruction::CallResetContinuationMarker(_) |
|
||||
&Instruction::ExecuteResetContinuationMarker(_) => true,
|
||||
&Instruction::CallResetContinuationMarker |
|
||||
&Instruction::ExecuteResetContinuationMarker => true,
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
@@ -4941,9 +4940,7 @@ impl Machine {
|
||||
|
||||
let p_functor = self.deref_register(2);
|
||||
|
||||
let p = to_local_code_ptr(&self.machine_st.heap, p_functor).unwrap();
|
||||
|
||||
let num_cells = *self.code[p].perm_vars_mut().unwrap();
|
||||
let num_cells = self.machine_st.stack.index_and_frame(e).prelude.num_cells;
|
||||
let mut addrs = vec![];
|
||||
|
||||
for idx in 1..num_cells + 1 {
|
||||
|
||||
Reference in New Issue
Block a user