remove Term

This commit is contained in:
Mark Thom
2024-07-16 15:38:22 -06:00
committed by Mark Thom
parent 34ac85bb6d
commit 1ef681bd21
43 changed files with 3823 additions and 2720 deletions

View File

@@ -1155,8 +1155,17 @@ impl MachineState {
value: HeapCellValue,
) -> Result<Number, MachineStub> {
let stub_gen = || functor_stub(atom!("is"), 2);
let mut iter =
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, value);
let root_loc = if value.is_ref() {
value.get_value() as usize
} else {
let type_error = self.type_error(ValidType::Evaluable, value);
return Err(self.error_form(type_error, stub_gen()));
};
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut self.heap, &mut self.stack, root_loc,
);
while let Some(value) = iter.next() {
if value.get_forwarding_bit() {

View File

@@ -11,8 +11,8 @@ use std::vec::IntoIter;
pub(super) type Bindings = Vec<(usize, HeapCellValue)>;
#[derive(Debug)]
pub(super) struct AttrVarInitializer {
pub(super) attr_var_queue: Vec<usize>,
pub(crate) struct AttrVarInitializer {
pub(crate) attr_var_queue: Vec<usize>,
pub(super) bindings: Bindings,
pub(super) p: usize,
pub(super) cp: usize,
@@ -131,9 +131,15 @@ impl MachineState {
pub(super) fn attr_vars_of_term(&mut self, cell: HeapCellValue) -> Vec<HeapCellValue> {
let mut seen_set = IndexSet::new();
let mut seen_vars = vec![];
let root_loc = if cell.is_ref() {
cell.get_value() as usize
} else {
return vec![];
};
let mut iter =
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, cell);
let mut iter = stackful_preorder_iter::<NonListElider>(
&mut self.heap, &mut self.stack, root_loc, // cell,
);
while let Some(value) = iter.next() {
read_heap_cell!(value,

View File

@@ -11,7 +11,6 @@ use crate::machine::term_stream::*;
use crate::machine::*;
use crate::parser::ast::*;
use std::cell::Cell;
use std::collections::VecDeque;
use std::mem;
use std::ops::Range;
@@ -1233,14 +1232,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
fn compile_standalone_clause(
&mut self,
term: Term,
term: FocusedHeap,
settings: CodeGenSettings,
) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(settings);
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
// let queue = preprocessor.parse_queue(self)?;
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
let clause_code = cg.compile_predicate(vec![clause])?;
@@ -1272,7 +1269,6 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
}
let mut cg = CodeGenerator::new(&LS::machine_st(&mut self.payload).atom_tbl, settings);
let mut code = cg.compile_predicate(clauses)?;
if settings.is_extensible {
@@ -1470,7 +1466,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn incremental_compile_clause(
&mut self,
key: PredicateKey,
clause: Term,
clause: FocusedHeap,
compilation_target: CompilationTarget,
non_counted_bt: bool,
append_or_prepend: AppendOrPrepend,
@@ -2005,16 +2001,13 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
}
impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn compile_clause_clauses<ClauseIter: Iterator<Item = (Term, Term)>>(
pub(super) fn compile_clause_clauses(
&mut self,
key: PredicateKey,
compilation_target: CompilationTarget,
clause_clauses: ClauseIter,
clause_clauses: Vec<FocusedHeap>,
append_or_prepend: AppendOrPrepend,
) -> Result<(), SessionError> {
let clause_predicates = clause_clauses
.map(|(head, body)| Term::Clause(Cell::default(), atom!("$clause"), vec![head, body]));
let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => CompilationTarget::Module(atom!("builtins")),
_ => compilation_target,
@@ -2022,7 +2015,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut num_clause_predicates = 0;
for clause_term in clause_predicates {
for clause_term in clause_clauses {
self.incremental_compile_clause(
(atom!("$clause"), 2),
clause_term,
@@ -2253,13 +2246,12 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.clause_clauses
.drain(0..std::cmp::min(predicates_len, clause_clauses_len))
.collect();
let compilation_target = self.payload.predicates.compilation_target;
self.compile_clause_clauses(
key,
compilation_target,
clauses_vec.into_iter(),
clauses_vec,
AppendOrPrepend::Append,
)?;
}
@@ -2288,15 +2280,43 @@ impl Machine {
pub(crate) fn compile_standalone_clause(
&mut self,
term_loc: RegType,
vars: &[Term],
term_reg: RegType,
vars: Vec<HeapCellValue>,
) -> Result<(), SessionError> {
let mut compile = || {
let cell = self.machine_st.store(self.machine_st.deref(self.machine_st[term_reg]));
// append the variables of vars.
let focus = cell.get_value() as usize;
let header_loc = term_nth_arg(&self.machine_st.heap, focus, 0).unwrap();
let name = term_name(&self.machine_st.heap, header_loc).unwrap();
let old_arity = term_arity(&self.machine_st.heap, header_loc);
let new_header_loc = self.machine_st.heap.len();
let new_arity = old_arity + vars.len();
self.machine_st.heap.push(atom_as_cell!(name, new_arity));
for idx in header_loc + 1 .. header_loc + 1 + old_arity {
self.machine_st.heap.push(self.machine_st.heap[idx]);
}
for var in vars {
self.machine_st.heap.push(var);
}
let value = if new_arity > 0 {
str_loc_as_cell!(new_header_loc)
} else {
heap_loc_as_cell!(new_header_loc)
};
let mut compile = |cell| {
use crate::heap_iter::eager_stackful_preorder_iter;
let mut loader: Loader<'_, InlineLoadState<'_>> =
Loader::new(self, InlineTermStream {});
let term = loader.read_term_from_heap(term_loc);
let clause = build_rule_body(vars, term);
let mut term = loader.copy_term_from_heap(cell);
let settings = CodeGenSettings {
global_clock_tick: None,
@@ -2304,10 +2324,16 @@ impl Machine {
non_counted_bt: true,
};
loader.compile_standalone_clause(clause, settings)
let value = term.heap[term.focus];
term.var_locs = var_locs_from_iter(
eager_stackful_preorder_iter(&mut term.heap, value),
);
loader.compile_standalone_clause(term, settings)
};
let StandaloneCompileResult { clause_code, .. } = compile()?;
let StandaloneCompileResult { clause_code, .. } = compile(value)?;
self.code.extend(clause_code);
Ok(())

View File

@@ -1,18 +1,19 @@
use crate::atom_table::*;
use crate::forms::*;
use crate::instructions::*;
use crate::iterators::*;
use crate::iterators::fact_iterator;
use crate::machine::Stack;
use crate::machine::loader::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use crate::parser::ast::*;
use crate::parser::dashu::Rational;
use crate::types::*;
use crate::variable_records::*;
use dashu::Integer;
use indexmap::{IndexMap, IndexSet};
use std::cell::Cell;
use std::cmp::Ordering;
use std::collections::VecDeque;
use std::hash::{Hash, Hasher};
@@ -147,11 +148,21 @@ enum TraversalState {
// where it leaves off.
BuildFinalDisjunct(usize),
Fail,
GetCutPoint { var_num: usize, prev_b: bool },
Cut { var_num: usize, is_global: bool },
Succeed,
GetCutPoint {
var_num: usize,
prev_b: bool,
},
Cut {
var_num: usize,
is_global: bool,
},
CutPrev(usize),
ResetCallPolicy(CallPolicy),
Term(Term),
Term {
subterm: HeapCellValue,
term_loc: usize,
},
OverrideGlobalCutVar(usize),
ResetGlobalCutVarOverride(Option<usize>),
RemoveBranchNum, // pop the current_branch_num and from the root set.
@@ -183,7 +194,7 @@ impl VarData {
fn emit_initial_get_level(&mut self, build_stack: &mut ChunkedTermVec) {
let global_cut_var_num = if let &Some(global_cut_var_num) = &self.global_cut_var_num {
match &self.records[global_cut_var_num].allocation {
VarAlloc::Perm(..) => Some(global_cut_var_num),
VarAlloc::Perm { .. } => Some(global_cut_var_num),
VarAlloc::Temp { term_loc, .. } if term_loc.chunk_num() > 0 => {
Some(global_cut_var_num)
}
@@ -196,7 +207,7 @@ impl VarData {
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);
VarAlloc::Perm { reg: 0, allocation: PermVarAllocation::Pending };
match build_stack.front_mut() {
Some(ChunkedTerms::Branch(_)) => {
@@ -213,8 +224,8 @@ impl VarData {
}
}
pub type ClassifyFactResult = (Term, VarData);
pub type ClassifyRuleResult = (Term, ChunkedTermVec, VarData);
pub type ClassifyFactResult = VarData;
pub type ClassifyRuleResult = (ChunkedTermVec, VarData);
fn merge_branch_seq(branches: impl Iterator<Item = BranchInfo>) -> BranchInfo {
let mut branch_info = BranchInfo::new(BranchNumber::default());
@@ -255,28 +266,32 @@ impl VariableClassifier {
}
}
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_fact(
mut self,
term: &mut FocusedHeap,
) -> Result<ClassifyFactResult, CompilationError> {
let focus = term.focus;
self.classify_head_variables(term, focus)?;
Ok(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,
term: &mut FocusedHeap,
) -> Result<ClassifyRuleResult, CompilationError> {
self.classify_head_variables(&head)?;
let head_loc = term.nth_arg(term.focus, 1).unwrap();
let body_loc = term.nth_arg(term.focus, 2).unwrap();
self.classify_head_variables(term, head_loc)?;
self.root_set.insert(self.current_branch_num.clone());
let mut query_terms = self.classify_body_variables(loader, body)?;
let mut query_terms = self.classify_body_variables(loader, term, body_loc)?;
self.merge_branches();
@@ -288,7 +303,7 @@ impl VariableClassifier {
var_data.emit_initial_get_level(&mut query_terms);
Ok((head, query_terms, var_data))
Ok((query_terms, var_data))
}
fn merge_branches(&mut self) {
@@ -332,22 +347,39 @@ impl VariableClassifier {
}
}
fn probe_body_term(&mut self, arg_c: usize, arity: usize, term: &Term) {
fn probe_body_term(
&mut self,
arg_c: usize,
arity: usize,
term: &mut FocusedHeap,
term_loc: usize,
) {
let classify_info = ClassifyInfo { arg_c, arity };
let mut lvl = Level::Shallow;
let mut stack = Stack::uninitialized();
let mut iter = fact_iterator::<false>(
&mut term.heap,
&mut stack,
term_loc,
);
// 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,
});
while let Some(subterm) = iter.next() {
if !subterm.is_var() {
lvl = Level::Deep;
continue;
}
let var_loc = subterm.get_value() as usize;
let var_ptr = term.var_locs.read_next_var_ptr_at_key(var_loc).unwrap();
self.probe_body_var(VarInfo {
var_ptr: var_ptr.clone(),
lvl,
classify_info,
chunk_type: self.current_chunk_type,
});
}
}
@@ -401,56 +433,79 @@ impl VariableClassifier {
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),
}
fn classify_head_variables(
&mut self,
term: &mut FocusedHeap,
head_loc: usize,
) -> Result<(), CompilationError> {
let arity = read_heap_cell!(term.deref_loc(head_loc),
(HeapCellValueTag::Str, s) => {
cell_as_atom_cell!(term.heap[s]).get_arity()
}
(HeapCellValueTag::Atom) => {
return Ok(());
}
_ => {
return Err(CompilationError::InvalidRuleHead);
}
);
let mut classify_info = ClassifyInfo {
arg_c: 1,
arity: term.arity(),
};
let mut classify_info = ClassifyInfo { arg_c: 1, arity };
if let Term::Clause(_, _, terms) = term {
for term in terms.iter() {
for term_ref in breadth_first_iter(term, RootIterationPolicy::Iterated) {
if let TermRef::Var(lvl, _, var_ptr) = term_ref {
// a body term, so we need the child level here.
let lvl = lvl.child_level();
if arity > 0 {
let (_term_loc, value) = subterm_index(&term.heap, head_loc);
let str_offset = value.get_value() as usize;
// the body of the if let here is an inlined
// "probe_head_var". note the difference between it
// and "probe_body_var".
let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
debug_assert_eq!(value.get_tag(), HeapCellValueTag::Str);
let needs_new_branch = branch_info_v.is_empty();
for idx in str_offset + 1 ..= str_offset + arity {
let mut lvl = Level::Shallow;
let mut stack = Stack::uninitialized();
let mut iter = fact_iterator::<false>(
&mut term.heap,
&mut stack,
idx,
);
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);
while let Some(subterm) = iter.next() {
if !subterm.is_var() {
lvl = Level::Deep;
continue;
}
let h = subterm.get_value() as usize;
let var_ptr = term.var_locs.read_next_var_ptr_at_key(h).unwrap().clone();
// the body of the if let here is an inlined
// "probe_head_var". note the difference between it
// and "probe_body_var".
let branch_info_v = self.branch_map.entry(var_ptr.clone()).or_default();
let needs_new_branch = branch_info_v.is_empty();
if needs_new_branch {
branch_info_v.push(BranchInfo::new(self.current_branch_num.clone()));
}
let branch_info = branch_info_v.last_mut().unwrap();
let needs_new_chunk = branch_info.chunks.is_empty();
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;
@@ -460,17 +515,40 @@ impl VariableClassifier {
Ok(())
}
fn new_cut_state(&mut self) -> TraversalState {
let (var_num, is_global) = if let Some(var_num) = self.global_cut_var_num_override {
(var_num, false)
} else if let Some(var_num) = self.global_cut_var_num {
(var_num, true)
} else {
let var_num = self.var_num;
self.global_cut_var_num = Some(var_num);
self.var_num += 1;
(var_num, true)
};
self.probe_in_situ_var(var_num);
TraversalState::Cut { var_num, is_global }
}
fn classify_body_variables<'a, LS: LoadState<'a>>(
&mut self,
loader: &mut Loader<'a, LS>,
term: Term,
terms: &mut FocusedHeap,
term_loc: usize,
) -> Result<ChunkedTermVec, CompilationError> {
let mut state_stack = vec![TraversalState::Term(term)];
let mut state_stack = vec![TraversalState::Term {
subterm: terms.heap[term_loc],
term_loc,
}];
let mut build_stack = ChunkedTermVec::new();
self.current_chunk_type = ChunkType::Mid;
while let Some(traversal_st) = state_stack.pop() {
'outer: while let Some(traversal_st) = state_stack.pop() {
match traversal_st {
TraversalState::AddBranchNum(branch_num) => {
self.root_set.insert(branch_num.clone());
@@ -544,297 +622,339 @@ impl VariableClassifier {
TraversalState::Fail => {
build_stack.push_chunk_term(QueryTerm::Fail);
}
TraversalState::Term(term) => {
TraversalState::Succeed => {
build_stack.push_chunk_term(QueryTerm::Succeed);
}
TraversalState::Term {
mut subterm,
mut term_loc,
} => {
// 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) {
let update_chunk_data = |classifier: &mut Self, key: PredicateKey| {
if ClauseType::is_inlined(key.0, key.1) {
classifier.try_set_chunk_at_inlined_boundary()
} else {
classifier.try_set_chunk_at_call_boundary()
}
};
let mut add_chunk = |classifier: &mut Self, name: Atom, terms: Vec<Term>| {
if update_chunk_data(classifier, name, terms.len()) {
build_stack.add_chunk();
}
for (arg_c, term) in terms.iter().enumerate() {
classifier.probe_body_term(arg_c + 1, terms.len(), term);
}
build_stack.push_chunk_term(clause_to_query_term(
loader,
name,
terms,
classifier.call_policy,
));
};
match term {
Term::Clause(
_,
name @ (atom!("->") | atom!(";") | atom!(",")),
mut terms,
) if terms.len() == 3 => {
if let Some(last_arg) = terms.last() {
if let Term::Literal(_, Literal::CodeIndex(_)) = last_arg {
terms.pop();
state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
name,
terms,
)));
} else {
add_chunk(self, name, terms);
}
}
}
Term::Clause(_, atom!(","), mut terms) if terms.len() == 2 => {
let tail = terms.pop().unwrap();
let head = terms.pop().unwrap();
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
});
macro_rules! add_chunk {
($classifier:ident, $key:expr, $tag:expr, $term_loc:expr) => {{
if update_chunk_data($classifier, $key) {
build_stack.add_chunk();
}
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]
for (arg_c, term_loc) in
($term_loc + 1 ..= $term_loc + $key.1).enumerate()
{
state_stack[final_disjunct_loc] =
TraversalState::BuildFinalDisjunct(build_stack_len);
$classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
}
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
}
Term::Clause(_, atom!("->"), mut terms) if terms.len() == 2 => {
let then_term = terms.pop().unwrap();
let if_term = terms.pop().unwrap();
let prev_b = if matches!(
state_stack.last(),
Some(TraversalState::RemoveBranchNum)
) {
// check if the second-to-last element
// is a regular BuildDisjunct, as we
// don't want to add GetPrevLevel in
// case of a TrustMe.
match state_stack.iter().rev().nth(1) {
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
preceding_len + 1 == build_stack.len()
}
_ => false,
}
} else {
false
};
state_stack.push(TraversalState::Term(then_term));
state_stack.push(TraversalState::Cut {
var_num: self.var_num,
is_global: false,
});
state_stack.push(TraversalState::Term(if_term));
state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num,
prev_b,
});
self.var_num += 1;
}
Term::Clause(_, atom!("\\+"), mut terms) if terms.len() == 1 => {
let not_term = terms.pop().unwrap();
let build_stack_len = build_stack.len();
build_stack.reserve_branch(2);
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Term(Term::Clause(
Cell::default(),
atom!("$succeed"),
vec![],
build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
loader,
$key,
terms.as_ref_mut($term_loc),
HeapCellValue::build_with($tag, $term_loc as u64),
$classifier.call_policy,
)));
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::CutPrev(self.var_num));
state_stack.push(TraversalState::ResetGlobalCutVarOverride(
self.global_cut_var_num_override,
));
state_stack.push(TraversalState::Term(not_term));
state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num,
prev_b: false,
});
}};
}
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
self.var_num += 1;
}
Term::Clause(_, atom!(":"), mut terms) if terms.len() == 2 => {
let predicate_name = terms.pop().unwrap();
let module_name = terms.pop().unwrap();
match (module_name, predicate_name) {
(
Term::Literal(_, Literal::Atom(module_name)),
Term::Literal(_, Literal::Atom(predicate_name)),
) => {
if update_chunk_data(self, predicate_name, 0) {
build_stack.add_chunk();
}
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) => {
add_chunk(self, name, terms);
}
var @ Term::Var(..) => {
if update_chunk_data(self, atom!("call"), 1) {
macro_rules! add_qualified_chunk {
($classifier:ident, $module_name:expr, $key:expr, $tag:expr, $term_loc:expr) => {{
if update_chunk_data($classifier, $key) {
build_stack.add_chunk();
}
self.probe_body_term(1, 1, &var);
for (arg_c, term_loc) in
($term_loc + 1..$term_loc + $key.1 + 1).enumerate()
{
$classifier.probe_body_term(arg_c + 1, $key.1, terms, term_loc);
}
build_stack.push_chunk_term(clause_to_query_term(
loader,
atom!("call"),
vec![var],
self.call_policy,
build_stack.push_chunk_term(QueryTerm::Clause(
qualified_clause_to_query_term(
loader,
$key,
$module_name,
terms.as_ref_mut($term_loc),
HeapCellValue::build_with($tag, $term_loc as u64),
$classifier.call_policy,
),
));
}
Term::Literal(_, Literal::Atom(atom!("!")) | Literal::Char('!')) => {
let (var_num, is_global) =
if let Some(var_num) = self.global_cut_var_num_override {
(var_num, false)
} else if let Some(var_num) = self.global_cut_var_num {
(var_num, true)
}};
}
loop {
read_heap_cell!(subterm,
(HeapCellValueTag::Str, subterm_loc) => {
let (name, arity) = cell_as_atom_cell!(terms.heap[subterm_loc])
.get_name_and_arity();
match (name, arity) {
(atom!("->") | atom!(";") | atom!(","), 3) => {
if blunt_index_ptr(&mut terms.heap, (name, 2), subterm_loc) {
subterm = terms.heap[subterm_loc];
continue;
}
add_chunk!(self, (name, 2), HeapCellValueTag::Str, subterm_loc);
}
(atom!(","), 2) => {
let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
let head = terms.heap[head_loc];
let iter = unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(","))
.into_iter()
.rev()
.chain(std::iter::once((head, head_loc)))
.map(|(subterm, term_loc)| {
TraversalState::Term { subterm, term_loc }
});
state_stack.extend(iter);
}
(atom!(";"), 2) => {
let head_loc = terms.nth_arg(subterm_loc, 1).unwrap();
let tail_loc = terms.nth_arg(subterm_loc, 2).unwrap();
let head = terms.heap[head_loc];
let first_branch_num = self.current_branch_num.split();
let branches: Vec<_> = std::iter::once((head, head_loc))
.chain(
unfold_by_str_locs(&mut terms.heap, tail_loc, atom!(";"))
.into_iter(),
)
.collect();
let mut branch_numbers = vec![first_branch_num];
for idx in 1..branches.len() {
let succ_branch_number = branch_numbers[idx - 1].incr_by_delta();
branch_numbers.push(if idx + 1 < branches.len() {
succ_branch_number.split()
} else {
succ_branch_number
});
}
let build_stack_len = build_stack.len();
build_stack.reserve_branch(branches.len());
state_stack.push(TraversalState::RepBranchNum(
self.current_branch_num.halve_delta(),
));
let iter = branches.into_iter().zip(branch_numbers.into_iter());
let final_disjunct_loc = state_stack.len();
for ((subterm, term_loc), branch_num) in iter.rev() {
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::RemoveBranchNum);
state_stack.push(TraversalState::Term { subterm, term_loc });
state_stack.push(TraversalState::AddBranchNum(branch_num));
}
if let TraversalState::BuildDisjunct(build_stack_len) =
state_stack[final_disjunct_loc]
{
state_stack[final_disjunct_loc] =
TraversalState::BuildFinalDisjunct(build_stack_len);
}
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
}
(atom!("->"), 2) => {
let if_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
let then_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
let if_term = terms.heap[if_term_loc];
let then_term = terms.heap[then_term_loc];
let prev_b = if matches!(
state_stack.last(),
Some(TraversalState::RemoveBranchNum)
) {
// check if the second-to-last element
// is a regular BuildDisjunct, as we
// don't want to add GetPrevLevel in
// case of a TrustMe.
match state_stack.iter().rev().nth(1) {
Some(&TraversalState::BuildDisjunct(preceding_len)) => {
preceding_len + 1 == build_stack.len()
}
_ => false,
}
} else {
false
};
state_stack.push(TraversalState::Term {
subterm: then_term,
term_loc: then_term_loc,
});
state_stack.push(TraversalState::Cut {
var_num: self.var_num,
is_global: false,
});
state_stack.push(TraversalState::Term {
subterm: if_term,
term_loc: if_term_loc,
});
state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num,
prev_b,
});
self.var_num += 1;
}
(atom!("\\+"), 1) => {
let not_term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
let not_term = terms.heap[not_term_loc];
let build_stack_len = build_stack.len();
build_stack.reserve_branch(2);
let branch_num = self.current_branch_num.split();
let succ_branch_num = branch_num.incr_by_delta();
state_stack.push(TraversalState::BuildFinalDisjunct(build_stack_len));
state_stack.push(TraversalState::Succeed);
state_stack.push(TraversalState::BuildDisjunct(build_stack_len));
state_stack.push(TraversalState::RepBranchNum(succ_branch_num));
state_stack.push(TraversalState::Fail);
state_stack.push(TraversalState::CutPrev(self.var_num));
state_stack.push(TraversalState::ResetGlobalCutVarOverride(
self.global_cut_var_num_override,
));
state_stack.push(TraversalState::Term {
subterm: not_term,
term_loc: not_term_loc,
});
state_stack.push(TraversalState::OverrideGlobalCutVar(self.var_num));
state_stack.push(TraversalState::GetCutPoint {
var_num: self.var_num,
prev_b: false,
});
state_stack.push(TraversalState::AddBranchNum(branch_num));
self.current_chunk_type = ChunkType::Mid;
self.current_chunk_num += 1;
self.var_num += 1;
}
(atom!(":"), 2) => {
let module_name_loc = terms.nth_arg(subterm_loc, 1).unwrap();
let predicate_term_loc = terms.nth_arg(subterm_loc, 2).unwrap();
let module_name = terms.deref_loc(module_name_loc);
let predicate_term = terms.deref_loc(predicate_term_loc);
read_heap_cell!(module_name,
(HeapCellValueTag::Atom, (module_name, arity)) => {
if arity == 0 {
read_heap_cell!(predicate_term,
(HeapCellValueTag::Str, s) => {
let key = cell_as_atom_cell!(terms.heap[s])
.get_name_and_arity();
add_qualified_chunk!(
self,
module_name,
key,
HeapCellValueTag::Str,
s
);
}
(HeapCellValueTag::Atom, (predicate_name, predicate_arity)) => {
debug_assert_eq!(predicate_arity, 0);
let key = (predicate_name, predicate_arity);
add_qualified_chunk!(
self,
module_name,
key,
HeapCellValueTag::Str,
predicate_term_loc
);
}
_ => {}
);
continue 'outer;
}
}
_ => {}
);
if update_chunk_data(self, (atom!("call"), 2)) {
build_stack.add_chunk();
}
self.probe_body_term(1, 0, terms, module_name_loc);
self.probe_body_term(2, 0, terms, predicate_term_loc);
let h = terms.heap.len();
terms.heap.push(atom_as_cell!(atom!("call"), 1));
terms.heap.push(str_loc_as_cell!(subterm_loc));
build_stack.push_chunk_term(QueryTerm::Clause(clause_to_query_term(
loader,
(atom!("call"), 1),
terms.as_ref_mut(h),
str_loc_as_cell!(h),
self.call_policy,
)));
}
(atom!("$call_with_inference_counting"), 1) => {
let term_loc = terms.nth_arg(subterm_loc, 1).unwrap();
let subterm = terms.deref_loc(term_loc);
state_stack.push(TraversalState::ResetCallPolicy(self.call_policy));
state_stack.push(TraversalState::Term { subterm, term_loc });
self.call_policy = CallPolicy::Counted;
}
(name, arity) => {
add_chunk!(self, (name, arity), HeapCellValueTag::Str, subterm_loc);
}
}
}
(HeapCellValueTag::Atom, (name, arity)) => {
debug_assert_eq!(arity, 0);
if name == atom!("!") {
state_stack.push(self.new_cut_state());
} else {
let var_num = self.var_num;
self.global_cut_var_num = Some(var_num);
self.var_num += 1;
(var_num, true)
};
self.probe_in_situ_var(var_num);
state_stack.push(TraversalState::Cut { var_num, is_global });
}
Term::Literal(_, Literal::Atom(name)) => {
if update_chunk_data(self, name, 0) {
build_stack.add_chunk();
add_chunk!(self, (name, 0), HeapCellValueTag::Var, term_loc);
}
}
(HeapCellValueTag::Char, c) => {
if c == '!' {
state_stack.push(self.new_cut_state());
} else {
return Err(CompilationError::InadmissibleQueryTerm);
}
}
(HeapCellValueTag::AttrVar | HeapCellValueTag::Var, h) => {
if h != term_loc {
subterm = terms.heap[h];
term_loc = h;
continue;
}
build_stack.push_chunk_term(clause_to_query_term(
loader,
name,
vec![],
self.call_policy,
));
}
_ => {
return Err(CompilationError::InadmissibleQueryTerm);
}
add_chunk!(self, (atom!("call"), 1), HeapCellValueTag::Var, h);
}
_ => {
return Err(CompilationError::InadmissibleQueryTerm);
}
);
break;
}
}
}
@@ -899,7 +1019,8 @@ impl BranchMap {
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));
let is_anon = var_info.var_ptr.is_anon();
var_info.var_ptr.set(Var::Generated { is_anon, var_num });
}
}
}

View File

@@ -2664,6 +2664,8 @@ impl Machine {
&Instruction::CallNamed(arity, name, ref idx) => {
let idx = idx.get();
// println!("calling {}/{}", name.as_str(), arity);
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
if self.machine_st.fail {
@@ -2675,6 +2677,8 @@ impl Machine {
&Instruction::ExecuteNamed(arity, name, ref idx) => {
let idx = idx.get();
// println!("executing {}/{}", name.as_str(), arity);
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
if self.machine_st.fail {
@@ -2686,6 +2690,8 @@ impl Machine {
&Instruction::DefaultCallNamed(arity, name, ref idx) => {
let idx = idx.get();
// println!("calling {}/{}", name.as_str(), arity);
try_or_throw!(self.machine_st, self.try_call(name, arity, idx));
if self.machine_st.fail {
@@ -2695,6 +2701,8 @@ impl Machine {
&Instruction::DefaultExecuteNamed(arity, name, ref idx) => {
let idx = idx.get();
// println!("executing {}/{}", name.as_str(), arity);
try_or_throw!(self.machine_st, self.try_execute(name, arity, idx));
if self.machine_st.fail {
@@ -3511,6 +3519,15 @@ impl Machine {
self.dynamic_module_resolution(arity - 2)
);
/*
println!(
"(slow) calling {}:{}/{}",
module_name.as_str(),
key.0.as_str(),
key.1,
);
*/
try_or_throw!(self.machine_st, self.call_clause(module_name, key));
if self.machine_st.fail {
@@ -3523,6 +3540,15 @@ impl Machine {
self.dynamic_module_resolution(arity - 2)
);
/*
println!(
"(slow) executing {}:{}/{}",
module_name.as_str(),
key.0.as_str(),
key.1,
);
*/
try_or_throw!(self.machine_st, self.execute_clause(module_name, key));
if self.machine_st.fail {

View File

@@ -7,6 +7,9 @@ use crate::types::*;
#[cfg(test)]
use crate::heap_iter::{FocusedHeapIter, HeapOrStackTag, IterStackLoc};
#[cfg(test)]
use std::ops::Deref;
pub(crate) trait UnmarkPolicy {
fn forward_attr_var(iter: &mut StacklessPreOrderHeapIter<Self>) -> Option<HeapCellValue>
where
@@ -103,6 +106,15 @@ pub(crate) struct StacklessPreOrderHeapIter<'a, UMP: UnmarkPolicy> {
iter_state: UMP,
}
#[cfg(test)]
impl<'a> Deref for StacklessPreOrderHeapIter<'a, IteratorUMP> {
type Target = [HeapCellValue];
fn deref(&self) -> &Self::Target {
self.heap
}
}
#[cfg(test)]
impl<'a> FocusedHeapIter for StacklessPreOrderHeapIter<'a, IteratorUMP> {
#[inline]

View File

@@ -436,7 +436,7 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
pub(super) fn try_term_to_tl(
&mut self,
term: Term,
term: FocusedHeap,
preprocessor: &mut Preprocessor,
) -> Result<PredicateClause, SessionError> {
let tl = preprocessor.try_term_to_tl(self, term)?;
@@ -1164,7 +1164,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let mut path_buf = PathBuf::from(&*filename.as_str());
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(
@@ -1245,7 +1246,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(&*filename.as_str());
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(

View File

@@ -15,7 +15,6 @@ use crate::types::*;
use indexmap::IndexSet;
use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::fmt;
@@ -177,18 +176,18 @@ impl CompilationTarget {
}
pub struct PredicateQueue {
pub(super) predicates: Vec<Term>,
pub(super) predicates: Vec<FocusedHeap>,
pub(super) compilation_target: CompilationTarget,
}
impl PredicateQueue {
#[inline]
pub(super) fn push(&mut self, clause: Term) {
pub(super) fn push(&mut self, clause: FocusedHeap) {
self.predicates.push(clause);
}
#[inline]
pub(crate) fn first(&self) -> Option<&Term> {
pub(crate) fn first(&self) -> Option<&FocusedHeap> {
self.predicates.first()
}
@@ -492,11 +491,23 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
}
}
pub(crate) fn read_term_from_heap(&mut self, r: RegType) -> Term {
let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r];
pub(crate) fn copy_term_from_heap(&mut self, cell: HeapCellValue) -> FocusedHeap {
use crate::iterators::fact_iterator;
machine_st.read_term_from_heap(cell)
let mut term = FocusedHeap::empty();
let mut stack = Stack::uninitialized();
let machine_st = LS::machine_st(&mut self.payload);
term.copy_term_from_machine_heap(machine_st, cell);
term.var_locs = var_locs_from_iter(
fact_iterator::<false>(
&mut term.heap,
&mut stack,
0,
),
);
term
}
pub(crate) fn load(mut self) -> Result<LS::Evacuable, SessionError> {
@@ -513,18 +524,17 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let compilation_target = &load_state.compilation_target;
let composite_op_dir = self.wam_prelude.composite_op_dir(compilation_target);
let term = load_state.term_stream.next(&composite_op_dir)?;
let mut term = load_state.term_stream.next(&composite_op_dir)?;
if !term.is_consistent(&load_state.predicates) {
self.compile_and_submit()?;
}
let term = match term {
Term::Clause(_, name, terms) if name == atom!(":-") && terms.len() == 1 => {
return Ok(Some(setup_declaration(self, terms)?));
}
term => term,
};
if Some(atom!(":-")) == term.name(term.focus) && term.arity(term.focus) == 1 {
let new_focus = term.nth_arg(term.focus, 1).unwrap();
let term = term.as_ref_mut(new_focus);
return Ok(Some(setup_declaration(self, term)?));
}
self.payload.predicates.push(term);
}
@@ -1045,31 +1055,60 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
let machine_st = LS::machine_st(&mut self.payload);
let cell = machine_st[r];
let export_list = machine_st.read_term_from_heap(cell);
let atom_tbl = &mut LS::machine_st(&mut self.payload).atom_tbl;
let export_list = setup_module_export_list(export_list, atom_tbl)?;
let export_list = FocusedHeapRefMut::from_cell(&mut machine_st.heap, cell);
let export_list = setup_module_export_list(export_list)?;
Ok(export_list.into_iter().collect())
}
fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> {
match term {
Term::Clause(_, atom!(":-"), mut terms) if terms.len() == 2 => {
let body = terms.pop().unwrap();
let head = terms.pop().unwrap();
fn clause_clause(&mut self, cell: HeapCellValue) -> Result<FocusedHeap, CompilationError> {
let machine_st = LS::machine_st(&mut self.payload);
let mut term = FocusedHeap::empty();
self.payload.clause_clauses.push((head, body));
read_heap_cell!(cell,
(HeapCellValueTag::Str, s) => {
let (name, arity) = cell_as_atom_cell!(machine_st.heap[s])
.get_name_and_arity();
term.copy_term_from_machine_heap(machine_st, cell);
let focus = term.heap.len();
term.heap.push(str_loc_as_cell!(focus+1));
term.heap.push(atom_as_cell!(atom!("clause"), 2));
match (name, arity) {
(atom!(":-"), 2) => {
term.heap.push(heap_loc_as_cell!(2));
term.heap.push(heap_loc_as_cell!(3));
}
_ => {
term.heap.push(heap_loc_as_cell!(0));
term.heap.push(atom_as_cell!(atom!("true")));
}
}
term.focus = focus;
}
head @ Term::Literal(_, Literal::Atom(..)) | head @ Term::Clause(..) => {
let body = Term::Literal(Cell::default(), Literal::Atom(atom!("true")));
self.payload.clause_clauses.push((head, body));
(HeapCellValueTag::Atom, (name, arity)) => {
if arity == 0 {
term.heap.push(str_loc_as_cell!(1));
term.heap.push(atom_as_cell!(atom!("clause"), 2));
term.heap.push(atom_as_cell!(name));
term.heap.push(atom_as_cell!(atom!("true")));
term.focus = 0;
} else {
return Err(CompilationError::InadmissibleFact);
}
}
_ => {
return Err(CompilationError::InadmissibleFact);
}
}
);
Ok(())
let value = term.heap[term.focus];
term.var_locs = var_locs_from_iter(eager_stackful_preorder_iter(&mut term.heap, value));
Ok(term)
}
fn add_extensible_predicate_declaration(
@@ -1287,9 +1326,14 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
)
}
fn add_clause_clause_if_dynamic(&mut self, term: &Term) -> Result<(), SessionError> {
if let Some(predicate_name) = ClauseInfo::name(term) {
let arity = ClauseInfo::arity(term);
fn add_clause_clause_if_dynamic(&mut self, value: HeapCellValue) -> Result<(), SessionError> {
let machine_st = LS::machine_st(&mut self.payload);
let term = FocusedHeapRefMut::from_cell(&mut machine_st.heap, value);
let name_opt = ClauseInfo::name(&term);
if let Some(predicate_name) = name_opt {
let arity = ClauseInfo::arity(&term);
let predicates_compilation_target = self.payload.predicates.compilation_target;
let is_dynamic = self
@@ -1300,7 +1344,8 @@ impl<'a, LS: LoadState<'a>> Loader<'a, LS> {
.unwrap_or(false);
if is_dynamic {
self.add_clause_clause(term.clone())?;
let clause_clause_term = self.clause_clause(value)?;
self.payload.clause_clauses.push(clause_clause_term);
}
}
@@ -1366,108 +1411,6 @@ impl<'a> MachinePreludeView<'a> {
}
}
impl MachineState {
pub(super) fn read_term_from_heap(&mut self, term_addr: HeapCellValue) -> Term {
let mut term_stack = vec![];
let mut iter =
stackful_post_order_iter::<NonListElider>(&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 = AtomTable::build_with(&self.atom_tbl, &string);
term_stack.push(Term::CompleteString(Cell::default(), atom));
}
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::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);
term_stack.pop().unwrap()
}
}
impl Machine {
pub(crate) fn use_module(&mut self) -> CallResult {
let subevacuable_addr = self
@@ -1628,10 +1571,11 @@ impl Machine {
}
pub(crate) fn add_term_expansion_clause(&mut self) -> CallResult {
let value = self.machine_st.registers[1];
let mut loader = self.loader_from_heap_evacuable(temp_v!(2));
let add_clause = || {
let term = loader.read_term_from_heap(temp_v!(1));
let term = loader.copy_term_from_heap(value);
loader.incremental_compile_clause(
(atom!("term_expansion"), 2),
@@ -1653,6 +1597,7 @@ impl Machine {
.machine_st
.store(self.machine_st.deref(self.machine_st.registers[1])));
let value = self.machine_st.registers[2];
let mut loader = self.loader_from_heap_evacuable(temp_v!(3));
let compilation_target = match target_module_name {
@@ -1661,21 +1606,21 @@ impl Machine {
};
let add_clause = || {
let term = loader.read_term_from_heap(temp_v!(2));
let term = loader.copy_term_from_heap(value);
let indexing_arg = match term.name() {
Some(atom!(":-")) => term.first_arg().and_then(Term::first_arg),
Some(_) => term.first_arg(),
let indexing_arg = match term.name(term.focus) {
Some(atom!(":-")) => term.nth_arg(term.focus, 1).and_then(|h| term.nth_arg(h, 1)),
Some(_) => term.nth_arg(term.focus, 1),
None => None,
};
if let Some(indexing_term) = indexing_arg {
if let Some(indexing_name) = indexing_term.name() {
if let Some(indexing_term_loc) = indexing_arg {
if let Some(indexing_name) = term.name(indexing_term_loc) {
loader
.wam_prelude
.indices
.goal_expansion_indices
.insert((indexing_name, indexing_term.arity()));
.insert((indexing_name, term.arity(indexing_term_loc)));
}
}
@@ -1981,30 +1926,24 @@ impl Machine {
};
let stub_gen = || functor_stub(key.0, key.1);
let assert_clause = self.machine_st.registers[2];
let (name, arity) = {
let term = FocusedHeapRefMut::from_cell(&mut self.machine_st.heap, assert_clause);
(ClauseInfo::name(&term), ClauseInfo::arity(&term))
};
let head = self.deref_register(2);
if head.is_var() {
let err = self.machine_st.instantiation_error();
return Err(self.machine_st.error_form(err, stub_gen()));
}
let mut compile_assert = || {
let mut compile_assert = |assert_clause, name, arity| {
let mut loader: Loader<'_, LiveLoadAndMachineState<'_>> =
Loader::new(self, LiveTermStream::new(ListingSource::User));
loader.payload.compilation_target = compilation_target;
let head =
LiveLoadAndMachineState::machine_st(&mut loader.payload).read_term_from_heap(head);
let name = if let Some(name) = head.name() {
let name = if let Some(name) = name {
name
} else {
return Err(SessionError::from(CompilationError::InvalidRuleHead));
};
let arity = head.arity();
let is_builtin = loader.wam_prelude.indices.builtin_property((name, arity));
let is_dynamic_predicate = loader
@@ -2036,16 +1975,9 @@ impl Machine {
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.
loader.add_dynamic_predicate(compilation_target, name, arity)?;
let asserted_clause = loader.copy_term_from_heap(assert_clause);
loader.incremental_compile_clause(
(name, arity),
@@ -2055,20 +1987,22 @@ impl Machine {
append_or_prepend,
)?;
let clause_clause_term = loader.clause_clause(assert_clause)?;
// the global clock is incremented after each assertion.
LiveLoadAndMachineState::machine_st(&mut loader.payload).global_clock += 1;
loader.compile_clause_clauses(
(name, arity),
compilation_target,
std::iter::once((head, body)),
vec![clause_clause_term],
append_or_prepend,
)?;
LiveLoadAndMachineState::evacuate(loader)
};
match compile_assert() {
match compile_assert(assert_clause, name, arity) {
Ok(_) => Ok(()),
Err(SessionError::CompilationError(
CompilationError::InvalidRuleHead | CompilationError::InadmissibleFact,
@@ -2474,9 +2408,12 @@ impl<'a> Loader<'a, LiveLoadAndMachineState<'a>> {
self.payload.predicates.compilation_target = compilation_target;
}
let term = self.read_term_from_heap(term_reg);
let machine_st = LiveLoadAndMachineState::machine_st(&mut self.payload);
let value = machine_st[term_reg];
self.add_clause_clause_if_dynamic(&term)?;
self.add_clause_clause_if_dynamic(value)?;
let term = self.copy_term_from_heap(value);
self.payload.term_stream.term_queue.push_back(term);
self.load()

View File

@@ -24,7 +24,7 @@ enum ErrorProvenance {
#[derive(Debug)]
pub(crate) struct MachineError {
stub: MachineStub,
location: Option<(usize, usize)>, // line_num, col_num
location: Option<ParserErrorSrc>,
from: ErrorProvenance,
}
@@ -649,7 +649,7 @@ impl MachineState {
stub[1] = err.stub[0];
}
if let Some((line_num, _)) = location {
if let Some(ParserErrorSrc { line_num, .. }) = location {
stub.push(atom_as_cell!(atom!(":"), 2));
stub.push(str_loc_as_cell!(h + 6 + stub_addition_len));
stub.push(integer_as_cell!(Number::arena_from(
@@ -741,9 +741,9 @@ impl From<ParserError> for CompilationError {
}
impl CompilationError {
pub(crate) fn line_and_col_num(&self) -> Option<(usize, usize)> {
pub(crate) fn line_and_col_num(&self) -> Option<ParserErrorSrc> {
match self {
CompilationError::ParserError(err) => err.line_and_col_num(),
CompilationError::ParserError(err) => Some(err.err_src()),
_ => None,
}
}
@@ -1044,13 +1044,6 @@ pub enum SessionError {
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
}
impl From<std::io::Error> for SessionError {
#[inline]
fn from(err: std::io::Error) -> SessionError {
SessionError::from(ParserError::from(err))
}
}
impl From<ParserError> for SessionError {
#[inline]
fn from(err: ParserError) -> Self {

View File

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

View File

@@ -71,7 +71,7 @@ pub struct MachineState {
pub(super) e: usize,
pub(super) num_of_args: usize,
pub(super) cp: usize,
pub(super) attr_var_init: AttrVarInitializer,
pub(crate) attr_var_init: AttrVarInitializer,
pub(super) fail: bool,
pub heap: Heap,
pub(super) mode: MachineMode,
@@ -200,20 +200,21 @@ pub fn pstr_loc_and_offset(heap: &[HeapCellValue], index: usize) -> (usize, Fixn
)
}
fn push_var_eq_functors<'a>(
fn push_var_eq_functors(
heap: &mut Heap,
iter: impl Iterator<Item = (&'a VarKey, &'a HeapCellValue)>,
iter: impl Iterator<Item = (usize, VarPtr)>, // (&'a VarPtr, &'a HeapCellValue)>,
atom_tbl: &AtomTable,
) -> Vec<HeapCellValue> {
let mut list_of_var_eqs = vec![];
for (var, binding) in iter {
let var_atom = AtomTable::build_with(atom_tbl, &var.to_string());
for (var_loc, var_ptr) in iter { // (var, binding) in iter {
let var_atom = AtomTable::build_with(atom_tbl, &*var_ptr.borrow().to_string());
let h = heap.len();
let binding = heap[var_loc];
heap.push(atom_as_cell!(atom!("="), 2));
heap.push(atom_as_cell!(var_atom));
heap.push(*binding);
heap.push(binding);
list_of_var_eqs.push(str_loc_as_cell!(h));
}
@@ -221,6 +222,16 @@ fn push_var_eq_functors<'a>(
list_of_var_eqs
}
pub(crate) fn copy_and_align_iter<Iter: Iterator<Item = HeapCellValue>>(
iter: Iter,
boundary: i64,
h: i64,
) -> impl Iterator<Item = HeapCellValue> {
let diff = boundary - h;
iter.map(move |heap_value| heap_value - diff)
}
#[derive(Debug)]
pub struct Ball {
pub(super) boundary: usize,
@@ -241,13 +252,7 @@ impl Ball {
}
pub(super) fn copy_and_align(&self, h: usize) -> Heap {
let diff = self.boundary as i64 - h as i64;
self.stub
.iter()
.cloned()
.map(|heap_value| heap_value - diff)
.collect()
copy_and_align_iter(self.stub.iter().cloned(), self.boundary as i64, h as i64).collect()
}
}
@@ -311,7 +316,7 @@ impl<'a> CopierTarget for CopyTerm<'a> {
}
#[derive(Debug)]
pub(super) struct CopyBallTerm<'a> {
pub(crate) struct CopyBallTerm<'a> {
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
@@ -320,7 +325,7 @@ pub(super) struct CopyBallTerm<'a> {
}
impl<'a> CopyBallTerm<'a> {
pub(super) fn new(
pub(crate) fn new(
attr_var_queue: &'a mut Vec<usize>,
stack: &'a mut Stack,
heap: &'a mut Heap,
@@ -536,18 +541,19 @@ impl MachineState {
pub fn write_read_term_options(
&mut self,
mut var_list: Vec<(VarKey, HeapCellValue, usize)>,
mut var_list: Vec<(VarPtr, HeapCellValue, usize)>,
singleton_var_list: Vec<HeapCellValue>,
) -> CallResult {
var_list.sort_by(|(_, _, idx_1), (_, _, idx_2)| idx_1.cmp(idx_2));
let list_of_var_eqs = push_var_eq_functors(
&mut self.heap,
var_list.iter().filter_map(|(var_name, var, _)| {
if var_name.is_anon() {
var_list.iter().filter_map(|(var_ptr, var, _)| {
if var_ptr.is_anon() {
None
} else {
Some((var_name, var))
let var_loc = var.get_value() as usize;
Some((var_loc, var_ptr.clone()))
}
}),
&self.atom_tbl,
@@ -586,13 +592,13 @@ impl MachineState {
Ok(unify_fn!(*self, var_names_offset, var_names_addr))
}
pub fn read_term_body(&mut self, mut term_write_result: TermWriteResult) -> CallResult {
let heap_loc = read_heap_cell!(self.heap[term_write_result.heap_loc],
pub fn read_term_body(&mut self, term: TermWriteResult) -> CallResult {
let heap_loc = read_heap_cell!(self.heap[term.heap_loc],
(HeapCellValueTag::PStr | HeapCellValueTag::PStrOffset) => {
pstr_loc_as_cell!(term_write_result.heap_loc)
pstr_loc_as_cell!(term.heap_loc)
}
_ => {
heap_loc_as_cell!(term_write_result.heap_loc)
heap_loc_as_cell!(term.heap_loc)
}
);
@@ -602,15 +608,15 @@ impl MachineState {
return Ok(());
}
/*
for var in term_write_result.var_dict.values_mut() {
*var = heap_bound_deref(&self.heap, *var);
}
*/
let mut singleton_var_set: IndexMap<Ref, bool> = IndexMap::new();
for cell in
stackful_preorder_iter::<NonListElider>(&mut self.heap, &mut self.stack, heap_loc)
{
for cell in eager_stackful_preorder_iter(&mut self.heap, heap_loc) {
let cell = unmark_cell_bits!(cell);
if let Some(var) = cell.as_var() {
@@ -624,34 +630,42 @@ impl MachineState {
let singleton_var_list = push_var_eq_functors(
&mut self.heap,
term_write_result
.var_dict
term.var_locs
.iter()
.filter(|(var_name, binding)| {
if var_name.is_anon() {
return false;
.filter_map(|(var_loc, var_ptrs)| {
let var_ptr = var_ptrs.front().unwrap();
if var_ptr.is_anon() {
return None;
}
if let Some(r) = binding.as_var() {
*singleton_var_set.get(&r).unwrap_or(&false)
// add h to offset the term variable into its heap location.
let r = Ref::heap_cell(var_loc);
if singleton_var_set.get(&r).cloned().unwrap_or(false) {
Some((var_loc, var_ptr.clone()))
} else {
false
None
}
}),
&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());
for (var_name, addr) in term_write_result.var_dict {
if let Some(var) = addr.as_var() {
if let Some(idx) = singleton_var_set.get_index_of(&var) {
var_list.push((var_name, addr, idx));
}
for (var_loc, var_ptrs) in term.var_locs.iter() {
let var_ptr = var_ptrs.front().unwrap().clone();
let r = Ref::heap_cell(var_loc);
let cell = self.heap[var_loc];
if let Some(idx) = singleton_var_set.get_index_of(&r) {
var_list.push((var_ptr, cell, idx));
}
}
@@ -734,8 +748,8 @@ impl MachineState {
}
loop {
match self.read(stream, &indices.op_dir) {
Ok(term_write_result) => return self.read_term_body(term_write_result),
match self.read_to_heap(stream, &indices.op_dir) {
Ok(term) => return self.read_term_body(term),
Err(err) => {
match &err {
CompilationError::ParserError(e) if e.is_unexpected_eof() => {
@@ -881,13 +895,16 @@ impl MachineState {
}
);
let h = self.heap.len();
self.heap.push(term_to_be_printed);
let mut printer = HCPrinter::new(
&mut self.heap,
Arc::clone(&self.atom_tbl),
&mut self.stack,
op_dir,
PrinterOutputter::new(),
term_to_be_printed,
h,
);
printer.ignore_ops = ignore_ops;

View File

@@ -39,7 +39,7 @@ impl MockWAM {
&mut self,
input_stream: Stream,
) -> Result<TermWriteResult, CompilationError> {
self.machine_st.read(input_stream, &self.op_dir)
self.machine_st.read_to_heap(input_stream, &self.op_dir)
}
pub fn parse_and_write_parsed_term_to_heap(
@@ -58,23 +58,24 @@ impl MockWAM {
print_heap_terms(self.machine_st.heap.iter(), term_write_result.heap_loc);
let var_names = term_write_result
.var_locs
.iter()
.map(|(var_loc, var_ptrs)| {
(self.machine_st.heap[var_loc], var_ptrs.front().unwrap().clone())
})
.collect();
let mut printer = HCPrinter::new(
&mut self.machine_st.heap,
Arc::clone(&self.machine_st.atom_tbl),
&mut self.machine_st.stack,
&self.op_dir,
PrinterOutputter::new(),
heap_loc_as_cell!(term_write_result.heap_loc),
term_write_result.heap_loc,
);
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();
printer.var_names = var_names;
Ok(printer.print().result())
}
@@ -217,7 +218,7 @@ pub(crate) fn write_parsed_term_to_heap(
input_stream: Stream,
op_dir: &OpDir,
) -> Result<TermWriteResult, CompilationError> {
machine_st.read(input_stream, op_dir)
machine_st.read_to_heap(input_stream, op_dir)
}
#[cfg(test)]
@@ -287,14 +288,15 @@ mod tests {
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(b,b).", &op_dir).unwrap();
unify!(
wam,
str_loc_as_cell!(1),
heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
@@ -307,14 +309,15 @@ mod tests {
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
@@ -327,14 +330,15 @@ mod tests {
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),Y).", &op_dir).unwrap();
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
@@ -347,14 +351,15 @@ mod tests {
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(f(A),A).", &op_dir).unwrap();
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
@@ -367,7 +372,8 @@ mod tests {
wam.heap.clear();
{
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(X,X).", &op_dir).unwrap();
let term_write_result_2 =
parse_and_write_parsed_term_to_heap(&mut wam, "f(A,f(A)).", &op_dir).unwrap();
@@ -376,7 +382,7 @@ mod tests {
unify!(
wam,
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_1.heap_loc),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
@@ -459,21 +465,8 @@ mod tests {
wam.heap.push(heap_loc_as_cell!(0));
unify!(wam, heap_loc_as_cell!(0), heap_loc_as_cell!(5));
assert!(!wam.fail);
all_cells_unmarked(&wam.heap);
wam.heap.clear();
{
let term_write_result_1 =
parse_and_write_parsed_term_to_heap(&mut wam, "X = g(X,y).", &op_dir).unwrap();
print_heap_terms(wam.heap.iter(), 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]
@@ -496,8 +489,8 @@ mod tests {
unify_with_occurs_check!(
wam,
str_loc_as_cell!(0),
str_loc_as_cell!(term_write_result_2.heap_loc)
heap_loc_as_cell!(0),
heap_loc_as_cell!(term_write_result_2.heap_loc)
);
assert!(wam.fail);

View File

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

View File

@@ -24,12 +24,7 @@ pub(crate) struct RawBlock<T: RawBlockTraits> {
impl<T: RawBlockTraits> RawBlock<T> {
pub(crate) fn new() -> Self {
let mut block = RawBlock {
size: 0,
base: ptr::null(),
top: ptr::null(),
_marker: PhantomData,
};
let mut block = Self::uninitialized();
unsafe {
block.grow();
@@ -38,6 +33,15 @@ impl<T: RawBlockTraits> RawBlock<T> {
block
}
pub(crate) fn uninitialized() -> Self {
Self {
size: 0,
base: ptr::null(),
top: ptr::null(),
_marker: PhantomData,
}
}
unsafe fn init_at_size(&mut self, cap: usize) {
let layout = alloc::Layout::from_size_align_unchecked(cap, T::align());

View File

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

View File

@@ -1880,7 +1880,7 @@ impl MachineState {
) -> Result<Stream, ParserError> {
match stream.peek_char() {
None => Ok(stream), // empty stream is handled gracefully by Lexer::eof
Some(Err(e)) => Err(ParserError::IO(e)),
Some(Err(e)) => Err(ParserError::IO(e, ParserErrorSrc::default())),
Some(Ok(c)) => {
if c == '\u{feff}' {
// skip UTF-8 BOM

View File

@@ -28,7 +28,7 @@ use crate::machine::stack::*;
use crate::machine::streams::*;
use crate::machine::{get_structure_index, Machine, VERIFY_ATTR_INTERRUPT_LOC};
use crate::parser::char_reader::*;
use crate::parser::dashu::Integer;
use crate::parser::dashu::{Integer, Rational};
use crate::read::*;
use crate::types::*;
use rand::rngs::StdRng;
@@ -824,25 +824,30 @@ impl MachineState {
) {
let mut seen_set = IndexSet::new();
{
let mut iter =
stackful_post_order_iter::<NonListElider>(&mut self.heap, &mut self.stack, term);
let outcome = if term.is_ref() {
{
let mut iter = stackful_post_order_iter::<NonListElider>(
&mut self.heap, &mut self.stack, term.get_value() as usize,
);
while let Some(value) = iter.next() {
if iter.parent_stack_len() >= max_depth {
iter.pop_stack();
continue;
}
while let Some(value) = iter.next() {
if iter.parent_stack_len() >= max_depth {
iter.pop_stack();
continue;
}
let value = unmark_cell_bits!(value);
let value = unmark_cell_bits!(value);
if value.is_var() {
seen_set.insert(value);
if value.is_var() {
seen_set.insert(value);
}
}
}
}
let outcome = heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter(),));
heap_loc_as_cell!(iter_to_heap_list(&mut self.heap, seen_set.into_iter()))
} else {
empty_list_as_cell!()
};
unify_fn!(*self, list_of_vars, outcome);
}
@@ -942,36 +947,51 @@ impl MachineState {
tokens.reverse();
match parser.read_term(&op_dir, Tokens::Provided(tokens)) {
Err(err) => {
let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen()));
}
Ok(Term::Literal(_, Literal::Rational(n))) => {
self.unify_rational(n, nx);
}
Ok(Term::Literal(_, Literal::Float(n))) => {
self.unify_f64(n.as_ptr(), nx);
}
Ok(Term::Literal(_, Literal::Integer(n))) => {
self.unify_big_int(n, nx);
}
Ok(Term::Literal(_, Literal::Fixnum(n))) => {
self.unify_fixnum(n, nx);
}
_ => {
let err = ParserError::ParseBigInt(0, 0);
let err = self.syntax_error(err);
Ok(term) => {
let mut error_gen = || {
let e = ParserError::ParseBigInt(ParserErrorSrc::default());
let e = self.syntax_error(e);
return Err(self.error_form(err, stub_gen()));
return Err(self.error_form(e, stub_gen()));
};
read_heap_cell!(term.heap[term.focus],
(HeapCellValueTag::Cons, c) => {
match_untyped_arena_ptr!(c,
(ArenaHeaderTag::Rational, n) => {
self.unify_rational(n, nx);
}
(ArenaHeaderTag::Integer, n) => {
self.unify_big_int(n, nx);
}
_ => {
return error_gen();
}
)
}
(HeapCellValueTag::F64, n) => {
self.unify_f64(n, nx);
}
(HeapCellValueTag::Fixnum, n) => {
self.unify_fixnum(n, nx);
}
_ => {
return error_gen();
}
);
}
Err(e) => {
let e = self.syntax_error(e);
return Err(self.error_form(e, stub_gen()));
}
}
break;
}
Ok(c) => {
let (line_num, col_num) = (lexer.line_num, lexer.col_num);
let err_src = lexer.loc_to_err_src();
let err = ParserError::UnexpectedChar(c, line_num, col_num);
let err = ParserError::UnexpectedChar(c, err_src);
let err = self.syntax_error(err);
return Err(self.error_form(err, stub_gen()));
@@ -1440,6 +1460,8 @@ impl Machine {
}
};
// println!("(fast) calling {}/{}", name.as_str(), arity);
if let Some(code_index) = index_cell {
if !code_index.is_undefined() {
load_registers(&mut self.machine_st, goal, goal_arity);
@@ -1599,12 +1621,12 @@ impl Machine {
let vars: Vec<_> = vars
.union(&result.supp_vars) // difference + union does not cancel.
.map(|v| Term::Var(Cell::default(), VarPtr::from(format!("_{}", v.get_value()))))
.cloned()
.collect();
let helper_clause_loc = self.code.len();
match self.compile_standalone_clause(temp_v!(1), &vars) {
match self.compile_standalone_clause(temp_v!(1), vars) {
Err(e) => {
let err = self.machine_st.session_error(e);
let stub = functor_stub(atom!("call"), result.key.1);
@@ -3572,7 +3594,9 @@ impl Machine {
}
Some(Err(e)) => {
let stub = functor_stub(atom!("$get_n_chars"), 3);
let err = self.machine_st.session_error(SessionError::from(e));
let err = self.machine_st.session_error(SessionError::from(
ParserError::IO(e, ParserErrorSrc::default()),
));
return Err(self.machine_st.error_form(err, stub));
}
@@ -6266,10 +6290,10 @@ impl Machine {
}
#[inline(always)]
fn read_term_and_write_to_heap(
fn read_term_from_atom(
&mut self,
atom_or_string: AtomOrString,
) -> Result<Option<TermWriteResult>, MachineStub> {
) -> Result<Option<FocusedHeap>, MachineStub> {
let string = match atom_or_string {
AtomOrString::Atom(atom!("[]")) => "".to_owned(),
_ => atom_or_string.into(),
@@ -6279,15 +6303,12 @@ impl Machine {
let mut parser = Parser::new(chars, &mut self.machine_st);
let op_dir = CompositeOpDir::new(&self.indices.op_dir, None);
let term_write_result = parser
let term = parser
.read_term(&op_dir, Tokens::Default)
.map_err(|err| error_after_read_term(err, 0, &parser))
.and_then(|term| {
write_term_to_heap(&term, &mut self.machine_st.heap, &self.machine_st.atom_tbl)
});
.map_err(|e| error_after_read_term(e, 0));
match term_write_result {
Ok(term_write_result) => Ok(Some(term_write_result)),
match term {
Ok(term) => Ok(Some(term)),
Err(CompilationError::ParserError(e)) if e.is_unexpected_eof() => {
let value = self.machine_st.registers[2];
self.machine_st.unify_atom(atom!("end_of_file"), value);
@@ -6305,42 +6326,50 @@ impl Machine {
#[inline(always)]
pub(crate) fn read_from_chars(&mut self) -> CallResult {
if let Some(atom_or_string) = self
let atom_or_string = self
.machine_st
.value_to_str_like(self.machine_st.registers[1])
{
if let Some(term_write_result) = self.read_term_and_write_to_heap(atom_or_string)? {
let result = heap_loc_as_cell!(term_write_result.heap_loc);
let var = self.deref_register(2).as_var().unwrap();
.unwrap();
self.machine_st.bind(var, result);
}
if let Some(mut term) = self.read_term_from_atom(atom_or_string)? {
let heap_len = self.machine_st.heap.len();
Ok(())
} else {
unreachable!()
self.machine_st.heap.extend(
copy_and_align_iter(term.heap.drain(..), 0, heap_len as i64),
);
let result = heap_loc_as_cell!(heap_len + term.focus);
let var = self.deref_register(2).as_var().unwrap();
self.machine_st.bind(var, result);
}
Ok(())
}
#[inline(always)]
pub(crate) fn read_term_from_chars(&mut self) -> CallResult {
if let Some(atom_or_string) = self
let atom_or_string = self
.machine_st
.value_to_str_like(self.machine_st.registers[1])
{
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![], vec![])?;
}
.unwrap();
Ok(())
}
} else {
unreachable!()
}
let string = match atom_or_string {
AtomOrString::Atom(atom!("[]")) => "".to_owned(),
_ => atom_or_string.into(),
};
let chars = CharReader::new(ByteStream::from_string(string));
let term_write_result = self.machine_st.read(chars, &self.indices.op_dir)
.map(|(term, _)| term.to_machine_heap(&mut self.machine_st))
.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_write_result)
}
#[inline(always)]
@@ -8095,8 +8124,13 @@ impl Machine {
match devour_whitespace(&mut parser) {
Ok(false) => {
// not at EOF.
// not at EOF ...
stream.add_lines_read(parser.lines_read());
// ... unless we are.
if stream.at_end_of_stream() {
self.machine_st.fail = true;
}
}
Ok(true) => {
stream.add_lines_read(parser.lines_read());

View File

@@ -20,11 +20,11 @@ pub struct LoadStatePayload<TS> {
pub(super) module_op_exports: ModuleOpExports,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey, FxBuildHasher>,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
pub(super) clause_clauses: Vec<FocusedHeap>,
}
pub trait TermStream: Sized {
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
}
@@ -52,7 +52,7 @@ impl<'a> BootstrappingTermStream<'a> {
impl<'a> TermStream for BootstrappingTermStream<'a> {
#[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
self.parser.reset();
self.parser
.read_term(op_dir, Tokens::Default)
@@ -72,7 +72,7 @@ impl<'a> TermStream for BootstrappingTermStream<'a> {
}
pub struct LiveTermStream {
pub(super) term_queue: VecDeque<Term>,
pub(super) term_queue: VecDeque<FocusedHeap>,
pub(super) listing_src: ListingSource,
}
@@ -108,7 +108,7 @@ impl<TS> LoadStatePayload<TS> {
impl TermStream for LiveTermStream {
#[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
}
@@ -126,8 +126,8 @@ impl TermStream for LiveTermStream {
pub struct InlineTermStream {}
impl TermStream for InlineTermStream {
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Err(CompilationError::from(ParserError::unexpected_eof()))
fn next(&mut self, _: &CompositeOpDir) -> Result<FocusedHeap, CompilationError> {
Err(CompilationError::from(ParserError::unexpected_eof(ParserErrorSrc::default())))
}
fn eof(&mut self) -> Result<bool, CompilationError> {

View File

@@ -705,13 +705,16 @@ fn bind_with_occurs_check<U: Unifier>(unifier: &mut U, r: Ref, value: HeapCellVa
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() {
let root_loc = value.get_value() as usize;
for cell in stackful_preorder_iter::<NonListElider>(
&mut machine_st.heap,
&mut machine_st.stack,
value,
root_loc, // value,
) {
let cell = unmark_cell_bits!(cell);