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(())
}
}

View File

@@ -1,11 +1,13 @@
use crate::machine::machine_indices::*;
use crate::machine::preprocessor::*;
use crate::machine::*;
use crate::machine::term_stream::*;
use prolog_parser::clause_name;
use crate::machine::term_stream::*;
use indexmap::IndexSet;
use ref_thread_local::RefThreadLocal;
use slice_deque::{sdeq, SliceDeque};
type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>;
@@ -328,28 +330,120 @@ fn import_qualified_module_exports_into_module(
}
impl<'a> LoadState<'a> {
#[inline]
pub(super) fn increment_clause_assert_margin(
pub(super) fn retract_local_clauses(
&mut self,
compilation_target: CompilationTarget,
incr: usize,
key: PredicateKey,
clause_locs: &SliceDeque<usize>,
) {
match compilation_target {
CompilationTarget::User => {}
CompilationTarget::Module(module_name) => {
self.wam
.indices
.modules
.get_mut(&module_name)
.map(|module| module.clause_assert_margin += incr);
let clause_target_poses: Vec<_> = self
.wam
.indices
.get_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| {
clause_locs
.iter()
.map(|clause_clause_loc| {
skeleton.target_pos_of_clause_clause_loc(
*clause_clause_loc,
)
})
.collect()
}).unwrap();
self.retraction_info
.push_record(RetractionRecord::IncreasedClauseAssertMargin(
module_name,
incr,
));
self.retract_local_clauses_by_locs(
compilation_target,
key,
clause_target_poses,
);
}
pub(super) fn retract_local_clauses_by_locs(
&mut self,
compilation_target: CompilationTarget,
key: PredicateKey,
mut clause_target_poses: Vec<Option<usize>>,
) {
let old_compilation_target = mem::replace(
&mut self.compilation_target,
compilation_target,
);
while let Some(target_pos_opt) = clause_target_poses.pop() {
match target_pos_opt {
Some(target_pos) => {
self.retract_clause(key.clone(), target_pos);
}
None => {
// Here because the clause was been removed
// earlier, e.g., by retract, without updating the
// local skeleton. In this case, do nothing.
}
}
}
self.compilation_target = old_compilation_target;
}
pub(super) fn retract_local_clause_clauses(
&mut self,
clause_clause_compilation_target: CompilationTarget,
clause_locs: &SliceDeque<usize>,
) {
let key = (clause_name!("$clause"), 2);
match self
.wam
.indices
.get_local_predicate_skeleton_mut(
&self.compilation_target,
clause_clause_compilation_target.clone(),
key.clone(),
)
{
Some(skeleton) => {
self.retraction_info.push_record(
RetractionRecord::RemovedLocalSkeletonClauseLocations(
self.compilation_target.clone(),
clause_clause_compilation_target.clone(),
key.clone(),
mem::replace(&mut skeleton.clause_clause_locs, sdeq![]),
),
);
skeleton.reset();
}
None => {
// The local skeleton might be removed when reloading
// or redefining a module, in which case no retraction
// record is necessary.
}
};
self.retract_local_clauses(
clause_clause_compilation_target,
key,
&clause_locs,
);
}
pub(super) fn try_term_to_tl(
&mut self,
term: Term,
preprocessor: &mut Preprocessor,
) -> Result<PredicateClause, SessionError> {
let tl = preprocessor.try_term_to_tl(
self,
term,
CutContext::BlocksCuts,
)?;
Ok(match tl {
TopLevel::Fact(fact) => PredicateClause::Fact(fact),
TopLevel::Rule(rule) => PredicateClause::Rule(rule),
TopLevel::Query(_) => return Err(SessionError::QueryCannotBeDefinedAsFact),
_ => unreachable!(),
})
}
#[inline]
@@ -451,16 +545,51 @@ impl<'a> LoadState<'a> {
.extensible_predicates
.insert(key.clone(), skeleton);
self.retraction_info
.push_record(RetractionRecord::AddedUserExtensiblePredicate(key));
let record = RetractionRecord::AddedExtensiblePredicate(
CompilationTarget::User,
key,
);
self.retraction_info.push_record(record);
}
CompilationTarget::Module(module_name) => {
if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
module.extensible_predicates.insert(key.clone(), skeleton);
module
.extensible_predicates
.insert(key.clone(), skeleton);
self.retraction_info.push_record(
RetractionRecord::AddedModuleExtensiblePredicate(module_name, key),
let record = RetractionRecord::AddedExtensiblePredicate(
CompilationTarget::Module(module_name),
key,
);
self.retraction_info.push_record(record);
} else {
unreachable!()
}
}
}
}
#[inline]
pub(super) fn add_local_extensible_predicate(
&mut self,
local_compilation_target: CompilationTarget,
key: PredicateKey,
skeleton: PredicateSkeleton,
) {
match self.compilation_target.clone() {
CompilationTarget::User => {
self.wam
.indices
.local_extensible_predicates
.insert((local_compilation_target.clone(), key.clone()), skeleton);
}
CompilationTarget::Module(module_name) => {
if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
module
.local_extensible_predicates
.insert((local_compilation_target.clone(), key.clone()), skeleton);
} else {
unreachable!()
}
@@ -604,32 +733,40 @@ impl<'a> LoadState<'a> {
}
}
None => {
let module_decl = ModuleDecl {
name: module_name.clone(),
exports: vec![],
};
self.add_dynamically_generated_module(&module_name);
let listing_src = ListingSource::DynamicallyGenerated;
let mut module = Module::new(module_decl, listing_src);
module.meta_predicates.insert(key.clone(), meta_specs);
if let Some(module) = self.wam.indices.modules.get_mut(&module_name) {
module.meta_predicates.insert(key.clone(), meta_specs);
} else {
unreachable!()
}
self.retraction_info
.push_record(RetractionRecord::AddedMetaPredicate(
module_name.clone(),
key,
));
self.retraction_info
.push_record(RetractionRecord::AddedModule(module_name.clone()));
self.wam.indices.modules.insert(module_name, module);
}
}
}
}
}
pub(super) fn add_dynamically_generated_module(&mut self, module_name: &ClauseName) {
let module_decl = ModuleDecl {
name: module_name.clone(),
exports: vec![],
};
let listing_src = ListingSource::DynamicallyGenerated;
let module = Module::new(module_decl, listing_src);
self.retraction_info
.push_record(RetractionRecord::AddedModule(module_name.clone()));
self.wam.indices.modules.insert(module_name.clone(), module);
}
fn import_builtins_in_module(
&mut self,
code_dir: &mut CodeDir,
@@ -651,16 +788,57 @@ impl<'a> LoadState<'a> {
pub(crate) fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) {
let module_name = module_decl.name.clone();
match self.wam.indices.modules.get_mut(&module_name) {
Some(module) => {
let old_module_decl = mem::replace(&mut module.module_decl, module_decl.clone());
let local_extensible_predicates = mem::replace(
&mut module.local_extensible_predicates,
LocalExtensiblePredicates::new(),
);
for ((compilation_target, key), skeleton) in local_extensible_predicates.iter() {
self.retract_local_clauses(
compilation_target.clone(),
key.clone(),
&skeleton.clause_clause_locs,
);
let is_dynamic = self
.wam
.indices
.get_predicate_skeleton(&compilation_target, &key)
.map(|skeleton| skeleton.is_dynamic)
.unwrap_or(false);
if is_dynamic {
let clause_clause_compilation_target = match compilation_target {
CompilationTarget::User => {
CompilationTarget::Module(clause_name!("builtins"))
}
module => {
module.clone()
}
};
self.retract_local_clause_clauses(
clause_clause_compilation_target,
&skeleton.clause_clause_locs,
);
}
}
self.retraction_info.push_record(RetractionRecord::ReplacedModule(
old_module_decl,
listing_src.clone(),
local_extensible_predicates,
));
}
None => {}
}
let mut module = match self.wam.indices.modules.remove(&module_name) {
Some(mut module) => {
let old_module_decl = mem::replace(&mut module.module_decl, module_decl);
self.retraction_info
.push_record(RetractionRecord::ReplacedModule(
old_module_decl,
listing_src.clone(),
));
module.listing_src = listing_src;
module
}

File diff suppressed because it is too large Load Diff

View File

@@ -4,6 +4,7 @@ use prolog_parser::{clause_name, temp_v};
use crate::forms::{ModuleSource, Number}; //, PredicateKey};
use crate::machine::PredicateKey;
use crate::machine::heap::*;
use crate::machine::loader::CompilationTarget;
use crate::machine::machine_indices::*;
use crate::machine::machine_state::*;
use crate::rug::Integer;
@@ -344,6 +345,22 @@ impl MachineError {
Self::permission_error(h, Permission::Create, "operator", functor!(clause_name(op)))
}
SessionError::CompilationError(err) => Self::syntax_error(h, err),
SessionError::PredicateNotMultifileOrDiscontiguous(compilation_target, key) => {
let functor_stub = Self::functor_stub(key.0, key.1);
let stub = functor!(
":",
SharedOpDesc::new(600, XFY),
[clause_name(compilation_target.module_name()), aux(h + 4, 0)],
[functor_stub]
);
Self::permission_error(
h,
Permission::Modify,
"not_declared_multifile_or_discontiguous",
stub,
)
}
SessionError::QueryCannotBeDefinedAsFact => Self::permission_error(
h,
Permission::Create,
@@ -808,6 +825,7 @@ pub enum SessionError {
ModuleCannotImportSelf(ClauseName),
NamelessEntry,
OpIsInfixAndPostFix(ClauseName),
PredicateNotMultifileOrDiscontiguous(CompilationTarget, PredicateKey),
QueryCannotBeDefinedAsFact,
}

View File

@@ -417,7 +417,9 @@ impl Default for CodeIndex {
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum REPLCodePtr {
AddDiscontiguousPredicate,
AddDynamicPredicate,
AddMultifilePredicate,
AddGoalExpansionClause,
AddTermExpansionClause,
ClauseToEvacuable,
@@ -743,6 +745,68 @@ impl IndexStore {
}
}
pub fn get_local_predicate_skeleton_mut(
&mut self,
src_compilation_target: &CompilationTarget,
local_compilation_target: CompilationTarget,
key: PredicateKey,
) -> Option<&mut PredicateSkeleton> {
match (key.0.as_str(), key.1) {
("term_expansion", 2) => {
self.local_extensible_predicates.get_mut(
&(local_compilation_target, key),
)
}
_ => match src_compilation_target {
CompilationTarget::User => {
self.local_extensible_predicates.get_mut(
&(local_compilation_target, key),
)
}
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.local_extensible_predicates.get_mut(
&(local_compilation_target, key),
)
} else {
None
}
}
},
}
}
pub fn get_local_predicate_skeleton(
&self,
src_compilation_target: &CompilationTarget,
local_compilation_target: CompilationTarget,
key: PredicateKey,
) -> Option<&PredicateSkeleton> {
match (key.0.as_str(), key.1) {
("term_expansion", 2) => {
self.local_extensible_predicates.get(
&(local_compilation_target, key),
)
}
_ => match src_compilation_target {
CompilationTarget::User => {
self.local_extensible_predicates.get(
&(local_compilation_target, key),
)
}
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get(module_name) {
module.local_extensible_predicates.get(
&(local_compilation_target, key),
)
} else {
None
}
}
},
}
}
pub fn get_predicate_skeleton(
&self,
compilation_target: &CompilationTarget,
@@ -767,18 +831,20 @@ impl IndexStore {
&mut self,
compilation_target: &CompilationTarget,
key: &PredicateKey,
) {
) -> Option<PredicateSkeleton> {
match (key.0.as_str(), key.1) {
("term_expansion", 2) => {
self.extensible_predicates.remove(key);
self.extensible_predicates.remove(key)
}
_ => match compilation_target {
CompilationTarget::User => {
self.extensible_predicates.remove(key);
self.extensible_predicates.remove(key)
}
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.extensible_predicates.remove(key);
module.extensible_predicates.remove(key)
} else {
None
}
}
},

View File

@@ -412,9 +412,15 @@ impl Machine {
fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) {
match code_ptr {
REPLCodePtr::AddDiscontiguousPredicate => {
self.add_discontiguous_predicate();
}
REPLCodePtr::AddDynamicPredicate => {
self.add_dynamic_predicate();
}
REPLCodePtr::AddMultifilePredicate => {
self.add_multifile_predicate();
}
REPLCodePtr::AddGoalExpansionClause => {
self.add_goal_expansion_clause();
}

View File

@@ -394,9 +394,6 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
return Ok(tl);
}
TopLevel::Declaration(_) if clauses.is_empty() => {
return Ok(tl);
}
TopLevel::Query(_) => {
return Err(CompilationError::InconsistentEntry);
}
@@ -409,10 +406,6 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationEr
clauses.push(clause);
}
TopLevel::Predicate(predicate) => clauses.extend(predicate.into_iter()),
_ => {
tls.push_front(tl);
break;
}
}
}
@@ -497,7 +490,7 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
}
}
fn setup_declaration<'a>(
pub(super) fn setup_declaration<'a>(
load_state: &LoadState<'a>,
mut terms: Vec<Box<Term>>,
) -> Result<Declaration, CompilationError> {
@@ -883,8 +876,6 @@ impl Preprocessor {
terms,
cut_context,
)?))
} else if name.as_str() == ":-" && terms.len() == 1 {
Ok(TopLevel::Declaration(setup_declaration(load_state, terms)?))
} else {
let term = Term::Clause(r, name, terms, fixity);
Ok(TopLevel::Fact(self.setup_fact(term)?))

View File

@@ -2,7 +2,6 @@ use prolog_parser::ast::*;
use prolog_parser::parser::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use crate::machine::*;
use indexmap::IndexSet;
@@ -100,7 +99,6 @@ pub struct LoadStatePayload {
pub(super) retraction_info: RetractionInfo,
pub(super) module_op_exports: Vec<(OpDecl, Option<(usize, Specifier)>)>,
pub(super) non_counted_bt_preds: IndexSet<PredicateKey>,
pub(super) preprocessor: Preprocessor,
pub(super) predicates: PredicateQueue,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
@@ -119,7 +117,6 @@ impl LoadStatePayload {
retraction_info: RetractionInfo::new(wam.code_repo.code.len()),
module_op_exports: vec![],
non_counted_bt_preds: IndexSet::new(),
preprocessor: Preprocessor::new(wam.machine_st.flags),
predicates: predicate_queue![],
clause_clauses: vec![],
}