support discontiguous and multifile declarations

This commit is contained in:
Mark Thom
2021-02-16 20:54:51 -07:00
parent e2a413df78
commit 6b6666be47
12 changed files with 1209 additions and 551 deletions

View File

@@ -3,9 +3,9 @@ use prolog_parser::clause_name;
use crate::codegen::*;
use crate::debray_allocator::*;
use crate::indexing::{merge_clause_index, remove_index};
use crate::machine::load_state::set_code_index;
use crate::machine::load_state::LoadState;
use crate::machine::load_state::*;
use crate::machine::loader::*;
use crate::machine::preprocessor::*;
use crate::machine::term_stream::*;
use crate::machine::*;
@@ -45,7 +45,7 @@ pub(super) fn compile_relation(
tl: &TopLevel,
) -> Result<Code, CompilationError> {
match tl {
&TopLevel::Declaration(_) | &TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
&TopLevel::Query(_) => Err(CompilationError::ExpectedRel),
&TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses),
&TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)),
&TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule),
@@ -54,16 +54,15 @@ pub(super) fn compile_relation(
pub(super) fn compile_appendix(
code: &mut Code,
queue: &VecDeque<TopLevel>,
mut queue: VecDeque<TopLevel>,
jmp_by_locs: Vec<usize>,
non_counted_bt: bool,
atom_tbl: TabledData<Atom>,
) -> Result<(), CompilationError> {
let mut jmp_by_locs = VecDeque::from(jmp_by_locs);
for tl in queue.iter() {
while let Some(jmp_by_offset) = jmp_by_locs.pop_front() {
let code_len = code.len();
let jmp_by_offset = jmp_by_locs.pop_front().unwrap();
match &mut code[jmp_by_offset] {
&mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => {
@@ -76,9 +75,10 @@ pub(super) fn compile_appendix(
// false because the inner predicate is a one-off, hence not extensible.
let settings = CodeGenSettings::new(false, non_counted_bt);
let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
let decl_code = compile_relation(&mut cg, tl)?;
let tl = queue.pop_front().unwrap();
let decl_code = compile_relation(&mut cg, &tl)?;
jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len()));
code.extend(decl_code.into_iter());
@@ -109,29 +109,6 @@ fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize)
0
}
fn compile_standalone_clause(
clause: PredicateClause,
queue: VecDeque<TopLevel>,
settings: CodeGenSettings,
atom_tbl: TabledData<Atom>,
) -> Result<StandaloneCompileResult, SessionError> {
let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
let mut clause_code = cg.compile_predicate(&vec![clause])?;
compile_appendix(
&mut clause_code,
&queue,
cg.jmp_by_locs,
settings.non_counted_bt,
atom_tbl,
)?;
Ok(StandaloneCompileResult {
clause_code,
standalone_skeleton: cg.skeleton,
})
}
fn derelictize_try_me_else(
code: &mut Code,
index: usize,
@@ -341,17 +318,21 @@ fn merge_indexed_subsequences(
None
}
fn delete_from_dynamic_skeleton(
fn delete_from_skeleton(
compilation_target: CompilationTarget,
key: PredicateKey,
skeleton: &mut PredicateSkeleton,
target_pos: usize,
retraction_info: &mut RetractionInfo,
) -> usize {
let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos);
let clause_index_info = skeleton.clauses.remove(target_pos);
let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos);
retraction_info.push_record(RetractionRecord::RemovedDynamicSkeletonClause(
if target_pos < skeleton.clause_assert_margin {
skeleton.clause_assert_margin -= 1;
}
retraction_info.push_record(RetractionRecord::RemovedSkeletonClause(
compilation_target,
key,
target_pos,
@@ -585,7 +566,7 @@ fn finalize_retract(
index_ptr_opt: Option<IndexPtr>,
retraction_info: &mut RetractionInfo,
) -> usize {
let clause_clause_loc = delete_from_dynamic_skeleton(
let clause_clause_loc = delete_from_skeleton(
compilation_target.clone(),
key.clone(),
skeleton,
@@ -1007,13 +988,40 @@ fn mergeable_indexed_subsequences(
}
impl<'a> LoadState<'a> {
fn compile_standalone_clause(
&mut self,
term: Term,
settings: CodeGenSettings,
atom_tbl: TabledData<Atom>,
) -> Result<StandaloneCompileResult, SessionError> {
let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags);
let mut cg = CodeGenerator::<DebrayAllocator>::new(atom_tbl.clone(), settings);
let clause = self.try_term_to_tl(term, &mut preprocessor)?;
let queue = preprocessor.parse_queue(self)?;
let mut clause_code = cg.compile_predicate(&vec![clause])?;
compile_appendix(
&mut clause_code,
queue,
cg.jmp_by_locs,
settings.non_counted_bt,
atom_tbl,
)?;
Ok(StandaloneCompileResult {
clause_code,
standalone_skeleton: cg.skeleton,
})
}
fn compile(
&mut self,
key: PredicateKey,
predicates: &PredicateQueue, // &Vec<PredicateClause>,
queue: &VecDeque<TopLevel>,
predicates: &mut PredicateQueue,
settings: CodeGenSettings,
) -> Result<IndexPtr, SessionError> {
) -> Result<(), SessionError> {
let code_index = self.get_or_insert_code_index(
key.clone(),
predicates.compilation_target.clone(),
@@ -1025,7 +1033,15 @@ impl<'a> LoadState<'a> {
let mut cg =
CodeGenerator::<DebrayAllocator>::new(self.wam.machine_st.atom_tbl.clone(), settings);
let mut code = cg.compile_predicate(&predicates.predicates)?;
let mut clauses = vec![];
let mut preprocessor = Preprocessor::new(self.wam.machine_st.flags);
for term in predicates.predicates.drain(0 ..) {
clauses.push(self.try_term_to_tl(term, &mut preprocessor)?);
}
let queue = preprocessor.parse_queue(self)?;
let mut code = cg.compile_predicate(&clauses)?;
compile_appendix(
&mut code,
@@ -1036,9 +1052,13 @@ impl<'a> LoadState<'a> {
)?;
if settings.is_extensible {
let mut clause_clause_locs = sdeq![];
for clause_index_info in cg.skeleton.clauses.iter_mut() {
clause_index_info.clause_start += code_len;
clause_index_info.opt_arg_index_key += code_len;
clause_clause_locs.push_back(clause_index_info.clause_start);
}
match &mut code[0] {
@@ -1062,8 +1082,15 @@ impl<'a> LoadState<'a> {
));
skeleton.clauses.extend(cg.skeleton.clauses.into_iter());
skeleton.clause_clause_locs.extend_from_slice(
&clause_clause_locs[0 ..]
);
}
None => {
cg.skeleton.clause_clause_locs.extend_from_slice(
&clause_clause_locs[0 ..]
);
self.add_extensible_predicate(
key.clone(),
cg.skeleton,
@@ -1071,6 +1098,15 @@ impl<'a> LoadState<'a> {
);
}
}
let mut skeleton = PredicateSkeleton::new();
skeleton.clause_clause_locs = clause_clause_locs;
self.add_local_extensible_predicate(
predicates.compilation_target.clone(),
key.clone(),
skeleton,
);
}
set_code_index(
@@ -1082,7 +1118,7 @@ impl<'a> LoadState<'a> {
);
self.wam.code_repo.code.extend(code.into_iter());
Ok(code_index.get())
Ok(())
}
fn record_incremental_compile(
@@ -1119,24 +1155,23 @@ impl<'a> LoadState<'a> {
pub(super) fn incremental_compile_clause(
&mut self,
key: PredicateKey,
clause: PredicateClause,
queue: VecDeque<TopLevel>,
clause: Term,
compilation_target: CompilationTarget,
non_counted_bt: bool,
append_or_prepend: AppendOrPrepend,
) -> Result<IndexPtr, SessionError> {
) -> Result<(), SessionError> {
self.record_incremental_compile(
key.clone(),
compilation_target.clone(),
append_or_prepend,
);
let skeleton = match self
match self
.wam
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
Some(skeleton) if !skeleton.clauses.is_empty() => skeleton,
Some(skeleton) if !skeleton.clauses.is_empty() => {},
_ => {
// true because this predicate is extensible.
let settings = CodeGenSettings::new(true, non_counted_bt);
@@ -1144,7 +1179,7 @@ impl<'a> LoadState<'a> {
let mut predicate_queue = predicate_queue![clause];
predicate_queue.compilation_target = compilation_target;
return self.compile(key, &predicate_queue, &queue, settings);
return self.compile(key, &mut predicate_queue, settings);
}
};
@@ -1154,13 +1189,25 @@ impl<'a> LoadState<'a> {
let StandaloneCompileResult {
clause_code,
mut standalone_skeleton,
} = compile_standalone_clause(clause, queue, settings, atom_tbl)?;
} = self.compile_standalone_clause(clause, settings, atom_tbl)?;
let code_len = self.wam.code_repo.code.len();
let skeleton = match self
.wam
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
Some(skeleton) if !skeleton.clauses.is_empty() => skeleton,
_ => unreachable!()
};
match append_or_prepend {
AppendOrPrepend::Append => {
skeleton
.clauses
.push_back(standalone_skeleton.clauses.pop_back().unwrap());
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
skeleton.clauses.push_back(clause_index_info);
skeleton.clause_clause_locs.push_back(code_len);
self.retraction_info
.push_record(RetractionRecord::SkeletonClausePopBack(
@@ -1175,6 +1222,38 @@ impl<'a> LoadState<'a> {
&mut self.retraction_info,
);
match self
.wam
.indices
.get_local_predicate_skeleton_mut(
&self.compilation_target,
compilation_target.clone(),
key.clone(),
)
{
Some(skeleton) => {
self.retraction_info.push_record(
RetractionRecord::SkeletonLocalClauseClausePopBack(
self.compilation_target.clone(),
compilation_target.clone(),
key.clone(),
),
);
skeleton.clause_clause_locs.push_back(code_len);
}
None => {
let mut skeleton = PredicateSkeleton::new();
skeleton.clause_clause_locs.push_back(code_len);
self.add_local_extensible_predicate(
compilation_target.clone(),
key.clone(),
skeleton,
);
}
}
let code_index = self.get_or_insert_code_index(
key.clone(),
compilation_target.clone(),
@@ -1190,12 +1269,14 @@ impl<'a> LoadState<'a> {
);
}
Ok(code_index.get())
Ok(())
}
AppendOrPrepend::Prepend => {
skeleton
.clauses
.push_front(standalone_skeleton.clauses.pop_back().unwrap());
let clause_index_info = standalone_skeleton.clauses.pop_back().unwrap();
skeleton.clauses.push_front(clause_index_info);
skeleton.clause_clause_locs.push_front(code_len);
skeleton.clause_assert_margin += 1;
self.retraction_info
.push_record(RetractionRecord::SkeletonClausePopFront(
@@ -1212,6 +1293,38 @@ impl<'a> LoadState<'a> {
&mut self.retraction_info,
);
match self
.wam
.indices
.get_local_predicate_skeleton_mut(
&self.compilation_target,
compilation_target.clone(),
key.clone(),
)
{
Some(skeleton) => {
self.retraction_info.push_record(
RetractionRecord::SkeletonLocalClauseClausePopFront(
self.compilation_target.clone(),
compilation_target.clone(),
key.clone(),
),
);
skeleton.clause_clause_locs.push_front(code_len);
}
None => {
let mut skeleton = PredicateSkeleton::new();
skeleton.clause_clause_locs.push_front(code_len);
self.add_local_extensible_predicate(
compilation_target.clone(),
key.clone(),
skeleton,
);
}
}
let code_index = self.get_or_insert_code_index(
key.clone(),
compilation_target.clone(),
@@ -1225,7 +1338,7 @@ impl<'a> LoadState<'a> {
IndexPtr::Index(threaded_choice_instr_loc),
);
Ok(IndexPtr::Index(threaded_choice_instr_loc))
Ok(())
}
}
}
@@ -1309,7 +1422,7 @@ impl<'a> LoadState<'a> {
skeleton.clauses[target_pos + 1].clause_start =
skeleton.clauses[target_pos].clause_start;
return delete_from_dynamic_skeleton(
return delete_from_skeleton(
self.compilation_target.clone(),
key,
skeleton,
@@ -1530,12 +1643,12 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
append_or_prepend: AppendOrPrepend,
) -> Result<(), SessionError> {
let clause_predicates = clause_clauses.map(|(head, body)| {
PredicateClause::Fact(Term::Clause(
Term::Clause(
Cell::default(),
clause_name!("$clause"),
vec![Box::new(head), Box::new(body)],
None,
))
)
});
let clause_clause_compilation_target = match compilation_target {
@@ -1543,49 +1656,64 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
_ => compilation_target.clone(),
};
let mut clause_clause_locs = sdeq![];
for clause_predicate in clause_predicates {
clause_clause_locs.push_back(self.load_state.wam.code_repo.code.len());
let mut num_clause_predicates = 0;
for clause_term in clause_predicates {
self.load_state.incremental_compile_clause(
(clause_name!("$clause"), 2),
clause_predicate,
VecDeque::new(),
clause_term,
clause_clause_compilation_target.clone(),
false, // non_counted_bt is false.
append_or_prepend,
)?;
num_clause_predicates += 1;
}
let locs_vec: Vec<_> = match self
.load_state
.wam
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
Some(skeleton) if append_or_prepend.is_append() => {
let tail_num = skeleton.clause_clause_locs.len() - num_clause_predicates;
skeleton.clause_clause_locs[tail_num ..]
.iter()
.cloned()
.collect()
}
Some(skeleton) => {
skeleton.clause_clause_locs[0 .. num_clause_predicates]
.iter()
.cloned()
.collect()
}
None => {
unreachable!()
}
};
match self.load_state.wam.indices.get_predicate_skeleton_mut(
&clause_clause_compilation_target,
&(clause_name!("$clause"), 2),
) {
Some(skeleton) if append_or_prepend.is_append() => {
self.load_state.retraction_info.push_record(
RetractionRecord::SkeletonClauseClausesTruncateBack(
clause_clause_compilation_target.clone(),
(clause_name!("$clause"), 2),
skeleton.clause_clause_locs.len(),
),
);
for _ in 0 .. num_clause_predicates {
skeleton.clause_clause_locs.pop_back();
}
skeleton
.clause_clause_locs
.extend_from_slice(&clause_clause_locs[0..]);
for loc in locs_vec {
skeleton.clause_clause_locs.push_back(loc);
}
}
Some(skeleton) => {
self.load_state.retraction_info.push_record(
RetractionRecord::SkeletonClauseClausesTruncateFront(
clause_clause_compilation_target.clone(),
(clause_name!("$clause"), 2),
skeleton.clause_clause_locs.len(),
),
);
for _ in 0 .. num_clause_predicates {
skeleton.clause_clause_locs.pop_front();
}
for loc in clause_clause_locs.iter() {
skeleton.clause_clause_locs.push_front(*loc);
for loc in locs_vec.into_iter().rev() {
skeleton.clause_clause_locs.push_front(loc);
}
}
None => {
@@ -1593,82 +1721,128 @@ impl<'a, TS: TermStream> Loader<'a, TS> {
}
}
match self
.load_state
.wam
.indices
.get_predicate_skeleton_mut(&compilation_target, &key)
{
Some(skeleton) if append_or_prepend.is_append() => {
self.load_state.retraction_info.push_record(
RetractionRecord::SkeletonClauseClausesTruncateBack(
compilation_target.clone(),
key.clone(),
skeleton.clause_clause_locs.len(),
),
);
skeleton.clause_clause_locs.append(&mut clause_clause_locs);
}
Some(skeleton) => {
self.load_state.retraction_info.push_record(
RetractionRecord::SkeletonClauseClausesTruncateFront(
compilation_target.clone(),
key.clone(),
skeleton.clause_clause_locs.len(),
),
);
for loc in clause_clause_locs.iter() {
skeleton.clause_clause_locs.push_front(*loc);
}
self.load_state.increment_clause_assert_margin(
clause_clause_compilation_target,
clause_clause_locs.len(),
);
}
None => {
unreachable!()
}
}
Ok(())
}
pub(super) fn compile_and_submit(&mut self) -> Result<(), SessionError> {
let queue = self.preprocessor.parse_queue(&mut self.load_state)?;
let key = self
.predicates
.first()
.and_then(|cl| {
let arity = cl.arity();
cl.name().map(|name| (name, arity))
let arity = ClauseInfo::arity(cl);
ClauseInfo::name(cl).map(|name| (name, arity))
})
.ok_or(SessionError::NamelessEntry)?;
let (is_dynamic, is_extensible) = self
let mut predicate_info = self
.load_state
.wam
.indices
.get_predicate_skeleton(&self.predicates.compilation_target, &key)
.map(|skeleton| (skeleton.is_dynamic, true))
.unwrap_or((false, false));
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
let non_counted_bt = self.non_counted_bt_preds.contains(&key);
let settings = CodeGenSettings::new(is_extensible, non_counted_bt);
let local_predicate_info = self
.load_state
.wam
.indices
.get_local_predicate_skeleton(
&self.load_state.compilation_target,
self.predicates.compilation_target.clone(),
key.clone(),
)
.map(|skeleton| skeleton.predicate_info())
.unwrap_or_default();
self.load_state
.compile(key.clone(), &self.predicates, &queue, settings)?;
if is_dynamic {
let iter = mem::replace(&mut self.clause_clauses, vec![]).into_iter();
let compilation_target = self.predicates.compilation_target.clone();
self.compile_clause_clauses(key, compilation_target, iter, AppendOrPrepend::Append)?;
if predicate_info.must_retract_local_clauses() {
self.retract_local_clauses(&key, predicate_info.is_dynamic);
}
Ok(self.predicates.clear())
let do_incremental_compile =
if self.load_state.compilation_target == self.predicates.compilation_target {
predicate_info.compile_incrementally()
} else {
local_predicate_info.is_multifile && predicate_info.compile_incrementally()
};
let predicates_len = self.predicates.len();
let non_counted_bt = self.non_counted_bt_preds.contains(&key);
if do_incremental_compile {
for term in self.predicates.predicates.drain(0 ..) {
self.load_state.incremental_compile_clause(
key.clone(),
term,
self.predicates.compilation_target.clone(),
non_counted_bt,
AppendOrPrepend::Append,
)?;
}
} else {
if self.load_state.compilation_target != self.predicates.compilation_target {
if !local_predicate_info.is_extensible {
if predicate_info.is_multifile {
println!("Warning: overwriting multifile predicate {}:{}/{} because \
it was not locally declared multifile.",
self.predicates.compilation_target, key.0, key.1);
}
if let Some(skeleton) = self.load_state
.wam
.indices
.remove_predicate_skeleton(
&self.predicates.compilation_target,
&key,
)
{
if predicate_info.is_dynamic {
let clause_clause_compilation_target =
match &self.predicates.compilation_target {
CompilationTarget::User => {
CompilationTarget::Module(clause_name!("builtins"))
}
module => {
module.clone()
}
};
self.load_state.retract_local_clauses_by_locs(
clause_clause_compilation_target,
(clause_name!("$clause"), 2),
(0 .. skeleton.clauses.len()).map(Some).collect(),
);
predicate_info.is_dynamic = false;
}
self.load_state.retraction_info.push_record(
RetractionRecord::RemovedSkeleton(
self.predicates.compilation_target.clone(),
key.clone(),
skeleton,
),
);
}
}
}
let settings = CodeGenSettings::new(predicate_info.is_extensible, non_counted_bt);
self.load_state.compile(key.clone(), &mut self.predicates, settings)?;
}
if predicate_info.is_dynamic {
let clauses_vec: Vec<_> = self.clause_clauses
.drain(0 .. predicates_len)
.collect();
self.compile_clause_clauses(
key,
self.predicates.compilation_target.clone(),
clauses_vec.into_iter(),
AppendOrPrepend::Append,
)?;
}
Ok(())
}
}