move to a predicate-based module system, move to loader.[rs|pl]-based compilation, add support for incremental clause compilation

This commit is contained in:
Mark Thom
2021-01-30 14:32:47 -07:00
parent b33158b92e
commit a4d15bfb88
55 changed files with 10501 additions and 7601 deletions

551
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -32,7 +32,7 @@ libc = "0.2.62"
nix = "0.15.0" nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.4" } num-rug-adapter = { optional = true, version = "0.1.4" }
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = { version = "0.8.68", default-features = false } prolog_parser = { version = "0.8.63", path = "../prolog_parser", default-features = false }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"
rug = { version = "1.4.0", optional = true } rug = { version = "1.4.0", optional = true }
rustyline = "7.0.0" rustyline = "7.0.0"
@@ -48,3 +48,4 @@ select = "0.4.3"
roxmltree = "0.11.0" roxmltree = "0.11.0"
base64 = "0.12.3" base64 = "0.12.3"
sodiumoxide = "0.2.6" sodiumoxide = "0.2.6"
slice-deque = "0.3.0"

View File

@@ -11,6 +11,7 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
Ok(entries) => entries, Ok(entries) => entries,
Err(_) => return, Err(_) => return,
}; };
for entry in entries.filter_map(Result::ok).map(|e| e.path()) { for entry in entries.filter_map(Result::ok).map(|e| e.path()) {
if entry.is_dir() { if entry.is_dir() {
if let Some(file_name) = entry.file_name() { if let Some(file_name) = entry.file_name() {
@@ -24,6 +25,7 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) {
let contain = let contain =
String::from_utf8(fs::read(&entry).unwrap()).unwrap(); String::from_utf8(fs::read(&entry).unwrap()).unwrap();
let name = entry.file_stem().unwrap().to_str().unwrap(); let name = entry.file_stem().unwrap().to_str().unwrap();
let line = format!( let line = format!(
" m.insert(\"{}\",\n{:?});\n", " m.insert(\"{}\",\n{:?});\n",
prefix.to_owned() + name, prefix.to_owned() + name,

View File

@@ -150,11 +150,11 @@ impl InlinedClauseType {
#[derive(Debug, Copy, Clone, Eq, PartialEq)] #[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum SystemClauseType { pub enum SystemClauseType {
AbolishClause, // AbolishClause,
AbolishModuleClause, // AbolishModuleClause,
AssertDynamicPredicateToBack, // AssertDynamicPredicateToBack,
AssertDynamicPredicateToFront, // AssertDynamicPredicateToFront,
AtEndOfExpansion, // AtEndOfExpansion,
AtomChars, AtomChars,
AtomCodes, AtomCodes,
AtomLength, AtomLength,
@@ -189,8 +189,8 @@ pub enum SystemClauseType {
DynamicModuleResolution(usize), DynamicModuleResolution(usize),
EnqueueAttributeGoal, EnqueueAttributeGoal,
EnqueueAttributedVar, EnqueueAttributedVar,
ExpandGoal, // ExpandGoal,
ExpandTerm, // ExpandTerm,
FetchGlobalVar, FetchGlobalVar,
FetchGlobalVarWithOffset, FetchGlobalVarWithOffset,
FirstStream, FirstStream,
@@ -207,16 +207,16 @@ pub enum SystemClauseType {
GetAttrVarQueueDelimiter, GetAttrVarQueueDelimiter,
GetAttrVarQueueBeyond, GetAttrVarQueueBeyond,
GetBValue, GetBValue,
GetClause, // GetClause,
GetContinuationChunk, GetContinuationChunk,
GetModuleClause, // GetModuleClause,
GetNextDBRef, GetNextDBRef,
GetNextOpDBRef, GetNextOpDBRef,
IsPartialString, IsPartialString,
LookupDBRef, LookupDBRef,
LookupOpDBRef, LookupOpDBRef,
Halt, Halt,
ModuleHeadIsDynamic, // ModuleHeadIsDynamic,
GetLiftedHeapFromOffset, GetLiftedHeapFromOffset,
GetLiftedHeapFromOffsetDiff, GetLiftedHeapFromOffsetDiff,
GetSCCCleaner, GetSCCCleaner,
@@ -224,11 +224,11 @@ pub enum SystemClauseType {
InstallSCCCleaner, InstallSCCCleaner,
InstallInferenceCounter, InstallInferenceCounter,
LiftedHeapLength, LiftedHeapLength,
ModuleAssertDynamicPredicateToFront, LoadLibraryAsStream,
ModuleAssertDynamicPredicateToBack, // ModuleAssertDynamicPredicateToFront,
// ModuleAssertDynamicPredicateToBack,
ModuleExists, ModuleExists,
ModuleOf, // ModuleRetractClause,
ModuleRetractClause,
NextEP, NextEP,
NoSuchPredicate, NoSuchPredicate,
NumberToChars, NumberToChars,
@@ -254,7 +254,7 @@ pub enum SystemClauseType {
ResetContinuationMarker, ResetContinuationMarker,
ResetGlobalVarAtKey, ResetGlobalVarAtKey,
ResetGlobalVarAtOffset, ResetGlobalVarAtOffset,
RetractClause, // RetractClause,
RestoreCutPolicy, RestoreCutPolicy,
SetCutPoint(RegType), SetCutPoint(RegType),
SetInput, SetInput,
@@ -324,11 +324,11 @@ pub enum SystemClauseType {
impl SystemClauseType { impl SystemClauseType {
pub fn name(&self) -> ClauseName { pub fn name(&self) -> ClauseName {
match self { match self {
&SystemClauseType::AbolishClause => clause_name!("$abolish_clause"), // &SystemClauseType::AbolishClause => clause_name!("$abolish_clause"),
&SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"), // &SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"),
&SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"), // &SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"),
&SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"), // &SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"),
&SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"), // &SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"),
&SystemClauseType::AtomChars => clause_name!("$atom_chars"), &SystemClauseType::AtomChars => clause_name!("$atom_chars"),
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"), &SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
&SystemClauseType::AtomLength => clause_name!("$atom_length"), &SystemClauseType::AtomLength => clause_name!("$atom_length"),
@@ -356,17 +356,50 @@ impl SystemClauseType {
&SystemClauseType::WorkingDirectory => clause_name!("$working_directory"), &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"),
&SystemClauseType::PathCanonical => clause_name!("$path_canonical"), &SystemClauseType::PathCanonical => clause_name!("$path_canonical"),
&SystemClauseType::FileTime => clause_name!("$file_time"), &SystemClauseType::FileTime => clause_name!("$file_time"),
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) =>
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), clause_name!("$add_dynamic_predicate"),
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => { &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) =>
clause_name!("$use_qualified_module") clause_name!("$add_goal_expansion_clause"),
} &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) =>
&SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => { clause_name!("$add_term_expansion_clause"),
clause_name!("$use_module_from_file") &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) =>
} clause_name!("$clause_to_evacuable"),
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => { &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) =>
clause_name!("$use_qualified_module_from_file") clause_name!("$conclude_load"),
} &SystemClauseType::REPL(REPLCodePtr::DeclareModule) =>
clause_name!("$declare_module"),
&SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary) =>
clause_name!("$load_compiled_library"),
&SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload) =>
clause_name!("$push_load_state_payload"),
&SystemClauseType::REPL(REPLCodePtr::UserAsserta) =>
clause_name!("$asserta"),
&SystemClauseType::REPL(REPLCodePtr::UserAssertz) =>
clause_name!("$assertz"),
&SystemClauseType::REPL(REPLCodePtr::UserRetract) =>
clause_name!("$retract_clause"),
&SystemClauseType::REPL(REPLCodePtr::UseModule) =>
clause_name!("$use_module"),
&SystemClauseType::REPL(REPLCodePtr::PushLoadContext) =>
clause_name!("$push_load_context"),
&SystemClauseType::REPL(REPLCodePtr::PopLoadContext) =>
clause_name!("$pop_load_context"),
&SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload) =>
clause_name!("$pop_load_state_payload"),
&SystemClauseType::REPL(REPLCodePtr::LoadContextSource) =>
clause_name!("$prolog_lc_source"),
&SystemClauseType::REPL(REPLCodePtr::LoadContextFile) =>
clause_name!("$prolog_lc_file"),
&SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory) =>
clause_name!("$prolog_lc_dir"),
&SystemClauseType::REPL(REPLCodePtr::LoadContextModule) =>
clause_name!("$prolog_lc_module"),
&SystemClauseType::REPL(REPLCodePtr::LoadContextStream) =>
clause_name!("$prolog_lc_stream"),
&SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty) =>
clause_name!("$cpp_meta_predicate_property"),
&SystemClauseType::REPL(REPLCodePtr::CompilePendingPredicates) =>
clause_name!("$compile_pending_predicates"),
&SystemClauseType::Close => clause_name!("$close"), &SystemClauseType::Close => clause_name!("$close"),
&SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"),
&SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"),
@@ -374,12 +407,9 @@ impl SystemClauseType {
&SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"), &SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"),
&SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"), &SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"),
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"), &SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"), &SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
&SystemClauseType::FetchGlobalVarWithOffset => { &SystemClauseType::FetchGlobalVarWithOffset =>
clause_name!("$fetch_global_var_with_offset") clause_name!("$fetch_global_var_with_offset"),
}
&SystemClauseType::FirstStream => clause_name!("$first_stream"), &SystemClauseType::FirstStream => clause_name!("$first_stream"),
&SystemClauseType::FlushOutput => clause_name!("$flush_output"), &SystemClauseType::FlushOutput => clause_name!("$flush_output"),
&SystemClauseType::GetByte => clause_name!("$get_byte"), &SystemClauseType::GetByte => clause_name!("$get_byte"),
@@ -405,13 +435,13 @@ impl SystemClauseType {
clause_name!("$get_lh_from_offset_diff") clause_name!("$get_lh_from_offset_diff")
} }
&SystemClauseType::GetBValue => clause_name!("$get_b_value"), &SystemClauseType::GetBValue => clause_name!("$get_b_value"),
&SystemClauseType::GetClause => clause_name!("$get_clause"), // &SystemClauseType::GetClause => clause_name!("$get_clause"),
&SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"), &SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
&SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"), &SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
&SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"), &SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"),
&SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"), &SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"),
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"), &SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
&SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"), // &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"), &SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
&SystemClauseType::Halt => clause_name!("$halt"), &SystemClauseType::Halt => clause_name!("$halt"),
&SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"), &SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"),
@@ -430,15 +460,14 @@ impl SystemClauseType {
&SystemClauseType::Maybe => clause_name!("maybe"), &SystemClauseType::Maybe => clause_name!("maybe"),
&SystemClauseType::CpuNow => clause_name!("$cpu_now"), &SystemClauseType::CpuNow => clause_name!("$cpu_now"),
&SystemClauseType::CurrentTime => clause_name!("$current_time"), &SystemClauseType::CurrentTime => clause_name!("$current_time"),
&SystemClauseType::ModuleAssertDynamicPredicateToFront => { // &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
clause_name!("$module_asserta") // clause_name!("$module_asserta")
} // }
&SystemClauseType::ModuleAssertDynamicPredicateToBack => { // &SystemClauseType::ModuleAssertDynamicPredicateToBack => {
clause_name!("$module_assertz") // clause_name!("$module_assertz")
} // }
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"), // &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
&SystemClauseType::ModuleExists => clause_name!("$module_exists"), &SystemClauseType::ModuleExists => clause_name!("$module_exists"),
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
&SystemClauseType::NextStream => clause_name!("$next_stream"), &SystemClauseType::NextStream => clause_name!("$next_stream"),
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"), &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
@@ -483,14 +512,13 @@ impl SystemClauseType {
&SystemClauseType::GetCutPoint => clause_name!("$get_cp"), &SystemClauseType::GetCutPoint => clause_name!("$get_cp"),
&SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"), &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_block"),
&SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"), &SystemClauseType::InstallNewBlock => clause_name!("$install_new_block"),
&SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"), // &SystemClauseType::ModuleRetractClause => clause_name!("$module_retract_clause"),
&SystemClauseType::NextEP => clause_name!("$nextEP"), &SystemClauseType::NextEP => clause_name!("$nextEP"),
&SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"), &SystemClauseType::ReadQueryTerm => clause_name!("$read_query_term"),
&SystemClauseType::ReadTerm => clause_name!("$read_term"), &SystemClauseType::ReadTerm => clause_name!("$read_term"),
&SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"), &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"),
&SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"), &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"),
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"), &SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"), &SystemClauseType::ResetBlock => clause_name!("$reset_block"),
&SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"), &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"),
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"), &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
@@ -533,22 +561,27 @@ impl SystemClauseType {
&SystemClauseType::SetEnv => clause_name!("$setenv"), &SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"), &SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
&SystemClauseType::CharsBase64 => clause_name!("$chars_base64"), &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"),
&SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"),
} }
} }
pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> { pub fn from(name: &str, arity: usize) -> Option<SystemClauseType> {
match (name, arity) { match (name, arity) {
("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause), // ("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause),
("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion), ("$add_dynamic_predicate", 3) =>
Some(SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate)),
("$add_goal_expansion_clause", 4) =>
Some(SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause)),
("$add_term_expansion_clause", 3) =>
Some(SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause)),
// ("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion),
("$atom_chars", 2) => Some(SystemClauseType::AtomChars), ("$atom_chars", 2) => Some(SystemClauseType::AtomChars),
("$atom_codes", 2) => Some(SystemClauseType::AtomCodes), ("$atom_codes", 2) => Some(SystemClauseType::AtomCodes),
("$atom_length", 2) => Some(SystemClauseType::AtomLength), ("$atom_length", 2) => Some(SystemClauseType::AtomLength),
("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause), // ("$abolish_module_clause", 3) => Some(SystemClauseType::AbolishModuleClause),
("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister), ("$bind_from_register", 2) => Some(SystemClauseType::BindFromRegister),
("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront), // ("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront),
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), // ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation),
("$char_code", 2) => Some(SystemClauseType::CharCode), ("$char_code", 2) => Some(SystemClauseType::CharCode),
("$char_type", 2) => Some(SystemClauseType::CharType), ("$char_type", 2) => Some(SystemClauseType::CharType),
@@ -559,7 +592,6 @@ impl SystemClauseType {
("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars),
("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString), ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString),
("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint),
("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)),
("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap),
("$close", 2) => Some(SystemClauseType::Close), ("$close", 2) => Some(SystemClauseType::Close),
("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname), ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname),
@@ -582,8 +614,8 @@ impl SystemClauseType {
("$peek_char", 2) => Some(SystemClauseType::PeekChar), ("$peek_char", 2) => Some(SystemClauseType::PeekChar),
("$peek_code", 2) => Some(SystemClauseType::PeekCode), ("$peek_code", 2) => Some(SystemClauseType::PeekCode),
("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString), ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString),
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), // ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), // ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$get_byte", 2) => Some(SystemClauseType::GetByte), ("$get_byte", 2) => Some(SystemClauseType::GetByte),
@@ -615,14 +647,14 @@ impl SystemClauseType {
} }
("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList), ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList),
("$get_b_value", 1) => Some(SystemClauseType::GetBValue), ("$get_b_value", 1) => Some(SystemClauseType::GetBValue),
("$get_clause", 2) => Some(SystemClauseType::GetClause), // ("$get_clause", 2) => Some(SystemClauseType::GetClause),
("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause), // ("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause),
("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), ("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset),
("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), ("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff),
("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes), ("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes),
("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner), ("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner),
("$halt", 1) => Some(SystemClauseType::Halt), ("$halt", 1) => Some(SystemClauseType::Halt),
("$head_is_dynamic", 1) => Some(SystemClauseType::HeadIsDynamic), ("$head_is_dynamic", 2) => Some(SystemClauseType::HeadIsDynamic),
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner), ("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter), ("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength), ("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
@@ -630,10 +662,9 @@ impl SystemClauseType {
("$cpu_now", 1) => Some(SystemClauseType::CpuNow), ("$cpu_now", 1) => Some(SystemClauseType::CpuNow),
("$current_time", 1) => Some(SystemClauseType::CurrentTime), ("$current_time", 1) => Some(SystemClauseType::CurrentTime),
("$module_exists", 1) => Some(SystemClauseType::ModuleExists), ("$module_exists", 1) => Some(SystemClauseType::ModuleExists),
("$module_of", 2) => Some(SystemClauseType::ModuleOf), // ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause), // ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic), ("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate),
("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate),
("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars),
("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes),
("$op", 3) => Some(SystemClauseType::OpDeclaration), ("$op", 3) => Some(SystemClauseType::OpDeclaration),
@@ -667,7 +698,7 @@ impl SystemClauseType {
("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker),
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey), ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset), ("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
("$retract_clause", 4) => Some(SystemClauseType::RetractClause), // ("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr), ("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
("$set_ball", 1) => Some(SystemClauseType::SetBall), ("$set_ball", 1) => Some(SystemClauseType::SetBall),
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
@@ -697,15 +728,17 @@ impl SystemClauseType {
("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory), ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory),
("$path_canonical", 2) => Some(SystemClauseType::PathCanonical), ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical),
("$file_time", 3) => Some(SystemClauseType::FileTime), ("$file_time", 3) => Some(SystemClauseType::FileTime),
("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), ("$clause_to_evacuable", 3) => Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable)),
("$use_module_from_file", 1) => ("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)),
Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)), ("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)),
("$use_qualified_module", 2) => ("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)),
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)), ("$load_compiled_library", 2) => Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary)),
("$use_qualified_module_from_file", 2) => ("$push_load_state_payload", 1) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload)),
Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)), ("$asserta", 4) => Some(SystemClauseType::REPL(REPLCodePtr::UserAsserta)),
("$assertz", 4) => Some(SystemClauseType::REPL(REPLCodePtr::UserAssertz)),
("$retract_clause", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UserRetract)),
("$variant", 2) => Some(SystemClauseType::Variant), ("$variant", 2) => Some(SystemClauseType::Variant),
("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions), ("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions),
("$write_term", 7) => Some(SystemClauseType::WriteTerm), ("$write_term", 7) => Some(SystemClauseType::WriteTerm),
("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars), ("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars),
("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion), ("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion),
@@ -727,6 +760,17 @@ impl SystemClauseType {
("$setenv", 2) => Some(SystemClauseType::SetEnv), ("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv), ("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
("$chars_base64", 4) => Some(SystemClauseType::CharsBase64), ("$chars_base64", 4) => Some(SystemClauseType::CharsBase64),
("$load_library_as_stream", 3) => Some(SystemClauseType::LoadLibraryAsStream),
("$push_load_context", 2) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadContext)),
("$pop_load_state_payload", 1) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadStatePayload)),
("$pop_load_context", 0) => Some(SystemClauseType::REPL(REPLCodePtr::PopLoadContext)),
("$prolog_lc_source", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextSource)),
("$prolog_lc_file", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextFile)),
("$prolog_lc_dir", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextDirectory)),
("$prolog_lc_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextModule)),
("$prolog_lc_stream", 1) => Some(SystemClauseType::REPL(REPLCodePtr::LoadContextStream)),
("$cpp_meta_predicate_property", 3) => Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty)),
("$compile_pending_predicates", 1) => Some(SystemClauseType::REPL(REPLCodePtr::CompilePendingPredicates)),
_ => None, _ => None,
} }
} }
@@ -754,7 +798,6 @@ pub enum BuiltInClauseType {
pub enum ClauseType { pub enum ClauseType {
BuiltIn(BuiltInClauseType), BuiltIn(BuiltInClauseType),
CallN, CallN,
Hook(CompileTimeHook),
Inlined(InlinedClauseType), Inlined(InlinedClauseType),
Named(ClauseName, usize, CodeIndex), // name, arity, index. Named(ClauseName, usize, CodeIndex), // name, arity, index.
Op(ClauseName, SharedOpDesc, CodeIndex), Op(ClauseName, SharedOpDesc, CodeIndex),
@@ -818,7 +861,6 @@ impl ClauseType {
match self { match self {
&ClauseType::BuiltIn(ref built_in) => built_in.name(), &ClauseType::BuiltIn(ref built_in) => built_in.name(),
&ClauseType::CallN => clause_name!("call"), &ClauseType::CallN => clause_name!("call"),
&ClauseType::Hook(ref hook) => hook.name(),
&ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()), &ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()),
&ClauseType::Op(ref name, ..) => name.clone(), &ClauseType::Op(ref name, ..) => name.clone(),
&ClauseType::Named(ref name, ..) => name.clone(), &ClauseType::Named(ref name, ..) => name.clone(),

View File

@@ -1,5 +1,6 @@
/// Code generation to WAM-like instructions. /// Code generation to WAM-like instructions.
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::TabledData;
use crate::allocator::*; use crate::allocator::*;
use crate::arithmetic::*; use crate::arithmetic::*;
@@ -9,20 +10,32 @@ use crate::forms::*;
use crate::indexing::*; use crate::indexing::*;
use crate::instructions::*; use crate::instructions::*;
use crate::iterators::*; use crate::iterators::*;
use crate::machine::machine_indices::*;
use crate::targets::*; use crate::targets::*;
use crate::machine::machine_errors::*;
use crate::indexmap::{IndexMap, IndexSet}; use crate::indexmap::{IndexMap, IndexSet};
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque;
use std::rc::Rc; use std::rc::Rc;
use std::vec::Vec;
#[derive(Debug)] #[inline]
pub struct CodeGenerator<TermMarker> { pub fn trust_me(non_counted_bt: bool) -> ChoiceInstruction {
marker: TermMarker, if non_counted_bt {
pub var_count: IndexMap<Rc<Var>, usize>, ChoiceInstruction::DefaultTrustMe(0)
non_counted_bt: bool, } else {
ChoiceInstruction::TrustMe(0)
}
}
#[inline]
pub fn retry_me_else(offset: usize, non_counted_bt: bool) -> ChoiceInstruction {
if non_counted_bt {
ChoiceInstruction::DefaultRetryMeElse(offset)
} else {
ChoiceInstruction::RetryMeElse(offset)
}
} }
#[derive(Debug)] #[derive(Debug)]
@@ -97,17 +110,46 @@ impl<'a> ConjunctInfo<'a> {
} }
} }
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> { #[derive(Clone, Copy, Debug)]
pub fn new(non_counted_bt: bool) -> Self { pub struct CodeGenSettings {
CodeGenerator { pub is_extensible: bool,
marker: Allocator::new(), pub non_counted_bt: bool,
var_count: IndexMap::new(), }
impl CodeGenSettings {
#[inline]
pub fn new(is_extensible: bool, non_counted_bt: bool) -> Self {
CodeGenSettings {
is_extensible,
non_counted_bt, non_counted_bt,
} }
} }
}
pub fn take_vars(self) -> AllocVarDict { #[derive(Debug)]
self.marker.take_bindings() pub struct CodeGenerator<TermMarker> {
atom_tbl: TabledData<Atom>,
marker: TermMarker,
pub var_count: IndexMap<Rc<Var>, usize>,
non_counted_bt: bool,
is_extensible: bool,
pub skeleton: PredicateSkeleton,
pub jmp_by_locs: Vec<usize>,
global_jmp_by_locs_offset: usize,
}
impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
pub fn new(atom_tbl: TabledData<Atom>, settings: CodeGenSettings) -> Self {
CodeGenerator {
atom_tbl,
marker: Allocator::new(),
var_count: IndexMap::new(),
non_counted_bt: settings.non_counted_bt,
is_extensible: settings.is_extensible,
skeleton: PredicateSkeleton::new(),
jmp_by_locs: vec![],
global_jmp_by_locs_offset: 0,
}
} }
fn update_var_count<Iter: Iterator<Item = TermRef<'a>>>(&mut self, iter: Iter) { fn update_var_count<Iter: Iterator<Item = TermRef<'a>>>(&mut self, iter: Iter) {
@@ -337,16 +379,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
ConjunctInfo::new(vs, num_of_chunks, has_deep_cut) ConjunctInfo::new(vs, num_of_chunks, has_deep_cut)
} }
fn add_conditional_call(code: &mut Code, qt: &QueryTerm, pvs: usize) { fn add_conditional_call(&mut self, code: &mut Code, qt: &QueryTerm, pvs: usize) {
match qt { match qt {
&QueryTerm::Jump(ref vars) => code.push(jmp_call!(vars.len(), 0, pvs)), &QueryTerm::Jump(ref vars) => {
self.jmp_by_locs.push(code.len());
code.push(jmp_call!(vars.len(), 0, pvs));
}
&QueryTerm::Clause(_, ref ct, ref terms, true) => { &QueryTerm::Clause(_, ref ct, ref terms, true) => {
code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs)) code.push(call_clause_by_default!(ct.clone(), terms.len(), pvs));
} }
&QueryTerm::Clause(_, ref ct, ref terms, false) => { &QueryTerm::Clause(_, ref ct, ref terms, false) => {
code.push(call_clause!(ct.clone(), terms.len(), pvs)) code.push(call_clause!(ct.clone(), terms.len(), pvs));
}
_ => {
} }
_ => {}
} }
} }
@@ -356,16 +402,22 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
match code.last_mut() { match code.last_mut() {
Some(&mut Line::Control(ref mut ctrl)) => match ctrl { Some(&mut Line::Control(ref mut ctrl)) => match ctrl {
&mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => { &mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => {
*last_call = true *last_call = true;
} }
&mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => { &mut ControlInstruction::JmpBy(_, _, _, ref mut last_call) => {
*last_call = true *last_call = true;
}
&mut ControlInstruction::Proceed => {
}
_ => {
dealloc_index += 1;
} }
&mut ControlInstruction::Proceed => {}
_ => dealloc_index += 1,
}, },
Some(&mut Line::Cut(CutInstruction::Cut(_))) => dealloc_index += 1, Some(&mut Line::Cut(CutInstruction::Cut(_))) => {
_ => {} dealloc_index += 1;
}
_ => {
}
}; };
dealloc_index dealloc_index
@@ -377,7 +429,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
terms: &'a Vec<Box<Term>>, terms: &'a Vec<Box<Term>>,
term_loc: GenContext, term_loc: GenContext,
code: &mut Code, code: &mut Code,
) -> Result<(), ParserError> { ) -> Result<(), CompilationError> {
match ct { match ct {
&InlinedClauseType::CompareNumber(cmp, ..) => { &InlinedClauseType::CompareNumber(cmp, ..) => {
self.marker.reset_arg(2); self.marker.reset_arg(2);
@@ -553,7 +605,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
code: &mut Code, code: &mut Code,
term_loc: GenContext, term_loc: GenContext,
use_default_call_policy: bool, use_default_call_policy: bool,
) -> Result<(), ParserError> { ) -> Result<(), CompilationError> {
let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?;
code.append(&mut acode); code.append(&mut acode);
@@ -656,7 +708,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
conjunct_info: &ConjunctInfo<'a>, conjunct_info: &ConjunctInfo<'a>,
code: &mut Code, code: &mut Code,
is_exposed: bool, is_exposed: bool,
) -> Result<(), ParserError> { ) -> Result<(), CompilationError> {
for (chunk_num, _, terms) in iter.rule_body_iter() { for (chunk_num, _, terms) in iter.rule_body_iter() {
for (i, term) in terms.iter().enumerate() { for (i, term) in terms.iter().enumerate() {
let term_loc = if i + 1 < terms.len() { let term_loc = if i + 1 < terms.len() {
@@ -669,18 +721,24 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
&QueryTerm::GetLevelAndUnify(ref cell, ref var) => { &QueryTerm::GetLevelAndUnify(ref cell, ref var) => {
self.compile_get_level_and_unify(code, cell, var.clone(), term_loc) self.compile_get_level_and_unify(code, cell, var.clone(), term_loc)
} }
&QueryTerm::UnblockedCut(ref cell) => self.compile_unblocked_cut(code, cell), &QueryTerm::UnblockedCut(ref cell) => {
&QueryTerm::BlockedCut => code.push(if chunk_num == 0 { self.compile_unblocked_cut(code, cell)
Line::Cut(CutInstruction::NeckCut) }
} else { &QueryTerm::BlockedCut => {
Line::Cut(CutInstruction::Cut(perm_v!(1))) code.push(if chunk_num == 0 {
}), Line::Cut(CutInstruction::NeckCut)
} else {
Line::Cut(CutInstruction::Cut(perm_v!(1)))
})
}
&QueryTerm::Clause( &QueryTerm::Clause(
_, _,
ClauseType::BuiltIn(BuiltInClauseType::Is(..)), ClauseType::BuiltIn(BuiltInClauseType::Is(..)),
ref terms, ref terms,
use_default_call_policy, use_default_call_policy,
) => self.compile_is_call(terms, code, term_loc, use_default_call_policy)?, ) => {
self.compile_is_call(terms, code, term_loc, use_default_call_policy)?
}
&QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => { &QueryTerm::Clause(_, ClauseType::Inlined(ref ct), ref terms, _) => {
self.compile_inlined(ct, terms, term_loc, code)? self.compile_inlined(ct, terms, term_loc, code)?
} }
@@ -714,7 +772,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
} }
} }
fn compile_cleanup(code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) { fn compile_cleanup(&mut self, code: &mut Code, conjunct_info: &ConjunctInfo, toc: &'a QueryTerm) {
// add a proceed to bookend any trailing cuts. // add a proceed to bookend any trailing cuts.
match toc { match toc {
&QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()), &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()),
@@ -726,11 +784,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
let dealloc_index = Self::lco(code); let dealloc_index = Self::lco(code);
if conjunct_info.allocates() { if conjunct_info.allocates() {
let offset = self.global_jmp_by_locs_offset;
if let Some(jmp_by_offset) = self.jmp_by_locs[offset ..].last_mut() {
if *jmp_by_offset == dealloc_index {
*jmp_by_offset += 1;
}
}
code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate)); code.insert(dealloc_index, Line::Control(ControlInstruction::Deallocate));
} }
} }
pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, ParserError> { pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result<Code, CompilationError> {
let iter = ChunkedIterator::from_rule(rule); let iter = ChunkedIterator::from_rule(rule);
let conjunct_info = self.collect_var_data(iter); let conjunct_info = self.collect_var_data(iter);
@@ -739,7 +805,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
ref clauses, ref clauses,
} = rule; } = rule;
let mut code = Vec::new(); let mut code = Code::new();
self.marker.reset_at_head(args); self.marker.reset_at_head(args);
self.compile_seq_prelude(&conjunct_info, &mut code); self.compile_seq_prelude(&conjunct_info, &mut code);
@@ -761,8 +827,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
self.compile_seq(iter, &conjunct_info, &mut code, false)?; self.compile_seq(iter, &conjunct_info, &mut code, false)?;
conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code); conjunct_info.mark_unsafe_vars(unsafe_var_marker, &mut code);
self.compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
Self::compile_cleanup(&mut code, &conjunct_info, clauses.last().unwrap_or(p1));
Ok(code) Ok(code)
} }
@@ -836,10 +902,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
} }
} }
Self::add_conditional_call(code, term, num_perm_vars_left); self.add_conditional_call(code, term, num_perm_vars_left);
} }
pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, ParserError> { /*
pub fn compile_query(&mut self, query: &'a Vec<QueryTerm>) -> Result<Code, CompilationError> {
let iter = ChunkedIterator::from_term_sequence(query); let iter = ChunkedIterator::from_term_sequence(query);
let conjunct_info = self.collect_var_data(iter); let conjunct_info = self.collect_var_data(iter);
@@ -857,6 +924,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
Ok(code) Ok(code)
} }
*/
#[inline]
fn increment_jmp_by_locs_by(&mut self, incr: usize) {
let offset = self.global_jmp_by_locs_offset;
for loc in &mut self.jmp_by_locs[offset ..] {
*loc += incr;
}
}
/// Returns the index of the first instantiated argument. /// Returns the index of the first instantiated argument.
fn first_instantiated_index(clauses: &[PredicateClause]) -> Option<usize> { fn first_instantiated_index(clauses: &[PredicateClause]) -> Option<usize> {
@@ -925,48 +1002,50 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
subseqs subseqs
} }
fn trust_me(&self) -> ChoiceInstruction {
if self.non_counted_bt {
ChoiceInstruction::DefaultTrustMe
} else {
ChoiceInstruction::TrustMe
}
}
fn retry_me_else(&self, offset: usize) -> ChoiceInstruction {
if self.non_counted_bt {
ChoiceInstruction::DefaultRetryMeElse(offset)
} else {
ChoiceInstruction::RetryMeElse(offset)
}
}
fn compile_pred_subseq<'b: 'a>( fn compile_pred_subseq<'b: 'a>(
&mut self, &mut self,
clauses: &'b [PredicateClause], clauses: &'b [PredicateClause],
optimal_index: usize, optimal_index: usize,
) -> Result<Code, ParserError> { ) -> Result<Code, CompilationError> {
let mut code_body = Vec::new(); let mut code = VecDeque::new();
let mut code_offsets = CodeOffsets::new(); let mut code_offsets = CodeOffsets::new(self.atom_tbl.clone(), optimal_index + 1);
let mut skip_stub_try_me_else = false;
let num_clauses = clauses.len(); let jmp_by_locs_len = self.jmp_by_locs.len();
for (i, clause) in clauses.iter().enumerate() { for (i, clause) in clauses.iter().enumerate() {
self.marker.reset(); self.marker.reset();
let mut clause_code = match *clause { let mut clause_index_info = ClauseIndexInfo::new(code.len());
PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact), self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
let clause_code = match clause {
&PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact),
&PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?,
}; };
if num_clauses > 1 { if clauses.len() > 1 {
let choice = match i { let choice = match i {
0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1), 0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1),
_ if i == num_clauses - 1 => self.trust_me(), _ if i == clauses.len() - 1 => trust_me(self.non_counted_bt),
_ => self.retry_me_else(clause_code.len() + 1), _ => retry_me_else(clause_code.len() + 1, self.non_counted_bt),
}; };
code_body.push(Line::Choice(choice)); code.push_back(Line::Choice(choice));
} else if self.is_extensible {
/*
generate stub choice instructions for extensible
predicates. if predicates are added to either the
inner or outer thread of choice instructions,
these stubs will be used, and surrounding indexing
instructions modified accordingly.
until then, the v offset of SwitchOnTerm will skip
over them.
*/
code.push_front(Line::Choice(ChoiceInstruction::TryMeElse(0)));
skip_stub_try_me_else = true;
} }
let arg = match clause.args() { let arg = match clause.args() {
@@ -976,47 +1055,86 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator<TermMarker> {
}, },
None => None, None => None,
}; };
if let Some(arg) = arg { if let Some(arg) = arg {
let index = code_body.len(); let index = code.len();
code_offsets.index_term(arg, index); code_offsets.index_term(arg, index, &mut clause_index_info);
} }
code_body.append(&mut clause_code); if !skip_stub_try_me_else {
self.increment_jmp_by_locs_by(code.len());
}
self.skeleton.clauses.push_back(clause_index_info);
code.extend(clause_code.into_iter());
} }
let mut code = Vec::new(); let index_code = code_offsets.compute_indices(skip_stub_try_me_else);
code_offsets.add_indices(&mut code, code_body, optimal_index + 1); self.global_jmp_by_locs_offset = jmp_by_locs_len;
Ok(code) if !index_code.is_empty() {
code.push_front(Line::IndexingCode(index_code));
if skip_stub_try_me_else {
// skip the TryMeElse(0) also.
self.increment_jmp_by_locs_by(2);
} else {
self.increment_jmp_by_locs_by(1);
}
} else if skip_stub_try_me_else {
// remove the TryMeElse(0).
code.pop_front();
}
Ok(Vec::from(code))
} }
pub fn compile_predicate<'b: 'a>( pub fn compile_predicate<'b: 'a>(
&mut self, &mut self,
clauses: &'b Vec<PredicateClause>, clauses: &'b Vec<PredicateClause>,
) -> Result<Code, ParserError> { ) -> Result<Code, CompilationError> {
let mut code = Vec::new(); let mut code = Code::new();
let optimal_index = match Self::first_instantiated_index(&clauses) { let optimal_index = match Self::first_instantiated_index(&clauses) {
Some(index) => index, Some(index) => index,
None => 0, // Default to first argument indexing. None => 0, // Default to first argument indexing.
}; };
let split_pred = Self::split_predicate(&clauses, optimal_index); let split_pred = Self::split_predicate(&clauses, optimal_index);
let multi_seq = split_pred.len() > 1; let multi_seq = split_pred.len() > 1;
for (l, r) in split_pred { for (l, r) in split_pred {
let mut code_segment = let skel_lower_bound = self.skeleton.clauses.len();
self.compile_pred_subseq(&clauses[l..r], optimal_index)?; let code_segment = self.compile_pred_subseq(&clauses[l .. r], optimal_index)?;
let clause_start_offset = code.len();
if multi_seq { if multi_seq {
let choice = match l { let choice = match l {
0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1), 0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1),
_ if r == clauses.len() => self.trust_me(), _ if r == clauses.len() => trust_me(self.non_counted_bt),
_ => self.retry_me_else(code_segment.len() + 1), _ => retry_me_else(code_segment.len() + 1, self.non_counted_bt),
}; };
code.push(Line::Choice(choice)); code.push(Line::Choice(choice));
} else if self.is_extensible {
code.push(Line::Choice(ChoiceInstruction::TryMeElse(0)));
} }
code.append(&mut code_segment); if self.is_extensible {
let segment_is_indexed = to_indexing_line(&code_segment[0]).is_some();
for clause_index_info in self.skeleton.clauses[skel_lower_bound ..].iter_mut() {
clause_index_info.clause_start +=
clause_start_offset + 2 * (segment_is_indexed as usize);
clause_index_info.opt_arg_index_key +=
clause_start_offset + 1;
}
}
self.increment_jmp_by_locs_by(code.len());
self.global_jmp_by_locs_offset = self.jmp_by_locs.len();
code.extend(code_segment.into_iter());
} }
Ok(code) Ok(code)

View File

@@ -1,6 +1,5 @@
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::OpDesc; use crate::prolog_parser::parser::OpDesc;
use crate::prolog_parser::tabled_rc::*;
use crate::clause_types::*; use crate::clause_types::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
@@ -8,15 +7,19 @@ use crate::machine::machine_indices::*;
use crate::ordered_float::OrderedFloat; use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational}; use crate::rug::{Integer, Rational};
use crate::indexmap::IndexMap; use crate::indexmap::{IndexMap, IndexSet};
use slice_deque::*;
use std::cell::Cell; use std::cell::Cell;
use std::collections::VecDeque; use std::ops::AddAssign;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
pub type PredicateKey = (ClauseName, usize); // name, arity. pub type PredicateKey = (ClauseName, usize); // name, arity.
pub type Predicate = Vec<PredicateClause>;
// vars of predicate, toplevel offset. Vec<Term> is always a vector // vars of predicate, toplevel offset. Vec<Term> is always a vector
// of vars (we get their adjoining cells this way). // of vars (we get their adjoining cells this way).
pub type JumpStub = Vec<Term>; pub type JumpStub = Vec<Term>;
@@ -24,19 +27,24 @@ pub type JumpStub = Vec<Term>;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum TopLevel { pub enum TopLevel {
Declaration(Declaration), Declaration(Declaration),
Fact(Term, usize, usize), // Term, line_num, col_num Fact(Term), // Term, line_num, col_num
Predicate(Predicate), Predicate(Predicate),
Query(Vec<QueryTerm>), Query(Vec<QueryTerm>),
Rule(Rule, usize, usize), // Rule, line_num, col_num Rule(Rule), // Rule, line_num, col_num
} }
impl TopLevel { #[derive(Debug, Clone, Copy)]
pub fn is_end_of_file_atom(&self) -> bool { pub enum AppendOrPrepend {
Append,
Prepend
}
impl AppendOrPrepend {
#[inline]
pub fn is_append(self) -> bool {
match self { match self {
&TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => { AppendOrPrepend::Append => true,
return name.as_str() == "end_of_file" AppendOrPrepend::Prepend => false,
}
_ => false,
} }
} }
} }
@@ -91,30 +99,9 @@ pub struct Rule {
pub clauses: Vec<QueryTerm>, pub clauses: Vec<QueryTerm>,
} }
#[derive(Debug, Clone)] #[derive(Clone, Debug, Hash)]
pub struct Predicate(pub Vec<PredicateClause>);
impl Predicate {
#[inline]
pub fn new() -> Self {
Predicate(vec![])
}
#[inline]
pub fn clauses(self) -> Vec<PredicateClause> {
self.0
}
#[inline]
pub fn predicate_indicator(&self) -> Option<(ClauseName, usize)> {
self.0
.first()
.and_then(|clause| clause.name().map(|name| (name, clause.arity())))
}
}
#[derive(Debug, Clone)]
pub enum ListingSource { pub enum ListingSource {
DynamicallyGenerated,
File(ClauseName, PathBuf), // filename, path File(ClauseName, PathBuf), // filename, path
User, User,
} }
@@ -123,98 +110,13 @@ impl ListingSource {
pub fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self { pub fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self {
ListingSource::File(filename, path_buf) ListingSource::File(filename, path_buf)
} }
pub fn name(&self) -> ClauseName {
match self {
ListingSource::File(ref filename, _) => filename.clone(),
ListingSource::User => clause_name!("[user]")
}
}
pub fn path(&self) -> PathBuf {
match self {
ListingSource::File(_, ref path) => path.clone(),
ListingSource::User => std::env::current_dir().unwrap(),
}
}
} }
fn resolved_term_and_module(term: &Term) -> Option<(ClauseName, ClauseName)> pub trait ClauseInfo {
{
match term {
Term::Clause(_, ref name, ref terms, _) => {
if name.as_str() == ":" && terms.len() == 2 {
let module_name = match terms[0].as_ref() {
&Term::Constant(_, Constant::Atom(ref module_name, _)) => {
module_name.clone()
}
_ => {
return Some((name.owning_module(), name.clone()));
}
};
match terms[1].as_ref() {
Term::Clause(_, ref name, ..)
| Term::Constant(_, Constant::Atom(ref name, ..)) => {
return Some((module_name, name.clone()));
}
_ => {
}
}
Some((name.owning_module(), name.clone()))
} else {
Some((name.owning_module(), name.clone()))
}
}
Term::Constant(_, Constant::Atom(ref name, _)) => {
Some((name.owning_module(), name.clone()))
}
_ => {
None
}
}
}
fn resolved_term_arity(term: &Term) -> usize
{
match term {
Term::Clause(_, ref name, ref terms, _) => {
if name.as_str() == ":" && terms.len() == 2 {
match terms[0].as_ref() {
&Term::Constant(_, Constant::Atom(..)) => {
}
_ => {
return 2;
}
}
match terms[1].as_ref() {
Term::Clause(_, _, ref terms, _) => {
terms.len()
}
Term::Constant(_, Constant::Atom(..)) => {
0
}
_ => {
2
}
}
} else {
terms.len()
}
}
_ => {
0
}
}
}
pub trait ClauseConsistency {
fn is_consistent(&self, clauses: &Vec<PredicateClause>) -> bool { fn is_consistent(&self, clauses: &Vec<PredicateClause>) -> bool {
match clauses.first() { match clauses.first() {
Some(ref cl) => { Some(cl) => {
self.name_and_module() == cl.name_and_module() && self.arity() == cl.arity() self.name() == cl.name() && self.arity() == cl.arity()
} }
None => { None => {
true true
@@ -222,33 +124,29 @@ pub trait ClauseConsistency {
} }
} }
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>; fn name(&self) -> Option<ClauseName>;
fn arity(&self) -> usize; fn arity(&self) -> usize;
} }
/* Of course '$current_module$' isn't the name of the current impl ClauseInfo for Term {
* module. It'll do if no module is explicitly specified through fn name(&self) -> Option<ClauseName> {
* (:)/2.
*/
impl ClauseConsistency for Term {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>
{
match self { match self {
Term::Clause(_, ref name, ref terms, _) => Term::Clause(_, ref name, ref terms, _) => {
match name.as_str() { match name.as_str() {
":-" => { ":-" => {
match terms.len() { match terms.len() {
1 => None, // a declaration. 1 => None, // a declaration.
2 => resolved_term_and_module(&terms[0]), 2 => terms[0].name(),
_ => Some((name.owning_module(), clause_name!(":-"))), _ => Some(clause_name!(":-")),
} }
} }
_ => { _ => {
resolved_term_and_module(self) Some(name.clone())
} }
}, }
}
Term::Constant(_, Constant::Atom(ref name, _)) => { Term::Constant(_, Constant::Atom(ref name, _)) => {
Some((name.owning_module(), name.clone())) Some(name.clone())
} }
_ => { _ => {
None None
@@ -263,12 +161,12 @@ impl ClauseConsistency for Term {
":-" => { ":-" => {
match terms.len() { match terms.len() {
1 => 0, 1 => 0,
2 => resolved_term_arity(&terms[0]), 2 => terms[0].arity(),
_ => terms.len(), _ => terms.len(),
} }
} }
_ => { _ => {
resolved_term_arity(self) terms.len()
} }
}, },
_ => { _ => {
@@ -278,9 +176,9 @@ impl ClauseConsistency for Term {
} }
} }
impl ClauseConsistency for Rule { impl ClauseInfo for Rule {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> { fn name(&self) -> Option<ClauseName> {
Some((self.head.0.owning_module(), self.head.0.clone())) Some(self.head.0.clone())
} }
fn arity(&self) -> usize { fn arity(&self) -> usize {
@@ -288,15 +186,14 @@ impl ClauseConsistency for Rule {
} }
} }
impl ClauseConsistency for PredicateClause { impl ClauseInfo for PredicateClause {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> { fn name(&self) -> Option<ClauseName> {
match self { match self {
&PredicateClause::Fact(ref term, ..) => { &PredicateClause::Fact(ref term, ..) => {
term.name_and_module() term.name()
.map(|(_, name)| (name.owning_module(), name))
} }
&PredicateClause::Rule(ref rule, ..) => { &PredicateClause::Rule(ref rule, ..) => {
rule.name_and_module() rule.name()
} }
} }
} }
@@ -313,22 +210,12 @@ impl ClauseConsistency for PredicateClause {
} }
} }
impl ClauseConsistency for Predicate { // pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
self.0.first().and_then(|clause| clause.name_and_module())
}
fn arity(&self) -> usize {
self.0.first().map(|clause| clause.arity()).unwrap_or(0)
}
}
pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum PredicateClause { pub enum PredicateClause {
Fact(Term, usize, usize), // Term, line number, column number. Fact(Term),
Rule(Rule, usize, usize), // Term, line number, column number. Rule(Rule),
} }
impl PredicateClause { impl PredicateClause {
@@ -395,66 +282,61 @@ impl ModuleSource {
} }
} }
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator. // pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
/*
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum MultiFileIndicator { pub enum MultiFileIndicator {
LocalScoped(ClauseName, usize), // name, arity LocalScoped(ClauseName, usize), // name, arity
ModuleScoped(ScopedPredicateKey), ModuleScoped(ScopedPredicateKey),
} }
*/
#[derive(Clone, Copy, Hash, Debug)]
pub enum MetaSpec {
Minus,
Plus,
Either,
RequiresExpansion,
RequiresExpansionWithArgument(usize),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Declaration { pub enum Declaration {
Dynamic(ClauseName, usize), // name, arity Dynamic(ClauseName, usize),
EndOfFile, MetaPredicate(ClauseName, ClauseName, Vec<MetaSpec>), // module name, name, meta-specs
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal
Module(ModuleDecl), Module(ModuleDecl),
MultiFile(MultiFileIndicator),
NonCountedBacktracking(ClauseName, usize), // name, arity NonCountedBacktracking(ClauseName, usize), // name, arity
Op(OpDecl), Op(OpDecl),
SetPrologFlag(DoubleQuotes),
UseModule(ModuleSource), UseModule(ModuleSource),
UseQualifiedModule(ModuleSource, Vec<ModuleExport>), UseQualifiedModule(ModuleSource, IndexSet<ModuleExport>),
} }
impl Declaration { #[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)]
#[inline] pub struct OpDecl {
pub fn is_module_decl(&self) -> bool { pub prec: usize,
if let &Declaration::Module(_) = self { pub spec: Specifier,
true pub name: ClauseName
} else {
false
}
}
#[inline]
pub fn is_end_of_file(&self) -> bool {
if let &Declaration::EndOfFile = self {
true
} else {
false
}
}
} }
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct OpDecl(pub usize, pub Specifier, pub ClauseName);
impl OpDecl { impl OpDecl {
#[inline] #[inline]
pub fn name(&self) -> ClauseName { pub fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self {
self.2.clone() Self { prec, spec, name }
} }
#[inline] #[inline]
pub fn remove(&self, op_dir: &mut OpDir) { pub fn remove(&mut self, op_dir: &mut OpDir) {
self.insert_into_op_dir(clause_name!(""), op_dir, 0); let prec = self.prec;
self.prec = 0;
self.insert_into_op_dir(op_dir);
self.prec = prec;
} }
#[inline] #[inline]
pub fn fixity(&self) -> Fixity { pub fn fixity(&self) -> Fixity {
match self.1 { match self.spec {
XFY | XFX | YFX => Fixity::In, XFY | XFX | YFX => Fixity::In,
XF | YF => Fixity::Post, XF | YF => Fixity::Post,
FX | FY => Fixity::Pre, FX | FY => Fixity::Pre,
@@ -462,29 +344,27 @@ impl OpDecl {
} }
} }
pub fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize) { pub fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> {
let (spec, name) = (self.1, self.2.clone()); let key = (self.name.clone(), self.fixity());
let fixity = self.fixity(); match op_dir.get(&key) {
match op_dir.get(&(name.clone(), fixity)) {
Some(cell) => { Some(cell) => {
cell.shared_op_desc().set(prec, spec); return Some(cell.shared_op_desc().replace((self.prec, self.spec)));
return; }
None => {
} }
None => {}
} }
op_dir.insert((name, fixity), OpDirValue::new(spec, prec, module)); op_dir.insert(key, OpDirValue::new(self.spec, self.prec))
.map(|op_dir_value| op_dir_value.shared_op_desc().get())
} }
pub fn submit( pub fn submit(
&self, &self,
module: ClauseName,
existing_desc: Option<OpDesc>, existing_desc: Option<OpDesc>,
op_dir: &mut OpDir, op_dir: &mut OpDir,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let (prec, spec, name) = (self.0, self.1, self.2.clone()); let (spec, name) = (self.spec, self.name.clone());
if is_infix!(spec) { if is_infix!(spec) {
if let Some(desc) = existing_desc { if let Some(desc) = existing_desc {
@@ -502,7 +382,8 @@ impl OpDecl {
} }
} }
Ok(self.insert_into_op_dir(module, op_dir, prec)) self.insert_into_op_dir(op_dir);
Ok(())
} }
} }
@@ -541,7 +422,7 @@ pub fn fetch_op_spec(
match arity { match arity {
2 => op_dir 2 => op_dir
.get(&(name, Fixity::In)) .get(&(name, Fixity::In))
.and_then(|OpDirValue(spec, _)| { .and_then(|OpDirValue(spec)| {
if spec.prec() > 0 { if spec.prec() > 0 {
Some(spec.clone()) Some(spec.clone())
} else { } else {
@@ -549,15 +430,15 @@ pub fn fetch_op_spec(
} }
}), }),
1 => { 1 => {
if let Some(OpDirValue(spec, _)) = op_dir.get(&(name.clone(), Fixity::Pre)) { if let Some(OpDirValue(spec)) = op_dir.get(&(name.clone(), Fixity::Pre)) {
if spec.prec() > 0 { if spec.prec() > 0 {
return Some(spec.clone()); return Some(spec.clone());
} }
} }
op_dir op_dir
.get(&(name, Fixity::Post)) .get(&(name.clone(), Fixity::Post))
.and_then(|OpDirValue(spec, _)| { .and_then(|OpDirValue(spec)| {
if spec.prec() > 0 { if spec.prec() > 0 {
Some(spec.clone()) Some(spec.clone())
} else { } else {
@@ -573,7 +454,7 @@ pub fn fetch_op_spec(
pub type ModuleDir = IndexMap<ClauseName, Module>; pub type ModuleDir = IndexMap<ClauseName, Module>;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub enum ModuleExport { pub enum ModuleExport {
OpDecl(OpDecl), OpDecl(OpDecl),
PredicateKey(PredicateKey), PredicateKey(PredicateKey),
@@ -587,21 +468,32 @@ pub struct ModuleDecl {
#[derive(Debug)] #[derive(Debug)]
pub struct Module { pub struct Module {
pub atom_tbl: TabledData<Atom>,
pub module_decl: ModuleDecl, pub module_decl: ModuleDecl,
pub code_dir: CodeDir, pub code_dir: CodeDir,
pub op_dir: OpDir, pub op_dir: OpDir,
pub term_dir: TermDir, // this contains multifile predicates. pub meta_predicates: MetaPredicateDir,
pub term_expansions: (Predicate, VecDeque<TopLevel>), pub extensible_predicates: IndexMap<PredicateKey, PredicateSkeleton>,
pub goal_expansions: (Predicate, VecDeque<TopLevel>),
pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
pub local_term_expansions: (Predicate, VecDeque<TopLevel>), // expansions local to the module.
pub local_goal_expansions: (Predicate, VecDeque<TopLevel>),
pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
pub is_impromptu_module: bool, pub is_impromptu_module: bool,
pub listing_src: ListingSource, pub listing_src: ListingSource,
} pub clause_assert_margin: usize,
}
// Module's and related types are defined in forms.
impl Module {
pub fn new(module_decl: ModuleDecl, listing_src: ListingSource) -> Self {
Module {
module_decl,
code_dir: CodeDir::new(),
op_dir: default_op_dir(),
meta_predicates: MetaPredicateDir::new(),
is_impromptu_module: false,
extensible_predicates: IndexMap::new(),
listing_src,
clause_assert_margin: 0,
}
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub enum Number { pub enum Number {
@@ -709,3 +601,154 @@ impl Number {
} }
} }
} }
#[derive(Debug, Clone)]
pub enum OptArgIndexKey {
Constant(usize, usize, Constant, Vec<Constant>), // index, IndexingCode location, opt arg, alternatives
List(usize, usize), // index, IndexingCode location
None,
Structure(usize, usize, ClauseName, usize), // index, IndexingCode location, name, arity
}
impl OptArgIndexKey {
#[inline]
pub fn take(&mut self) -> OptArgIndexKey {
std::mem::replace(self, OptArgIndexKey::None)
}
#[inline]
pub fn arg_num(&self) -> usize {
match &self {
OptArgIndexKey::Constant(arg_num, ..) |
OptArgIndexKey::Structure(arg_num, ..) |
OptArgIndexKey::List(arg_num, _) => {
// these are always at least 1.
*arg_num
}
OptArgIndexKey::None => {
0
}
}
}
#[inline]
pub fn is_some(&self) -> bool {
self.switch_on_term_loc().is_some()
}
#[inline]
pub fn switch_on_term_loc(&self) -> Option<usize> {
match &self {
OptArgIndexKey::Constant(_, loc, ..) |
OptArgIndexKey::Structure(_, loc, ..) |
OptArgIndexKey::List(_, loc) => {
Some(*loc)
}
OptArgIndexKey::None => {
None
}
}
}
#[inline]
pub fn set_switch_on_term_loc(&mut self, value: usize) {
match self {
OptArgIndexKey::Constant(_, ref mut loc, ..) |
OptArgIndexKey::Structure(_, ref mut loc, ..) |
OptArgIndexKey::List(_, ref mut loc) => {
*loc = value;
}
OptArgIndexKey::None => {
}
}
}
}
impl AddAssign<usize> for OptArgIndexKey {
#[inline]
fn add_assign(&mut self, n: usize) {
match self {
OptArgIndexKey::Constant(_, ref mut o, ..) |
OptArgIndexKey::List(_, ref mut o) |
OptArgIndexKey::Structure(_, ref mut o, ..) => {
*o += n;
}
OptArgIndexKey::None => {
}
}
}
}
#[derive(Debug)]
pub struct ClauseIndexInfo {
pub clause_start: usize,
pub opt_arg_index_key: OptArgIndexKey,
}
impl ClauseIndexInfo {
#[inline]
pub fn new(clause_start: usize) -> Self {
Self {
clause_start,
opt_arg_index_key: OptArgIndexKey::None,
// index_locs: vec![],
}
}
}
#[derive(Debug)]
pub struct PredicateSkeleton {
pub is_discontiguous: bool,
pub is_dynamic: bool,
pub is_multifile: bool,
pub clauses: SliceDeque<ClauseIndexInfo>,
pub clause_clause_locs: SliceDeque<usize>,
}
impl PredicateSkeleton {
#[inline]
pub fn new() -> Self {
PredicateSkeleton {
is_discontiguous: false,
is_dynamic: false,
is_multifile: false,
clauses: sdeq![],
clause_clause_locs: sdeq![],
}
}
/*
#[inline]
pub fn set_discontiguous(self, is_discontiguous: bool) -> Self {
PredicateSkeleton {
is_discontiguous,
is_dynamic: self.is_dynamic,
is_multifile: self.is_multifile,
clauses: self.clauses,
}
}
*/
#[inline]
pub fn set_dynamic(self, is_dynamic: bool) -> Self {
PredicateSkeleton {
is_discontiguous: self.is_discontiguous,
is_dynamic,
is_multifile: self.is_multifile,
clauses: self.clauses,
clause_clause_locs: self.clause_clause_locs,
}
}
/*
#[inline]
pub fn set_multifile(self, is_multifile: bool) -> Self {
PredicateSkeleton {
is_discontiguous: self.is_discontiguous,
is_dynamic: self.is_dynamic,
is_multifile,
clauses: self.clauses,
}
}
*/
}

View File

@@ -45,10 +45,13 @@ impl<'a> HCPreOrderIterator<'a> {
| HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => { | HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => {
Addr::Con(h) Addr::Con(h)
} }
HeapCellValue::LoadStatePayload(_) => {
Addr::LoadStatePayload(h)
}
HeapCellValue::Stream(_) => { HeapCellValue::Stream(_) => {
Addr::Stream(h) Addr::Stream(h)
} }
&HeapCellValue::TcpListener(_) => { HeapCellValue::TcpListener(_) => {
Addr::TcpListener(h) Addr::TcpListener(h)
} }
} }
@@ -175,13 +178,17 @@ impl<'a> Iterator for HCPostOrderIterator<'a> {
} }
&HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => {
match &self.machine_st.heap[h] { match &self.machine_st.heap[h] {
&HeapCellValue::PartialString(ref pstr, _) => { &HeapCellValue::PartialString(..) => {// ref pstr, _) => {
/*
let c = pstr.range_from(n ..).next().unwrap(); let c = pstr.range_from(n ..).next().unwrap();
let next_n = n + c.len_utf8(); let next_n = n + c.len_utf8();
if !pstr.at_end(next_n) { if !pstr.at_end(next_n) {
self.parent_stack.push((2, Addr::PStrLocation(h, next_n))); */
} // self.parent_stack.push((2, Addr::PStrLocation(h, next_n)));
// }
self.parent_stack.push((2, Addr::PStrLocation(h, n)));
} }
_ => { _ => {
unreachable!() unreachable!()

View File

@@ -402,6 +402,7 @@ pub fn requires_space(atom: &str, op: &str) -> bool {
} }
} }
/*
fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict { fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict {
machine_st machine_st
.heap_locs .heap_locs
@@ -414,6 +415,7 @@ fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict {
}) })
.collect() .collect()
} }
*/
fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char) -> bool { fn non_quoted_graphic_token<Iter: Iterator<Item = char>>(mut iter: Iter, c: char) -> bool {
if c == '/' { if c == '/' {
@@ -503,7 +505,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
max_depth: 0, max_depth: 0,
} }
} }
/*
pub fn from_heap_locs( pub fn from_heap_locs(
machine_st: &'a MachineState, machine_st: &'a MachineState,
op_dir: &'a OpDir, op_dir: &'a OpDir,
@@ -520,17 +522,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
printer printer
} }
*/
/*
pub fn drop_toplevel_spec(&mut self) { pub fn drop_toplevel_spec(&mut self) {
self.toplevel_spec = None; self.toplevel_spec = None;
} }
*/
/*
#[inline] #[inline]
pub fn see_all_locs(&mut self) { pub fn see_all_locs(&mut self) {
for key in self.heap_locs.keys().cloned() { for key in self.heap_locs.keys().cloned() {
self.printed_vars.insert(key); self.printed_vars.insert(key);
} }
} }
*/
#[inline] #[inline]
fn ambiguity_check(&self, atom: &str) -> bool { fn ambiguity_check(&self, atom: &str) -> bool {
@@ -1024,7 +1029,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
fn print_rational(&mut self, r: &Rational, add_brackets: bool) { fn print_rational(&mut self, r: &Rational, add_brackets: bool) {
match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) { match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) {
Some(OpDirValue(ref spec, _)) => { Some(OpDirValue(ref spec)) => {
if add_brackets { if add_brackets {
self.state_stack.push(TokenOrRedirect::Close); self.state_stack.push(TokenOrRedirect::Close);
} }

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,7 @@ use crate::prolog_parser::ast::*;
use crate::clause_types::*; use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_errors::MachineStub; use crate::machine::machine_errors::MachineStub;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
@@ -9,7 +10,8 @@ use crate::rug::Integer;
use crate::indexmap::IndexMap; use crate::indexmap::IndexMap;
use std::collections::VecDeque; use slice_deque::SliceDeque;
use std::rc::Rc; use std::rc::Rc;
fn reg_type_into_functor(r: RegType) -> MachineStub { fn reg_type_into_functor(r: RegType) -> MachineStub {
@@ -48,9 +50,9 @@ impl ArithmeticTerm {
#[derive(Debug)] #[derive(Debug)]
pub enum ChoiceInstruction { pub enum ChoiceInstruction {
DefaultRetryMeElse(usize), DefaultRetryMeElse(usize),
DefaultTrustMe, DefaultTrustMe(usize),
RetryMeElse(usize), RetryMeElse(usize),
TrustMe, TrustMe(usize),
TryMeElse(usize), TryMeElse(usize),
} }
@@ -63,14 +65,14 @@ impl ChoiceInstruction {
&ChoiceInstruction::RetryMeElse(offset) => { &ChoiceInstruction::RetryMeElse(offset) => {
functor!("retry_me_else", [integer(offset)]) functor!("retry_me_else", [integer(offset)])
} }
&ChoiceInstruction::TrustMe => { &ChoiceInstruction::TrustMe(offset) => {
functor!("trust_me") functor!("trust_me", [integer(offset)])
} }
&ChoiceInstruction::DefaultRetryMeElse(offset) => { &ChoiceInstruction::DefaultRetryMeElse(offset) => {
functor!("default_retry_me_else", [integer(offset)]) functor!("default_retry_me_else", [integer(offset)])
} }
&ChoiceInstruction::DefaultTrustMe => { &ChoiceInstruction::DefaultTrustMe(offset) => {
functor!("default_trust_me") functor!("default_trust_me", [integer(offset)])
} }
} }
} }
@@ -106,19 +108,13 @@ impl CutInstruction {
} }
} }
#[derive(Debug)] #[derive(Clone, Copy, Debug)]
pub enum IndexedChoiceInstruction { pub enum IndexedChoiceInstruction {
Retry(usize), Retry(usize),
Trust(usize), Trust(usize),
Try(usize), Try(usize),
} }
impl From<IndexedChoiceInstruction> for Line {
fn from(i: IndexedChoiceInstruction) -> Self {
Line::IndexedChoice(i)
}
}
impl IndexedChoiceInstruction { impl IndexedChoiceInstruction {
pub fn offset(&self) -> usize { pub fn offset(&self) -> usize {
match self { match self {
@@ -144,6 +140,26 @@ impl IndexedChoiceInstruction {
} }
/// A `Line` is an instruction (cf. page 98 of wambook). /// A `Line` is an instruction (cf. page 98 of wambook).
#[derive(Debug)]
pub enum IndexingLine {
Indexing(IndexingInstruction),
IndexedChoice(SliceDeque<IndexedChoiceInstruction>),
}
impl From<IndexingInstruction> for IndexingLine {
#[inline]
fn from(instr: IndexingInstruction) -> Self {
IndexingLine::Indexing(instr)
}
}
impl From<SliceDeque<IndexedChoiceInstruction>> for IndexingLine {
#[inline]
fn from(instrs: SliceDeque<IndexedChoiceInstruction>) -> Self {
IndexingLine::IndexedChoice(instrs)
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum Line { pub enum Line {
Arithmetic(ArithmeticInstruction), Arithmetic(ArithmeticInstruction),
@@ -151,12 +167,13 @@ pub enum Line {
Control(ControlInstruction), Control(ControlInstruction),
Cut(CutInstruction), Cut(CutInstruction),
Fact(FactInstruction), Fact(FactInstruction),
Indexing(IndexingInstruction), IndexingCode(Vec<IndexingLine>),
IndexedChoice(IndexedChoiceInstruction), IndexedChoice(IndexedChoiceInstruction),
Query(QueryInstruction), Query(QueryInstruction),
} }
impl Line { impl Line {
#[inline]
pub fn is_head_instr(&self) -> bool { pub fn is_head_instr(&self) -> bool {
match self { match self {
&Line::Cut(_) => true, &Line::Cut(_) => true,
@@ -166,16 +183,64 @@ impl Line {
} }
} }
pub fn to_functor(&self, h: usize) -> MachineStub { pub fn enqueue_functors(&self, mut h: usize, functors: &mut Vec<MachineStub>) {
match self { match self {
&Line::Arithmetic(ref arith_instr) => arith_instr.to_functor(h), &Line::Arithmetic(ref arith_instr) =>
&Line::Choice(ref choice_instr) => choice_instr.to_functor(), functors.push(arith_instr.to_functor(h)),
&Line::Control(ref control_instr) => control_instr.to_functor(), &Line::Choice(ref choice_instr) =>
&Line::Cut(ref cut_instr) => cut_instr.to_functor(h), functors.push(choice_instr.to_functor()),
&Line::Fact(ref fact_instr) => fact_instr.to_functor(h), &Line::Control(ref control_instr) =>
&Line::Indexing(ref indexing_instr) => indexing_instr.to_functor(), functors.push(control_instr.to_functor()),
&Line::IndexedChoice(ref indexed_choice_instr) => indexed_choice_instr.to_functor(), &Line::Cut(ref cut_instr) =>
&Line::Query(ref query_instr) => query_instr.to_functor(h), functors.push(cut_instr.to_functor(h)),
&Line::Fact(ref fact_instr) =>
functors.push(fact_instr.to_functor(h)),
&Line::IndexingCode(ref indexing_instrs) => {
for indexing_instr in indexing_instrs {
match indexing_instr {
IndexingLine::Indexing(indexing_instr) => {
let section = indexing_instr.to_functor(h);
h += section.len();
functors.push(section);
}
IndexingLine::IndexedChoice(indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
let section = indexed_choice_instr.to_functor();
h += section.len();
functors.push(section);
}
}
}
}
}
&Line::IndexedChoice(ref indexed_choice_instr) =>
functors.push(indexed_choice_instr.to_functor()),
&Line::Query(ref query_instr) =>
functors.push(query_instr.to_functor(h)),
}
}
}
#[inline]
pub fn to_indexing_line_mut(line: &mut Line) -> Option<&mut Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref mut indexing_code) => {
Some(indexing_code)
}
_ => {
None
}
}
}
#[inline]
pub fn to_indexing_line(line: &Line) -> Option<&Vec<IndexingLine>> {
match line {
Line::IndexingCode(ref indexing_code) => {
Some(indexing_code)
}
_ => {
None
} }
} }
} }
@@ -386,6 +451,9 @@ pub enum ControlInstruction {
CallClause(ClauseType, usize, usize, bool, bool), CallClause(ClauseType, usize, usize, bool, bool),
Deallocate, Deallocate,
JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call. JmpBy(usize, usize, usize, bool), // arity, global_offset, perm_vars after threshold, last call.
RevJmpBy(usize), // notice the lack of context change as in
// JmpBy. RevJmpBy is used only to patch extensible
// predicates together.
Proceed, Proceed,
} }
@@ -418,6 +486,9 @@ impl ControlInstruction {
&ControlInstruction::JmpBy(_, offset, ..) => { &ControlInstruction::JmpBy(_, offset, ..) => {
functor!("jmp_by", [integer(offset)]) functor!("jmp_by", [integer(offset)])
} }
&ControlInstruction::RevJmpBy(offset) => {
functor!("rev_jmp_by", [integer(offset)])
}
&ControlInstruction::Proceed => { &ControlInstruction::Proceed => {
functor!("proceed") functor!("proceed")
} }
@@ -429,40 +500,94 @@ impl ControlInstruction {
#[derive(Debug)] #[derive(Debug)]
pub enum IndexingInstruction { pub enum IndexingInstruction {
// The first index is the optimal argument being indexed. // The first index is the optimal argument being indexed.
SwitchOnTerm(usize, usize, usize, usize, usize), SwitchOnTerm(usize, usize, IndexingCodePtr, IndexingCodePtr, IndexingCodePtr),
SwitchOnConstant(usize, usize, IndexMap<Constant, usize>), SwitchOnConstant(IndexMap<Constant, IndexingCodePtr>),
SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>), SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>),
}
impl From<IndexingInstruction> for Line {
fn from(i: IndexingInstruction) -> Self {
Line::Indexing(i)
}
} }
impl IndexingInstruction { impl IndexingInstruction {
pub fn to_functor(&self) -> MachineStub { pub fn to_functor(&self, mut h: usize) -> MachineStub {
match self { match self {
&IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => {
functor!( functor!(
"switch_on_term", "switch_on_term",
[integer(arg), [integer(arg),
integer(vars), integer(vars),
integer(constants), indexing_code_ptr(h, constants),
integer(lists), indexing_code_ptr(h, lists),
integer(structures)] indexing_code_ptr(h, structures)]
) )
} }
&IndexingInstruction::SwitchOnConstant(arg, constants, _) => { &IndexingInstruction::SwitchOnConstant(ref constants) => {
let mut key_value_list_stub = vec![];
let orig_h = h;
h += 2; // skip the 2-cell "switch_on_constant" functor.
for (c, ptr) in constants.iter() {
let key_value_pair = functor!(
":",
SharedOpDesc::new(600, XFY),
[constant(c),
indexing_code_ptr(h + 3, *ptr)]
);
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
key_value_list_stub.push(HeapCellValue::Addr(
Addr::HeapCell(h + 3 + key_value_pair.len())
));
h += key_value_pair.len() + 3;
key_value_list_stub.extend(key_value_pair.into_iter());
}
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
functor!( functor!(
"switch_on_constant", "switch_on_constant",
[integer(arg), integer(constants)] [aux(orig_h, 0)],
[key_value_list_stub]
) )
} }
&IndexingInstruction::SwitchOnStructure(arg, structures, _) => { &IndexingInstruction::SwitchOnStructure(ref structures) => {
let mut key_value_list_stub = vec![];
let orig_h = h;
h += 2; // skip the 2-cell "switch_on_constant" functor.
for ((name, arity), ptr) in structures.iter() {
let predicate_indicator_stub = functor!(
"/",
SharedOpDesc::new(400, YFX),
[clause_name(name.clone()),
integer(*arity)]
);
let key_value_pair = functor!(
":",
SharedOpDesc::new(600, XFY),
[aux(h + 3, 0),
indexing_code_ptr(h + 3, *ptr)],
[predicate_indicator_stub]
);
key_value_list_stub.push(HeapCellValue::Addr(Addr::Lis(h + 1)));
key_value_list_stub.push(HeapCellValue::Addr(Addr::Str(h + 3)));
key_value_list_stub.push(HeapCellValue::Addr(
Addr::HeapCell(h + 3 + key_value_pair.len())
));
h += key_value_pair.len() + 3;
key_value_list_stub.extend(key_value_pair.into_iter());
}
key_value_list_stub.push(HeapCellValue::Addr(Addr::EmptyList));
functor!( functor!(
"switch_on_structure", "switch_on_structure",
[integer(arg), integer(structures)] [aux(orig_h, 0)],
[key_value_list_stub]
) )
} }
} }
@@ -710,8 +835,4 @@ impl QueryInstruction {
pub type CompiledFact = Vec<FactInstruction>; pub type CompiledFact = Vec<FactInstruction>;
pub type ThirdLevelIndex = Vec<IndexedChoiceInstruction>;
pub type Code = Vec<Line>; pub type Code = Vec<Line>;
pub type CodeDeque = VecDeque<Line>;

View File

@@ -481,7 +481,7 @@ impl<'a> ChunkedIterator<'a> {
} }
})) }))
} }
/*
pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self { pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self {
ChunkedIterator { ChunkedIterator {
chunk_num: 0, chunk_num: 0,
@@ -490,7 +490,7 @@ impl<'a> ChunkedIterator<'a> {
cut_var_in_head: false, cut_var_in_head: false,
} }
} }
*/
pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self { pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec<QueryTerm>) -> Self {
let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1)));
let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))); let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t)));

View File

@@ -1,4 +1,5 @@
:- module(atts, [op(1199, fx, attribute), call_residue_vars/2, :- module(atts, [op(1199, fx, attribute),
call_residue_vars/2,
term_attributed_variables/2, term_attributed_variables/2,
'$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2, '$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2,
'$put_attr'/2, '$absent_from_list'/2, '$put_attr'/2, '$absent_from_list'/2,
@@ -19,9 +20,7 @@
). ).
'$default_attr_list'([PG | PGs], Module, AttrVar) --> '$default_attr_list'([PG | PGs], Module, AttrVar) -->
( { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)] [Module:put_atts(AttrVar, PG)],
; { true }
),
'$default_attr_list'(PGs, Module, AttrVar). '$default_attr_list'(PGs, Module, AttrVar).
'$default_attr_list'([], _, _) --> []. '$default_attr_list'([], _, _) --> [].
@@ -66,7 +65,8 @@
'$del_attr_step'(Ls1, V, Attr) :- '$del_attr_step'(Ls1, V, Attr) :-
( nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr) ( nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr)
; true ). ; true
).
%% assumptions: Ls0 is a list, Ls1 is its tail; %% assumptions: Ls0 is a list, Ls1 is its tail;
%% the head of Ls0 can be ignored. %% the head of Ls0 can be ignored.
@@ -75,8 +75,8 @@
; Ls1 = [Att | Ls2] -> ; Ls1 = [Att | Ls2] ->
( Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr) ( Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr)
; '$enqueue_attr_var'(V), ; '$enqueue_attr_var'(V),
'$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking. '$del_attr_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking.
'$del_attr_step'(Ls1, V, Attr) '$del_attr_step'(Ls1, V, Attr)
) )
). ).
@@ -88,66 +88,66 @@ user:term_expansion(Term0, Terms) :-
nonvar(Term0), nonvar(Term0),
Term0 = (:- attribute Atts), Term0 = (:- attribute Atts),
nonvar(Atts), nonvar(Atts),
phrase(expand_terms(Atts), Terms). loader:prolog_load_context(module, Module),
phrase(expand_terms(Atts, Module), Terms).
expand_terms(Atts) --> expand_terms(Atts, Module) -->
put_attrs_var_check, put_attrs_var_check,
put_attrs(Atts), put_attrs(Atts, Module),
get_attrs_var_check, get_attrs_var_check,
get_attrs(Atts). get_attrs(Atts, Module).
put_attrs_var_check --> put_attrs_var_check -->
{ numbervars([Var, Attr], 0, _) },
[(put_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), put_atts/2))), [(put_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), put_atts/2))),
(put_atts(Var, Attr) :- var(Attr), throw(error(instantiation_error, put_atts/2)))]. (put_atts(Var, Attr) :- var(Attr), throw(error(instantiation_error, put_atts/2)))].
get_attrs_var_check --> get_attrs_var_check -->
{ numbervars([Var, Ls, Attr], 0, _) },
[(get_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), get_atts/2))), [(get_atts(Var, Attr) :- nonvar(Var), throw(error(type_error(variable, Var), get_atts/2))),
(get_atts(Var, Attr) :- var(Attr), !, '$get_attr_list'(Var, Ls), nonvar(Ls), (get_atts(Var, Attr) :- var(Attr), !, '$get_attr_list'(Var, Ls), nonvar(Ls),
'$copy_attr_list'(Ls, Attr))]. '$copy_attr_list'(Ls, Attr))].
put_attrs(Name/Arity) --> put_attrs(Name/Arity, Module) -->
put_attr(Name, Arity), put_attr(Name, Arity, Module),
{ numbervars([Var, Attr], 0, _) },
[(put_atts(Var, Attr) :- lists:maplist(put_atts(Var), Attr), !)]. [(put_atts(Var, Attr) :- lists:maplist(put_atts(Var), Attr), !)].
put_attrs((Name/Arity, Atts)) --> put_attrs((Name/Arity, Atts), Module) -->
{ nonvar(Atts) }, { nonvar(Atts) },
put_attr(Name, Arity), put_attr(Name, Arity, Module),
put_attrs(Atts). put_attrs(Atts, Module).
get_attrs(Name/Arity) --> get_attrs(Name/Arity, Module) -->
get_attr(Name, Arity). get_attr(Name, Arity, Module).
get_attrs((Name/Arity, Atts)) --> get_attrs((Name/Arity, Atts), Module) -->
{ nonvar(Atts) }, { nonvar(Atts) },
get_attr(Name, Arity), get_attr(Name, Arity, Module),
get_attrs(Atts). get_attrs(Atts, Module).
put_attr(Name, Arity) --> put_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity), { functor(Attr, Name, Arity) },
numbervars(Attr, 0, Arity), [(put_atts(V, +Attr) :-
V = '$VAR'(Arity) }, !,
[(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), functor(Attr, Head, Arity),
functor(AttrForm, Head, Arity), functor(AttrForm, Head, Arity),
'$get_attr_list'(V, Ls), '$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, AttrForm), '$del_attr'(Ls, V, Module:AttrForm),
'$put_attr'(V, Attr)), '$put_attr'(V, Module:Attr)),
(put_atts(V, Attr) :- !, functor(Attr, Head, Arity), (put_atts(V, Attr) :-
functor(AttrForm, Head, Arity), !,
'$get_attr_list'(V, Ls), functor(Attr, Head, Arity),
'$del_attr'(Ls, V, AttrForm), functor(AttrForm, Head, Arity),
'$put_attr'(V, Attr)), '$get_attr_list'(V, Ls),
(put_atts(V, -Attr) :- !, functor(Attr, _, _), '$del_attr'(Ls, V, Module:AttrForm),
'$get_attr_list'(V, Ls), '$put_attr'(V, Module:Attr)),
'$del_attr'(Ls, V, Attr))]. (put_atts(V, -Attr) :-
!,
functor(Attr, _, _),
'$get_attr_list'(V, Ls),
'$del_attr'(Ls, V, Module:Attr))].
get_attr(Name, Arity) --> get_attr(Name, Arity, Module) -->
{ functor(Attr, Name, Arity), { functor(Attr, Name, Arity) },
numbervars(Attr, 0, Arity), [(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)),
V = '$VAR'(Arity) }, (get_atts(V, Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)),
[(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)), (get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Module:Attr))].
(get_atts(V, Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)),
(get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Attr))].
user:goal_expansion(Term, M:put_atts(Var, Attr)) :- user:goal_expansion(Term, M:put_atts(Var, Attr)) :-
nonvar(Term), nonvar(Term),

File diff suppressed because it is too large Load Diff

View File

@@ -17,8 +17,8 @@
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(clpb, [op(300, fy, ~), :- module(clpb, [op(300, fy, ~),
op(500, yfx, #), op(500, yfx, #),
sat/1, sat/1,
taut/2, taut/2,
labeling/1, labeling/1,
sat_count/2, sat_count/2,

View File

@@ -5,13 +5,21 @@
:- use_module(library(error)). :- use_module(library(error)).
:- use_module(library(lists), [append/3]). :- use_module(library(lists), [append/3]).
:- use_module(library(loader), [strip_module/3]).
:- meta_predicate phrase(2, ?).
:- meta_predicate phrase(2, ?, ?).
phrase(GRBody, S0) :- phrase(GRBody, S0) :-
phrase(GRBody, S0, []). phrase(GRBody, S0, []).
phrase(GRBody, S0, S) :- phrase(GRBody, S0, S) :-
( var(GRBody) -> throw(error(instantiation_error, phrase/3)) ( var(GRBody) -> throw(error(instantiation_error, phrase/3))
; dcg_constr(GRBody) -> phrase_(GRBody, S0, S) ; strip_module(GRBody, _, GRBody0),
dcg_constr(GRBody0) ->
phrase_(GRBody0, S0, S)
; functor(GRBody, _, _) -> call(GRBody, S0, S) ; functor(GRBody, _, _) -> call(GRBody, S0, S)
; throw(error(type_error(callable, GRBody), phrase/3)) ; throw(error(type_error(callable, GRBody), phrase/3))
). ).

View File

@@ -2,13 +2,23 @@
:- use_module(library(error)). :- use_module(library(error)).
wam_instructions(Clause, Listing) :- wam_instructions(Clause, Listing) :-
( nonvar(Clause) -> ( nonvar(Clause) ->
Clause = Name / Arity, ( Clause = Name / Arity ->
must_be(atom, Name), fetch_instructions(user, Name, Arity, Listing)
must_be(integer, Arity), ; Clause = Module : (Name / Arity) ->
( Arity >= 0 -> '$wam_instructions'(Name, Arity, Listing) fetch_instructions(Module, Name, Arity, Listing)
; throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2))
) )
; throw(error(instantiation_error, wam_instructions/2)) ; throw(error(instantiation_error, wam_instructions/2))
). ).
fetch_instructions(Module, Name, Arity, Listing) :-
must_be(atom, Module),
must_be(atom, Name),
must_be(integer, Arity),
( Arity >= 0 ->
'$wam_instructions'(Module, Name, Arity, Listing)
; throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2))
).

View File

@@ -8,8 +8,8 @@
put_dif_att(Var, X, Y) :- put_dif_att(Var, X, Y) :-
( get_atts(Var, +dif(Z)) -> ( get_atts(Var, +dif(Z)) ->
sort([X \== Y | Z], NewZ), sort([X \== Y | Z], NewZ),
put_atts(Var, +dif(NewZ)) put_atts(Var, +dif(NewZ))
; put_atts(Var, +dif([X \== Y])) ; put_atts(Var, +dif([X \== Y]))
). ).
@@ -21,8 +21,8 @@ dif_set_variables([Var|Vars], X, Y) :-
append_goals([], _). append_goals([], _).
append_goals([Var|Vars], Goals) :- append_goals([Var|Vars], Goals) :-
( get_atts(Var, +dif(VarGoals)) -> ( get_atts(Var, +dif(VarGoals)) ->
append(Goals, VarGoals, NewGoals0), append(Goals, VarGoals, NewGoals0),
sort(NewGoals0, NewGoals) sort(NewGoals0, NewGoals)
; NewGoals = Goals ; NewGoals = Goals
), ),
put_atts(Var, +dif(NewGoals)), put_atts(Var, +dif(NewGoals)),
@@ -30,8 +30,8 @@ append_goals([Var|Vars], Goals) :-
verify_attributes(Var, Value, Goals) :- verify_attributes(Var, Value, Goals) :-
( get_atts(Var, +dif(Goals)) -> ( get_atts(Var, +dif(Goals)) ->
term_variables(Value, ValueVars), term_variables(Value, ValueVars),
append_goals(ValueVars, Goals) append_goals(ValueVars, Goals)
; Goals = [] ; Goals = []
). ).
@@ -50,7 +50,7 @@ dif(X, Y) :-
gather_dif_goals([]) --> []. gather_dif_goals([]) --> [].
gather_dif_goals([(X \== Y) | Goals]) --> gather_dif_goals([(X \== Y) | Goals]) -->
( { X \= Y } -> [] ( { X \= Y } -> []
; [dif(X, Y)] ; [dif:dif(X, Y)]
), ),
gather_dif_goals(Goals). gather_dif_goals(Goals).

View File

@@ -44,10 +44,10 @@ must_be_(var, Term) :-
). ).
must_be_(integer, Term) :- check_(integer, integer, Term). must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(atom, Term) :- check_(atom, atom, Term). must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(character, character, T). must_be_(character, T) :- check_(error:character, character, T).
must_be_(list, Term) :- check_(ilist, list, Term). must_be_(list, Term) :- check_(error:ilist, list, Term).
must_be_(type, Term) :- check_(type, type, Term). must_be_(type, Term) :- check_(error:type, type, Term).
must_be_(boolean, Term) :- check_(boolean, boolean, Term). must_be_(boolean, Term) :- check_(error:boolean, boolean, Term).
check_(Pred, Type, Term) :- check_(Pred, Type, Term) :-
( var(Term) -> instantiation_error(must_be/2) ( var(Term) -> instantiation_error(must_be/2)

View File

@@ -23,9 +23,9 @@ bb_put(Key, _) :- throw(error(type_error(atom, Key), bb_put/2)).
bb_b_put(Key, NewValue) :- bb_b_put(Key, NewValue) :-
( '$bb_get_with_offset'(Key, OldValue, OldOffset) -> ( '$bb_get_with_offset'(Key, OldValue, OldOffset) ->
call_cleanup((store_global_var_with_offset(Key, NewValue) ; false), call_cleanup((iso_ext:store_global_var_with_offset(Key, NewValue) ; false),
reset_global_var_at_offset(Key, OldValue, OldOffset)) reset_global_var_at_offset(Key, OldValue, OldOffset))
; call_cleanup((store_global_var_with_offset(Key, NewValue) ; false), ; call_cleanup((iso_ext:store_global_var_with_offset(Key, NewValue) ; false),
reset_global_var_at_key(Key)) reset_global_var_at_key(Key))
). ).
@@ -45,11 +45,16 @@ reset_global_var_at_offset(Key, Value, Offset) :- '$reset_global_var_at_offset'(
bb_get(Key, Value) :- atom(Key), !, '$fetch_global_var'(Key, Value). bb_get(Key, Value) :- atom(Key), !, '$fetch_global_var'(Key, Value).
bb_get(Key, _) :- throw(error(type_error(atom, Key), bb_get/2)). bb_get(Key, _) :- throw(error(type_error(atom, Key), bb_get/2)).
:- meta_predicate call_cleanup(:, :).
call_cleanup(G, C) :- setup_call_cleanup(true, G, C). call_cleanup(G, C) :- setup_call_cleanup(true, G, C).
% setup_call_cleanup. % setup_call_cleanup.
:- meta_predicate setup_call_cleanup(:, :, :).
setup_call_cleanup(S, G, C) :- setup_call_cleanup(S, G, C) :-
'$get_b_value'(B), '$get_b_value'(B),
call(S), call(S),
@@ -117,6 +122,8 @@ handle_ile(B, E, _) :-
'$remove_call_policy_check'(B), '$remove_call_policy_check'(B),
'$call_with_default_policy'(throw(E)). '$call_with_default_policy'(throw(E)).
:- meta_predicate call_with_inference_limit(:, ?, ?).
call_with_inference_limit(G, L, R) :- call_with_inference_limit(G, L, R) :-
'$get_current_block'(Bb), '$get_current_block'(Bb),
'$get_b_value'(B), '$get_b_value'(B),

View File

@@ -1,15 +1,29 @@
:- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5, :- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5,
memberchk/2, reverse/2, length/2, maplist/2, memberchk/2, reverse/2, length/2, maplist/2,
maplist/3, maplist/4, maplist/5, maplist/6, maplist/3, maplist/4, maplist/5, maplist/6,
maplist/7, maplist/8, maplist/9, same_length/2, nth0/3, maplist/7, maplist/8, maplist/9, same_length/2, nth0/3,
sum_list/2, transpose/2, list_to_set/2, list_max/2, list_min/2]). sum_list/2, transpose/2, list_to_set/2, list_max/2, list_min/2]).
:- use_module(library(error)). :- use_module(library(error)).
:- meta_predicate maplist(1, ?).
:- meta_predicate maplist(2, ?, ?).
:- meta_predicate maplist(3, ?, ?, ?).
:- meta_predicate maplist(4, ?, ?, ?, ?).
:- meta_predicate maplist(5, ?, ?, ?, ?, ?).
:- meta_predicate maplist(6, ?, ?, ?, ?, ?, ?).
:- meta_predicate maplist(7, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate maplist(8, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate foldl(3, ?, ?, ?).
:- meta_predicate foldl(4, ?, ?, ?, ?).
length(Xs, N) :- length(Xs, N) :-
var(N), !, var(N),
!,
'$skip_max_list'(M, -1, Xs, Xs0), '$skip_max_list'(M, -1, Xs, Xs0),
( Xs0 == [] -> N = M ( Xs0 == [] -> N = M
; var(Xs0) -> length_addendum(Xs0, N, M)). ; var(Xs0) -> length_addendum(Xs0, N, M)).
@@ -66,7 +80,6 @@ reverse([], [], YsRev, YsRev).
reverse([_|Xs], [Y1|Ys], YsPreludeRev, Xss) :- reverse([_|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss). reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
maplist(_, []). maplist(_, []).
maplist(Cont1, [E1|E1s]) :- maplist(Cont1, [E1|E1s]) :-
call(Cont1, E1), call(Cont1, E1),
@@ -87,21 +100,25 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s]) :-
call(Cont, E1, E2, E3, E4), call(Cont, E1, E2, E3, E4),
maplist(Cont, E1s, E2s, E3s, E4s). maplist(Cont, E1s, E2s, E3s, E4s).
maplist(_, [], [], [], [], []). maplist(_, [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :- maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :-
call(Cont, E1, E2, E3, E4, E5), call(Cont, E1, E2, E3, E4, E5),
maplist(Cont, E1s, E2s, E3s, E4s, E5s). maplist(Cont, E1s, E2s, E3s, E4s, E5s).
maplist(_, [], [], [], [], [], []). maplist(_, [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :- maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :-
call(Cont, E1, E2, E3, E4, E5, E6), call(Cont, E1, E2, E3, E4, E5, E6),
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s). maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s).
maplist(_, [], [], [], [], [], [], []). maplist(_, [], [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s]) :- maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s]) :-
call(Cont, E1, E2, E3, E4, E5, E6, E7), call(Cont, E1, E2, E3, E4, E5, E6, E7),
maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s). maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s).
maplist(_, [], [], [], [], [], [], [], []). maplist(_, [], [], [], [], [], [], [], []).
maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :- maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7s], [E8|E8s]) :-
call(Cont, E1, E2, E3, E4, E5, E6, E7, E8), call(Cont, E1, E2, E3, E4, E5, E6, E7, E8),
@@ -111,7 +128,7 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s], [E7|E7
sum_list(Ls, S) :- sum_list(Ls, S) :-
foldl(sum_, Ls, 0, S). foldl(sum_, Ls, 0, S).
sum_(L, S0, S) :- S is S0 + L. sum_(L, S0, S) :- is(S, +(S0, L)).
@@ -132,6 +149,7 @@ foldl_([L|Ls], G_3, A0, A) :-
foldl(Goal_4, Xs, Ys, A0, A) :- foldl(Goal_4, Xs, Ys, A0, A) :-
foldl_(Xs, Ys, Goal_4, A0, A). foldl_(Xs, Ys, Goal_4, A0, A).
foldl_([], [], _, A, A). foldl_([], [], _, A, A).
foldl_([X|Xs], [Y|Ys], G_4, A0, A) :- foldl_([X|Xs], [Y|Ys], G_4, A0, A) :-
call(G_4, X, Y, A0, A1), call(G_4, X, Y, A0, A1),

View File

@@ -0,0 +1,127 @@
:- op(400, yfx, /).
% module resolution operator.
:- op(600, xfy, :).
:- op(1199, fx, meta_predicate).
/* this is an implementation specific declarative operator used to implement call_with_inference_limit/3
and setup_call_cleanup/3. switches to the default trust_me and retry_me_else. Indexing choice
instructions are unchanged. */
:- op(700, fx, non_counted_backtracking).
% arithmetic operators.
:- op(700, xfx, is).
:- op(500, yfx, +).
:- op(500, yfx, -).
:- op(400, yfx, *).
:- op(200, xfy, **).
:- op(200, xfy, ^).
:- op(500, yfx, /\).
:- op(500, yfx, \/).
:- op(500, yfx, xor).
:- op(400, yfx, div).
:- op(400, yfx, //).
:- op(400, yfx, rdiv).
:- op(400, yfx, <<).
:- op(400, yfx, >>).
:- op(400, yfx, mod).
:- op(400, yfx, rem).
:- op(200, fy, +).
:- op(200, fy, -).
:- op(200, fy, \).
% arithmetic comparison operators.
:- op(700, xfx, >).
:- op(700, xfx, <).
:- op(700, xfx, =\=).
:- op(700, xfx, =:=).
:- op(700, xfx, >=).
:- op(700, xfx, =<).
% term comparison.
:- op(700, xfx, ==).
:- op(700, xfx, \==).
:- op(700, xfx, @=<).
:- op(700, xfx, @>=).
:- op(700, xfx, @<).
:- op(700, xfx, @>).
% conditional operators.
:- op(1050, xfy, ->).
:- op(1100, xfy, ;).
% control.
:- op(700, xfx, =).
:- op(700, xfx, =..).
:- op(700, xfx, \=).
:- op(900, fy, \+).
:- op(1200, xfx, -->).
% meta_predicate declarations for call/{0, 64}.
:- meta_predicate call(:).
:- meta_predicate call(:, ?).
:- meta_predicate call(:, ?, ?).
:- meta_predicate call(:, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).
:- meta_predicate call(:, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?).

View File

@@ -5,6 +5,8 @@
map_list_to_pairs/3]). map_list_to_pairs/3]).
:- meta_predicate map_list_to_pairs(:, ?, ?).
pairs_keys_values([], [], []). pairs_keys_values([], [], []).
pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :- pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :-
pairs_keys_values(ABs, As, Bs). pairs_keys_values(ABs, As, Bs).

View File

@@ -75,7 +75,7 @@ wrappers(Name/Arity) -->
atom_concat(Name, ' tabled', WrapName), atom_concat(Name, ' tabled', WrapName),
Head =.. [Name|Args], Head =.. [Name|Args],
WrappedHead =.. [WrapName|Args], WrappedHead =.. [WrapName|Args],
'$module_of'(Module, Name) %prolog_load_context(module, Module) prolog_load_context(module, Module)
}, },
[ ( Head :- [ ( Head :-
start_tabling(Module:Head, WrappedHead) start_tabling(Module:Head, WrappedHead)
@@ -109,10 +109,10 @@ rename_term(Name, WrapName) :-
user:term_expansion(Term0, Clauses) :- user:term_expansion(Term0, Clauses) :-
nonvar(Term0), nonvar(Term0),
Term0 = (:- table Preds), Term0 = (:- table Preds),
phrase(wrappers(Preds), Clauses). phrase(wrappers(Preds), Clauses).
user:term_expansion(Clause, NewClause) :- user:term_expansion(Clause, NewClause) :-
nonvar(Clause), nonvar(Clause),
'$module_of'(Module, Clause), prolog_load_context(module, Module),
rename(Clause, NewClause, Module). rename(Clause, NewClause, Module).

View File

@@ -82,6 +82,8 @@ sleep(T) :-
% '$cpu_now' can be replaced by statistics/2 once that is implemented. % '$cpu_now' can be replaced by statistics/2 once that is implemented.
:- meta_predicate time(:).
time(Goal) :- time(Goal) :-
'$cpu_now'(T0), '$cpu_now'(T0),
setup_call_cleanup(true, setup_call_cleanup(true,

433
src/loader.pl Normal file
View File

@@ -0,0 +1,433 @@
:- module(loader, [consult/1,
expand_goal/3,
expand_term/2,
file_load/2,
load/1,
predicate_property/2,
prolog_load_context/2,
strip_module/3,
use_module/1,
use_module/2
]).
:- use_module(library(error)).
:- use_module(library(lists)).
:- use_module(library(pairs)).
create_file_load_context(Stream, Path, Evacuable) :-
'$push_load_context'(Stream, Path),
'$push_load_state_payload'(Evacuable).
create_load_context(Stream, Evacuable) :-
'$push_load_context'(Stream, ''),
'$push_load_state_payload'(Evacuable).
unload_evacuable(Evacuable) :-
'$pop_load_state_payload'(Evacuable),
'$pop_load_context'.
file_load(Stream, Path) :-
file_load(Stream, Path, _).
file_load(Stream, Path, Evacuable) :-
create_file_load_context(Stream, Path, Evacuable),
catch(loader:load_loop(Stream, Evacuable),
E,
(loader:unload_evacuable(Evacuable), throw(E))),
'$pop_load_context'.
load(Stream) :-
create_load_context(Stream, Evacuable),
catch(loader:load_loop(Stream, Evacuable),
E,
(loader:unload_evacuable(Evacuable), throw(E))),
'$pop_load_context'.
load_loop(Stream, Evacuable) :-
read_term(Stream, Term, [variable_names(VNs), singletons(Singletons)]),
( Term == end_of_file ->
close(Stream),
'$conclude_load'(Evacuable)
; var(Term) ->
instantiation_error(load/1)
; expand_terms_and_goals(Term, Terms),
!,
( var(Terms) ->
instantiation_error(load/1)
; Terms = [_|_] ->
compile_dispatch_or_clause_on_list(Terms, Evacuable, VNs)
; compile_dispatch_or_clause(Terms, Evacuable, VNs)
),
load_loop(Stream, Evacuable)
).
inner_meta_specs((:), HeadArg, InnerHeadArgs, InnerMetaSpecs) :-
!,
predicate_property(HeadArg, meta_predicate(InnerMetaSpecs)),
HeadArg =.. [_ | InnerHeadArgs].
inner_meta_specs(N, HeadArg, InnerHeadArgs, InnerMetaSpecs) :-
integer(N),
N >= 0,
HeadArg =.. [Functor | InnerHeadArgs],
length(InnerHeadArgs1, N),
append(InnerHeadArgs, InnerHeadArgs1, InnerHeadArgs0),
CompleteHeadArg =.. [Functor | InnerHeadArgs0],
predicate_property(CompleteHeadArg, meta_predicate(InnerMetaSpecs)).
module_expanded_head_variables_([], _, HeadVars, HeadVars).
module_expanded_head_variables_([HeadArg | HeadArgs], [MetaSpec | MetaSpecs], HeadVars, HeadVars0) :-
( ( MetaSpec == (:)
; integer(MetaSpec),
MetaSpec >= 0
) ->
( var(HeadArg) ->
HeadVars = [HeadArg-HeadArg | HeadVars1],
module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars1, HeadVars0)
; inner_meta_specs(MetaSpec, HeadArg, InnerHeadArgs, InnerMetaSpecs) ->
module_expanded_head_variables_(InnerHeadArgs, InnerMetaSpecs, HeadVars, HeadVars1),
module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars1, HeadVars0)
; module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, HeadVars0)
)
; module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, HeadVars0)
).
module_expanded_head_variables(Head, MetaSpecs, HeadVars) :-
( var(Head) ->
instantiation_error(load/1)
; predicate_property(Head, meta_predicate(MetaSpecs)),
Head =.. [_ | HeadArgs] ->
module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, [])
; HeadVars = []
).
expand_terms_and_goals(Term, Terms) :-
expand_term(Term, Terms0),
( var(Terms0) ->
instantiation_error(load/1)
; Terms0 = (Head1 :- Body0) ->
( var(Head1) ->
instantiation_error(load/1)
; prolog_load_context(module, Target),
module_expanded_head_variables(Head1, MetaSpecs, HeadVars),
expand_goal(Body0, Target, Body1, HeadVars)
),
Terms = (Head1 :- Body1)
; Terms = Terms0
).
expand_term(UnexpandedTerm, ExpandedTerm) :-
user:term_expansion(UnexpandedTerm, ExpandedTerm).
compile_dispatch_or_clause_on_list([], Evacuable, VNs).
compile_dispatch_or_clause_on_list([Term | Terms], Evacuable, VNs) :-
compile_dispatch_or_clause(Term, Evacuable, VNs),
compile_dispatch_or_clause_on_list(Terms, Evacuable, VNs).
compile_dispatch_or_clause(Term, Evacuable, VNs) :-
( var(Term) ->
instantiation_error(load/1)
; compile_dispatch(Term, Evacuable, VNs) ->
true
;
compile_clause(Term, Evacuable, VNs)
).
compile_dispatch((:- Declaration), Evacuable, _VNs) :-
( var(Declaration) ->
instantiation_error(load/1)
;
compile_declaration(Declaration, Evacuable)
).
compile_dispatch(term_expansion(Term, Terms), Evacuable, VNs) :-
'$add_term_expansion_clause'('$term_expansion'(Term, Terms), Evacuable, VNs).
compile_dispatch((term_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
'$add_term_expansion_clause'(('$term_expansion'(Term, Terms) :- Body), Evacuable, VNs).
compile_dispatch(user:term_expansion(Term, Terms), Evacuable, VNs) :-
'$add_term_expansion_clause'('$term_expansion'(Term, Terms), Evacuable, VNs).
compile_dispatch((user:term_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
'$add_term_expansion_clause'(('$term_expansion'(Term, Terms) :- Body), Evacuable, VNs).
compile_dispatch(goal_expansion(Term, Terms), Evacuable, VNs) :-
prolog_load_context(module, Target),
'$add_goal_expansion_clause'(Target, goal_expansion(Term, Terms), Evacuable, VNs).
compile_dispatch((goal_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
prolog_load_context(module, Target),
'$add_goal_expansion_clause'(Target, (goal_expansion(Term, Terms) :- Body), Evacuable, VNs).
compile_dispatch(Target:goal_expansion(Term, Terms), Evacuable, VNs) :-
'$add_goal_expansion_clause'(Target, goal_expansion(Term, Terms), Evacuable, VNs).
compile_dispatch((Target:goal_expansion(Term, Terms) :- Body), Evacuable, VNs) :-
'$add_goal_expansion_clause'(Target, (goal_expansion(Term, Terms) :- Body), Evacuable, VNs).
compile_declaration(use_module(Module), Evacuable) :-
use_module(Module, [], Evacuable).
compile_declaration(use_module(Module, Exports), Evacuable) :-
( Exports == [] ->
'$remove_module_exports'(Module, Evacuable) % TODO: implement this.
;
use_module(Module, Exports, Evacuable)
).
compile_declaration(module(Module, Exports), Evacuable) :-
( atom(Module) ->
'$declare_module'(Module, Exports, Evacuable)
;
type_error(atom, Module, load/1)
).
compile_declaration(dynamic(Name/Arity), Evacuable) :-
must_be(atom, Name),
must_be(integer, Arity),
'$add_dynamic_predicate'(Name, Arity, Evacuable).
compile_declaration(initialization(Goal), Evacuable) :-
prolog_load_context(module, Module),
'$compile_pending_predicates'(Evacuable),
expand_goal(call(Goal), Module, call(ExpandedGoal)),
call(ExpandedGoal).
compile_clause(Clause, Evacuable, VNs) :-
'$clause_to_evacuable'(Clause, Evacuable, VNs).
prolog_load_context(source, Source) :-
%% The absolute path name of the file being compiled. During
%% loading of a PO file, the corresponding source file name is
%% returned.
'$prolog_lc_source'(Source).
prolog_load_context(file, File) :-
%% Outside included files (see Include Declarations) this is the
%% same as the source key. In included files this is the absolute
%% path name of the file being included.
'$prolog_lc_file'(File).
prolog_load_context(directory, Dir) :-
%% The absolute path name of the directory of the file being
%% compiled/loaded. In included files this is the directory of the
%% file being included.
'$prolog_lc_dir'(Dir).
prolog_load_context(module, Module) :-
%% The source module (see ref-mod-mne). This is useful for example
%% if you are defining clauses for user:term_expansion/6 and need
%% to access the source module at compile time.
'$prolog_lc_module'(Module).
prolog_load_context(stream, Stream) :-
%% The stream being compiled or loaded from.
'$prolog_lc_stream'(Stream).
prolog_load_context(term_position, TermPosition) :-
%% TermPosition represents the stream position of the last term read.
'$prolog_lc_stream'(Stream),
stream_property(Stream, position(TermPosition)).
consult(Item) :-
( atom(Item) -> use_module(Item)
; type_error(atom, Item, consult/1)
).
use_module(Module) :-
'$push_load_state_payload'(Evacuable),
use_module(Module, [], Evacuable).
use_module(Module, Exports) :-
'$push_load_state_payload'(Evacuable),
( Exports == [] ->
'$remove_module_exports'(Module, Evacuable)
;
use_module(Module, Exports, Evacuable)
).
%% If use_module is invoked in an existing load context, use its
%% directory. Otherwise, use the relative path of Path.
load_context_path(Module, Path) :-
( prolog_load_context(directory, CurrentDir) ->
atom_concat(CurrentDir, Path, Module)
;
Module = Path
).
use_module(Module, Exports, Evacuable) :-
( var(Module) ->
instantiation_error(load/1)
; Module = library(Library) ->
( atom(Library) ->
( '$load_compiled_library'(Library, Evacuable) -> %% TODO: What about Exports?
true
;
'$load_library_as_stream'(Library, Stream, Path),
file_load(Stream, Path, Subevacuable),
'$use_module'(Evacuable, Subevacuable, Exports)
)
; var(Library) ->
instantiation_error(load/1)
;
type_error(atom, Library, load/1)
)
; atom(Module) ->
load_context_path(Module, Path),
open(Path, read, Stream),
file_load(Stream, Path, Subevacuable),
'$use_module'(Evacuable, Subevacuable, Exports)
;
type_error(atom, Library, load/1)
).
check_predicate_property(meta_predicate, Name, Arity, MetaPredicateTerm) :-
must_be(atom, Name),
must_be(integer, Arity),
'$cpp_meta_predicate_property'(Name, Arity, MetaPredicateTerm).
predicate_property(Callable, Property) :-
( var(Callable) ->
instantiation_error(load/1)
; functor(Callable, Name, Arity),
( var(Property) ->
true
; functor(Property, PropertyType, _)
),
check_predicate_property(PropertyType, Name, Arity, Property)
).
strip_module_(M0, G0, M1, G1) :-
( nonvar(G0),
G0 = (MG1:G2) ->
strip_module_(MG1, G2, M1, G1)
; M0 = M1,
G0 = G1
).
strip_module(Goal, M, G) :-
strip_module_(_, Goal, M, G).
expand_subgoal(UnexpandedGoals, MS, Module, ExpandedGoals, HeadVars) :-
( var(UnexpandedGoals) ->
UnexpandedGoals = ExpandedGoals
; user:goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
( Module \== user ->
user:goal_expansion(UnexpandedGoals1, user, Goals)
; Goals = UnexpandedGoals1
),
( inner_meta_specs(MS, Goals, _, MetaSpecs) ->
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars)
; Goals = ExpandedGoals
)
; UnexpandedGoals = ExpandedGoals
).
expand_module_name(ESG0, M, ESG) :-
( var(ESG0) ->
ESG = M:ESG0
; ESG0 = _:ESG1 ->
ESG = ESG0
; ESG = M:ESG0
).
expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars) :-
( ( MS == (:)
; integer(MS),
MS >= 0
) ->
( var(SG),
pairs:same_key(SG, HeadVars, [_|_], _) ->
expand_subgoal(SG, MS, M, ESG, HeadVars)
; expand_subgoal(SG, MS, M, ESG0, HeadVars),
expand_module_name(ESG0, M, ESG)
),
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
; ESG = SG,
expand_meta_predicate_subgoals(SGs, MSs, M, ESGs, HeadVars)
).
expand_meta_predicate_subgoals([], _, _, [], _).
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars) :-
Goals =.. [GoalFunctor | SubGoals],
( GoalFunctor == (:) ->
false
; expand_meta_predicate_subgoals(SubGoals, MetaSpecs, Module, ExpandedGoalList, HeadVars),
ExpandedGoals =.. [GoalFunctor | ExpandedGoalList]
).
expand_goal(UnexpandedGoals, Module, ExpandedGoals) :-
expand_goal(UnexpandedGoals, Module, ExpandedGoals, []),
!.
expand_goal(UnexpandedGoals, Module, ExpandedGoals, HeadVars) :-
( var(UnexpandedGoals) ->
UnexpandedGoals = ExpandedGoals
; user:goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1),
( Module \== user ->
user:goal_expansion(UnexpandedGoals1, user, Goals)
; Goals = UnexpandedGoals1
),
( Goals = (Goal0, Goals0) ->
( expand_goal(Goal0, Module, Goal1, HeadVars) ->
expand_goal(Goals0, Module, Goals1, HeadVars),
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
; expand_goal(Goals0, Module, Goals1, HeadVars),
ExpandedGoals = (Goal0, Goals1)
)
; Goals = (Goals0 -> Goals1) ->
expand_goal(Goals0, Module, ExpandedGoals0, HeadVars),
expand_goal(Goals1, Module, ExpandedGoals1, HeadVars),
ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1)
; Goals = (Goals0 ; Goals1) ->
expand_goal(Goals0, Module, ExpandedGoals0, HeadVars),
expand_goal(Goals1, Module, ExpandedGoals1, HeadVars),
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
; Goals = (\+ Goals0) ->
expand_goal(Goals0, Module, Goals1, HeadVars),
ExpandedGoals = (\+ Goals1)
; predicate_property(Goals, meta_predicate(MetaSpecs)) ->
expand_module_names(Goals, MetaSpecs, Module, ExpandedGoals, HeadVars)
; thread_goals(Goals, ExpandedGoals, (','))
; Goals = ExpandedGoals
)
).
thread_goals(Goals0, Goals1, Functor) :-
( var(Goals0) ->
Goals0 = Goals1
; ( Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
)
).
thread_goals(Goals0, Goals1, Hole, Functor) :-
( var(Goals0) ->
Goals0 = Goals1
; ( Goals0 = [G | Gs] ->
( Gs == [] ->
Goals1 =.. [Functor, G, Hole]
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Hole, Functor)
)
; Goals1 =.. [Functor, Goals0, Hole]
)
).

View File

@@ -13,10 +13,16 @@ iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed]
iterate(VarBindings, ValueBindings, ListsCubed). iterate(VarBindings, ValueBindings, ListsCubed).
iterate([], [], []). iterate([], [], []).
/*
gather_modules(Attrs, []) :- var(Attrs), !. gather_modules(Attrs, []) :- var(Attrs), !.
gather_modules([Attr|Attrs], [Module|Modules]) :- gather_modules([Attr|Attrs], [Module|Modules]) :-
'$module_of'(Module, Attr), % write the owning module of Attr to Module. '$module_of'(Module, Attr), % write the owning module of Attr to Module.
gather_modules(Attrs, Modules). gather_modules(Attrs, Modules).
*/
gather_modules(Attrs, []) :- var(Attrs), !.
gather_modules([Module:_|Attrs], [Module|Modules]) :-
gather_modules(Attrs, Modules).
call_verify_attributes(Attrs, _, _, []) :- call_verify_attributes(Attrs, _, _, []) :-
var(Attrs), !. var(Attrs), !.
@@ -24,7 +30,7 @@ call_verify_attributes([], _, _, []).
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :- call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
gather_modules([Attr|Attrs], Modules0), gather_modules([Attr|Attrs], Modules0),
sort(Modules0, Modules), sort(Modules0, Modules),
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists). % verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :- verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals), catch(Module:verify_attributes(Var, Value, Goals),
@@ -33,6 +39,15 @@ verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
verify_attrs(Modules, Var, Value, ListOfGoalLists). verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []). verify_attrs([], _, _, []).
/*
verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :-
catch(Module:verify_attributes(Var, Value, Goals),
error(evaluation_error((Module:verify_attributes)/3), verify_attributes/3),
Goals = []),
verify_attrs(Modules, Var, Value, ListOfGoalLists).
verify_attrs([], _, _, []).
*/
call_goals([ListOfGoalLists | ListsCubed]) :- call_goals([ListOfGoalLists | ListsCubed]) :-
call_goals_0(ListOfGoalLists), call_goals_0(ListOfGoalLists),
call_goals(ListsCubed). call_goals(ListsCubed).

View File

@@ -6,9 +6,6 @@ use crate::indexmap::IndexSet;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::vec::IntoIter; use std::vec::IntoIter;
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
pub static PROJECT_ATTRS: &str = include_str!("project_attributes.pl");
pub(super) type Bindings = Vec<(usize, Addr)>; pub(super) type Bindings = Vec<(usize, Addr)>;
#[derive(Debug)] #[derive(Debug)]
@@ -126,7 +123,7 @@ impl MachineState {
self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp; self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp;
for i in 1 .. self.num_of_args + 1 { for i in 1 .. self.num_of_args + 1 {
self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)].clone(); self.stack.index_and_frame_mut(e)[i] = self[RegType::Temp(i)];
} }
self.stack.index_and_frame_mut(e)[self.num_of_args + 1] = self.stack.index_and_frame_mut(e)[self.num_of_args + 1] =

View File

@@ -1,127 +1,52 @@
use crate::clause_types::*; use crate::clause_types::*;
use crate::codegen::*;
use crate::debray_allocator::*;
use crate::forms::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::indexmap::IndexSet;
use std::collections::VecDeque;
use std::mem;
#[derive(Debug)] #[derive(Debug)]
pub struct CodeRepo { pub struct CodeRepo {
pub(super) cached_query: Code,
pub(super) goal_expanders: Code,
pub(super) term_expanders: Code,
pub(super) code: Code, pub(super) code: Code,
pub(super) in_situ_code: Code,
pub(super) term_dir: TermDir,
} }
impl CodeRepo { impl CodeRepo {
#[inline] #[inline]
pub(super) fn new() -> Self { pub(super)
fn new() -> Self {
CodeRepo { CodeRepo {
cached_query: vec![],
goal_expanders: Code::new(),
term_expanders: Code::new(),
code: Code::new(), code: Code::new(),
in_situ_code: Code::new(),
term_dir: TermDir::new(),
} }
} }
#[inline] #[inline]
pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) { pub(super)
self.term_dir fn lookup_local_instr<'a>(
.get(&key) &'a self,
.map(|entry| ((entry.0).0.len(), entry.1.len())) p: LocalCodePtr,
.unwrap_or((0, 0)) ) -> RefOrOwned<'a, Line> {
} match p {
LocalCodePtr::Halt => {
#[inline] unreachable!()
pub fn truncate_terms(
&mut self,
key: PredicateKey,
len: usize,
queue_len: usize,
) -> (Predicate, VecDeque<TopLevel>) {
self.term_dir
.get_mut(&key)
.map(|entry| {
let terms =
if len < (entry.0).0.len() {
(entry.0).0.drain(len ..).collect()
} else {
vec![]
};
let queue =
if queue_len < entry.1.len() {
entry.1.drain(queue_len ..).collect()
} else {
VecDeque::new()
};
(Predicate(terms), queue)
})
.unwrap_or((Predicate::new(), VecDeque::new()))
}
pub(crate)
fn add_in_situ_result(
&mut self,
result: &CompiledResult,
in_situ_code_dir: &mut InSituCodeDir,
in_situ_module_dir: &mut ModuleStubDir,
non_counted_bt_preds: &IndexSet<PredicateKey>,
) -> Result<(), SessionError> {
let (ref decl, ref queue) = result;
let (name, arity) = decl
.0
.first()
.and_then(|cl| {
let arity = cl.arity();
cl.name().map(|name| (name, arity))
})
.ok_or(SessionError::NamelessEntry)?;
let non_counted_bt = non_counted_bt_preds.contains(&(name.clone(), arity));
let module_name = name.owning_module();
let p = self.in_situ_code.len();
match in_situ_module_dir.get_mut(&module_name) {
Some(ref mut module_stub) if name.has_table(&module_stub.atom_tbl) => {
module_stub.in_situ_code_dir.insert((name, arity), p);
} }
_ => { LocalCodePtr::DirEntry(p) => {
in_situ_code_dir.insert((name, arity), p); RefOrOwned::Borrowed(&self.code[p as usize])
}
LocalCodePtr::IndexingBuf(p, o, i) => {
match &self.code[p] {
&Line::IndexingCode(ref indexing_lines) => {
match &indexing_lines[o] {
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
RefOrOwned::Owned(Line::IndexedChoice(indexed_choice_instrs[i]))
}
_ => {
unreachable!()
}
}
}
_ => {
unreachable!()
}
}
} }
} }
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt);
let mut decl_code = cg.compile_predicate(&decl.0)?;
compile_appendix(&mut decl_code, queue, non_counted_bt)?;
Ok(self.in_situ_code.extend(decl_code.into_iter()))
}
#[inline]
pub(super)
fn size_of_cached_query(&self) -> usize {
self.cached_query.len()
}
#[inline]
pub(super)
fn take_in_situ_code(&mut self) -> Code {
mem::replace(&mut self.in_situ_code, Code::new())
} }
pub(super) pub(super)
@@ -131,32 +56,12 @@ impl CodeRepo {
p: &CodePtr, p: &CodePtr,
) -> Option<RefOrOwned<'a, Line>> { ) -> Option<RefOrOwned<'a, Line>> {
match p { match p {
&CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) => { &CodePtr::Local(local) => {
if p < self.goal_expanders.len() { return Some(self.lookup_local_instr(local));
Some(RefOrOwned::Borrowed(&self.goal_expanders[p]))
} else {
None
}
} }
&CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) => { &CodePtr::REPL(..) => {
if p < self.term_expanders.len() { None
Some(RefOrOwned::Borrowed(&self.term_expanders[p]))
} else {
None
}
} }
&CodePtr::Local(LocalCodePtr::TopLevel(_, p)) => {
if p < self.cached_query.len() {
Some(RefOrOwned::Borrowed(&self.cached_query[p]))
} else {
None
}
}
&CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) => {
Some(RefOrOwned::Borrowed(&self.in_situ_code[p]))
}
&CodePtr::Local(LocalCodePtr::DirEntry(p)) => Some(RefOrOwned::Borrowed(&self.code[p])),
&CodePtr::REPL(..) => None,
&CodePtr::BuiltInClause(ref built_in, _) => { &CodePtr::BuiltInClause(ref built_in, _) => {
let call_clause = call_clause!( let call_clause = call_clause!(
ClauseType::BuiltIn(built_in.clone()), ClauseType::BuiltIn(built_in.clone()),
@@ -164,14 +69,27 @@ impl CodeRepo {
0, 0,
last_call last_call
); );
Some(RefOrOwned::Owned(call_clause)) Some(RefOrOwned::Owned(call_clause))
} }
&CodePtr::CallN(arity, _, last_call) => { &CodePtr::CallN(arity, _, last_call) => {
let call_clause = call_clause!(ClauseType::CallN, arity, 0, last_call); let call_clause = call_clause!(
ClauseType::CallN,
arity,
0,
last_call
);
Some(RefOrOwned::Owned(call_clause)) Some(RefOrOwned::Owned(call_clause))
} }
&CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])), &CodePtr::VerifyAttrInterrupt(p) => {
&CodePtr::DynamicTransaction(..) => None, Some(RefOrOwned::Borrowed(&self.code[p]))
}
/*
&CodePtr::DynamicTransaction(..) => {
None
}
*/
} }
} }
} }

View File

@@ -1,73 +1,39 @@
use crate::instructions::*; use crate::instructions::*;
use std::collections::VecDeque; use indexmap::IndexSet;
fn scan_for_trust_me( fn capture_offset(line: &Line, index: usize, stack: &mut Vec<usize>) -> bool {
code: &Code, match line {
jmp_offsets: &mut VecDeque<usize>, &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => {
before_idx: usize, stack.push(index + offset);
after_idx: &mut usize, }
) { &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) |
// record the location of the line after the TrustMe capping the &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => {
// choice instruction sequence to after_idx. stack.push(index + offset);
loop { }
match &code[*after_idx] { &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
&Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) | stack.push(index + offset);
&Line::Choice(ChoiceInstruction::RetryMeElse(offset)) | }
&Line::IndexedChoice(IndexedChoiceInstruction::Retry(offset)) => { &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
*after_idx += offset; stack.push(index + offset);
} return true;
&Line::Choice(ChoiceInstruction::DefaultTrustMe) | }
&Line::Choice(ChoiceInstruction::TrustMe) | &Line::Control(ControlInstruction::Proceed) |
&Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => { &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => {
break; return true;
} }
_ => { &Line::Control(ControlInstruction::RevJmpBy(offset)) => {
*after_idx += 1; if offset > 0 {
stack.push(index - offset);
} else {
return true;
} }
} }
} _ => {
// search the code in the range for JmpBy instructions and record their
// offsets for future scanning.
for (idx, instr) in code[before_idx .. *after_idx].iter().enumerate() {
match instr {
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
jmp_offsets.push_back(before_idx + idx + offset)
}
_ => {
}
} }
} };
*after_idx += 1; false
}
fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
loop {
match &code[*last_idx] {
&Line::Choice(ChoiceInstruction::TryMeElse(offset)) |
&Line::IndexedChoice(IndexedChoiceInstruction::Try(offset)) => {
let before_idx = *last_idx;
*last_idx += offset;
scan_for_trust_me(code, queue, before_idx, last_idx);
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => {
queue.push_back(*last_idx + offset);
*last_idx += 1;
}
&Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => {
queue.push_back(*last_idx + offset);
break;
}
&Line::Control(ControlInstruction::Proceed) |
&Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) =>
break,
_ =>
*last_idx += 1,
};
}
} }
/* This function walks the code of a single predicate, supposed to /* This function walks the code of a single predicate, supposed to
@@ -76,15 +42,22 @@ fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut u
*/ */
pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line)) pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
{ {
let mut queue = VecDeque::from(vec![p]); let mut stack = vec![p];
let mut visited_indices = IndexSet::new();
while let Some(first_idx) = queue.pop_front() { while let Some(first_index) = stack.pop() {
let mut last_idx = first_idx; if visited_indices.contains(&first_index) {
continue;
} else {
visited_indices.insert(first_index);
}
capture_next_range(code, &mut queue, &mut last_idx); for (index, instr) in code[first_index ..].iter().enumerate() {
for instr in &code[first_idx .. last_idx + 1] {
walker(instr); walker(instr);
if capture_offset(instr, first_index + index, &mut stack) {
break;
}
} }
} }
} }
@@ -92,6 +65,7 @@ pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
/* A function for code walking that might result in modification to /* A function for code walking that might result in modification to
* the code. Otherwise identical to walk_code. * the code. Otherwise identical to walk_code.
*/ */
/*
pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line)) pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
{ {
let mut queue = VecDeque::from(vec![p]); let mut queue = VecDeque::from(vec![p]);
@@ -106,3 +80,4 @@ pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line
} }
} }
} }
*/

File diff suppressed because it is too large Load Diff

View File

@@ -1,396 +0,0 @@
use crate::prolog_parser::ast::*;
use crate::heap_print::*;
use crate::machine::*;
use crate::machine::compile::*;
use crate::machine::machine_errors::*;
use crate::machine::streams::*;
use std::convert::TryFrom;
impl Machine {
pub(super) fn atom_tbl_of(&self, name: &ClauseName) -> TabledData<Atom> {
match name {
&ClauseName::User(ref rc) => rc.table.clone(),
_ => self.indices.atom_tbl(),
}
}
fn compile_into_machine(
&mut self,
src: Stream,
name: ClauseName,
arity: usize,
) -> EvalSession {
match name.owning_module().as_str() {
"user" => match self.indices.code_dir.get(&(name.clone(), arity)).cloned() {
Some(idx) => {
let module = idx.0.borrow().1.clone();
match module.as_str() {
"user" => compile_user_module(self, src, true, ListingSource::User),
_ => compile_into_module(self, module, src, name)
}
}
None => compile_user_module(self, src, true, ListingSource::User),
},
_ => compile_into_module(self, name.owning_module(), src, name),
}
}
fn get_predicate_key(&self, name: RegType, arity: RegType) -> PredicateKey {
let name = self.machine_st[name].clone();
let arity = self.machine_st[arity].clone();
let name = match self.machine_st.store(self.machine_st.deref(name)) {
Addr::Con(h) =>
if let HeapCellValue::Atom(ref name, _) = &self.machine_st.heap[h] {
name.clone()
} else {
unreachable!()
},
_ => unreachable!(),
};
let arity = match self.machine_st.store(self.machine_st.deref(arity)) {
Addr::Con(h) => {
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
}
Addr::Fixnum(arity) => {
usize::try_from(arity).unwrap()
}
Addr::Usize(n) => {
n
}
_ => {
unreachable!()
}
};
(name, arity)
}
fn print_new_dynamic_clause(
&self,
addrs: VecDeque<Addr>,
name: ClauseName,
arity: usize,
) -> String {
let mut output = PrinterOutputter::new();
output.append(format!(":- dynamic({}/{}). ", name.as_str(), arity).as_str());
for addr in addrs {
let mut printer = HCPrinter::new(&self.machine_st, &self.indices.op_dir, output);
printer.quoted = true;
output = printer.print(addr);
output.append(". ");
}
output.result()
}
fn make_undefined(&mut self, name: ClauseName, arity: usize) {
let module_name = name.owning_module();
match self.indices.modules.get(&module_name) {
Some(ref module) => {
if let Some(idx) = module.code_dir.get(&(name.clone(), arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, module_name);
}
}
None => {
}
}
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
}
fn make_undefined_in_module(&mut self, module_name: ClauseName, name: ClauseName, arity: usize) {
if let Some(idx) = self.indices.code_dir.get(&(name, arity)) {
if idx.module_name() == module_name {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
}
}
fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) {
let (name, arity) = self.get_predicate_key(name, arity);
self.make_undefined(name.clone(), arity);
self.indices.remove_code_index((name.clone(), arity));
self.indices.remove_clause_subsection(name.owning_module(), name, arity);
}
fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
let (name, arity) = self.get_predicate_key(name, arity);
let module_addr = self.machine_st[module].clone();
let module_name = match self.machine_st.store(self.machine_st.deref(module_addr)) {
Addr::Con(h) =>
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
match self.indices.modules.get_mut(module) {
Some(ref mut module) => {
module.code_dir.remove(&(name.clone(), arity));
module.module_decl.name.clone()
}
_ => {
self.machine_st.fail = true;
return;
}
}
} else {
unreachable!()
},
_ => unreachable!(),
};
self.make_undefined_in_module(module_name.clone(), name.clone(), arity);
self.indices.remove_code_index((name.clone(), arity));
self.indices.remove_clause_subsection(module_name, name, arity);
}
fn handle_eval_result_from_dynamic_compile(
&mut self,
pred_str: String,
name: ClauseName,
arity: usize,
src: ClauseName,
) {
let machine_st = mem::replace(&mut self.machine_st, MachineState::new());
let result = self.compile_into_machine(
Stream::from(pred_str),
name,
arity,
);
self.machine_st = machine_st;
if let EvalSession::Error(err) = result {
let h = self.machine_st.heap.h();
let stub = MachineError::functor_stub(src, 1);
let err = MachineError::session_error(h, err);
let err = self.machine_st.error_form(err, stub);
self.machine_st.throw_exception(err);
}
}
fn recompile_dynamic_predicate_impl(
&mut self,
place: DynamicAssertPlace,
name: ClauseName,
arity: usize,
) {
let stub = MachineError::functor_stub(place.predicate_name(), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(2), stub) {
Ok(addrs) => {
let mut addrs = VecDeque::from(addrs);
let added_clause = self.machine_st[temp_v!(1)].clone();
place.push_to_queue(&mut addrs, added_clause);
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
place.predicate_name(),
);
}
fn set_module_atom_tbl(&mut self, module_addr: Addr, name: &mut ClauseName) -> bool {
let atom_tbl = match self.machine_st.store(self.machine_st.deref(module_addr)) {
Addr::Con(h) =>
if let HeapCellValue::Atom(ref module, _) = &self.machine_st.heap[h] {
match self.indices.modules.get(module) {
Some(ref module) => module.atom_tbl.clone(),
None => {
self.machine_st.fail = true;
return false;
}
}
} else {
self.machine_st.fail = true;
return false;
},
_ => unreachable!(),
};
if let &mut ClauseName::User(ref mut rc) = name {
rc.table = atom_tbl;
}
true
}
fn recompile_dynamic_predicate_in_module(&mut self, place: DynamicAssertPlace) {
let (mut name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
let module_addr = self.machine_st[temp_v!(5)].clone();
if self.set_module_atom_tbl(module_addr, &mut name) {
self.recompile_dynamic_predicate_impl(place, name, arity);
}
}
fn recompile_dynamic_predicate(&mut self, place: DynamicAssertPlace) {
let (name, arity) = self.get_predicate_key(temp_v!(3), temp_v!(4));
self.recompile_dynamic_predicate_impl(place, name, arity);
}
fn retract_from_dynamic_predicate_in_module(&mut self) {
let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(h) =>
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
Addr::Fixnum(arity) => {
usize::try_from(arity).unwrap()
}
_ => {
unreachable!()
}
};
let (mut name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
let module_addr = self.machine_st[temp_v!(5)].clone();
if self.set_module_atom_tbl(module_addr, &mut name) {
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
Ok(addrs) => {
let mut addrs = VecDeque::from(addrs);
addrs.remove(index);
if addrs.is_empty() {
self.make_undefined(name.clone(), arity);
}
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
clause_name!("retract"),
);
}
}
fn retract_from_dynamic_predicate(&mut self) {
let index = self.machine_st[temp_v!(3)].clone();
let index = match self.machine_st.store(self.machine_st.deref(index)) {
Addr::Con(h) => {
match &self.machine_st.heap[h] {
HeapCellValue::Integer(ref arity) => {
arity.to_usize().unwrap()
}
HeapCellValue::Addr(Addr::Fixnum(arity)) => {
usize::try_from(*arity).unwrap()
}
_ => {
unreachable!()
}
}
}
Addr::Usize(n) => {
n
}
Addr::Fixnum(n) => {
usize::try_from(n).unwrap()
}
_ => {
unreachable!()
}
};
let (name, arity) = self.get_predicate_key(temp_v!(1), temp_v!(2));
let stub = MachineError::functor_stub(clause_name!("retract"), 1);
let pred_str = match self.machine_st.try_from_list(temp_v!(4), stub) {
Ok(addrs) => {
let mut addrs = VecDeque::from(addrs);
addrs.remove(index);
if addrs.is_empty() {
self.make_undefined(name.clone(), arity);
}
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => {
return self.machine_st.throw_exception(err);
}
};
self.handle_eval_result_from_dynamic_compile(
pred_str,
name,
arity,
clause_name!("retract"),
);
}
pub(super) fn dynamic_transaction(
&mut self,
trans_type: DynamicTransactionType,
p: LocalCodePtr,
) {
match trans_type {
DynamicTransactionType::Abolish => {
self.abolish_dynamic_clause(temp_v!(1), temp_v!(2))
}
DynamicTransactionType::Assert(place) => {
self.recompile_dynamic_predicate(place)
}
DynamicTransactionType::ModuleAbolish => {
self.abolish_dynamic_clause_in_module(temp_v!(1), temp_v!(2), temp_v!(3))
}
DynamicTransactionType::ModuleAssert(place) => {
self.recompile_dynamic_predicate_in_module(place)
}
DynamicTransactionType::ModuleRetract => {
self.retract_from_dynamic_predicate_in_module()
}
DynamicTransactionType::Retract => {
self.retract_from_dynamic_predicate()
}
}
self.machine_st.p = CodePtr::Local(p);
}
}

View File

@@ -168,6 +168,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
&HeapCellValue::Integer(ref n) => { &HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone()) HeapCellValue::Integer(n.clone())
} }
&HeapCellValue::LoadStatePayload(_) => {
HeapCellValue::Addr(Addr::LoadStatePayload(h))
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => { &HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone()) HeapCellValue::NamedStr(arity, name.clone(), op.clone())
} }
@@ -295,6 +298,9 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
val @ HeapCellValue::Rational(_) => { val @ HeapCellValue::Rational(_) => {
Addr::Con(self.push(val)) Addr::Con(self.push(val))
} }
val @ HeapCellValue::LoadStatePayload(_) => {
Addr::LoadStatePayload(self.push(val))
}
val @ HeapCellValue::NamedStr(..) => { val @ HeapCellValue::NamedStr(..) => {
Addr::Str(self.push(val)) Addr::Str(self.push(val))
} }
@@ -371,15 +377,6 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
} }
} }
#[inline]
pub(crate)
fn take(&mut self) -> Self {
HeapTemplate {
buf: self.buf.take(),
_marker: PhantomData,
}
}
#[inline] #[inline]
pub(crate) pub(crate)
fn truncate(&mut self, h: usize) { fn truncate(&mut self, h: usize) {
@@ -479,9 +476,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
("dir_entry", 1) => { ("dir_entry", 1) => {
extract_integer(s+1).map(LocalCodePtr::DirEntry) extract_integer(s+1).map(LocalCodePtr::DirEntry)
} }
("in_situ_dir_entry", 1) => { /*
extract_integer(s+1).map(LocalCodePtr::InSituDirEntry)
}
("top_level", 2) => { ("top_level", 2) => {
if let Some(chunk_num) = extract_integer(s+1) { if let Some(chunk_num) = extract_integer(s+1) {
if let Some(p) = extract_integer(s+2) { if let Some(p) = extract_integer(s+2) {
@@ -491,13 +486,10 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
None None
} }
("user_goal_expansion", 1) => { */
extract_integer(s+1).map(LocalCodePtr::UserGoalExpansion) _ => {
None
} }
("user_term_expansion", 1) => {
extract_integer(s+1).map(LocalCodePtr::UserTermExpansion)
}
_ => None
} }
} }
_ => unreachable!() _ => unreachable!()
@@ -508,8 +500,7 @@ impl<T: RawBlockTraits> HeapTemplate<T> {
} }
#[inline] #[inline]
pub pub fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> {
match addr { match addr {
&Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => { &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => {
RefOrOwned::Borrowed(&self[h]) RefOrOwned::Borrowed(&self[h])

918
src/machine/load_state.rs Normal file
View File

@@ -0,0 +1,918 @@
use crate::machine::*;
use crate::machine::machine_indices::*;
use crate::machine::term_stream::*;
use indexmap::IndexSet;
use crate::ref_thread_local::RefThreadLocal;
type ModuleOpExports = Vec<(OpDecl, Option<(usize, Specifier)>)>;
/*
* We will want to borrow these fields from Loader separately, without
* restricting access to other fields by borrowing them mutably.
*/
pub(super) struct LoadState<'a> {
pub(super) compilation_target: CompilationTarget,
pub(super) module_op_exports: ModuleOpExports,
pub(super) retraction_info: RetractionInfo,
pub(super) wam: &'a mut Machine,
}
pub(super)
fn set_code_index(
retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget,
key: PredicateKey,
code_index: &CodeIndex,
code_ptr: IndexPtr,
) {
let record =
match compilation_target {
CompilationTarget::User => {
if IndexPtr::Undefined == code_index.get() {
code_index.set(code_ptr);
RetractionRecord::AddedUserPredicate(key)
} else {
// TODO: emit warning about overwriting previous record
let replaced = code_index.replace(code_ptr);
RetractionRecord::ReplacedUserPredicate(key, replaced)
}
}
CompilationTarget::Module(ref module_name) => {
if IndexPtr::Undefined == code_index.get() {
code_index.set(code_ptr);
RetractionRecord::AddedModulePredicate(module_name.clone(), key)
} else {
// TODO: emit warning about overwriting previous record
let replaced = code_index.replace(code_ptr);
RetractionRecord::ReplacedModulePredicate(module_name.clone(), key, replaced)
}
}
};
retraction_info.push_record(record);
}
fn add_op_decl_as_module_export(
module_op_dir: &mut OpDir,
compilation_target: &CompilationTarget,
retraction_info: &mut RetractionInfo,
wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
op_decl: &OpDecl,
) {
/*
insert the operator at top-level so it can
inform the parser. it will be retracted
from the user-level op_dir when the load
succeeds.
*/
match op_decl.insert_into_op_dir(wam_op_dir) {
Some((prec, spec)) => {
retraction_info.push_record(
RetractionRecord::ReplacedUserOp(op_decl.clone(), prec, spec)
);
module_op_exports.push((op_decl.clone(), Some((prec, spec))));
}
None => {
retraction_info.push_record(
RetractionRecord::AddedUserOp(op_decl.clone())
);
module_op_exports.push((op_decl.clone(), None));
}
}
add_op_decl(retraction_info, compilation_target, module_op_dir, op_decl);
}
pub(super)
fn add_op_decl(
retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget,
op_dir: &mut OpDir,
op_decl: &OpDecl,
) {
match op_decl.insert_into_op_dir(op_dir) {
Some((prec, spec)) => {
match &compilation_target {
CompilationTarget::User => {
retraction_info.push_record(
RetractionRecord::ReplacedUserOp(op_decl.clone(), prec, spec),
);
}
CompilationTarget::Module(ref module_name) => {
retraction_info.push_record(
RetractionRecord::ReplacedModuleOp(
module_name.clone(), op_decl.clone(), prec, spec,
),
);
}
}
}
None => {
match &compilation_target {
CompilationTarget::User => {
retraction_info.push_record(
RetractionRecord::AddedUserOp(op_decl.clone()),
);
}
CompilationTarget::Module(ref module_name) => {
retraction_info.push_record(
RetractionRecord::AddedModuleOp(module_name.clone(), op_decl.clone()),
);
}
}
}
}
}
pub(super)
fn import_module_exports(
retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget,
imported_module: &Module,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir,
) {
for export in imported_module.module_decl.exports.iter() {
match export {
ModuleExport::PredicateKey((ref name, arity)) => {
let key = (name.clone(), *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
meta_predicates.insert(key.clone(), meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
.entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
set_code_index(
retraction_info,
compilation_target,
key,
&target_code_index,
src_code_index.get(),
);
} else {
unreachable!()
}
}
ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(
retraction_info,
compilation_target,
op_dir,
op_decl,
);
}
}
}
}
fn import_module_exports_into_module(
retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget,
imported_module: &Module,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir,
wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports
) {
for export in imported_module.module_decl.exports.iter() {
match export {
ModuleExport::PredicateKey((ref name, arity)) => {
let key = (name.clone(), *arity);
if let Some(meta_specs) = imported_module.meta_predicates.get(&key) {
meta_predicates.insert(key.clone(), meta_specs.clone());
}
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
.entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
set_code_index(
retraction_info,
compilation_target,
key,
&target_code_index,
src_code_index.get(),
);
} else {
unreachable!()
}
}
ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export(
op_dir,
compilation_target,
retraction_info,
wam_op_dir,
module_op_exports,
op_decl,
);
}
}
}
}
fn import_qualified_module_exports(
retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget,
imported_module: &Module,
exports: &IndexSet<ModuleExport>,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
) {
for export in imported_module.module_decl.exports.iter() {
if !exports.contains(export) {
continue;
}
match export {
ModuleExport::PredicateKey((ref name, arity)) => {
let key = (name.clone(), *arity);
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
.entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
set_code_index(
retraction_info,
compilation_target,
key,
&target_code_index,
src_code_index.get(),
);
} else {
unreachable!()
}
}
ModuleExport::OpDecl(ref op_decl) => {
add_op_decl(
retraction_info,
compilation_target,
op_dir,
op_decl,
);
}
}
}
}
fn import_qualified_module_exports_into_module(
retraction_info: &mut RetractionInfo,
compilation_target: &CompilationTarget,
imported_module: &Module,
exports: &IndexSet<ModuleExport>,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
wam_op_dir: &mut OpDir,
module_op_exports: &mut ModuleOpExports,
) {
for export in imported_module.module_decl.exports.iter() {
if !exports.contains(export) {
continue;
}
match export {
ModuleExport::PredicateKey((ref name, arity)) => {
let key = (name.clone(), *arity);
if let Some(src_code_index) = imported_module.code_dir.get(&key) {
let target_code_index = code_dir
.entry(key.clone())
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
set_code_index(
retraction_info,
compilation_target,
key,
&target_code_index,
src_code_index.get(),
);
} else {
unreachable!()
}
}
ModuleExport::OpDecl(ref op_decl) => {
add_op_decl_as_module_export(
op_dir,
compilation_target,
retraction_info,
wam_op_dir,
module_op_exports,
op_decl,
);
}
}
}
}
impl<'a> LoadState<'a> {
#[inline]
pub(super)
fn increment_clause_assert_margin(&mut self, incr: usize) {
match &self.compilation_target {
CompilationTarget::User => {
}
CompilationTarget::Module(ref module_name) => {
self.retraction_info.push_record(
RetractionRecord::IncreasedClauseAssertMargin(
module_name.clone(),
incr,
),
);
self.wam.indices.modules.get_mut(module_name)
.map(|module| module.clause_assert_margin += incr);
}
}
}
#[inline]
pub(super)
fn remove_module_op_exports(&mut self) {
for (mut op_decl, record) in self.module_op_exports.drain(0 ..) {
op_decl.remove(&mut self.wam.indices.op_dir);
if let Some((prec, spec)) = record {
op_decl.prec = prec;
op_decl.spec = spec;
op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir);
}
}
}
fn get_or_insert_local_code_index(
&mut self,
module_name: ClauseName,
key: PredicateKey,
) -> CodeIndex {
match self.wam.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
module.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone()
}
None => {
let mut module = Module::new(
ModuleDecl { name: module_name.clone(), exports: vec![] },
ListingSource::DynamicallyGenerated,
);
let code_index = module.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
self.retraction_info.push_record(
RetractionRecord::AddedModule(module_name.clone()),
);
self.wam.indices.modules.insert(module_name, module);
code_index
}
}
}
pub(super)
fn get_or_insert_code_index(&mut self, key: PredicateKey) -> CodeIndex {
match self.compilation_target.clone() {
CompilationTarget::User => {
self.wam.indices.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone()
}
CompilationTarget::Module(module_name) => {
self.get_or_insert_local_code_index(module_name, key)
}
}
}
pub(super)
fn get_or_insert_qualified_code_index(
&mut self,
module_name: ClauseName,
key: PredicateKey,
) -> CodeIndex {
if module_name.as_str() == "user" {
return self.wam.indices.code_dir
.entry(key)
.or_insert_with(|| CodeIndex::new(IndexPtr::Undefined))
.clone();
} else {
self.get_or_insert_local_code_index(module_name, key)
}
}
#[inline]
pub(super)
fn add_extensible_predicate(&mut self, key: PredicateKey, skeleton: PredicateSkeleton) {
match &self.compilation_target {
CompilationTarget::User => {
self.wam.indices.extensible_predicates.insert(key.clone(), skeleton);
self.retraction_info.push_record(
RetractionRecord::AddedUserExtensiblePredicate(key),
);
}
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.wam.indices.modules.get_mut(module_name) {
module.extensible_predicates.insert(key.clone(), skeleton);
self.retraction_info.push_record(
RetractionRecord::AddedModuleExtensiblePredicate(module_name.clone(), key),
);
} else {
unreachable!()
}
}
}
}
pub(super)
fn add_op_decl(&mut self, op_decl: &OpDecl) {
match &self.compilation_target {
CompilationTarget::User => {
add_op_decl(
&mut self.retraction_info,
&self.compilation_target,
&mut self.wam.indices.op_dir,
op_decl,
);
}
CompilationTarget::Module(ref module_name) => {
match self.wam.indices.modules.get_mut(module_name) {
Some(ref mut module) => {
add_op_decl_as_module_export(
&mut module.op_dir,
&self.compilation_target,
&mut self.retraction_info,
&mut self.wam.indices.op_dir,
&mut self.module_op_exports,
op_decl,
);
}
_ => {
unreachable!()
}
}
}
}
}
pub(super)
fn get_clause_type(
&mut self,
name: ClauseName,
arity: usize,
fixity: Option<SharedOpDesc>,
) -> ClauseType {
match ClauseType::from(name, arity, fixity) {
ClauseType::Named(name, arity, _) => {
let idx = self.get_or_insert_code_index((name.clone(), arity));
ClauseType::Named(name, arity, idx)
}
ClauseType::Op(name, fixity, _) => {
let idx = self.get_or_insert_code_index((name.clone(), arity));
ClauseType::Op(name, fixity, idx)
}
ct => {
ct
}
}
}
pub(super)
fn get_qualified_clause_type(
&mut self,
module_name: ClauseName,
name: ClauseName,
arity: usize,
fixity: Option<SharedOpDesc>,
) -> ClauseType {
match ClauseType::from(name, arity, fixity) {
ClauseType::Named(name, arity, _) => {
let key = (name.clone(), arity);
let idx = self.get_or_insert_qualified_code_index(module_name, key);
ClauseType::Named(name, arity, idx)
}
ClauseType::Op(name, fixity, _) => {
let key = (name.clone(), arity);
let idx = self.get_or_insert_qualified_code_index(module_name, key);
ClauseType::Op(name, fixity, idx)
}
ct => {
ct
}
}
}
#[inline]
pub(super)
fn module_name(&self) -> ClauseName {
match self.compilation_target {
CompilationTarget::User => {
clause_name!("user")
}
CompilationTarget::Module(ref module_name) => {
module_name.clone()
}
}
}
pub(super)
fn add_meta_predicate_record(
&mut self,
module_name: ClauseName,
name: ClauseName,
meta_specs: Vec<MetaSpec>,
) {
let arity = meta_specs.len();
let key = (name, arity);
match module_name.as_str() {
"user" => {
match self.wam.indices.meta_predicates.insert(key.clone(), meta_specs) {
Some(old_meta_specs) => {
self.retraction_info.push_record(
RetractionRecord::ReplacedMetaPredicate(
module_name.clone(), key.0, old_meta_specs,
),
);
}
None => {
self.retraction_info.push_record(
RetractionRecord::AddedMetaPredicate(
module_name.clone(), key,
)
);
}
}
}
_ => {
match self.wam.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
match module.meta_predicates.insert(key.clone(), meta_specs) {
Some(old_meta_specs) => {
self.retraction_info.push_record(
RetractionRecord::ReplacedMetaPredicate(
module_name.clone(), key.0, old_meta_specs,
),
);
}
None => {
self.retraction_info.push_record(
RetractionRecord::AddedMetaPredicate(
module_name.clone(), key,
)
);
}
}
}
None => {
let module_decl = ModuleDecl {
name: module_name.clone(),
exports: vec![],
};
let listing_src = ListingSource::DynamicallyGenerated;
let mut module = Module::new(module_decl, listing_src);
module.meta_predicates.insert(key.clone(), meta_specs);
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);
}
}
}
}
}
fn import_builtins_in_module(
&mut self,
code_dir: &mut CodeDir,
op_dir: &mut OpDir,
meta_predicates: &mut MetaPredicateDir,
) {
if let Some(builtins) = self.wam.indices.modules.get(&clause_name!("builtins")) {
import_module_exports(
&mut self.retraction_info,
&self.compilation_target,
builtins,
code_dir,
op_dir,
meta_predicates,
);
}
}
pub(crate)
fn add_module(&mut self, module_decl: ModuleDecl, listing_src: ListingSource) {
let module_name = module_decl.name.clone();
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
}
None => {
self.retraction_info.push_record(
RetractionRecord::AddedModule(module_name.clone()),
);
Module::new(module_decl, listing_src)
}
};
self.import_builtins_in_module(
&mut module.code_dir,
&mut module.op_dir,
&mut module.meta_predicates,
);
for export in &module.module_decl.exports {
if let ModuleExport::OpDecl(ref op_decl) = export {
add_op_decl_as_module_export(
&mut module.op_dir,
&self.compilation_target, // this is a Module.
&mut self.retraction_info,
&mut self.wam.indices.op_dir,
&mut self.module_op_exports,
op_decl,
);
}
}
if let Some(load_context) = self.wam.load_contexts.last_mut() {
load_context.module = module_name.clone();
}
self.wam.indices.modules.insert(module_name, module);
}
pub(super)
fn import_module(&mut self, module_name: ClauseName) -> Result<(), SessionError> {
if let Some(module) = self.wam.indices.modules.remove(&module_name) {
match &self.compilation_target {
CompilationTarget::User => {
import_module_exports(
&mut self.retraction_info,
&self.compilation_target,
&module,
&mut self.wam.indices.code_dir,
&mut self.wam.indices.op_dir,
&mut self.wam.indices.meta_predicates,
);
}
CompilationTarget::Module(ref defining_module_name) => {
match self.wam.indices.modules.get_mut(defining_module_name) {
Some(ref mut target_module) => {
import_module_exports_into_module(
&mut self.retraction_info,
&self.compilation_target,
&module,
&mut target_module.code_dir,
&mut target_module.op_dir,
&mut target_module.meta_predicates,
&mut self.wam.indices.op_dir,
&mut self.module_op_exports,
);
}
None => {
// we find ourselves here because we're trying to import
// a module into itself as it is being defined.
self.wam.indices.modules.insert(module_name.clone(), module);
return Err(SessionError::ModuleCannotImportSelf(module_name));
}
}
}
}
self.wam.indices.modules.insert(module_name, module);
Ok(())
} else {
Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
}
}
fn import_qualified_module(
&mut self,
module_name: ClauseName,
exports: IndexSet<ModuleExport>,
) -> Result<(), SessionError> {
if let Some(module) = self.wam.indices.modules.remove(&module_name) {
match &self.compilation_target {
CompilationTarget::User => {
import_qualified_module_exports(
&mut self.retraction_info,
&self.compilation_target,
&module,
&exports,
&mut self.wam.indices.code_dir,
&mut self.wam.indices.op_dir,
);
}
CompilationTarget::Module(ref defining_module_name) => {
match self.wam.indices.modules.get_mut(defining_module_name) {
Some(ref mut target_module) => {
import_qualified_module_exports_into_module(
&mut self.retraction_info,
&self.compilation_target,
&module,
&exports,
&mut target_module.code_dir,
&mut target_module.op_dir,
&mut self.wam.indices.op_dir,
&mut self.module_op_exports,
);
}
None => {
// we find ourselves here because we're trying to import
// a module into itself as it is being defined.
self.wam.indices.modules.insert(module_name.clone(), module);
return Err(SessionError::ModuleCannotImportSelf(module_name));
}
}
}
}
self.wam.indices.modules.insert(module_name, module);
Ok(())
} else {
Err(SessionError::ExistenceError(ExistenceError::Module(module_name)))
}
}
pub(crate)
fn use_module(&mut self, module_src: ModuleSource) -> Result<(), SessionError> {
let (stream, listing_src) =
match module_src {
ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(filename.as_str());
path_buf.set_extension("pl");
let file = File::open(&path_buf)?;
(Stream::from_file_as_input(filename.clone(), file),
ListingSource::File(filename, path_buf))
}
ModuleSource::Library(library) => {
match LIBRARIES.borrow().get(library.as_str()) {
Some(code) => {
if let Some(ref module) = self.wam.indices.modules.get(&library) {
if let ListingSource::DynamicallyGenerated = &module.listing_src {
(Stream::from(*code), ListingSource::User)
} else {
return self.import_module(library);
}
} else {
(Stream::from(*code), ListingSource::User)
}
}
None => {
return self.import_module(library);
}
}
}
};
let compilation_target = {
let stream = &mut parsing_stream(stream)?;
let ts = BootstrappingTermStream::from_prolog_stream(
stream,
self.wam.machine_st.atom_tbl.clone(),
self.wam.machine_st.flags,
listing_src,
);
let subloader = Loader::new(ts, self.wam);
subloader.load()?
};
match compilation_target {
CompilationTarget::User => {
// nothing to do.
Ok(())
}
CompilationTarget::Module(module_name) => {
self.import_module(module_name)
}
}
}
pub(crate)
fn use_qualified_module(
&mut self,
module_src: ModuleSource,
exports: IndexSet<ModuleExport>,
) -> Result<(), SessionError> {
let (stream, listing_src) =
match module_src {
ModuleSource::File(filename) => {
let mut path_buf = PathBuf::from(filename.as_str());
path_buf.set_extension("pl");
let file = File::open(&path_buf)?;
(Stream::from_file_as_input(filename.clone(), file),
ListingSource::File(filename, path_buf))
}
ModuleSource::Library(library) => {
match LIBRARIES.borrow().get(library.as_str()) {
Some(code) => {
if self.wam.indices.modules.contains_key(&library) {
return self.import_qualified_module(library, exports);
} else {
(Stream::from(*code), ListingSource::User)
}
}
None => {
return self.import_qualified_module(library, exports);
}
}
}
};
let compilation_target = {
let stream = &mut parsing_stream(stream)?;
let ts = BootstrappingTermStream::from_prolog_stream(
stream,
self.wam.machine_st.atom_tbl.clone(),
self.wam.machine_st.flags,
listing_src,
);
let subloader = Loader::new(ts, self.wam);
subloader.load()?
};
match compilation_target {
CompilationTarget::User => {
// nothing to do.
Ok(())
}
CompilationTarget::Module(module_name) => {
self.import_qualified_module(module_name, exports)
}
}
}
#[inline]
pub(super)
fn composite_op_dir(&self) -> CompositeOpDir {
match &self.compilation_target {
CompilationTarget::User => {
CompositeOpDir::new(&self.wam.indices.op_dir, None)
}
CompilationTarget::Module(ref module_name) => {
match self.wam.indices.modules.get(module_name) {
Some(ref module) => {
CompositeOpDir::new(&self.wam.indices.op_dir, Some(&module.op_dir))
}
None => {
unreachable!()
}
}
}
}
}
}

1708
src/machine/loader.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::*;
use crate::forms::{ModuleSource, Number, PredicateKey}; use crate::forms::{ModuleSource, Number}; //, PredicateKey};
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
@@ -355,24 +355,11 @@ impl MachineError {
} }
} }
pub(super)
fn uninstantiation_error(culprit: Addr) -> Self {
let stub = functor!(
"uninstantiation_error",
[addr(culprit)]
);
MachineError {
stub,
location: None,
from: ErrorProvenance::Received,
}
}
pub(super) pub(super)
fn session_error(h: usize, err: SessionError) -> Self { fn session_error(h: usize, err: SessionError) -> Self {
match err { match err {
SessionError::CannotOverwriteBuiltIn(pred_str) | // SessionError::CannotOverwriteBuiltIn(pred_str) |
/*
SessionError::CannotOverwriteImport(pred_str) => { SessionError::CannotOverwriteImport(pred_str) => {
Self::permission_error( Self::permission_error(
h, h,
@@ -381,12 +368,14 @@ impl MachineError {
functor!(clause_name(pred_str)), functor!(clause_name(pred_str)),
) )
} }
*/
SessionError::ExistenceError(err) => { SessionError::ExistenceError(err) => {
Self::existence_error(h, err) Self::existence_error(h, err)
} }
SessionError::InvalidFileName(filename) => { // SessionError::InvalidFileName(filename) => {
Self::existence_error(h, ExistenceError::Module(filename)) // Self::existence_error(h, ExistenceError::Module(filename))
} // }
/*
SessionError::ModuleDoesNotContainExport(..) => { SessionError::ModuleDoesNotContainExport(..) => {
Self::permission_error( Self::permission_error(
h, h,
@@ -395,6 +384,15 @@ impl MachineError {
functor!("module_does_not_contain_claimed_export"), functor!("module_does_not_contain_claimed_export"),
) )
} }
*/
SessionError::ModuleCannotImportSelf(module_name) => {
Self::permission_error(
h,
Permission::Modify,
"module",
functor!("module_cannot_import_self", [clause_name(module_name)]),
)
}
SessionError::NamelessEntry => { SessionError::NamelessEntry => {
Self::permission_error( Self::permission_error(
h, h,
@@ -411,7 +409,7 @@ impl MachineError {
functor!(clause_name(op)), functor!(clause_name(op)),
) )
} }
SessionError::ParserError(err) => { SessionError::CompilationError(err) => {
Self::syntax_error(h, err) Self::syntax_error(h, err)
} }
SessionError::QueryCannotBeDefinedAsFact => { SessionError::QueryCannotBeDefinedAsFact => {
@@ -426,13 +424,15 @@ impl MachineError {
} }
pub(super) pub(super)
fn syntax_error(h: usize, err: ParserError) -> Self { fn syntax_error<E: Into<CompilationError>>(h: usize, err: E) -> Self {
if let ParserError::Arithmetic(err) = err { let err = err.into();
if let CompilationError::Arithmetic(err) = err {
return Self::arithmetic_error(h, err); return Self::arithmetic_error(h, err);
} }
let location = err.line_and_col_num(); let location = err.line_and_col_num();
let stub = functor!(err.as_str()); let stub = err.as_functor(h);
let stub = functor!( let stub = functor!(
"syntax_error", "syntax_error",
@@ -475,9 +475,103 @@ impl MachineError {
} }
} }
#[derive(Debug)]
pub enum CompilationError {
Arithmetic(ArithmeticError),
ParserError(ParserError),
// BadPendingByte,
CannotParseCyclicTerm,
// ExpandedTermsListNotAList,
ExpectedRel,
// ExpectedTopLevelTerm,
InadmissibleFact,
InadmissibleQueryTerm,
InconsistentEntry,
// InvalidDoubleQuotesDecl,
// InvalidHook,
InvalidMetaPredicateDecl,
InvalidModuleDecl,
InvalidModuleExport,
InvalidRuleHead,
InvalidUseModuleDecl,
InvalidModuleResolution(ClauseName),
UnreadableTerm,
}
impl From<ArithmeticError> for CompilationError {
#[inline]
fn from(err: ArithmeticError) -> CompilationError {
CompilationError::Arithmetic(err)
}
}
impl From<ParserError> for CompilationError {
#[inline]
fn from(err: ParserError) -> CompilationError {
CompilationError::ParserError(err)
}
}
impl CompilationError {
pub fn line_and_col_num(&self) -> Option<(usize, usize)> {
match self {
&CompilationError::ParserError(ref err) =>
err.line_and_col_num(),
_ =>
None
}
}
pub fn as_functor(&self, _h: usize) -> MachineStub {
match self {
&CompilationError::Arithmetic(..) =>
functor!("arithmetic_error"),
// &CompilationError::BadPendingByte =>
// functor!("bad_pending_byte"),
&CompilationError::CannotParseCyclicTerm =>
functor!("cannot_parse_cyclic_term"),
// &CompilationError::ExpandedTermsListNotAList =>
// functor!("expanded_terms_list_is_not_a_list"),
&CompilationError::ExpectedRel =>
functor!("expected_relation"),
// &CompilationError::ExpectedTopLevelTerm =>
// functor!("expected_atom_or_cons_or_clause"),
&CompilationError::InadmissibleFact =>
functor!("inadmissible_fact"),
&CompilationError::InadmissibleQueryTerm =>
functor!("inadmissible_query_term"),
&CompilationError::InconsistentEntry =>
functor!("inconsistent_entry"),
// &CompilationError::InvalidDoubleQuotesDecl =>
// functor!("invalid_double_quotes_declaration"),
// &CompilationError::InvalidHook =>
// functor!("invalid_hook"),
&CompilationError::InvalidMetaPredicateDecl =>
functor!("invalid_meta_predicate_decl"),
&CompilationError::InvalidModuleDecl =>
functor!("invalid_module_declaration"),
&CompilationError::InvalidModuleExport =>
functor!("invalid_module_export"),
&CompilationError::InvalidModuleResolution(ref module_name) =>
functor!(
"no_such_module",
[clause_name(module_name.clone())]
),
&CompilationError::InvalidRuleHead =>
functor!("invalid_head_of_rule"),
&CompilationError::InvalidUseModuleDecl =>
functor!("invalid_use_module_declaration"),
&CompilationError::ParserError(ref err) =>
functor!(err.as_str()),
&CompilationError::UnreadableTerm =>
functor!("unreadable_term"),
}
}
}
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum Permission { pub enum Permission {
Access, // Access,
Create, Create,
InputStream, InputStream,
Modify, Modify,
@@ -490,7 +584,7 @@ impl Permission {
#[inline] #[inline]
pub fn as_str(self) -> &'static str { pub fn as_str(self) -> &'static str {
match self { match self {
Permission::Access => "access", // Permission::Access => "access",
Permission::Create => "create", Permission::Create => "create",
Permission::InputStream => "input", Permission::InputStream => "input",
Permission::Modify => "modify", Permission::Modify => "modify",
@@ -807,37 +901,55 @@ pub enum ExistenceError {
#[derive(Debug)] #[derive(Debug)]
pub enum SessionError { pub enum SessionError {
CannotOverwriteBuiltIn(ClauseName), CompilationError(CompilationError),
CannotOverwriteImport(ClauseName), // CannotOverwriteBuiltIn(ClauseName),
// CannotOverwriteImport(ClauseName),
ExistenceError(ExistenceError), ExistenceError(ExistenceError),
InvalidFileName(ClauseName), // InvalidFileName(ClauseName),
ModuleDoesNotContainExport(ClauseName, PredicateKey), // ModuleDoesNotContainExport(ClauseName, PredicateKey),
ModuleCannotImportSelf(ClauseName),
NamelessEntry, NamelessEntry,
OpIsInfixAndPostFix(ClauseName), OpIsInfixAndPostFix(ClauseName),
QueryCannotBeDefinedAsFact, QueryCannotBeDefinedAsFact,
ParserError(ParserError),
} }
#[derive(Debug)] #[derive(Debug)]
pub enum EvalSession { pub enum EvalSession {
EntrySuccess, // EntrySuccess,
Error(SessionError), Error(SessionError),
} }
impl From<SessionError> for EvalSession { impl From<SessionError> for EvalSession {
#[inline]
fn from(err: SessionError) -> Self { fn from(err: SessionError) -> Self {
EvalSession::Error(err) EvalSession::Error(err)
} }
} }
impl From<std::io::Error> for SessionError {
#[inline]
fn from(err: std::io::Error) -> SessionError {
SessionError::from(ParserError::from(err))
}
}
impl From<ParserError> for SessionError { impl From<ParserError> for SessionError {
#[inline]
fn from(err: ParserError) -> Self { fn from(err: ParserError) -> Self {
SessionError::ParserError(err) SessionError::CompilationError(CompilationError::from(err))
}
}
impl From<CompilationError> for SessionError {
#[inline]
fn from(err: CompilationError) -> Self {
SessionError::CompilationError(err)
} }
} }
impl From<ParserError> for EvalSession { impl From<ParserError> for EvalSession {
#[inline]
fn from(err: ParserError) -> Self { fn from(err: ParserError) -> Self {
EvalSession::from(SessionError::ParserError(err)) EvalSession::from(SessionError::from(err))
} }
} }

View File

@@ -1,9 +1,9 @@
use crate::prolog_parser::ast::*; use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::clause_types::*; use crate::clause_types::*;
use crate::fixtures::*; use crate::fixtures::*;
use crate::forms::*; use crate::forms::*;
use crate::machine::CompilationTarget;
use crate::machine::code_repo::CodeRepo; use crate::machine::code_repo::CodeRepo;
use crate::machine::Ball; use crate::machine::Ball;
use crate::machine::heap::*; use crate::machine::heap::*;
@@ -11,20 +11,21 @@ use crate::machine::machine_state::*;
use crate::machine::partial_string::*; use crate::machine::partial_string::*;
use crate::machine::raw_block::RawBlockTraits; use crate::machine::raw_block::RawBlockTraits;
use crate::machine::streams::Stream; use crate::machine::streams::Stream;
use crate::machine::term_stream::LoadStatePayload;
use crate::instructions::*; use crate::instructions::*;
use crate::ordered_float::OrderedFloat; use crate::ordered_float::OrderedFloat;
use crate::rug::{Integer, Rational}; use crate::rug::{Integer, Rational};
use crate::indexmap::IndexMap; use crate::indexmap::IndexMap;
use std::cell::RefCell; use std::cell::Cell;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet, VecDeque}; use std::collections::{BTreeMap, BTreeSet};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::fmt; use std::fmt;
use std::mem; // use std::mem;
use std::net::TcpListener; use std::net::TcpListener;
use std::ops::{Add, AddAssign, Sub, SubAssign}; use std::ops::{Add, AddAssign, Deref, Sub, SubAssign};
use std::rc::Rc; use std::rc::Rc;
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -64,6 +65,7 @@ pub enum Addr {
Fixnum(isize), Fixnum(isize),
Float(OrderedFloat<f64>), Float(OrderedFloat<f64>),
Lis(usize), Lis(usize),
LoadStatePayload(usize),
HeapCell(usize), HeapCell(usize),
PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes.
StackCell(usize, usize), StackCell(usize, usize),
@@ -231,7 +233,7 @@ impl Addr {
Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => {
Some(TermOrderCategory::Compound) Some(TermOrderCategory::Compound)
} }
Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => { Addr::CutPoint(_) | Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
None None
} }
} }
@@ -369,6 +371,7 @@ pub enum HeapCellValue {
Atom(ClauseName, Option<SharedOpDesc>), Atom(ClauseName, Option<SharedOpDesc>),
DBRef(DBRef), DBRef(DBRef),
Integer(Rc<Integer>), Integer(Rc<Integer>),
LoadStatePayload(LoadStatePayload),
NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one. NamedStr(usize, ClauseName, Option<SharedOpDesc>), // arity, name, precedence/Specifier if it has one.
Rational(Rc<Rational>), Rational(Rc<Rational>),
PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant. PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant.
@@ -387,6 +390,9 @@ impl HeapCellValue {
HeapCellValue::Rational(..) => { HeapCellValue::Rational(..) => {
Addr::Con(focus) Addr::Con(focus)
} }
HeapCellValue::LoadStatePayload(_) => {
Addr::LoadStatePayload(focus)
}
HeapCellValue::NamedStr(_, _, _) => { HeapCellValue::NamedStr(_, _, _) => {
Addr::Str(focus) Addr::Str(focus)
} }
@@ -417,6 +423,9 @@ impl HeapCellValue {
&HeapCellValue::Integer(ref n) => { &HeapCellValue::Integer(ref n) => {
HeapCellValue::Integer(n.clone()) HeapCellValue::Integer(n.clone())
} }
&HeapCellValue::LoadStatePayload(_) => {
HeapCellValue::Atom(clause_name!("$live_term_stream"), None)
}
&HeapCellValue::NamedStr(arity, ref name, ref op) => { &HeapCellValue::NamedStr(arity, ref name, ref op) => {
HeapCellValue::NamedStr(arity, name.clone(), op.clone()) HeapCellValue::NamedStr(arity, name.clone(), op.clone())
} }
@@ -443,50 +452,42 @@ impl From<Addr> for HeapCellValue {
} }
} }
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] #[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub enum IndexPtr { pub enum IndexPtr {
DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined.
Undefined,
InSituDirEntry(usize),
Index(usize), Index(usize),
UserGoalExpansion, Undefined,
UserTermExpansion
} }
#[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>); pub struct CodeIndex(pub Rc<Cell<IndexPtr>>);
impl Deref for CodeIndex {
type Target = Cell<IndexPtr>;
#[inline]
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl CodeIndex { impl CodeIndex {
#[inline] #[inline]
pub fn new(ptr: IndexPtr, module_name: ClauseName) -> Self { pub(super)
CodeIndex(Rc::new(RefCell::new(( ptr, module_name )))) fn new(ptr: IndexPtr) -> Self {
CodeIndex(Rc::new(Cell::new(ptr)))
} }
#[inline] #[inline]
pub fn is_undefined(&self) -> bool { pub fn is_undefined(&self) -> bool {
let index_ptr = &self.0.borrow().0; match self.0.get() {
IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true,
match index_ptr {
&IndexPtr::Undefined | &IndexPtr::DynamicUndefined => true,
_ => false _ => false
} }
} }
#[inline]
pub fn dynamic_undefined(module_name: ClauseName) -> Self {
CodeIndex(Rc::new(RefCell::new((
IndexPtr::DynamicUndefined,
module_name
))))
}
#[inline]
pub fn module_name(&self) -> ClauseName {
self.0.borrow().1.clone()
}
pub fn local(&self) -> Option<usize> { pub fn local(&self) -> Option<usize> {
match self.0.borrow().0 { match self.0.get() {
IndexPtr::Index(i) => Some(i), IndexPtr::Index(i) => Some(i),
_ => None, _ => None,
} }
@@ -495,60 +496,34 @@ impl CodeIndex {
impl Default for CodeIndex { impl Default for CodeIndex {
fn default() -> Self { fn default() -> Self {
CodeIndex(Rc::new(RefCell::new(( CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined)))
IndexPtr::Undefined,
clause_name!(""),
))))
} }
} }
impl From<(usize, ClauseName)> for CodeIndex {
fn from(value: (usize, ClauseName)) -> Self {
CodeIndex(Rc::new(RefCell::new((IndexPtr::Index(value.0), value.1))))
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DynamicAssertPlace {
Back,
Front,
}
impl DynamicAssertPlace {
#[inline]
pub fn predicate_name(self) -> ClauseName {
match self {
DynamicAssertPlace::Back => clause_name!("assertz"),
DynamicAssertPlace::Front => clause_name!("asserta"),
}
}
#[inline]
pub fn push_to_queue(self, addrs: &mut VecDeque<Addr>, new_addr: Addr) {
match self {
DynamicAssertPlace::Back => addrs.push_back(new_addr),
DynamicAssertPlace::Front => addrs.push_front(new_addr),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum DynamicTransactionType {
Abolish,
Assert(DynamicAssertPlace),
ModuleAbolish,
ModuleAssert(DynamicAssertPlace),
ModuleRetract,
Retract, // dynamic index of the clause to remove.
}
#[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum REPLCodePtr { pub enum REPLCodePtr {
CompileBatch, AddDynamicPredicate,
AddGoalExpansionClause,
AddTermExpansionClause,
ClauseToEvacuable,
ConcludeLoad,
DeclareModule,
LoadCompiledLibrary,
LoadContextSource,
LoadContextFile,
LoadContextDirectory,
LoadContextModule,
LoadContextStream,
PopLoadContext,
PopLoadStatePayload,
PushLoadContext,
PushLoadStatePayload,
UseModule, UseModule,
UseQualifiedModule, MetaPredicateProperty,
UseModuleFromFile, CompilePendingPredicates,
UseQualifiedModuleFromFile UserAsserta,
UserAssertz,
UserRetract,
} }
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@@ -556,7 +531,7 @@ pub enum CodePtr {
BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call.
CallN(usize, LocalCodePtr, bool), // arity, local, last call. CallN(usize, LocalCodePtr, bool), // arity, local, last call.
Local(LocalCodePtr), Local(LocalCodePtr),
DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer. // DynamicTransaction(DynamicTransactionType, LocalCodePtr), // the type of transaction, the return pointer.
REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer. REPL(REPLCodePtr, LocalCodePtr), // the REPL code, the return pointer.
VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir.
} }
@@ -568,18 +543,26 @@ impl CodePtr {
| &CodePtr::CallN(_, ref local, _) | &CodePtr::CallN(_, ref local, _)
| &CodePtr::Local(ref local) => local.clone(), | &CodePtr::Local(ref local) => local.clone(),
&CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p), &CodePtr::VerifyAttrInterrupt(p) => LocalCodePtr::DirEntry(p),
&CodePtr::REPL(_, p) | &CodePtr::DynamicTransaction(_, p) => p, &CodePtr::REPL(_, p) => p // | &CodePtr::DynamicTransaction(_, p) => p,
}
}
#[inline]
pub fn is_halt(&self) -> bool {
if let CodePtr::Local(LocalCodePtr::Halt) = self {
true
} else {
false
} }
} }
} }
#[derive(Copy, Clone, Debug, PartialEq)] #[derive(Copy, Clone, Debug, PartialEq)]
pub enum LocalCodePtr { pub enum LocalCodePtr {
DirEntry(usize), // offset. DirEntry(usize), // offset
InSituDirEntry(usize), Halt,
TopLevel(usize, usize), // chunk_num, offset. IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset
UserGoalExpansion(usize), // TopLevel(usize, usize), // chunk_num, offset
UserTermExpansion(usize),
} }
impl LocalCodePtr { impl LocalCodePtr {
@@ -591,6 +574,16 @@ impl LocalCodePtr {
} }
} }
#[inline]
pub(crate)
fn abs_loc(&self) -> usize {
match self {
LocalCodePtr::DirEntry(ref p) => *p,
LocalCodePtr::IndexingBuf(ref p, ..) => *p,
LocalCodePtr::Halt => unreachable!(),
}
}
pub(crate) pub(crate)
fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool { fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool {
match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) { match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) {
@@ -621,28 +614,21 @@ impl LocalCodePtr {
[integer(*p)] [integer(*p)]
)); ));
} }
LocalCodePtr::InSituDirEntry(p) => { LocalCodePtr::Halt => {
heap.append(functor!( heap.append(functor!("halt"));
"in_situ_dir_entry",
[integer(*p)]
));
} }
/*
LocalCodePtr::TopLevel(chunk_num, offset) => { LocalCodePtr::TopLevel(chunk_num, offset) => {
heap.append(functor!( heap.append(functor!(
"top_level", "top_level",
[integer(*chunk_num), integer(*offset)] [integer(*chunk_num), integer(*offset)]
)); ));
} }
LocalCodePtr::UserGoalExpansion(p) => { */
LocalCodePtr::IndexingBuf(p, o, i) => {
heap.append(functor!( heap.append(functor!(
"user_goal_expansion", "indexed_buf",
[integer(*p)] [integer(*p), integer(*o), integer(*i)]
));
}
LocalCodePtr::UserTermExpansion(p) => {
heap.append(functor!(
"user_term_expansion",
[integer(*p)]
)); ));
} }
} }
@@ -651,6 +637,7 @@ impl LocalCodePtr {
} }
} }
/*
impl PartialOrd<CodePtr> for CodePtr { impl PartialOrd<CodePtr> for CodePtr {
fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> { fn partial_cmp(&self, other: &CodePtr) -> Option<Ordering> {
match (self, other) { match (self, other) {
@@ -667,11 +654,8 @@ impl PartialOrd<CodePtr> for CodePtr {
impl PartialOrd<LocalCodePtr> for LocalCodePtr { impl PartialOrd<LocalCodePtr> for LocalCodePtr {
fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> { fn partial_cmp(&self, other: &LocalCodePtr) -> Option<Ordering> {
match (self, other) { match (self, other) {
(&LocalCodePtr::InSituDirEntry(p1), &LocalCodePtr::InSituDirEntry(ref p2)) (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) |
| (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
| (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2))
| (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2))
| (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => {
p1.partial_cmp(p2) p1.partial_cmp(p2)
} }
(_, &LocalCodePtr::TopLevel(_, _)) => { (_, &LocalCodePtr::TopLevel(_, _)) => {
@@ -683,29 +667,34 @@ impl PartialOrd<LocalCodePtr> for LocalCodePtr {
} }
} }
} }
*/
impl Default for CodePtr { impl Default for CodePtr {
#[inline]
fn default() -> Self { fn default() -> Self {
CodePtr::Local(LocalCodePtr::default()) CodePtr::Local(LocalCodePtr::default())
} }
} }
impl Default for LocalCodePtr { impl Default for LocalCodePtr {
#[inline]
fn default() -> Self { fn default() -> Self {
LocalCodePtr::TopLevel(0, 0) LocalCodePtr::DirEntry(0)
} }
} }
impl Add<usize> for LocalCodePtr { impl Add<usize> for LocalCodePtr {
type Output = LocalCodePtr; type Output = LocalCodePtr;
#[inline]
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
LocalCodePtr::InSituDirEntry(p) => LocalCodePtr::InSituDirEntry(p + rhs), LocalCodePtr::DirEntry(p) =>
LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs), LocalCodePtr::DirEntry(p + rhs),
LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::TopLevel(cn, p + rhs), LocalCodePtr::Halt =>
LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::UserTermExpansion(p + rhs), unreachable!(),
LocalCodePtr::UserGoalExpansion(p) => LocalCodePtr::UserGoalExpansion(p + rhs), LocalCodePtr::IndexingBuf(p, o, i) =>
LocalCodePtr::IndexingBuf(p, o, i + rhs),
} }
} }
} }
@@ -713,30 +702,40 @@ impl Add<usize> for LocalCodePtr {
impl Sub<usize> for LocalCodePtr { impl Sub<usize> for LocalCodePtr {
type Output = Option<LocalCodePtr>; type Output = Option<LocalCodePtr>;
#[inline]
fn sub(self, rhs: usize) -> Self::Output { fn sub(self, rhs: usize) -> Self::Output {
match self { match self {
LocalCodePtr::InSituDirEntry(p) =>
p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry),
LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p) =>
p.checked_sub(rhs).map(LocalCodePtr::DirEntry), p.checked_sub(rhs).map(LocalCodePtr::DirEntry),
LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::Halt =>
p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)), unreachable!(),
LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::IndexingBuf(p, o, i) =>
p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion), i.checked_sub(rhs).map(|r| LocalCodePtr::IndexingBuf(p, o, r)),
LocalCodePtr::UserGoalExpansion(p) =>
p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion),
} }
} }
} }
impl SubAssign<usize> for LocalCodePtr {
#[inline]
fn sub_assign(&mut self, rhs: usize) {
match self {
LocalCodePtr::DirEntry(ref mut p) =>
*p -= rhs,
LocalCodePtr::Halt | LocalCodePtr::IndexingBuf(..) =>
unreachable!(),
}
}
}
impl AddAssign<usize> for LocalCodePtr { impl AddAssign<usize> for LocalCodePtr {
#[inline]
fn add_assign(&mut self, rhs: usize) { fn add_assign(&mut self, rhs: usize) {
match self { match self {
&mut LocalCodePtr::InSituDirEntry(ref mut p) &mut LocalCodePtr::DirEntry(ref mut p) /* |
| &mut LocalCodePtr::UserGoalExpansion(ref mut p) &mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs,
| &mut LocalCodePtr::UserTermExpansion(ref mut p) &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs,
| &mut LocalCodePtr::DirEntry(ref mut p) &mut LocalCodePtr::Halt => unreachable!(),
| &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs,
} }
} }
} }
@@ -746,10 +745,14 @@ impl Add<usize> for CodePtr {
fn add(self, rhs: usize) -> Self::Output { fn add(self, rhs: usize) -> Self::Output {
match self { match self {
p @ CodePtr::REPL(..) p @ CodePtr::REPL(..) |
| p @ CodePtr::VerifyAttrInterrupt(_) p @ CodePtr::VerifyAttrInterrupt(_) => { // |
| p @ CodePtr::DynamicTransaction(..) => p, // p @ CodePtr::DynamicTransaction(..) => {
CodePtr::Local(local) => CodePtr::Local(local + rhs), p
}
CodePtr::Local(local) => {
CodePtr::Local(local + rhs)
}
CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => {
CodePtr::Local(local + rhs) CodePtr::Local(local + rhs)
} }
@@ -767,186 +770,206 @@ impl AddAssign<usize> for CodePtr {
} }
} }
pub type HeapVarDict = IndexMap<Rc<Var>, Addr>; impl SubAssign<usize> for CodePtr {
pub type AllocVarDict = IndexMap<Rc<Var>, VarData>; #[inline]
fn sub_assign(&mut self, rhs: usize) {
#[derive(Debug, Clone)] match self {
pub struct DynamicPredicateInfo { CodePtr::Local(ref mut local) => *local -= rhs,
pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value. _ => unreachable!(),
}
impl Default for DynamicPredicateInfo {
fn default() -> Self {
DynamicPredicateInfo {
clauses_subsection_p: 0,
} }
} }
} }
pub type HeapVarDict = IndexMap<Rc<Var>, Addr>;
pub type AllocVarDict = IndexMap<Rc<Var>, VarData>;
pub type InSituCodeDir = IndexMap<PredicateKey, usize>; pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
// key type: module name, predicate indicator.
pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>;
pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>; pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
#[derive(Debug)] #[derive(Debug)]
pub(crate) struct ModuleStub { pub(crate) struct ModuleStub {
pub(crate) atom_tbl: TabledData<Atom>,
pub(crate) in_situ_code_dir: InSituCodeDir, pub(crate) in_situ_code_dir: InSituCodeDir,
} }
impl ModuleStub { // pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
pub(crate) fn new(atom_tbl: TabledData<Atom>) -> Self {
ModuleStub {
atom_tbl,
in_situ_code_dir: InSituCodeDir::new(),
}
}
}
pub(crate) type ModuleStubDir = IndexMap<ClauseName, ModuleStub>;
pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>; pub(crate) type StreamAliasDir = IndexMap<ClauseName, Stream>;
pub(crate) type StreamDir = BTreeSet<Stream>; pub(crate) type StreamDir = BTreeSet<Stream>;
pub type MetaPredicateDir = IndexMap<PredicateKey, Vec<MetaSpec>>;
pub type ExtensiblePredicates = IndexMap<PredicateKey, PredicateSkeleton>;
#[derive(Debug)] #[derive(Debug)]
pub struct IndexStore { pub struct IndexStore {
pub(super) atom_tbl: TabledData<Atom>,
pub(super) code_dir: CodeDir, pub(super) code_dir: CodeDir,
pub(super) dynamic_code_dir: DynamicCodeDir, pub(super) extensible_predicates: ExtensiblePredicates,
pub(super) global_variables: GlobalVarDir, pub(super) global_variables: GlobalVarDir,
pub(super) in_situ_code_dir: InSituCodeDir, pub(super) meta_predicates: MetaPredicateDir,
pub(super) in_situ_module_dir: ModuleStubDir,
pub(super) module_dir: ModuleDir,
pub(super) modules: ModuleDir, pub(super) modules: ModuleDir,
pub(super) op_dir: OpDir, pub(super) op_dir: OpDir,
pub(super) streams: StreamDir, pub(super) streams: StreamDir,
pub(super) stream_aliases: StreamAliasDir, pub(super) stream_aliases: StreamAliasDir,
} }
impl Default for IndexStore {
#[inline]
fn default() -> Self {
index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new())
}
}
impl IndexStore { impl IndexStore {
pub fn predicate_exists( pub fn get_predicate_skeleton(
&self, &mut self,
name: ClauseName, compilation_target: &CompilationTarget,
module: ClauseName, key: &PredicateKey,
arity: usize, ) -> Option<&mut PredicateSkeleton> {
op_spec: Option<SharedOpDesc>, match (key.0.as_str(), key.1) {
) -> bool { ("term_expansion", 2) => {
match self.modules.get(&module) { self.extensible_predicates.get_mut(key)
Some(module) => match ClauseType::from(name, arity, op_spec) { }
ClauseType::Named(name, arity, _) => module.code_dir.contains_key(&(name, arity)), _ => {
ClauseType::Op(name, spec, ..) => { match compilation_target {
module.code_dir.contains_key(&(name, spec.arity())) CompilationTarget::User => {
self.extensible_predicates.get_mut(key)
}
CompilationTarget::Module(ref module_name) => {
if let Some(module) = self.modules.get_mut(module_name) {
module.extensible_predicates.get_mut(key)
} else {
None
}
}
} }
_ => true, }
},
None => match ClauseType::from(name, arity, op_spec) {
ClauseType::Named(name, arity, _) => self.code_dir.contains_key(&(name, arity)),
ClauseType::Op(name, spec, ..) => self.code_dir.contains_key(&(name, spec.arity())),
_ => true,
},
} }
} }
pub fn add_term_and_goal_expansion_indices(&mut self) { pub fn remove_predicate_skeleton(
self.code_dir.insert((clause_name!("term_expansion"), 2), &mut self,
CodeIndex(Rc::new(RefCell::new( compilation_target: &CompilationTarget,
(IndexPtr::UserTermExpansion, key: &PredicateKey,
clause_name!("user")) ) {
)))); match (key.0.as_str(), key.1) {
self.code_dir.insert((clause_name!("goal_expansion"), 2), ("term_expansion", 2) => {
CodeIndex(Rc::new(RefCell::new( self.extensible_predicates.remove(key);
(IndexPtr::UserGoalExpansion, },
clause_name!("user")) _ => {
)))); match compilation_target {
CompilationTarget::User => {
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);
}
}
}
}
}
} }
#[inline] pub fn get_predicate_code_index(
pub fn remove_clause_subsection(&mut self, module: ClauseName, name: ClauseName, arity: usize) {
self.dynamic_code_dir.swap_remove(&(module, name, arity));
}
#[inline]
pub fn get_clause_subsection(
&self, &self,
module: ClauseName,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
) -> Option<DynamicPredicateInfo> { module: ClauseName,
self.dynamic_code_dir.get(&(module, name, arity)).cloned() op_spec: Option<SharedOpDesc>,
) -> Option<CodeIndex> {
if module.as_str() == "user" {
match ClauseType::from(name, arity, op_spec) {
ClauseType::Named(name, arity, _) => {
self.code_dir.get(&(name, arity)).cloned()
}
ClauseType::Op(name, spec, ..) => {
self.code_dir.get(&(name, spec.arity())).cloned()
}
_ => {
None
}
}
} else {
self.modules.get(&module).and_then(|module| {
match ClauseType::from(name, arity, op_spec) {
ClauseType::Named(name, arity, _) => {
module.code_dir.get(&(name, arity)).cloned()
}
ClauseType::Op(name, spec, ..) => {
module.code_dir.get(&(name, spec.arity())).cloned()
}
_ => {
None
}
}
})
}
} }
#[inline] pub fn get_meta_predicate_spec(
pub(crate) fn take_in_situ_module_dir(&mut self) -> ModuleStubDir { &self,
mem::replace(&mut self.in_situ_module_dir, ModuleStubDir::new()) name: ClauseName,
arity: usize,
compilation_target: &CompilationTarget,
) -> Option<&Vec<MetaSpec>> {
match compilation_target {
CompilationTarget::User => {
self.meta_predicates.get(&(name, arity))
}
CompilationTarget::Module(ref module_name) => {
match self.modules.get(module_name) {
Some(ref module) => {
module.meta_predicates.get(&(name.clone(), arity))
.or_else(|| {
self.meta_predicates.get(&(name, arity))
})
}
None => {
self.meta_predicates.get(&(name, arity))
}
}
}
}
} }
#[inline] pub fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool {
pub fn take_in_situ_code_dir(&mut self) -> InSituCodeDir { match module_name.as_str() {
mem::replace(&mut self.in_situ_code_dir, InSituCodeDir::new()) "user" => {
} self.extensible_predicates.get(&key)
.map(|skeleton| skeleton.is_dynamic)
#[inline] .unwrap_or(false)
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> { }
self.modules.swap_remove(&name) _ => {
} match self.modules.get(&module_name) {
Some(ref module) => {
#[inline] module.extensible_predicates.get(&key)
pub fn insert_module(&mut self, module: Module) { .map(|skeleton| skeleton.is_dynamic)
self.modules.insert(module.module_decl.name.clone(), module); .unwrap_or(false)
}
None => {
false
}
}
}
}
} }
#[inline] #[inline]
pub(super) fn new() -> Self { pub(super) fn new() -> Self {
IndexStore { IndexStore::default()
atom_tbl: TabledData::new(Rc::new("user".to_string())),
code_dir: CodeDir::new(),
module_dir: ModuleDir::new(),
dynamic_code_dir: DynamicCodeDir::new(),
global_variables: GlobalVarDir::new(),
in_situ_code_dir: InSituCodeDir::new(),
in_situ_module_dir: ModuleStubDir::new(),
op_dir: default_op_dir(),
modules: ModuleDir::new(),
stream_aliases: StreamAliasDir::new(),
streams: StreamDir::new(),
}
} }
#[inline] pub(super)
pub(super) fn copy_and_swap(&mut self, other: &mut IndexStore) { fn get_cleaner_sites(&self) -> (usize, usize) {
self.code_dir = other.code_dir.clone();
self.op_dir = other.op_dir.clone();
mem::swap(&mut self.code_dir, &mut other.code_dir);
mem::swap(&mut self.op_dir, &mut other.op_dir);
mem::swap(&mut self.modules, &mut other.modules);
}
#[inline]
fn get_internal(
&self,
name: ClauseName,
arity: usize,
in_mod: ClauseName,
) -> Option<CodeIndex> {
self.modules
.get(&in_mod)
.and_then(|ref module| module.code_dir.get(&(name, arity)))
.cloned()
}
pub(super) fn get_cleaner_sites(&self) -> (usize, usize) {
let r_w_h = clause_name!("run_cleaners_with_handling"); let r_w_h = clause_name!("run_cleaners_with_handling");
let r_wo_h = clause_name!("run_cleaners_without_handling"); let r_wo_h = clause_name!("run_cleaners_without_handling");
let iso_ext = clause_name!("iso_ext"); let iso_ext = clause_name!("iso_ext");
let r_w_h = self let r_w_h = self
.get_internal(r_w_h, 0, iso_ext.clone()) .get_predicate_code_index(r_w_h, 0, iso_ext.clone(), None)
.and_then(|item| item.local()); .and_then(|item| item.local());
let r_wo_h = self let r_wo_h = self
.get_internal(r_wo_h, 1, iso_ext) .get_predicate_code_index(r_wo_h, 1, iso_ext, None)
.and_then(|item| item.local()); .and_then(|item| item.local());
if let Some(r_w_h) = r_w_h { if let Some(r_w_h) = r_w_h {
@@ -960,129 +983,6 @@ impl IndexStore {
} }
pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>; pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
#[derive(Debug)]
pub struct TermDirQuantumEntry {
pub old_terms: (Predicate, VecDeque<TopLevel>),
pub new_terms: (Predicate, VecDeque<TopLevel>),
pub is_fresh: bool,
}
impl TermDirQuantumEntry {
#[inline]
pub fn new() -> Self {
TermDirQuantumEntry {
old_terms: (Predicate::new(), VecDeque::new()),
new_terms: (Predicate::new(), VecDeque::new()),
is_fresh: false,
}
}
pub fn from(preds: &Predicate, queue: &VecDeque<TopLevel>) -> Self
{
let mut entry = TermDirQuantumEntry::new();
entry.is_fresh = false;
(entry.old_terms.0).0.extend(preds.0.iter().cloned());
entry.old_terms.1.extend(queue.iter().cloned());
entry
}
}
#[derive(Debug)]
pub struct TermDirQuantum(IndexMap<PredicateKey, TermDirQuantumEntry>);
impl TermDirQuantum {
#[inline]
pub fn new() -> Self {
TermDirQuantum(IndexMap::new())
}
#[inline]
pub fn insert_or_refresh(&mut self, key: PredicateKey, mut entry: TermDirQuantumEntry) {
if let Some(prev_entry) = self.get_mut(&key) {
prev_entry.is_fresh = true;
} else {
entry.is_fresh = true;
self.0.insert(key, entry);
}
}
#[inline]
pub fn insert(&mut self, key: PredicateKey, entry: TermDirQuantumEntry) {
self.0.insert(key, entry);
}
#[inline]
pub fn get_mut(&mut self, key: &PredicateKey) -> Option<&mut TermDirQuantumEntry> {
self.0.get_mut(key)
}
pub fn consolidate(self) -> TermDir {
let mut term_dir = TermDir::new();
for (key, entry) in self.0 {
let (preds, queue) =
term_dir.entry(key).or_insert((Predicate::new(), VecDeque::new()));
preds.0.extend((entry.new_terms.0).0.into_iter());
queue.extend(entry.new_terms.1.into_iter());
}
term_dir
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
pub enum CompileTimeHook {
GoalExpansion,
TermExpansion,
UserGoalExpansion,
UserTermExpansion,
}
impl CompileTimeHook {
pub fn name(self) -> ClauseName {
match self {
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
clause_name!("goal_expansion")
}
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
clause_name!("term_expansion")
}
}
}
#[inline]
pub fn arity(self) -> usize {
match self {
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => 2,
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => 2,
}
}
#[inline]
pub fn user_scope(self) -> Self {
match self {
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => {
CompileTimeHook::UserGoalExpansion
}
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => {
CompileTimeHook::UserTermExpansion
}
}
}
#[inline]
pub fn has_module_scope(self) -> bool {
match self {
CompileTimeHook::UserTermExpansion | CompileTimeHook::UserGoalExpansion => false,
_ => true,
}
}
}
pub enum RefOrOwned<'a, T: 'a> { pub enum RefOrOwned<'a, T: 'a> {
Borrowed(&'a T), Borrowed(&'a T),
@@ -1094,7 +994,8 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> {
match self { match self {
&RefOrOwned::Borrowed(ref borrowed) => &RefOrOwned::Borrowed(ref borrowed) =>
write!(f, "Borrowed({:?})", borrowed), write!(f, "Borrowed({:?})", borrowed),
&RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned), &RefOrOwned::Owned(ref owned) =>
write!(f, "Owned({:?})", owned),
} }
} }
} }
@@ -1107,9 +1008,7 @@ impl<'a, T> RefOrOwned<'a, T> {
} }
} }
pub fn to_owned(self) -> T pub fn to_owned(self) -> T where T: Clone
where
T: Clone,
{ {
match self { match self {
RefOrOwned::Borrowed(item) => item.clone(), RefOrOwned::Borrowed(item) => item.clone(),

View File

@@ -9,14 +9,14 @@ use crate::machine::copier::*;
use crate::machine::heap::*; use crate::machine::heap::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::modules::*; use crate::machine::partial_string::HeapPStrIter;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::rug::Integer; use crate::rug::Integer;
use crate::downcast::Any; use crate::downcast::Any;
use crate::indexmap::{IndexMap, IndexSet}; use crate::indexmap::IndexMap;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -25,292 +25,6 @@ use std::io::Write;
use std::mem; use std::mem;
use std::ops::{Index, IndexMut}; use std::ops::{Index, IndexMut};
#[derive(Debug)]
pub(crate) struct HeapPStrIter<'a> {
focus: Addr,
machine_st: &'a MachineState,
seen: IndexSet<Addr>,
}
impl<'a> HeapPStrIter<'a> {
#[inline]
fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
HeapPStrIter {
focus,
machine_st,
seen: IndexSet::new(),
}
}
#[inline]
pub(crate)
fn focus(&self) -> Addr {
self.machine_st.store(self.machine_st.deref(self.focus))
}
#[inline]
pub(crate)
fn to_string(&mut self) -> String {
let mut buf = String::new();
while let Some(iteratee) = self.next() {
match iteratee {
PStrIteratee::Char(c) => {
buf.push(c);
}
PStrIteratee::PStrSegment(h, n) => {
match &self.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
buf += pstr.as_str_from(n);
}
_ => {
unreachable!()
}
}
}
}
}
buf
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum PStrIteratee {
Char(char),
PStrSegment(usize, usize),
}
impl<'a> Iterator for HeapPStrIter<'a> {
type Item = PStrIteratee;
fn next(&mut self) -> Option<Self::Item> {
let addr = self.machine_st.store(self.machine_st.deref(self.focus));
if !self.seen.contains(&addr) {
self.seen.insert(addr);
} else {
return None;
}
match addr {
Addr::PStrLocation(h, n) => {
if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
self.focus = if has_tail {
Addr::HeapCell(h + 1)
} else {
Addr::EmptyList
};
return Some(PStrIteratee::PStrSegment(h, n));
} else {
unreachable!()
}
}
Addr::Lis(l) => {
let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
let opt_c = match addr {
Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
if atom.is_char() {
Some(atom.as_str().chars().next().unwrap())
} else {
None
}
} else {
unreachable!()
}
}
Addr::Char(c) => {
Some(c)
}
_ => {
None
}
};
if let Some(c) = opt_c {
self.focus = Addr::HeapCell(l + 1);
return Some(PStrIteratee::Char(c));
} else {
return None;
}
}
Addr::EmptyList => {
self.focus = Addr::EmptyList;
return None;
}
_ => {
return None;
}
}
}
}
#[inline]
pub(super)
fn compare_pstr_prefixes<'a>(
i1: &mut HeapPStrIter<'a>,
i2: &mut HeapPStrIter<'a>,
) -> Option<Ordering> {
let mut r1 = i1.next();
let mut r2 = i2.next();
loop {
if let Some(r1i) = r1 {
if let Some(r2i) = r2 {
match (r1i, r2i) {
(PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => {
if c1 != c2 {
return c1.partial_cmp(&c2);
}
}
(PStrIteratee::Char(c1), PStrIteratee::PStrSegment(h, n)) => {
if let &HeapCellValue::PartialString(ref pstr, _) = &i2.machine_st.heap[h] {
if let Some(c2) = pstr.as_str_from(n).chars().next() {
if c1 != c2 {
return c1.partial_cmp(&c2);
} else {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h, n + c2.len_utf8()));
continue;
}
} else {
r2 = i2.next();
continue;
}
} else {
unreachable!()
}
}
(PStrIteratee::PStrSegment(h, n), PStrIteratee::Char(c2)) => {
if let &HeapCellValue::PartialString(ref pstr, _) = &i1.machine_st.heap[h] {
if let Some(c1) = pstr.as_str_from(n).chars().next() {
if c1 != c2 {
return c2.partial_cmp(&c1);
} else {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h, n + c1.len_utf8()));
continue;
}
} else {
r1 = i1.next();
continue;
}
} else {
unreachable!()
}
}
(PStrIteratee::PStrSegment(h1, n1), PStrIteratee::PStrSegment(h2, n2)) => {
match (&i1.machine_st.heap[h1], &i2.machine_st.heap[h2]) {
(
&HeapCellValue::PartialString(ref pstr1, _),
&HeapCellValue::PartialString(ref pstr2, _),
) => {
let str1 = pstr1.as_str_from(n1);
let str2 = pstr2.as_str_from(n2);
if str1.starts_with(str2) {
r1 = Some(PStrIteratee::PStrSegment(h1, n1 + str2.len()));
r2 = i2.next();
continue;
} else if str2.starts_with(str1) {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len()));
continue;
} else {
return str1.partial_cmp(str2);
}
}
_ => {
unreachable!()
}
}
}
}
r1 = i1.next();
r2 = i2.next();
continue;
}
}
return match (i1.focus(), i2.focus()) {
(Addr::EmptyList, Addr::EmptyList) => {
Some(Ordering::Equal)
}
(Addr::EmptyList, _) => {
Some(Ordering::Less)
}
(_, Addr::EmptyList) => {
Some(Ordering::Greater)
}
_ => {
None
}
};
}
}
#[inline]
pub(super)
fn compare_pstr_to_string<'a>(
heap_pstr_iter: &mut HeapPStrIter<'a>,
s: &String,
) -> Option<usize> {
let mut s_offset = 0;
while let Some(iteratee) = heap_pstr_iter.next() {
match iteratee {
PStrIteratee::Char(c1) => {
if let Some(c2) = s[s_offset ..].chars().next() {
if c1 != c2 {
return None;
} else {
s_offset += c1.len_utf8();
}
} else {
return Some(s_offset);
}
}
PStrIteratee::PStrSegment(h, n) => {
match heap_pstr_iter.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
let t = pstr.as_str_from(n);
if s[s_offset ..].starts_with(t) {
s_offset += t.len();
} else if t.starts_with(&s[s_offset ..]) {
heap_pstr_iter.focus =
Addr::PStrLocation(h, n + s[s_offset ..].len());
s_offset += s[s_offset ..].len();
return Some(s_offset);
} else {
return None;
}
}
_ => {
unreachable!()
}
}
}
}
if s[s_offset ..].is_empty() {
return Some(s_offset);
}
}
Some(s_offset)
}
#[derive(Debug)] #[derive(Debug)]
pub struct Ball { pub struct Ball {
pub(super) boundary: usize, pub(super) boundary: usize,
@@ -332,17 +46,6 @@ impl Ball {
self.stub.clear(); self.stub.clear();
} }
pub(super)
fn take(&mut self) -> Ball {
let boundary = self.boundary;
self.boundary = 0;
Ball {
boundary,
stub: self.stub.take(),
}
}
pub(super) pub(super)
fn copy_and_align(&self, h: usize) -> Heap { fn copy_and_align(&self, h: usize) -> Heap {
let diff = self.boundary as i64 - h as i64; let diff = self.boundary as i64 - h as i64;
@@ -586,6 +289,7 @@ impl Default for HeapPtr {
#[derive(Debug)] #[derive(Debug)]
pub struct MachineState { pub struct MachineState {
pub(crate) atom_tbl: TabledData<Atom>,
pub(super) s: HeapPtr, pub(super) s: HeapPtr,
pub(super) p: CodePtr, pub(super) p: CodePtr,
pub(super) b: usize, pub(super) b: usize,
@@ -640,7 +344,7 @@ impl MachineState {
loop { loop {
match self.read( match self.read(
stream.clone(), stream.clone(),
indices.atom_tbl.clone(), self.atom_tbl.clone(),
&indices.op_dir, &indices.op_dir,
) { ) {
Ok(term_write_result) => { Ok(term_write_result) => {
@@ -654,7 +358,7 @@ impl MachineState {
let mut list_of_var_eqs = vec![]; let mut list_of_var_eqs = vec![];
for (var, binding) in term_write_result.var_dict.into_iter() { for (var, binding) in term_write_result.var_dict.into_iter() {
let var_atom = clause_name!(var.to_string(), indices.atom_tbl); let var_atom = clause_name!(var.to_string(), self.atom_tbl);
let h = self.heap.h(); let h = self.heap.h();
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir);
@@ -854,6 +558,15 @@ impl MachineState {
Ok(Some(printer)) Ok(Some(printer))
} }
pub(super)
fn throw_undefined_error(&mut self, name: ClauseName, arity: usize) -> MachineStub {
let stub = MachineError::functor_stub(name.clone(), arity);
let h = self.heap.h();
let key = ExistenceError::Procedure(name, arity);
self.error_form(MachineError::existence_error(h, key), stub)
}
#[inline] #[inline]
pub(crate) pub(crate)
fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> { fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> {
@@ -895,6 +608,24 @@ impl MachineState {
Ok(chars) Ok(chars)
} }
pub(super)
fn read_predicate_key(&self, name: Addr, arity: Addr) -> (ClauseName, usize) {
let predicate_name = atom_from!(self, self.store(self.deref(name)));
let arity = self.store(self.deref(arity));
let arity =
match Number::try_from((arity, &self.heap)) {
Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY =>
n.to_usize().unwrap(),
Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize =>
usize::try_from(n).unwrap(),
_ =>
unreachable!()
};
(predicate_name, arity)
}
pub(super) pub(super)
fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) {
self.cp.assign_if_local(self.p.clone() + 1); self.cp.assign_if_local(self.p.clone() + 1);
@@ -914,58 +645,35 @@ impl MachineState {
fn module_lookup( fn module_lookup(
&mut self, &mut self,
indices: &IndexStore, indices: &IndexStore,
call_policy: &mut Box<dyn CallPolicy>,
key: PredicateKey, key: PredicateKey,
module_name: ClauseName, module_name: ClauseName,
last_call: bool, _last_call: bool,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
let (name, arity) = key; if module_name.as_str() == "user" {
return call_policy.call_clause_type(
if let Some(ref idx) = indices.get_code_index((name.clone(), arity), module_name.clone()) { self,
match idx.0.borrow().0 { key,
IndexPtr::Index(compiled_tl_index) => { &indices.code_dir,
if last_call { &indices.op_dir,
self.execute_at_index(arity, dir_entry!(compiled_tl_index)); current_input_stream,
} else { current_output_stream,
self.call_at_index(arity, dir_entry!(compiled_tl_index)); );
} } else if let Some(module) = indices.modules.get(&module_name) {
return call_policy.call_clause_type(
return Ok(()); self,
} key,
IndexPtr::DynamicUndefined => { &module.code_dir,
self.fail = true; &module.op_dir,
return Ok(()); current_input_stream,
} current_output_stream,
IndexPtr::UserTermExpansion => { );
if last_call {
self.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
} else {
self.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
}
return Ok(());
}
IndexPtr::UserGoalExpansion => {
if last_call {
self.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
} else {
self.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
}
return Ok(());
}
IndexPtr::InSituDirEntry(p) => {
if last_call {
self.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
} else {
self.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
}
return Ok(());
}
_ => {}
}
} }
let (name, arity) = key;
let h = self.heap.h(); let h = self.heap.h();
let stub = MachineError::functor_stub(name.clone(), arity); let stub = MachineError::functor_stub(name.clone(), arity);
let err = MachineError::module_resolution_error(h, module_name, name, arity); let err = MachineError::module_resolution_error(h, module_name, name, arity);
@@ -974,49 +682,6 @@ impl MachineState {
} }
} }
fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<LocalCodePtr>
{
match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
Some(p) => Some(LocalCodePtr::InSituDirEntry(*p)),
None =>
match indices.code_dir.get(&(name, arity)) {
Some(ref idx) => {
if let IndexPtr::Index(p) = idx.0.borrow().0 {
Some(LocalCodePtr::DirEntry(p))
} else {
None
}
}
_ => None,
},
}
}
fn try_in_situ(
machine_st: &mut MachineState,
name: ClauseName,
arity: usize,
indices: &IndexStore,
last_call: bool,
) -> CallResult {
if let Some(p) = try_in_situ_lookup(name.clone(), arity, indices) {
if last_call {
machine_st.execute_at_index(arity, p);
} else {
machine_st.call_at_index(arity, p);
}
machine_st.p = CodePtr::Local(p);
Ok(())
} else {
let stub = MachineError::functor_stub(name.clone(), arity);
let h = machine_st.heap.h();
let key = ExistenceError::Procedure(name, arity);
Err(machine_st.error_form(MachineError::existence_error(h, key), stub))
}
}
pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>; pub(crate) type CallResult = Result<(), Vec<HeapCellValue>>;
pub(crate) trait CallPolicy: Any + fmt::Debug { pub(crate) trait CallPolicy: Any + fmt::Debug {
@@ -1090,7 +755,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
machine_st.attr_var_init.backtrack(attr_var_init_queue_b, attr_var_init_bindings_b); machine_st.attr_var_init.backtrack(attr_var_init_queue_b, attr_var_init_bindings_b);
machine_st.hb = machine_st.heap.h(); machine_st.hb = machine_st.heap.h();
machine_st.p += offset; machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
Ok(()) Ok(())
} }
@@ -1130,7 +795,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
machine_st.stack.truncate(b); machine_st.stack.truncate(b);
machine_st.hb = machine_st.heap.h(); machine_st.hb = machine_st.heap.h();
machine_st.p += offset; machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset));
Ok(()) Ok(())
} }
@@ -1180,13 +845,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
machine_st: &mut MachineState, machine_st: &mut MachineState,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
idx: CodeIndex, idx: &CodeIndex,
indices: &mut IndexStore,
) -> CallResult { ) -> CallResult {
if machine_st.last_call { if machine_st.last_call {
self.try_execute(machine_st, name, arity, idx, indices) self.try_execute(machine_st, name, arity, idx)
} else { } else {
self.try_call(machine_st, name, arity, idx, indices) self.try_call(machine_st, name, arity, idx)
} }
} }
@@ -1195,27 +859,18 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
machine_st: &mut MachineState, machine_st: &mut MachineState,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
idx: CodeIndex, idx: &CodeIndex,
indices: &IndexStore,
) -> CallResult { ) -> CallResult {
match idx.0.borrow().0 { match idx.get() {
IndexPtr::DynamicUndefined => { IndexPtr::DynamicUndefined => {
machine_st.fail = true; machine_st.fail = true;
return Ok(());
} }
IndexPtr::Undefined => { IndexPtr::Undefined => {
return try_in_situ(machine_st, name, arity, indices, false); return Err(machine_st.throw_undefined_error(name, arity));
} }
IndexPtr::Index(compiled_tl_index) => { IndexPtr::Index(compiled_tl_index) => {
machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index)) machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index));
}
IndexPtr::UserTermExpansion => {
machine_st.call_at_index(arity, LocalCodePtr::UserTermExpansion(0));
}
IndexPtr::UserGoalExpansion => {
machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
}
IndexPtr::InSituDirEntry(p) => {
machine_st.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
} }
} }
@@ -1227,26 +882,19 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
machine_st: &mut MachineState, machine_st: &mut MachineState,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
idx: CodeIndex, idx: &CodeIndex,
indices: &IndexStore,
) -> CallResult { ) -> CallResult {
match idx.0.borrow().0 { match idx.get() {
IndexPtr::DynamicUndefined => IndexPtr::DynamicUndefined => {
machine_st.fail = true, machine_st.fail = true;
IndexPtr::Undefined => return Ok(());
return try_in_situ(machine_st, name, arity, indices, true), }
IndexPtr::Undefined => {
return Err(machine_st.throw_undefined_error(name, arity));
}
IndexPtr::Index(compiled_tl_index) => { IndexPtr::Index(compiled_tl_index) => {
machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index)) machine_st.execute_at_index(arity, dir_entry!(compiled_tl_index))
} }
IndexPtr::UserTermExpansion => {
machine_st.execute_at_index(arity, LocalCodePtr::UserTermExpansion(0));
}
IndexPtr::UserGoalExpansion => {
machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
}
IndexPtr::InSituDirEntry(p) => {
machine_st.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
}
} }
Ok(()) Ok(())
@@ -1256,7 +904,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
&mut self, &mut self,
machine_st: &mut MachineState, machine_st: &mut MachineState,
ct: &BuiltInClauseType, ct: &BuiltInClauseType,
indices: &mut IndexStore, _code_dir: &CodeDir,
op_dir: &OpDir,
current_input_stream: &mut Stream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream, current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
@@ -1305,15 +954,15 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
let atom = match machine_st.compare_term_test(&a2, &a3) { let atom = match machine_st.compare_term_test(&a2, &a3) {
Some(Ordering::Greater) => { Some(Ordering::Greater) => {
let spec = fetch_atom_op_spec(clause_name!(">"), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!(">"), None, op_dir);
HeapCellValue::Atom(clause_name!(">"), spec) HeapCellValue::Atom(clause_name!(">"), spec)
} }
Some(Ordering::Equal) => { Some(Ordering::Equal) => {
let spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!("="), None, op_dir);
HeapCellValue::Atom(clause_name!("="), spec) HeapCellValue::Atom(clause_name!("="), spec)
} }
None | Some(Ordering::Less) => { None | Some(Ordering::Less) => {
let spec = fetch_atom_op_spec(clause_name!("<"), None, &indices.op_dir); let spec = fetch_atom_op_spec(clause_name!("<"), None, op_dir);
HeapCellValue::Atom(clause_name!("<"), spec) HeapCellValue::Atom(clause_name!("<"), spec)
} }
}; };
@@ -1338,8 +987,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
&BuiltInClauseType::Read => { &BuiltInClauseType::Read => {
match machine_st.read( match machine_st.read(
current_input_stream.clone(), current_input_stream.clone(),
indices.atom_tbl.clone(), machine_st.atom_tbl.clone(),
&indices.op_dir, op_dir,
) { ) {
Ok(offset) => { Ok(offset) => {
let addr = machine_st[temp_v!(1)]; let addr = machine_st[temp_v!(1)];
@@ -1347,16 +996,18 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
} }
Err(ParserError::UnexpectedEOF) => { Err(ParserError::UnexpectedEOF) => {
let addr = machine_st[temp_v!(1)]; let addr = machine_st[temp_v!(1)];
let eof = clause_name!("end_of_file".to_string(), let eof = clause_name!("end_of_file".to_string(), machine_st.atom_tbl);
indices.atom_tbl);
let atom = machine_st.heap.to_unifiable( let atom = machine_st.heap.to_unifiable(
HeapCellValue::Atom(eof, None) HeapCellValue::Atom(eof, None)
); );
machine_st.unify(addr, atom); machine_st.unify(addr, atom);
} }
Err(e) => { Err(e) => {
let h = machine_st.heap.h(); let h = machine_st.heap.h();
let stub = MachineError::functor_stub(clause_name!("read"), 1); let stub = MachineError::functor_stub(clause_name!("read"), 1);
let err = MachineError::syntax_error(h, e); let err = MachineError::syntax_error(h, e);
let err = machine_st.error_form(err, stub); let err = machine_st.error_form(err, stub);
@@ -1382,7 +1033,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::Functor => { &BuiltInClauseType::Functor => {
machine_st.try_functor(&indices)?; machine_st.try_functor(op_dir)?;
return_from_clause!(machine_st.last_call, machine_st) return_from_clause!(machine_st.last_call, machine_st)
} }
&BuiltInClauseType::NotEq => { &BuiltInClauseType::NotEq => {
@@ -1453,24 +1104,66 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
} }
} }
fn compile_hook( fn call_clause_type(
&mut self, &mut self,
machine_st: &mut MachineState, machine_st: &mut MachineState,
hook: &CompileTimeHook, key: PredicateKey,
code_dir: &CodeDir,
op_dir: &OpDir,
current_input_stream: &mut Stream,
current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
machine_st.cp = LocalCodePtr::TopLevel(0, 0); let (name, arity) = key;
machine_st.num_of_args = hook.arity(); match ClauseType::from(name.clone(), arity, None) {
machine_st.b0 = machine_st.b; ClauseType::BuiltIn(built_in) => {
machine_st.setup_built_in_call(built_in.clone());
self.call_builtin(
machine_st,
&built_in,
code_dir,
op_dir,
current_input_stream,
current_output_stream,
)?;
}
ClauseType::CallN => {
machine_st.handle_internal_call_n(arity);
machine_st.p = match hook { if machine_st.fail {
CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { return Ok(());
CodePtr::Local(LocalCodePtr::UserTermExpansion(0)) }
machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
} }
CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { ClauseType::Inlined(inlined) => {
CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)) machine_st.execute_inlined(&inlined);
if machine_st.last_call {
machine_st.p = CodePtr::Local(machine_st.cp);
}
} }
}; ClauseType::Op(..) | ClauseType::Named(..) => {
if let Some(idx) = code_dir.get(&(name.clone(), arity)) {
self.context_call(machine_st, name, arity, idx)?;
} else {
return Err(machine_st.throw_undefined_error(name, arity));
}
}
ClauseType::System(_) => {
let name = functor!(clause_name(name));
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
return Err(machine_st.error_form(
MachineError::type_error(
machine_st.heap.h(),
ValidType::Callable,
name
),
stub,
));
}
}
Ok(()) Ok(())
} }
@@ -1479,57 +1172,20 @@ pub(crate) trait CallPolicy: Any + fmt::Debug {
&mut self, &mut self,
machine_st: &mut MachineState, machine_st: &mut MachineState,
arity: usize, arity: usize,
indices: &mut IndexStore, code_dir: &CodeDir,
op_dir: &OpDir,
current_input_stream: &mut Stream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream, current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
if let Some((name, arity)) = machine_st.setup_call_n(arity) { if let Some(key) = machine_st.setup_call_n(arity) {
match ClauseType::from(name.clone(), arity, None) { self.call_clause_type(
ClauseType::BuiltIn(built_in) => { machine_st,
machine_st.setup_built_in_call(built_in.clone()); key,
self.call_builtin( code_dir,
machine_st, op_dir,
&built_in, current_input_stream,
indices, current_output_stream,
current_input_stream, )?;
current_output_stream,
)?;
}
ClauseType::CallN => {
machine_st.handle_internal_call_n(arity);
if machine_st.fail {
return Ok(());
}
machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call);
}
ClauseType::Inlined(inlined) => {
machine_st.execute_inlined(&inlined);
if machine_st.last_call {
machine_st.p = CodePtr::Local(machine_st.cp);
}
}
ClauseType::Op(..) | ClauseType::Named(..) => {
let module = name.owning_module();
if let Some(idx) = indices.get_code_index((name.clone(), arity), module) {
self.context_call(machine_st, name, arity, idx, indices)?;
} else {
try_in_situ(machine_st, name, arity, indices, machine_st.last_call)?;
}
}
ClauseType::Hook(_) | ClauseType::System(_) => {
let name = functor!(clause_name(name));
let stub = MachineError::functor_stub(clause_name!("call"), arity + 1);
return Err(machine_st.error_form(
MachineError::type_error(machine_st.heap.h(), ValidType::Callable, name),
stub,
));
}
};
} }
Ok(()) Ok(())
@@ -1542,11 +1198,9 @@ impl CallPolicy for CWILCallPolicy {
machine_st: &mut MachineState, machine_st: &mut MachineState,
name: ClauseName, name: ClauseName,
arity: usize, arity: usize,
idx: CodeIndex, idx: &CodeIndex,
indices: &mut IndexStore,
) -> CallResult { ) -> CallResult {
self.prev_policy self.prev_policy.context_call(machine_st, name, arity, idx)?;//, indices)?;
.context_call(machine_st, name, arity, idx, indices)?;
self.increment(machine_st) self.increment(machine_st)
} }
@@ -1574,14 +1228,16 @@ impl CallPolicy for CWILCallPolicy {
&mut self, &mut self,
machine_st: &mut MachineState, machine_st: &mut MachineState,
ct: &BuiltInClauseType, ct: &BuiltInClauseType,
indices: &mut IndexStore, code_dir: &CodeDir,
op_dir: &OpDir,
current_input_stream: &mut Stream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream, current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
self.prev_policy.call_builtin( self.prev_policy.call_builtin(
machine_st, machine_st,
ct, ct,
indices, code_dir,
op_dir,
current_input_stream, current_input_stream,
current_output_stream current_output_stream
)?; )?;
@@ -1593,14 +1249,16 @@ impl CallPolicy for CWILCallPolicy {
&mut self, &mut self,
machine_st: &mut MachineState, machine_st: &mut MachineState,
arity: usize, arity: usize,
indices: &mut IndexStore, code_dir: &CodeDir,
op_dir: &OpDir,
current_input_stream: &mut Stream, current_input_stream: &mut Stream,
current_output_stream: &mut Stream, current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
self.prev_policy.call_n( self.prev_policy.call_n(
machine_st, machine_st,
arity, arity,
indices, code_dir,
op_dir,
current_input_stream, current_input_stream,
current_output_stream, current_output_stream,
)?; )?;

View File

@@ -4,6 +4,7 @@ use crate::prolog_parser::tabled_rc::*;
use crate::clause_types::*; use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::heap_iter::*; use crate::heap_iter::*;
use crate::indexing::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::INTERRUPT; use crate::machine::INTERRUPT;
use crate::machine::attributed_variables::*; use crate::machine::attributed_variables::*;
@@ -13,6 +14,7 @@ use crate::machine::heap::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::partial_string::*;
use crate::machine::stack::*; use crate::machine::stack::*;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::ordered_float::*; use crate::ordered_float::*;
@@ -24,22 +26,11 @@ use std::cmp::Ordering;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::rc::Rc; use std::rc::Rc;
macro_rules! try_or_fail {
($s:ident, $e:expr) => {{
match $e {
Ok(val) => val,
Err(msg) => {
$s.throw_exception(msg);
return;
}
}
}};
}
impl MachineState { impl MachineState {
pub(crate) pub(crate)
fn new() -> Self { fn new() -> Self {
MachineState { MachineState {
atom_tbl: TabledData::new(Rc::new("".to_owned())),
s: HeapPtr::default(), s: HeapPtr::default(),
p: CodePtr::default(), p: CodePtr::default(),
b: 0, b: 0,
@@ -67,36 +58,6 @@ impl MachineState {
} }
} }
pub(crate)
fn with_small_heap() -> Self {
MachineState {
s: HeapPtr::default(),
p: CodePtr::default(),
b: 0,
b0: 0,
e: 0,
num_of_args: 0,
cp: LocalCodePtr::default(),
attr_var_init: AttrVarInitializer::new(0, 0),
fail: false,
heap: Heap::new(),
mode: MachineMode::Write,
stack: Stack::new(),
registers: vec![Addr::HeapCell(0); MAX_ARITY + 1], // self.registers[0] is never used.
trail: vec![],
tr: 0,
hb: 0,
block: 0,
ball: Ball::new(),
lifted_heap: Heap::new(),
interms: vec![Number::default(); 0],
last_call: false,
heap_locs: HeapVarDict::new(),
flags: MachineFlags::default(),
at_end_of_expansion: false
}
}
#[inline] #[inline]
pub fn machine_flags(&self) -> MachineFlags { pub fn machine_flags(&self) -> MachineFlags {
self.flags self.flags
@@ -1390,85 +1351,130 @@ impl MachineState {
} }
pub(super) pub(super)
fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) { fn execute_indexing_instr(
match instr { &mut self,
&IndexingInstruction::SwitchOnTerm(arg, v, c, l, s) => { indexing_lines: &Vec<IndexingLine>,
let addr = self[temp_v!(arg)]; call_policy: &mut Box<dyn CallPolicy>,
let addr = self.store(self.deref(addr)); ) {
let mut index = 0;
let addr =
match &indexing_lines[0] {
&IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(arg, ..)) => {
self.store(self.deref(self[temp_v!(arg)]))
}
_ => {
unreachable!()
}
};
let offset = match addr { loop {
Addr::Stream(_) | Addr::TcpListener(_) => { match &indexing_lines[index] {
0 &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => {
} let offset = match addr {
Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => { Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => {
v IndexingCodePtr::Fail
}
Addr::PStrLocation(..) => {
l
}
Addr::Char(_) | Addr::Con(_) | Addr::CutPoint(_) |
Addr::EmptyList | Addr::Fixnum(_) | Addr::Float(_) | Addr::Usize(_) => {
c
}
Addr::Lis(_) => {
l
}
Addr::Str(_) => {
s
}
};
match offset {
0 => self.fail = true,
o => self.p += o,
};
}
&IndexingInstruction::SwitchOnConstant(arg, _, ref hm) => {
let addr = self[temp_v!(arg)];
let addr = self.store(self.deref(addr));
let offset =
match addr.as_constant_index(&self) {
Some(c) => {
match hm.get(&c) {
Some(offset) => *offset,
_ => 0,
}
} }
None => { Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => {
0 IndexingCodePtr::External(v)
}
Addr::PStrLocation(..) => {
l
}
Addr::Char(_) | Addr::Con(_) | Addr::CutPoint(_) |
Addr::EmptyList | Addr::Fixnum(_) | Addr::Float(_) | Addr::Usize(_) => {
c
}
Addr::Lis(_) => {
l
}
Addr::Str(_) => {
s
} }
}; };
match offset { match offset {
0 => self.fail = true, IndexingCodePtr::Fail => {
o => self.p += o, self.fail = true;
}; break;
} }
&IndexingInstruction::SwitchOnStructure(arg, _, ref hm) => { IndexingCodePtr::External(o) => {
let a1 = self.registers[arg]; self.p += o;
let addr = self.store(self.deref(a1)); break;
}
let offset = match addr { IndexingCodePtr::Internal(o) => {
Addr::Str(s) => { index += o;
if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] { }
match hm.get(&(name.clone(), arity)) { };
Some(offset) => *offset, }
_ => 0, &IndexingLine::Indexing(IndexingInstruction::SwitchOnConstant(ref hm)) => {
let offset =
match addr.as_constant_index(&self) {
Some(c) => {
match hm.get(&c) {
Some(offset) => *offset,
_ => IndexingCodePtr::Fail,
}
} }
} else { None => {
0 IndexingCodePtr::Fail
}
};
match offset {
IndexingCodePtr::Fail => {
self.fail = true;
break;
}
IndexingCodePtr::External(o) => {
self.p += o;
break;
}
IndexingCodePtr::Internal(o) => {
index += o;
}
};
}
&IndexingLine::Indexing(IndexingInstruction::SwitchOnStructure(ref hm)) => {
let offset = match addr {
Addr::Str(s) => {
if let &HeapCellValue::NamedStr(arity, ref name, _) = &self.heap[s] {
match hm.get(&(name.clone(), arity)) {
Some(offset) => *offset,
_ => IndexingCodePtr::Fail
}
} else {
IndexingCodePtr::Fail
}
}
_ => {
IndexingCodePtr::Fail
}
};
match offset {
IndexingCodePtr::Fail => {
self.fail = true;
break;
}
IndexingCodePtr::External(o) => {
self.p += o;
break;
}
IndexingCodePtr::Internal(o) => {
index += o;
} }
} }
_ => { }
0 &IndexingLine::IndexedChoice(ref instrs) => {
if let LocalCodePtr::DirEntry(p) = self.p.local() {
self.p = CodePtr::Local(LocalCodePtr::IndexingBuf(p, index, 0));
} else {
unreachable!()
} }
};
match offset { self.execute_indexed_choice_instr(instrs.first().unwrap(), call_policy);
0 => self.fail = true, break;
o => self.p += o, }
};
} }
}; };
} }
@@ -1679,23 +1685,38 @@ impl MachineState {
Some((name, arity + narity - 1)) Some((name, arity + narity - 1))
} }
pub(super) fn unwind_stack(&mut self) { pub(super)
fn unwind_stack(&mut self) {
self.b = self.block; self.b = self.block;
self.fail = true; self.fail = true;
} }
pub(crate) fn is_cyclic_term(&self, addr: Addr) -> bool { pub(crate)
fn is_cyclic_term(&self, addr: Addr) -> bool {
let mut seen = IndexSet::new(); let mut seen = IndexSet::new();
let mut fail = false; let mut fail = false;
let mut iter = self.pre_order_iter(addr); let mut iter = self.pre_order_iter(addr);
let is_composite = |addr: &Addr| {
match *addr {
Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => {
true
}
_ => {
false
}
}
};
loop { loop {
if let Some(addr) = iter.stack().last() { if let Some(addr) = iter.stack().last() {
if !seen.contains(addr) { if is_composite(addr) {
seen.insert(*addr); if !seen.contains(addr) {
} else { seen.insert(*addr);
fail = true; } else {
break; fail = true;
break;
}
} }
} }
@@ -2513,7 +2534,7 @@ impl MachineState {
} }
pub(super) pub(super)
fn try_functor(&mut self, indices: &IndexStore) -> CallResult { fn try_functor(&mut self, op_dir: &OpDir) -> CallResult {
let stub = MachineError::functor_stub(clause_name!("functor"), 3); let stub = MachineError::functor_stub(clause_name!("functor"), 3);
let a1 = self.store(self.deref(self[temp_v!(1)])); let a1 = self.store(self.deref(self[temp_v!(1)]));
@@ -2531,7 +2552,7 @@ impl MachineState {
name.clone(), name.clone(),
arity, arity,
spec, spec,
&indices.op_dir, &op_dir,
); );
self.try_functor_compound_case(name, arity, spec) self.try_functor_compound_case(name, arity, spec)
@@ -2545,7 +2566,7 @@ impl MachineState {
clause_name!("."), clause_name!("."),
2, 2,
None, None,
&indices.op_dir, &op_dir,
); );
self.try_functor_compound_case(clause_name!("."), 2, spec) self.try_functor_compound_case(clause_name!("."), 2, spec)
@@ -2620,7 +2641,7 @@ impl MachineState {
name, name,
arity as usize, arity as usize,
spec, spec,
&indices.op_dir, &op_dir,
a1.as_var().unwrap(), a1.as_var().unwrap(),
); );
} else { } else {
@@ -2637,10 +2658,10 @@ impl MachineState {
} }
Addr::Char(c) => { Addr::Char(c) => {
self.try_functor_fabricate_struct( self.try_functor_fabricate_struct(
clause_name!(c.to_string(), indices.atom_tbl), clause_name!(c.to_string(), self.atom_tbl),
arity as usize, arity as usize,
None, None,
&indices.op_dir, &op_dir,
a1.as_var().unwrap(), a1.as_var().unwrap(),
); );
} }
@@ -3156,16 +3177,23 @@ impl MachineState {
call_policy.call_builtin( call_policy.call_builtin(
self, self,
ct, ct,
indices, &indices.code_dir,
&indices.op_dir,
current_input_stream, current_input_stream,
current_output_stream, current_output_stream,
) )
), ),
&ClauseType::CallN => try_or_fail!( &ClauseType::CallN => try_or_fail!(
self, self,
call_policy.call_n(self, arity, indices, current_input_stream, current_output_stream) call_policy.call_n(
self,
arity,
&indices.code_dir,
&indices.op_dir,
current_input_stream,
current_output_stream,
)
), ),
&ClauseType::Hook(ref hook) => try_or_fail!(self, call_policy.compile_hook(self, hook)),
&ClauseType::Inlined(ref ct) => { &ClauseType::Inlined(ref ct) => {
self.execute_inlined(ct); self.execute_inlined(ct);
@@ -3176,7 +3204,7 @@ impl MachineState {
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
try_or_fail!( try_or_fail!(
self, self,
call_policy.context_call(self, name.clone(), arity, idx.clone(), indices) call_policy.context_call(self, name.clone(), arity, idx)
) )
} }
&ClauseType::System(ref ct) => try_or_fail!( &ClauseType::System(ref ct) => try_or_fail!(
@@ -3234,6 +3262,9 @@ impl MachineState {
self.b0 = self.b; self.b0 = self.b;
self.p += offset; self.p += offset;
} }
&ControlInstruction::RevJmpBy(offset) => {
self.p -= offset;
}
&ControlInstruction::Proceed => { &ControlInstruction::Proceed => {
self.p = CodePtr::Local(self.cp); self.p = CodePtr::Local(self.cp);
} }
@@ -3272,7 +3303,7 @@ impl MachineState {
} }
self.hb = self.heap.h(); self.hb = self.heap.h();
self.p += offset; self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset));
} }
&IndexedChoiceInstruction::Retry(l) => { &IndexedChoiceInstruction::Retry(l) => {
try_or_fail!(self, call_policy.retry(self, l)); try_or_fail!(self, call_policy.retry(self, l));
@@ -3283,7 +3314,8 @@ impl MachineState {
}; };
} }
pub(super) fn execute_choice_instr( pub(super)
fn execute_choice_instr(
&mut self, &mut self,
instr: &ChoiceInstruction, instr: &ChoiceInstruction,
call_policy: &mut Box<dyn CallPolicy>, call_policy: &mut Box<dyn CallPolicy>,
@@ -3320,14 +3352,14 @@ impl MachineState {
let mut call_policy = DefaultCallPolicy {}; let mut call_policy = DefaultCallPolicy {};
try_or_fail!(self, call_policy.retry_me_else(self, offset)) try_or_fail!(self, call_policy.retry_me_else(self, offset))
} }
&ChoiceInstruction::DefaultTrustMe => { &ChoiceInstruction::DefaultTrustMe(_) => {
let mut call_policy = DefaultCallPolicy {}; let mut call_policy = DefaultCallPolicy {};
try_or_fail!(self, call_policy.trust_me(self)) try_or_fail!(self, call_policy.trust_me(self))
} }
&ChoiceInstruction::RetryMeElse(offset) => { &ChoiceInstruction::RetryMeElse(offset) => {
try_or_fail!(self, call_policy.retry_me_else(self, offset)) try_or_fail!(self, call_policy.retry_me_else(self, offset))
} }
&ChoiceInstruction::TrustMe => { &ChoiceInstruction::TrustMe(_) => {
try_or_fail!(self, call_policy.trust_me(self)) try_or_fail!(self, call_policy.trust_me(self))
} }
} }
@@ -3374,30 +3406,4 @@ impl MachineState {
} }
} }
} }
pub fn reset(&mut self) {
self.stack.drop_in_place();
self.hb = 0;
self.e = 0;
self.b = 0;
self.b0 = 0;
self.s = HeapPtr::default();
self.tr = 0;
self.p = CodePtr::default();
self.cp = LocalCodePtr::default();
self.attr_var_init.reset();
self.num_of_args = 0;
self.fail = false;
self.trail.clear();
self.heap.clear();
self.mode = MachineMode::Write;
self.registers = vec![Addr::HeapCell(0); MAX_ARITY + 1]; // self.registers[0] is never used.
self.block = 0;
self.ball.reset();
self.heap_locs.clear();
self.lifted_heap.clear();
}
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,371 +0,0 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::forms::*;
use crate::machine::code_repo::*;
use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*;
use std::collections::VecDeque;
use std::mem;
// Module's and related types are defined in forms.
impl Module {
pub fn new(
module_decl: ModuleDecl,
atom_tbl: TabledData<Atom>,
listing_src: ListingSource,
) -> Self
{
Module {
atom_tbl,
module_decl,
term_dir: TermDir::new(),
user_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
user_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
term_expansions: (Predicate::new(), VecDeque::from(vec![])),
goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
local_term_expansions: (Predicate::new(), VecDeque::from(vec![])),
local_goal_expansions: (Predicate::new(), VecDeque::from(vec![])),
code_dir: CodeDir::new(),
op_dir: default_op_dir(),
inserted_expansions: false,
is_impromptu_module: false,
listing_src,
}
}
pub fn dump_expansions(
&self,
code_repo: &mut CodeRepo,
) -> Result<(), ParserError> {
{
let te = code_repo
.term_dir
.entry((clause_name!("term_expansion"), 2))
.or_insert((Predicate::new(), VecDeque::from(vec![])));
(te.0)
.0
.extend((self.user_term_expansions.0).0.iter().cloned());
te.1.extend(self.user_term_expansions.1.iter().cloned());
}
{
let ge = code_repo
.term_dir
.entry((clause_name!("goal_expansion"), 2))
.or_insert((Predicate::new(), VecDeque::from(vec![])));
(ge.0)
.0
.extend((self.user_goal_expansions.0).0.iter().cloned());
ge.1.extend(self.user_goal_expansions.1.iter().cloned());
}
code_repo.compile_hook(CompileTimeHook::TermExpansion)?;
code_repo.compile_hook(CompileTimeHook::GoalExpansion)?;
Ok(())
}
pub fn add_expansion_record(
&mut self,
hook: CompileTimeHook,
clause: PredicateClause,
queue: VecDeque<TopLevel>,
) {
match hook {
CompileTimeHook::TermExpansion | CompileTimeHook::UserTermExpansion => {
(self.term_expansions.0).0.push(clause);
self.term_expansions.1.extend(queue.into_iter());
}
CompileTimeHook::GoalExpansion | CompileTimeHook::UserGoalExpansion => {
(self.goal_expansions.0).0.push(clause);
self.goal_expansions.1.extend(queue.into_iter());
}
}
}
pub fn add_local_expansion(
&mut self,
hook: CompileTimeHook,
clause: PredicateClause,
queue: VecDeque<TopLevel>,
) {
match hook {
CompileTimeHook::TermExpansion => {
(self.local_term_expansions.0).0.push(clause);
self.local_term_expansions.1.extend(queue.into_iter());
}
CompileTimeHook::GoalExpansion => {
(self.local_goal_expansions.0).0.push(clause);
self.local_goal_expansions.1.extend(queue.into_iter());
}
_ => {}
}
}
pub fn take_local_expansions(&mut self) -> Vec<(Predicate, VecDeque<TopLevel>)>
{
let term_expansions =
mem::replace(&mut self.local_term_expansions, (Predicate::new(), VecDeque::new()));
let goal_expansions =
mem::replace(&mut self.local_goal_expansions, (Predicate::new(), VecDeque::new()));
vec![term_expansions, goal_expansions]
}
}
pub trait SubModuleUser {
fn atom_tbl(&self) -> TabledData<Atom>;
fn op_dir(&mut self) -> &mut OpDir;
fn remove_code_index(&mut self, _: PredicateKey);
fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option<CodeIndex>;
fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex);
fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option<ClauseName> {
self.op_dir()
.get(&(name, fixity))
.map(|op_val| op_val.owning_module())
}
fn remove_module(&mut self, mod_name: ClauseName, module: &Module) {
for export in module.module_decl.exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
let name = name.defrock_brackets();
match self.get_code_index((name.clone(), arity), mod_name.clone()) {
Some(CodeIndex(ref code_idx)) => {
if &code_idx.borrow().1 != &module.module_decl.name {
continue;
}
self.remove_code_index((name.clone(), arity));
// remove or respecify ops.
if arity == 2 {
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::In) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::In));
}
}
} else if arity == 1 {
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Pre) {
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Pre));
}
}
if let Some(mod_name) = self.get_op_module_name(name.clone(), Fixity::Post)
{
if mod_name == module.module_decl.name {
self.op_dir().remove(&(name.clone(), Fixity::Post));
}
}
}
}
_ => {}
};
},
ModuleExport::OpDecl(op_decl) => {
let op_dir = self.op_dir();
op_dir.remove(&(op_decl.name(), op_decl.fixity()));
}
}
}
}
// returns true on successful import.
fn import_decl(&mut self, name: ClauseName, arity: usize, submodule: &Module) -> bool {
let name = name.defrock_brackets();
if let Some(code_data) = submodule.code_dir.get(&(name.clone(), arity)) {
let name = name.with_table(submodule.atom_tbl.clone());
let atom_tbl = self.atom_tbl();
atom_tbl.borrow_mut().insert(name.to_rc());
self.insert_dir_entry(name, arity, code_data.clone());
true
} else {
submodule.is_impromptu_module
}
}
fn use_qualified_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
_: &Module,
_: &Vec<ModuleExport>,
) -> Result<(), SessionError>;
fn use_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
_: &Module
) -> Result<(), SessionError>;
}
pub fn use_qualified_module<User>(
user: &mut User,
submodule: &Module,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError>
where
User: SubModuleUser,
{
for export in exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
if !submodule
.module_decl
.exports
.contains(&ModuleExport::PredicateKey((name.clone(), arity)))
{
continue;
}
if !user.import_decl(name.clone(), arity, submodule) {
let submodule_name = submodule.module_decl.name.clone();
return Err(SessionError::ModuleDoesNotContainExport(
submodule_name,
(name, arity)
));
}
},
ModuleExport::OpDecl(op_decl) => {
if !submodule
.module_decl
.exports
.contains(&ModuleExport::OpDecl(op_decl.clone()))
{
continue;
}
let op_dir = user.op_dir();
let prec = op_decl.0;
op_decl.insert_into_op_dir(
submodule.module_decl.name.clone(),
op_dir,
prec,
);
}
}
}
Ok(())
}
pub fn use_module<User: SubModuleUser>(
user: &mut User,
submodule: &Module,
) -> Result<(), SessionError> {
for export in submodule.module_decl.exports.iter().cloned() {
match export {
ModuleExport::PredicateKey((name, arity)) => {
if !user.import_decl(name.clone(), arity, submodule) {
let submodule_name = submodule.module_decl.name.clone();
return Err(SessionError::ModuleDoesNotContainExport(
submodule_name,
(name, arity)
));
}
}
ModuleExport::OpDecl(op_decl) => {
let op_dir = user.op_dir();
let prec = op_decl.0;
op_decl.insert_into_op_dir(
submodule.module_decl.name.clone(),
op_dir,
prec,
);
}
}
}
Ok(())
}
impl SubModuleUser for Module {
fn atom_tbl(&self) -> TabledData<Atom> {
self.atom_tbl.clone()
}
fn op_dir(&mut self) -> &mut OpDir {
&mut self.op_dir
}
fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option<CodeIndex> {
self.code_dir.get(&key).cloned()
}
fn remove_code_index(&mut self, key: PredicateKey) {
self.code_dir.remove(&key);
}
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
self.code_dir.insert((name, arity), idx);
}
fn use_qualified_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
submodule: &Module,
exports: &Vec<ModuleExport>,
) -> Result<(), SessionError> {
use_qualified_module(self, submodule, exports)?;
(self.user_term_expansions.0)
.0
.extend((submodule.term_expansions.0).0.iter().cloned());
self.user_term_expansions
.1
.extend(submodule.term_expansions.1.iter().cloned());
(self.user_goal_expansions.0)
.0
.extend((submodule.goal_expansions.0).0.iter().cloned());
self.user_goal_expansions
.1
.extend(submodule.goal_expansions.1.iter().cloned());
Ok(())
}
fn use_module(
&mut self,
_: &mut CodeRepo,
_: MachineFlags,
submodule: &Module,
) -> Result<(), SessionError> {
use_module(self, submodule)?;
(self.user_term_expansions.0)
.0
.extend((submodule.term_expansions.0).0.iter().cloned());
self.user_term_expansions
.1
.extend(submodule.term_expansions.1.iter().cloned());
(self.user_goal_expansions.0)
.0
.extend((submodule.goal_expansions.0).0.iter().cloned());
self.user_goal_expansions
.1
.extend(submodule.goal_expansions.1.iter().cloned());
Ok(())
}
}

View File

@@ -1,12 +1,18 @@
use crate::machine::*;
use crate::machine::machine_indices::*;
use core::marker::PhantomData; use core::marker::PhantomData;
use std::alloc; use std::alloc;
use std::cmp::Ordering;
use std::mem; use std::mem;
use std::ptr; use std::ptr;
use std::ops::RangeFrom; use std::ops::RangeFrom;
use std::slice; use std::slice;
use std::str; use std::str;
use indexmap::IndexSet;
#[derive(Debug)] #[derive(Debug)]
pub struct PartialString { pub struct PartialString {
buf: *const u8, buf: *const u8,
@@ -200,3 +206,290 @@ impl PartialString {
} }
} }
} }
#[derive(Debug)]
pub(crate) struct HeapPStrIter<'a> {
focus: Addr,
machine_st: &'a MachineState,
seen: IndexSet<Addr>,
}
impl<'a> HeapPStrIter<'a> {
#[inline]
pub(super)
fn new(machine_st: &'a MachineState, focus: Addr) -> Self {
HeapPStrIter {
focus,
machine_st,
seen: IndexSet::new(),
}
}
#[inline]
pub(crate)
fn focus(&self) -> Addr {
self.machine_st.store(self.machine_st.deref(self.focus))
}
#[inline]
pub(crate)
fn to_string(&mut self) -> String {
let mut buf = String::new();
while let Some(iteratee) = self.next() {
match iteratee {
PStrIteratee::Char(c) => {
buf.push(c);
}
PStrIteratee::PStrSegment(h, n) => {
match &self.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
buf += pstr.as_str_from(n);
}
_ => {
unreachable!()
}
}
}
}
}
buf
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) enum PStrIteratee {
Char(char),
PStrSegment(usize, usize),
}
impl<'a> Iterator for HeapPStrIter<'a> {
type Item = PStrIteratee;
fn next(&mut self) -> Option<Self::Item> {
let addr = self.machine_st.store(self.machine_st.deref(self.focus));
if !self.seen.contains(&addr) {
self.seen.insert(addr);
} else {
return None;
}
match addr {
Addr::PStrLocation(h, n) => {
if let &HeapCellValue::PartialString(_, has_tail) = &self.machine_st.heap[h] {
self.focus = if has_tail {
Addr::HeapCell(h + 1)
} else {
Addr::EmptyList
};
return Some(PStrIteratee::PStrSegment(h, n));
} else {
unreachable!()
}
}
Addr::Lis(l) => {
let addr = self.machine_st.store(self.machine_st.deref(Addr::HeapCell(l)));
let opt_c = match addr {
Addr::Con(h) if self.machine_st.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.machine_st.heap[h] {
if atom.is_char() {
Some(atom.as_str().chars().next().unwrap())
} else {
None
}
} else {
unreachable!()
}
}
Addr::Char(c) => {
Some(c)
}
_ => {
None
}
};
if let Some(c) = opt_c {
self.focus = Addr::HeapCell(l + 1);
return Some(PStrIteratee::Char(c));
} else {
return None;
}
}
Addr::EmptyList => {
self.focus = Addr::EmptyList;
return None;
}
_ => {
return None;
}
}
}
}
#[inline]
pub(super)
fn compare_pstr_prefixes<'a>(
i1: &mut HeapPStrIter<'a>,
i2: &mut HeapPStrIter<'a>,
) -> Option<Ordering> {
let mut r1 = i1.next();
let mut r2 = i2.next();
loop {
if let Some(r1i) = r1 {
if let Some(r2i) = r2 {
match (r1i, r2i) {
(PStrIteratee::Char(c1), PStrIteratee::Char(c2)) => {
if c1 != c2 {
return c1.partial_cmp(&c2);
}
}
(PStrIteratee::Char(c1), PStrIteratee::PStrSegment(h, n)) => {
if let &HeapCellValue::PartialString(ref pstr, _) = &i2.machine_st.heap[h] {
if let Some(c2) = pstr.as_str_from(n).chars().next() {
if c1 != c2 {
return c1.partial_cmp(&c2);
} else {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h, n + c2.len_utf8()));
continue;
}
} else {
r2 = i2.next();
continue;
}
} else {
unreachable!()
}
}
(PStrIteratee::PStrSegment(h, n), PStrIteratee::Char(c2)) => {
if let &HeapCellValue::PartialString(ref pstr, _) = &i1.machine_st.heap[h] {
if let Some(c1) = pstr.as_str_from(n).chars().next() {
if c1 != c2 {
return c2.partial_cmp(&c1);
} else {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h, n + c1.len_utf8()));
continue;
}
} else {
r1 = i1.next();
continue;
}
} else {
unreachable!()
}
}
(PStrIteratee::PStrSegment(h1, n1), PStrIteratee::PStrSegment(h2, n2)) => {
match (&i1.machine_st.heap[h1], &i2.machine_st.heap[h2]) {
(
&HeapCellValue::PartialString(ref pstr1, _),
&HeapCellValue::PartialString(ref pstr2, _),
) => {
let str1 = pstr1.as_str_from(n1);
let str2 = pstr2.as_str_from(n2);
if str1.starts_with(str2) {
r1 = Some(PStrIteratee::PStrSegment(h1, n1 + str2.len()));
r2 = i2.next();
continue;
} else if str2.starts_with(str1) {
r1 = i1.next();
r2 = Some(PStrIteratee::PStrSegment(h2, n2 + str1.len()));
continue;
} else {
return str1.partial_cmp(str2);
}
}
_ => {
unreachable!()
}
}
}
}
r1 = i1.next();
r2 = i2.next();
continue;
}
}
return match (i1.focus(), i2.focus()) {
(Addr::EmptyList, Addr::EmptyList) => {
Some(Ordering::Equal)
}
(Addr::EmptyList, _) => {
Some(Ordering::Less)
}
(_, Addr::EmptyList) => {
Some(Ordering::Greater)
}
_ => {
None
}
};
}
}
#[inline]
pub(super)
fn compare_pstr_to_string<'a>(
heap_pstr_iter: &mut HeapPStrIter<'a>,
s: &String,
) -> Option<usize> {
let mut s_offset = 0;
while let Some(iteratee) = heap_pstr_iter.next() {
match iteratee {
PStrIteratee::Char(c1) => {
if let Some(c2) = s[s_offset ..].chars().next() {
if c1 != c2 {
return None;
} else {
s_offset += c1.len_utf8();
}
} else {
return Some(s_offset);
}
}
PStrIteratee::PStrSegment(h, n) => {
match heap_pstr_iter.machine_st.heap[h] {
HeapCellValue::PartialString(ref pstr, _) => {
let t = pstr.as_str_from(n);
if s[s_offset ..].starts_with(t) {
s_offset += t.len();
} else if t.starts_with(&s[s_offset ..]) {
heap_pstr_iter.focus =
Addr::PStrLocation(h, n + s[s_offset ..].len());
s_offset += s[s_offset ..].len();
return Some(s_offset);
} else {
return None;
}
}
_ => {
unreachable!()
}
}
}
}
if s[s_offset ..].is_empty() {
return Some(s_offset);
}
}
Some(s_offset)
}

987
src/machine/preprocessor.rs Normal file
View File

@@ -0,0 +1,987 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::tabled_rc::*;
use crate::forms::*;
use crate::iterators::*;
use crate::machine::*;
use crate::machine::load_state::*;
use crate::machine::machine_errors::*;
use crate::indexmap::IndexSet;
use std::cell::Cell;
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::rc::Rc;
/*
* The preprocessor fabricates if-then-else ( .. -> ... ; ...)
* clauses into nameless standalone predicates, which it queues for
* later preprocessing and compilation. Fabricated predicates inherit
* explicit "cut variables" from the handwritten predicate
* surrounding their source if-then-else. They must be specially
* handled.
*/
#[derive(Clone, Copy, Debug)]
pub(crate) enum CutContext {
BlocksCuts,
HasCutVariable,
}
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(
Cell::default(),
sym.clone(),
vec![Box::new(prec), Box::new(term)],
None,
);
}
term
}
pub fn to_op_decl(prec: usize, spec: &str, name: ClauseName) -> Result<OpDecl, CompilationError> {
match spec {
"xfx" => Ok(OpDecl::new(prec, XFX, name)),
"xfy" => Ok(OpDecl::new(prec, XFY, name)),
"yfx" => Ok(OpDecl::new(prec, YFX, name)),
"fx" => Ok(OpDecl::new(prec, FX, name)),
"fy" => Ok(OpDecl::new(prec, FY, name)),
"xf" => Ok(OpDecl::new(prec, XF, name)),
"yf" => Ok(OpDecl::new(prec, YF, name)),
_ => Err(CompilationError::InconsistentEntry),
}
}
fn setup_op_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<OpDecl, CompilationError> {
let name = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
_ => return Err(CompilationError::InconsistentEntry),
};
let spec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Atom(name, _)) => name,
Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl),
_ => return Err(CompilationError::InconsistentEntry),
};
let prec = match *terms.pop().unwrap() {
Term::Constant(_, Constant::Fixnum(bi)) => match usize::try_from(bi) {
Ok(n) if n <= 1200 => n,
_ => return Err(CompilationError::InconsistentEntry),
},
_ => return Err(CompilationError::InconsistentEntry),
};
to_op_decl(prec, spec.as_str(), name)
}
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, CompilationError>
{
match term {
Term::Clause(_, ref slash, ref mut terms, Some(_))
if (slash.as_str() == "/" || slash.as_str() == "//") && terms.len() == 2 =>
{
let arity = *terms.pop().unwrap();
let name = *terms.pop().unwrap();
let arity = arity
.to_constant()
.and_then(|c| {
match c {
Constant::Integer(n) => n.to_usize(),
Constant::Fixnum(n) => usize::try_from(n).ok(),
_ => None
}
})
.ok_or(CompilationError::InvalidModuleExport)?;
let name = name
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
if slash.as_str() == "/" {
Ok((name, arity))
} else {
Ok((name, arity + 2))
}
}
_ => {
Err(CompilationError::InvalidModuleExport)
}
}
}
/*
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, CompilationError>
{
match term {
Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == ":" && terms.len() == 2 =>
{
let mut predicate_indicator = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
let module_name = module_name
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleExport)?;
let key = setup_predicate_indicator(&mut predicate_indicator)?;
Ok((module_name, key))
}
_ => Err(CompilationError::InvalidModuleExport),
}
}
*/
fn setup_module_export(
mut term: Term,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleExport, CompilationError> {
setup_predicate_indicator(&mut term)
.map(ModuleExport::PredicateKey)
.or_else(|_| {
if let Term::Clause(_, name, terms, _) = term {
if terms.len() == 3 && name.as_str() == "op" {
Ok(ModuleExport::OpDecl(setup_op_decl(
terms,
atom_tbl
)?))
} else {
Err(CompilationError::InvalidModuleDecl)
}
} else {
Err(CompilationError::InvalidModuleDecl)
}
})
}
pub(super)
fn setup_module_export_list(
mut export_list: Term,
atom_tbl: TabledData<Atom>,
) -> Result<Vec<ModuleExport>, CompilationError> {
let mut exports = vec![];
while let Term::Cons(_, t1, t2) = export_list {
let module_export = setup_module_export(*t1, atom_tbl.clone())?;
exports.push(module_export);
export_list = *t2;
}
if export_list.to_constant() != Some(Constant::EmptyList) {
Err(CompilationError::InvalidModuleDecl)
} else {
Ok(exports)
}
}
fn setup_module_decl(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<ModuleDecl, CompilationError> {
let export_list = *terms.pop().unwrap();
let name = terms
.pop()
.unwrap()
.to_constant()
.and_then(|c| c.to_atom())
.ok_or(CompilationError::InvalidModuleDecl)?;
let exports = setup_module_export_list(export_list, atom_tbl)?;
Ok(ModuleDecl { name, exports })
}
fn setup_use_module_decl(mut terms: Vec<Box<Term>>) -> Result<ModuleSource, CompilationError> {
match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
{
terms
.pop()
.unwrap()
.to_constant()
.and_then(|c| c.to_atom())
.map(|c| ModuleSource::Library(c))
.ok_or(CompilationError::InvalidUseModuleDecl)
}
Term::Constant(_, Constant::Atom(ref name, _)) =>
Ok(ModuleSource::File(name.clone())),
_ => Err(CompilationError::InvalidUseModuleDecl),
}
}
/*
fn setup_double_quotes(mut terms: Vec<Box<Term>>) -> Result<DoubleQuotes, CompilationError> {
let dbl_quotes = *terms.pop().unwrap();
match terms[0].as_ref() {
Term::Constant(_, Constant::Atom(ref name, _))
if name.as_str() == "double_quotes" => {
match dbl_quotes {
Term::Constant(_, Constant::Atom(name, _)) => {
match name.as_str() {
"atom" => Ok(DoubleQuotes::Atom),
"chars" => Ok(DoubleQuotes::Chars),
"codes" => Ok(DoubleQuotes::Codes),
_ => Err(CompilationError::InvalidDoubleQuotesDecl),
}
}
_ => {
Err(CompilationError::InvalidDoubleQuotesDecl)
}
}
},
_ => {
Err(CompilationError::InvalidDoubleQuotesDecl)
}
}
}
*/
type UseModuleExport = (ModuleSource, IndexSet<ModuleExport>);
fn setup_qualified_import(
mut terms: Vec<Box<Term>>,
atom_tbl: TabledData<Atom>,
) -> Result<UseModuleExport, CompilationError> {
let mut export_list = *terms.pop().unwrap();
let module_src = match *terms.pop().unwrap() {
Term::Clause(_, ref name, ref mut terms, None)
if name.as_str() == "library" && terms.len() == 1 =>
{
terms
.pop()
.unwrap()
.to_constant()
.and_then(|c| c.to_atom())
.map(|c| ModuleSource::Library(c))
.ok_or(CompilationError::InvalidUseModuleDecl)
}
Term::Constant(_, Constant::Atom(ref name, _)) => {
Ok(ModuleSource::File(name.clone()))
}
_ => {
Err(CompilationError::InvalidUseModuleDecl)
}
}?;
let mut exports = IndexSet::new();
while let Term::Cons(_, t1, t2) = export_list {
exports.insert(setup_module_export(*t1, atom_tbl.clone())?);
export_list = *t2;
}
if export_list.to_constant() != Some(Constant::EmptyList) {
Err(CompilationError::InvalidModuleDecl)
} else {
Ok((module_src, exports))
}
}
/*
* setup_meta_predicate tries to extract meta-predicate information
* from an appropriately formed declaration
*
* :- meta_predicate maplist(:, ?, ?).
*
* indicating that, for each QueryTerm call to maplist/3, the first
* argument is to be expanded with the call resolution ((:)/2)
* operator, the first argument of which is the name of the host
* module, as an atom. For example,
*
* p(X) :- maplist(X, [a,b,c], Result).
*
* If p/2 is defined in a module named "mod", the call is expanded to
*
* maplist(mod:X, [a,b,c], Result).
*
* before the predicate is compiled to WAM instructions.
*
* If the term bound to X -- the predicate to be called -- is
* qualified with (:)/2 already, the innermost qualifier is used for
* call resolution.
*
* The three arguments returned by a successful call are the module name,
* predicate name, and the list of meta-specs, one for each predicate argument.
*
* The module name might be used to specify intra-module meta-predicates whose
* module is not yet defined. There are several examples of this
* contained in src/lib/ops_and_meta_predicates.pl, which is loaded before
* src/lib/builtins.pl.
*
* Meta-specs have three forms:
*
* (:) (the argument should be expanded with (:)/2 as described above)
* + (mode declarations under the mode syntax, which currently have no effect)
* -
* ?
*/
fn setup_meta_predicate<'a>(
mut terms: Vec<Box<Term>>,
load_state: &LoadState<'a>,
) -> Result<(ClauseName, ClauseName, Vec<MetaSpec>), CompilationError>
{
fn get_name_and_meta_specs(
name: ClauseName,
terms: &mut [Box<Term>],
) -> Result<(ClauseName, Vec<MetaSpec>), CompilationError> {
let mut meta_specs = vec![];
for meta_spec in terms.into_iter() {
match &**meta_spec {
Term::Constant(_, Constant::Atom(meta_spec, _)) => {
let meta_spec =
match meta_spec.as_str() {
":" => MetaSpec::RequiresExpansion,
"+" => MetaSpec::Plus,
"-" => MetaSpec::Minus,
"?" => MetaSpec::Either,
_ => return Err(CompilationError::InvalidMetaPredicateDecl),
};
meta_specs.push(meta_spec);
}
Term::Constant(_, Constant::Fixnum(n)) => {
match usize::try_from(*n) {
Ok(n) if n <= MAX_ARITY => {
meta_specs.push(MetaSpec::RequiresExpansionWithArgument(n));
}
_ => {
return Err(CompilationError::InvalidMetaPredicateDecl);
}
}
}
_ => {
return Err(CompilationError::InvalidMetaPredicateDecl);
}
}
}
Ok((name, meta_specs))
}
match *terms.pop().unwrap() {
Term::Clause(_, name, mut terms, _)
if name.as_str() == ":" && terms.len() == 2 => {
let spec = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
match module_name {
Term::Constant(_, Constant::Atom(module_name, _)) => {
match spec {
Term::Clause(_, name, mut terms, _) => {
let (name, meta_specs) =
get_name_and_meta_specs(name, &mut terms)?;
Ok((module_name, name, meta_specs))
}
_ => {
Err(CompilationError::InvalidMetaPredicateDecl)
}
}
}
_ => {
Err(CompilationError::InvalidMetaPredicateDecl)
}
}
}
Term::Clause(_, name, mut terms, _) => {
let (name, meta_specs) = get_name_and_meta_specs(name, &mut terms)?;
Ok((load_state.module_name(), name, meta_specs))
}
_ => {
Err(CompilationError::InvalidMetaPredicateDecl)
}
}
}
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, CompilationError>
{
let mut clauses = vec![];
while let Some(tl) = tls.pop_front() {
match tl {
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => {
return Ok(tl);
}
TopLevel::Declaration(_) if clauses.is_empty() => {
return Ok(tl);
}
TopLevel::Query(_) => {
return Err(CompilationError::InconsistentEntry);
}
TopLevel::Fact(fact) => {
let clause = PredicateClause::Fact(fact);
clauses.push(clause);
}
TopLevel::Rule(rule) => {
let clause = PredicateClause::Rule(rule);
clauses.push(clause);
}
TopLevel::Predicate(predicate) => {
clauses.extend(predicate.into_iter())
}
_ => {
tls.push_front(tl);
break;
}
}
}
if clauses.is_empty() {
Err(CompilationError::InconsistentEntry)
} else {
Ok(TopLevel::Predicate(clauses))
}
}
fn mark_cut_variables_as(terms: &mut Vec<Term>, name: ClauseName) {
for term in terms.iter_mut() {
match term {
&mut Term::Constant(_, Constant::Atom(ref mut var, _)) if var.as_str() == "!" => {
*var = name.clone()
}
_ => {}
}
}
}
fn mark_cut_variable(term: &mut Term) -> bool {
let cut_var_found = match term {
&mut Term::Constant(_, Constant::Atom(ref var, _)) if var.as_str() == "!" => true,
_ => false,
};
if cut_var_found {
*term = Term::Var(Cell::default(), rc_atom!("!"));
true
} else {
false
}
}
fn mark_cut_variables(terms: &mut Vec<Term>) -> bool {
let mut found_cut_var = false;
for item in terms.iter_mut() {
found_cut_var = mark_cut_variable(item) || found_cut_var;
}
found_cut_var
}
// terms is a list of goals composing one clause in a (;) functor. it
// checks that the first (and only) of these clauses is a ->. if so,
// it expands its terms using a blocked_!.
fn check_for_internal_if_then(terms: &mut Vec<Term>) {
if terms.len() != 1 {
return;
}
if let Some(Term::Clause(_, ref name, ref subterms, _)) = terms.last() {
if name.as_str() != "->" || subterms.len() != 2 {
return;
}
} else {
return;
}
if let Some(Term::Clause(_, _, mut subterms, _)) = terms.pop() {
let mut conq_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
let mut pre_cut_terms = VecDeque::from(unfold_by_str(*subterms.pop().unwrap(), ","));
conq_terms.push_front(Term::Constant(
Cell::default(),
Constant::Atom(clause_name!("blocked_!"), None))
);
while let Some(term) = pre_cut_terms.pop_back() {
conq_terms.push_front(term);
}
let tail_term = conq_terms.pop_back().unwrap();
terms.push(fold_by_str(
conq_terms.into_iter(),
tail_term,
clause_name!(","),
));
}
}
fn setup_declaration<'a>(
load_state: &LoadState<'a>,
mut terms: Vec<Box<Term>>,
) -> Result<Declaration, CompilationError> {
let term = *terms.pop().unwrap();
let atom_tbl = load_state.wam.machine_st.atom_tbl.clone();
match term {
Term::Clause(_, name, mut terms, _) =>
match (name.as_str(), terms.len()) {
("dynamic", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::Dynamic(name, arity))
}
("module", 2) =>
Ok(Declaration::Module(setup_module_decl(terms, atom_tbl)?)),
("op", 3) =>
Ok(Declaration::Op(setup_op_decl(terms, atom_tbl)?)),
("non_counted_backtracking", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?;
Ok(Declaration::NonCountedBacktracking(name, arity))
}
("use_module", 1) => {
Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
}
("use_module", 2) => {
let (name, exports) = setup_qualified_import(terms, atom_tbl)?;
Ok(Declaration::UseQualifiedModule(name, exports))
}
("meta_predicate", 1) => {
let (module_name, name, meta_specs) = setup_meta_predicate(terms, load_state)?;
Ok(Declaration::MetaPredicate(module_name, name, meta_specs))
}
_ => {
Err(CompilationError::InconsistentEntry)
}
},
_ => {
Err(CompilationError::InconsistentEntry)
}
}
}
#[inline]
fn clause_to_query_term<'a>(
load_state: &mut LoadState<'a>,
name: ClauseName,
terms: Vec<Box<Term>>,
fixity: Option<SharedOpDesc>,
) -> QueryTerm {
let ct = load_state.get_clause_type(name, terms.len(), fixity);
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[inline]
fn qualified_clause_to_query_term<'a>(
load_state: &mut LoadState<'a>,
module_name: ClauseName,
name: ClauseName,
terms: Vec<Box<Term>>,
fixity: Option<SharedOpDesc>,
) -> QueryTerm {
let ct = load_state.get_qualified_clause_type(module_name, name, terms.len(), fixity);
QueryTerm::Clause(Cell::default(), ct, terms, false)
}
#[derive(Debug)]
pub(crate) struct Preprocessor {
flags: MachineFlags,
queue: VecDeque<VecDeque<Term>>,
}
impl Preprocessor {
pub(super)
fn new(flags: MachineFlags) -> Self {
Preprocessor {
flags,
queue: VecDeque::new(),
}
}
fn setup_fact(&mut self, term: Term) -> Result<Term, CompilationError> {
match term {
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
Ok(term)
}
_ => {
Err(CompilationError::InadmissibleFact)
}
}
}
fn compute_head(&self, term: &Term) -> Vec<Term> {
let mut vars = IndexSet::new();
for term in post_order_iter(term) {
if let TermRef::Var(_, _, v) = term {
vars.insert(v.clone());
}
}
vars.insert(rc_atom!("!"));
vars.into_iter()
.map(|v| Term::Var(Cell::default(), v))
.collect()
}
fn fabricate_rule_body(&self, vars: &Vec<Term>, body_term: Term) -> Term {
let vars_of_head = vars.iter().cloned().map(Box::new).collect();
let head_term = Term::Clause(Cell::default(), clause_name!(""), vars_of_head, None);
let rule = vec![Box::new(head_term), Box::new(body_term)];
let turnstile = clause_name!(":-");
Term::Clause(Cell::default(), turnstile, rule, None)
}
// the terms form the body of the rule. We create a head, by
// gathering variables from the body of terms and recording them
// in the head clause.
fn fabricate_rule(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
// collect the vars of body_term into a head, return the num_vars
// (the arity) as well.
let vars = self.compute_head(&body_term);
let rule = self.fabricate_rule_body(&vars, body_term);
(vars, VecDeque::from(vec![rule]))
}
fn fabricate_disjunct(&self, body_term: Term) -> (JumpStub, VecDeque<Term>) {
let vars = self.compute_head(&body_term);
let results = unfold_by_str(body_term, ";")
.into_iter()
.map(|term| {
let mut subterms = unfold_by_str(term, ",");
mark_cut_variables(&mut subterms);
check_for_internal_if_then(&mut subterms);
let term = subterms.pop().unwrap();
let clause = fold_by_str(subterms.into_iter(), term, clause_name!(","));
self.fabricate_rule_body(&vars, clause)
})
.collect();
(vars, results)
}
fn fabricate_if_then(&self, prec: Term, conq: Term) -> (JumpStub, VecDeque<Term>) {
let mut prec_seq = unfold_by_str(prec, ",");
let comma_sym = clause_name!(",");
let cut_sym = atom!("!");
prec_seq.push(Term::Constant(Cell::default(), cut_sym));
mark_cut_variables_as(&mut prec_seq, clause_name!("blocked_!"));
let mut conq_seq = unfold_by_str(conq, ",");
mark_cut_variables(&mut conq_seq);
prec_seq.extend(conq_seq.into_iter());
let back_term = Box::new(prec_seq.pop().unwrap());
let front_term = Box::new(prec_seq.pop().unwrap());
let body_term = Term::Clause(
Cell::default(),
comma_sym.clone(),
vec![front_term, back_term],
None,
);
self.fabricate_rule(fold_by_str(prec_seq.into_iter(), body_term, comma_sym))
}
fn to_query_term<'a>(
&mut self,
load_state: &mut LoadState<'a>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Constant(_, Constant::Atom(name, fixity)) => {
if name.as_str() == "!" || name.as_str() == "blocked_!" {
Ok(QueryTerm::BlockedCut)
} else {
Ok(clause_to_query_term(load_state, name, vec![], fixity))
}
}
Term::Var(_, ref v) if v.as_str() == "!" => {
Ok(QueryTerm::UnblockedCut(Cell::default()))
}
Term::Clause(r, name, mut terms, fixity) => {
match (name.as_str(), terms.len()) {
(";", 2) => {
let term = Term::Clause(r, name.clone(), terms, fixity);
let (stub, clauses) = self.fabricate_disjunct(term);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("->", 2) => {
let conq = *terms.pop().unwrap();
let prec = *terms.pop().unwrap();
let (stub, clauses) = self.fabricate_if_then(prec, conq);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("\\+", 1) => {
terms.push(Box::new(Term::Constant(
Cell::default(),
Constant::Atom(clause_name!("$fail"), None)
)));
let conq = Term::Constant(
Cell::default(),
Constant::Atom(clause_name!("true"), None)
);
let prec = Term::Clause(Cell::default(), clause_name!("->"), terms, None);
let terms = vec![Box::new(prec), Box::new(conq)];
let term = Term::Clause(Cell::default(), clause_name!(";"), terms, None);
let (stub, clauses) = self.fabricate_disjunct(term);
debug_assert!(clauses.len() > 0);
self.queue.push_back(clauses);
Ok(QueryTerm::Jump(stub))
}
("$get_level", 1) => {
if let Term::Var(_, ref var) = *terms[0] {
Ok(QueryTerm::GetLevelAndUnify(Cell::default(), var.clone()))
} else {
Err(CompilationError::InadmissibleQueryTerm)
}
}
(":", 2) => {
let predicate_name = *terms.pop().unwrap();
let module_name = *terms.pop().unwrap();
match (module_name, predicate_name) {
(Term::Constant(_, Constant::Atom(module_name, _)),
Term::Constant(_, Constant::Atom(predicate_name, fixity))) => {
Ok(qualified_clause_to_query_term(
load_state,
module_name,
predicate_name,
vec![],
fixity,
))
}
(Term::Constant(_, Constant::Atom(module_name, _)),
Term::Clause(_, name, terms, fixity)) => {
Ok(qualified_clause_to_query_term(
load_state,
module_name,
name,
terms,
fixity,
))
}
(module_name, predicate_name) => {
terms.push(Box::new(module_name));
terms.push(Box::new(predicate_name));
Ok(clause_to_query_term(load_state, name, terms, fixity))
}
}
}
_ => {
Ok(clause_to_query_term(load_state, name, terms, fixity))
}
}
}
Term::Var(..) => {
Ok(QueryTerm::Clause(
Cell::default(),
ClauseType::CallN,
vec![Box::new(term)],
false,
))
}
_ => {
Err(CompilationError::InadmissibleQueryTerm)
}
}
}
fn pre_query_term<'a>(
&mut self,
load_state: &mut LoadState<'a>,
term: Term,
) -> Result<QueryTerm, CompilationError> {
match term {
Term::Clause(r, name, mut subterms, fixity) => {
if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" {
self.to_query_term(load_state, *subterms.pop().unwrap())
.map(|mut query_term| {
query_term.set_default_caller();
query_term
})
} else {
self.to_query_term(load_state, Term::Clause(r, name, subterms, fixity))
}
}
_ => {
self.to_query_term(load_state, term)
}
}
}
fn setup_query<'a>(
&mut self,
load_state: &mut LoadState<'a>,
terms: Vec<Box<Term>>,
cut_context: CutContext,
) -> Result<Vec<QueryTerm>, CompilationError> {
let mut query_terms = vec![];
let mut work_queue = VecDeque::from(terms);
while let Some(term) = work_queue.pop_front() {
let mut term = *term;
if let Term::Clause(cell, name, terms, op_spec) = term {
if name.as_str() == "," && terms.len() == 2 {
let term = Term::Clause(cell, name, terms, op_spec);
let mut subterms = unfold_by_str(term, ",");
while let Some(subterm) = subterms.pop() {
work_queue.push_front(Box::new(subterm));
}
continue;
} else {
term = Term::Clause(cell, name, terms, op_spec);
}
}
if let CutContext::HasCutVariable = cut_context {
mark_cut_variable(&mut term);
}
query_terms.push(self.pre_query_term(load_state, term)?);
}
Ok(query_terms)
}
fn setup_rule<'a>(
&mut self,
load_state: &mut LoadState<'a>,
mut terms: Vec<Box<Term>>,
cut_context: CutContext,
) -> Result<Rule, CompilationError> {
let post_head_terms: Vec<_> = terms.drain(1 ..).collect();
let mut query_terms =
self.setup_query(load_state, post_head_terms, cut_context)?;
let clauses = query_terms.drain(1 ..).collect();
let qt = query_terms.pop().unwrap();
match *terms.pop().unwrap() {
Term::Clause(_, name, terms, _) => {
Ok(Rule {
head: (name, terms, qt),
clauses,
})
}
Term::Constant(_, Constant::Atom(name, _)) => {
Ok(Rule {
head: (name, vec![], qt),
clauses,
})
}
_ => {
Err(CompilationError::InvalidRuleHead)
}
}
}
fn try_term_to_query<'a>(
&mut self,
load_state: &mut LoadState<'a>,
terms: Vec<Box<Term>>,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
Ok(TopLevel::Query(self.setup_query(load_state, terms, cut_context)?))
}
pub(super)
fn try_term_to_tl<'a>(
&mut self,
load_state: &mut LoadState<'a>,
term: Term,
cut_context: CutContext,
) -> Result<TopLevel, CompilationError> {
match term {
Term::Clause(r, name, terms, fixity) => {
if name.as_str() == "?-" {
self.try_term_to_query(load_state, terms, cut_context)
} else if name.as_str() == ":-" && terms.len() == 2 {
Ok(TopLevel::Rule(self.setup_rule(
load_state,
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)?))
}
}
term => {
Ok(TopLevel::Fact(self.setup_fact(term)?))
}
}
}
fn try_terms_to_tls<'a, I: IntoIterator<Item = Term>>(
&mut self,
load_state: &mut LoadState<'a>,
terms: I,
cut_context: CutContext,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut results = VecDeque::new();
for term in terms.into_iter() {
results.push_back(self.try_term_to_tl(load_state, term, cut_context)?);
}
Ok(results)
}
pub(super)
fn parse_queue<'a>(
&mut self,
load_state: &mut LoadState<'a>,
) -> Result<VecDeque<TopLevel>, CompilationError> {
let mut queue = VecDeque::new();
while let Some(terms) = self.queue.pop_front() {
let clauses = merge_clauses(
&mut self.try_terms_to_tls(
load_state,
terms,
CutContext::HasCutVariable,
)?
)?;
queue.push_back(clauses);
}
Ok(queue)
}
}

View File

@@ -1,11 +1,11 @@
:- module('$project_atts', [copy_term/3]). :- module('$project_atts', [copy_term/3]).
'$attribute_goals_driver'(QueryVars, AttrVars) :- driver(QueryVars, AttrVars) :-
gather_modules(AttrVars, Modules0, _), gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules), sort(Modules0, Modules),
call_project_attributes(Modules, QueryVars, AttrVars), call_project_attributes(Modules, QueryVars, AttrVars),
call_attribute_goals(Modules, call_query_var_goals, QueryVars), call_attribute_goals(Modules, '$project_atts':call_query_var_goals, QueryVars),
call_attribute_goals(Modules, call_attr_var_goals, AttrVars). call_attribute_goals(Modules, '$project_atts':call_attr_var_goals, AttrVars).
enqueue_goals(Goals0) :- enqueue_goals(Goals0) :-
nonvar(Goals0), nonvar(Goals0),
@@ -36,7 +36,7 @@ call_project_attributes([Module|Modules], QueryVars, AttrVars) :-
call_project_attributes(Modules, QueryVars, AttrVars). call_project_attributes(Modules, QueryVars, AttrVars).
call_attribute_goals([], _, _). call_attribute_goals([], _, _).
call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :- call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :-
call(GoalCaller, AttrVars, Module, Goals), call(GoalCaller, AttrVars, Module, Goals),
enqueue_goals(Goals), enqueue_goals(Goals),
call_attribute_goals(Modules, GoalCaller, AttrVars). call_attribute_goals(Modules, GoalCaller, AttrVars).
@@ -51,13 +51,13 @@ call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :-
call_query_var_goals([], _, []). call_query_var_goals([], _, []).
call_query_var_goals([AttrVar|AttrVars], Module, Goals) :- call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0) ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0),
, atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals)
), ),
E, E,
( '$print_attribute_goals_exception'(Module, E), ( '$project_atts':'$print_attribute_goals_exception'(Module, E),
atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals) atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
)) ))
-> true -> true
; atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals) ; atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals)
), ),
@@ -66,25 +66,14 @@ call_query_var_goals([AttrVar|AttrVars], Module, Goals) :-
call_attr_var_goals([], _, []). call_attr_var_goals([], _, []).
call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :- call_attr_var_goals([AttrVar|AttrVars], Module, Goals) :-
( catch(Module:attribute_goals(AttrVar, Goals, RGoals), ( catch(Module:attribute_goals(AttrVar, Goals, RGoals),
E, E,
'$print_attribute_goals_exception'(Module, E) '$project_atts':'$print_attribute_goals_exception'(Module, E)
) )
-> true -> true
; true ; true
), ),
call_attr_var_goals(AttrVars, Module, RGoals). call_attr_var_goals(AttrVars, Module, RGoals).
gather_modules([], [], _).
gather_modules([AttrVar|AttrVars], Modules, Modules0) :-
'$get_attr_list'(AttrVar, Attrs),
gather_modules_for_attrs(Attrs, Modules, Modules0),
gather_modules(AttrVars, Modules0, _).
gather_modules_for_attrs(Attrs, Modules, Modules) :-
var(Attrs), !.
gather_modules_for_attrs([Attr|Attrs], [Module|Modules], Modules0) :-
'$module_of'(Module, Attr),
gather_modules_for_attrs(Attrs, Modules, Modules0).
module_prefixed_goals([], _, Gs, Gs). module_prefixed_goals([], _, Gs, Gs).
module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :- module_prefixed_goals([G|Gs], Module, [MG|MGs], TailGs) :-
@@ -100,11 +89,25 @@ call_attribute_goals_with_module_prefix([Module | Modules], GoalCaller, AttrVars
module_prefixed_goals(Goals0, Module, Goals, Gs), module_prefixed_goals(Goals0, Module, Goals, Gs),
call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs). call_attribute_goals_with_module_prefix(Modules, GoalCaller, AttrVars, Gs).
gather_attr_modules([], []).
gather_attr_modules([AttrVar|AttrVars], Modules) :-
'$get_attr_list'(AttrVar, Attrs),
copy_attribute_modules(Attrs, Modules, Modules0),
gather_attr_modules(AttrVars, Modules0).
copy_attribute_modules(Attrs, Ls, Ls) :-
var(Attrs), !.
copy_attribute_modules([Module:_|Attrs], [Module|Modules0], Modules1) :-
copy_attribute_modules(Attrs, Modules0, Modules1).
copy_term(Source, Dest, Goals) :- copy_term(Source, Dest, Goals) :-
'$term_attributed_variables'(Source, Vars), '$term_attributed_variables'(Source, AttrVars),
gather_modules(Vars, Modules0, _), gather_attr_modules(AttrVars, Modules0),
sort(Modules0, Modules), sort(Modules0, Modules),
call_attribute_goals_with_module_prefix(Modules, call_query_var_goals, Vars, Goals0), call_attribute_goals_with_module_prefix(Modules, '$project_atts':call_query_var_goals,
AttrVars, Goals0),
sort(Goals0, Goals1), sort(Goals0, Goals1),
!, !,
'$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]). '$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]).

View File

@@ -246,10 +246,6 @@ impl Stack {
} }
} }
pub fn take(&mut self) -> Self {
Stack { buf: self.buf.take(), _marker: PhantomData }
}
#[inline] #[inline]
pub fn truncate(&mut self, b: usize) { pub fn truncate(&mut self, b: usize) {
if b == 0 { if b == 0 {

View File

@@ -179,10 +179,10 @@ impl Drop for StreamInstance {
fn drop(&mut self) { fn drop(&mut self) {
match self { match self {
StreamInstance::TcpStream(_, ref mut tcp_stream) => { StreamInstance::TcpStream(_, ref mut tcp_stream) => {
discard_result!(tcp_stream.shutdown(Shutdown::Both)); tcp_stream.shutdown(Shutdown::Both).unwrap();
} }
StreamInstance::TlsStream(_, ref mut tls_stream) => { StreamInstance::TlsStream(_, ref mut tls_stream) => {
discard_result!(tls_stream.shutdown()); tls_stream.shutdown().unwrap();
} }
_ => { _ => {
} }

View File

@@ -6,14 +6,16 @@ use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::heap_print::*; use crate::heap_print::*;
use crate::instructions::*; use crate::instructions::*;
use crate::machine;
use crate::machine::code_repo::CodeRepo; use crate::machine::code_repo::CodeRepo;
use crate::machine::copier::*; use crate::machine::copier::*;
use crate::machine::code_walker::*; use crate::machine::code_walker::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
use crate::machine::machine_state::*; use crate::machine::machine_state::*;
use crate::machine::preprocessor::to_op_decl;
use crate::machine::streams::*; use crate::machine::streams::*;
use crate::machine::toplevel::to_op_decl;
use crate::ordered_float::OrderedFloat; use crate::ordered_float::OrderedFloat;
use crate::read::readline; use crate::read::readline;
use crate::rug::Integer; use crate::rug::Integer;
@@ -402,9 +404,7 @@ impl MachineState {
} }
} }
let mode = let mode = atom_from!(self, self.store(self.deref(self[temp_v!(2)])));
atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)])));
let mut open_options = fs::OpenOptions::new(); let mut open_options = fs::OpenOptions::new();
let (is_input_file, in_append_mode) = let (is_input_file, in_append_mode) =
@@ -560,7 +560,7 @@ impl MachineState {
let spec = get_clause_spec( let spec = get_clause_spec(
name.clone(), name.clone(),
*arity, *arity,
composite_op!(&indices.op_dir), &CompositeOpDir::new(&indices.op_dir, None),
); );
let addr = self.heap.to_unifiable(HeapCellValue::DBRef( let addr = self.heap.to_unifiable(HeapCellValue::DBRef(
@@ -681,11 +681,11 @@ impl MachineState {
let mut parser = Parser::new( let mut parser = Parser::new(
&mut stream, &mut stream,
indices.atom_tbl.clone(), self.atom_tbl.clone(),
self.machine_flags(), self.machine_flags(),
); );
match parser.read_term(composite_op!(&indices.op_dir)) { match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) {
Err(err) => { Err(err) => {
let h = self.heap.h(); let h = self.heap.h();
let err = MachineError::syntax_error(h, err); let err = MachineError::syntax_error(h, err);
@@ -792,6 +792,7 @@ impl MachineState {
current_output_stream: &mut Stream, current_output_stream: &mut Stream,
) -> CallResult { ) -> CallResult {
match ct { match ct {
/*
&SystemClauseType::AbolishClause => { &SystemClauseType::AbolishClause => {
let p = self.cp; let p = self.cp;
let trans_type = DynamicTransactionType::Abolish; let trans_type = DynamicTransactionType::Abolish;
@@ -806,6 +807,7 @@ impl MachineState {
self.p = CodePtr::DynamicTransaction(trans_type, p); self.p = CodePtr::DynamicTransaction(trans_type, p);
return Ok(()); return Ok(());
} }
*/
&SystemClauseType::BindFromRegister => { &SystemClauseType::BindFromRegister => {
let reg = self.store(self.deref(self[temp_v!(2)])); let reg = self.store(self.deref(self[temp_v!(2)]));
let n = let n =
@@ -833,6 +835,7 @@ impl MachineState {
self.fail = true; self.fail = true;
} }
/*
&SystemClauseType::AssertDynamicPredicateToFront => { &SystemClauseType::AssertDynamicPredicateToFront => {
let p = self.cp; let p = self.cp;
let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front); let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front);
@@ -841,19 +844,21 @@ impl MachineState {
return Ok(()); return Ok(());
} }
&SystemClauseType::AssertDynamicPredicateToBack => { &SystemClauseType::AssertDynamicPredicateToBack => {
let p = self.cp; // let p = self.cp;
let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back); // let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back);
self.p = CodePtr::DynamicTransaction(trans_type, p); // self.p = CodePtr::DynamicTransaction(trans_type, p);
self.p = CodePtr::REPL(REPLCodePtr::UserAssertz, self.cp);
return Ok(()); return Ok(());
} }
*/
&SystemClauseType::CurrentHostname => { &SystemClauseType::CurrentHostname => {
match hostname::get().ok() { match hostname::get().ok() {
Some(host) => { Some(host) => {
match host.into_string().ok() { match host.into_string().ok() {
Some(host) => { Some(host) => {
let hostname = self.heap.to_unifiable( let hostname = self.heap.to_unifiable(
HeapCellValue::Atom(clause_name!(host, indices.atom_tbl), None) HeapCellValue::Atom(clause_name!(host, self.atom_tbl), None)
); );
self.unify(self[temp_v!(1)], hostname); self.unify(self[temp_v!(1)], hostname);
@@ -1016,6 +1021,7 @@ impl MachineState {
return Err(err); return Err(err);
} }
}; };
let chars = self.heap.put_complete_string(current); let chars = self.heap.put_complete_string(current);
self.unify(self[temp_v!(1)], chars); self.unify(self[temp_v!(1)], chars);
@@ -1092,11 +1098,13 @@ impl MachineState {
return Ok(()); return Ok(());
} }
} }
/*
&SystemClauseType::AtEndOfExpansion => { &SystemClauseType::AtEndOfExpansion => {
if self.cp == LocalCodePtr::TopLevel(0, 0) { if self.cp == LocalCodePtr::TopLevel(0, 0) {
self.at_end_of_expansion = true; self.at_end_of_expansion = true;
} }
} }
*/
&SystemClauseType::AtomChars => { &SystemClauseType::AtomChars => {
let a1 = self[temp_v!(1)]; let a1 = self[temp_v!(1)];
@@ -1139,7 +1147,7 @@ impl MachineState {
if &string == "[]" { if &string == "[]" {
self.unify(addr, Addr::EmptyList); self.unify(addr, Addr::EmptyList);
} else { } else {
let chars = clause_name!(string, indices.atom_tbl); let chars = clause_name!(string, self.atom_tbl);
let atom = self.heap.to_unifiable( let atom = self.heap.to_unifiable(
HeapCellValue::Atom(chars, None) HeapCellValue::Atom(chars, None)
); );
@@ -1254,7 +1262,7 @@ impl MachineState {
} }
let string = self.heap.to_unifiable( let string = self.heap.to_unifiable(
HeapCellValue::Atom(clause_name!(chars, indices.atom_tbl), None) HeapCellValue::Atom(clause_name!(chars, self.atom_tbl), None)
); );
self.bind(addr.as_var().unwrap(), string); self.bind(addr.as_var().unwrap(), string);
@@ -1281,7 +1289,7 @@ impl MachineState {
clause_name!("[]") clause_name!("[]")
} }
Addr::Char(c) => { Addr::Char(c) => {
clause_name!(c.to_string(), indices.atom_tbl) clause_name!(c.to_string(), self.atom_tbl)
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -1858,6 +1866,7 @@ impl MachineState {
} }
} }
} }
/*
&SystemClauseType::ModuleAssertDynamicPredicateToFront => { &SystemClauseType::ModuleAssertDynamicPredicateToFront => {
let p = self.cp; let p = self.cp;
let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front); let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front);
@@ -1872,6 +1881,7 @@ impl MachineState {
self.p = CodePtr::DynamicTransaction(trans_type, p); self.p = CodePtr::DynamicTransaction(trans_type, p);
return Ok(()); return Ok(());
} }
*/
&SystemClauseType::LiftedHeapLength => { &SystemClauseType::LiftedHeapLength => {
let a1 = self[temp_v!(1)]; let a1 = self[temp_v!(1)];
let lh_len = Addr::Usize(self.lifted_heap.h()); let lh_len = Addr::Usize(self.lifted_heap.h());
@@ -2854,6 +2864,7 @@ impl MachineState {
self.unify(Addr::Char(c), a1); self.unify(Addr::Char(c), a1);
} }
/*
&SystemClauseType::GetModuleClause => { &SystemClauseType::GetModuleClause => {
let module = self[temp_v!(3)]; let module = self[temp_v!(3)];
let head = self[temp_v!(1)]; let head = self[temp_v!(1)];
@@ -2944,20 +2955,24 @@ impl MachineState {
_ => unreachable!(), _ => unreachable!(),
}; };
} }
*/
&SystemClauseType::HeadIsDynamic => { &SystemClauseType::HeadIsDynamic => {
let head = self[temp_v!(1)]; let module_name = atom_from!(
self,
self.store(self.deref(
self[temp_v!(1)]
))
);
self.fail = !match self.store(self.deref(head)) { self.fail = !match self.store(self.deref(self[temp_v!(2)])) {
Addr::Str(s) => match &self.heap[s] { Addr::Str(s) => match &self.heap[s] {
&HeapCellValue::NamedStr(arity, ref name, ..) => indices &HeapCellValue::NamedStr(arity, ref name, ..) =>
.get_clause_subsection(name.owning_module(), name.clone(), arity) indices.is_dynamic_predicate(module_name, (name.clone(), arity)),
.is_some(),
_ => unreachable!(), _ => unreachable!(),
}, },
Addr::Con(h) if self.heap.atom_at(h) => { Addr::Con(h) if self.heap.atom_at(h) => {
if let HeapCellValue::Atom(name, _) = &self.heap[h] { if let HeapCellValue::Atom(name, _) = &self.heap[h] {
indices.get_clause_subsection(name.owning_module(), name.clone(), 0) indices.is_dynamic_predicate(module_name, (name.clone(), 0))
.is_some()
} else { } else {
unreachable!() unreachable!()
} }
@@ -3111,21 +3126,27 @@ impl MachineState {
return self.module_lookup( return self.module_lookup(
indices, indices,
call_policy,
(name, arity + narity), (name, arity + narity),
module_name, module_name,
true, true,
current_input_stream,
current_output_stream,
); );
} else { } else {
unreachable!() unreachable!()
} }
} }
Addr::Con(h) if self.heap.atom_at(h) => { Addr::Con(h) if self.heap.atom_at(h) => {
if let HeapCellValue::Atom(name, _) = self.heap.clone(h) { if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
return self.module_lookup( return self.module_lookup(
indices, indices,
call_policy,
(name.clone(), narity), (name.clone(), narity),
module_name, module_name,
true, true,
current_input_stream,
current_output_stream,
); );
} else { } else {
unreachable!() unreachable!()
@@ -3160,6 +3181,7 @@ impl MachineState {
} }
} }
} }
/*
&SystemClauseType::ExpandGoal => { &SystemClauseType::ExpandGoal => {
self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)); self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0));
return Ok(()); return Ok(());
@@ -3168,6 +3190,7 @@ impl MachineState {
self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0)); self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0));
return Ok(()); return Ok(());
} }
*/
&SystemClauseType::GetNextDBRef => { &SystemClauseType::GetNextDBRef => {
let a1 = self[temp_v!(1)]; let a1 = self[temp_v!(1)];
@@ -3185,7 +3208,7 @@ impl MachineState {
let spec = get_clause_spec( let spec = get_clause_spec(
name.clone(), name.clone(),
*arity, *arity,
composite_op!(&indices.op_dir), &CompositeOpDir::new(&indices.op_dir, None),
); );
let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); let db_ref = DBRef::NamedPred(name.clone(), *arity, spec);
@@ -3429,7 +3452,7 @@ impl MachineState {
let op = match self.store(self.deref(op)) { let op = match self.store(self.deref(op)) {
Addr::Char(c) => Addr::Char(c) =>
clause_name!(c.to_string(), indices.atom_tbl), clause_name!(c.to_string(), self.atom_tbl),
Addr::Con(h) if self.heap.atom_at(h) => Addr::Con(h) if self.heap.atom_at(h) =>
if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { if let HeapCellValue::Atom(ref name, _) = &self.heap[h] {
name.clone() name.clone()
@@ -3440,16 +3463,18 @@ impl MachineState {
unreachable!(), unreachable!(),
}; };
let module = op.owning_module();
let result = to_op_decl(priority, specifier.as_str(), op) let result = to_op_decl(priority, specifier.as_str(), op)
.map_err(SessionError::from) .map_err(SessionError::from)
.and_then(|op_decl| { .and_then(|mut op_decl| {
if op_decl.0 == 0 { if op_decl.prec == 0 {
Ok(op_decl.remove(&mut indices.op_dir)) Ok(op_decl.remove(&mut indices.op_dir))
} else { } else {
let spec = get_desc(op_decl.name(), composite_op!(&indices.op_dir)); let spec = get_op_desc(
op_decl.submit(module, spec, &mut indices.op_dir) op_decl.name.clone(),
&CompositeOpDir::new(&indices.op_dir, None),
);
op_decl.submit(spec, &mut indices.op_dir)
} }
}); });
@@ -3493,10 +3518,10 @@ impl MachineState {
let mut heap_pstr_iter = let mut heap_pstr_iter =
self.heap_pstr_iter(Addr::PStrLocation(h, n)); self.heap_pstr_iter(Addr::PStrLocation(h, n));
let file_spec = let file_spec =
clause_name!( clause_name!(
heap_pstr_iter.to_string(), heap_pstr_iter.to_string(),
indices.atom_tbl.clone() self.atom_tbl
); );
self.stream_from_file_spec(file_spec, indices, &options)? self.stream_from_file_spec(file_spec, indices, &options)?
@@ -3901,65 +3926,18 @@ impl MachineState {
} }
}; };
} }
&SystemClauseType::ModuleOf => {
let module = self.store(self.deref(self[temp_v!(2)]));
match module {
Addr::Con(h) if self.heap.atom_at(h) => {
if let HeapCellValue::Atom(name, _) = self.heap.clone(h) {
let module = self.heap.to_unifiable(
HeapCellValue::Atom(
name.owning_module(),
None
),
);
let target = self[temp_v!(1)];
self.unify(target, module);
} else {
unreachable!()
}
}
Addr::Str(s) => match self.heap.clone(s) {
HeapCellValue::NamedStr(_, name, ..) => {
let module = self.heap.to_unifiable(
HeapCellValue::Atom(
name.owning_module(),
None
),
);
let target = self[temp_v!(1)];
self.unify(target, module);
}
HeapCellValue::Addr(addr) if addr.is_ref() => {
let err = MachineError::uninstantiation_error(addr);
let stub = MachineError::functor_stub(
clause_name!("$module_of"),
2,
);
return Err(self.error_form(err, stub));
}
_ => {
unreachable!()
}
},
_ => {
self.fail = true;
}
};
}
&SystemClauseType::NoSuchPredicate => { &SystemClauseType::NoSuchPredicate => {
let head = self[temp_v!(1)]; let module_name = atom_from!(self, self.store(self.deref(self[temp_v!(1)])));
self.fail = match self.store(self.deref(head)) { self.fail = match self.store(self.deref(self[temp_v!(2)])) {
Addr::Str(s) => match &self.heap[s] { Addr::Str(s) => match &self.heap[s] {
&HeapCellValue::NamedStr(arity, ref name, ref spec) => { &HeapCellValue::NamedStr(arity, ref name, ref spec) => {
let module = name.owning_module(); indices.get_predicate_code_index(
indices.predicate_exists(name.clone(), module, arity, spec.clone()) name.clone(),
arity,
module_name,
spec.clone(),
).is_some()
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -3967,14 +3945,14 @@ impl MachineState {
}, },
Addr::Con(h) if self.heap.atom_at(h) => { Addr::Con(h) if self.heap.atom_at(h) => {
if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] {
let module = name.owning_module();
let spec = fetch_atom_op_spec( let spec = fetch_atom_op_spec(
name.clone(), name.clone(),
spec.clone(), spec.clone(),
&indices.op_dir, &indices.op_dir,
); );
indices.predicate_exists(name.clone(), module, 0, spec) indices.get_predicate_code_index(name.clone(), 0, module_name, spec)
.is_some()
} else { } else {
unreachable!() unreachable!()
} }
@@ -4116,6 +4094,7 @@ impl MachineState {
&SystemClauseType::REPL(repl_code_ptr) => { &SystemClauseType::REPL(repl_code_ptr) => {
return self.repl_redirect(repl_code_ptr); return self.repl_redirect(repl_code_ptr);
} }
/*
&SystemClauseType::ModuleRetractClause => { &SystemClauseType::ModuleRetractClause => {
let p = self.cp; let p = self.cp;
let trans_type = DynamicTransactionType::ModuleRetract; let trans_type = DynamicTransactionType::ModuleRetract;
@@ -4130,6 +4109,7 @@ impl MachineState {
self.p = CodePtr::DynamicTransaction(trans_type, p); self.p = CodePtr::DynamicTransaction(trans_type, p);
return Ok(()); return Ok(());
} }
*/
&SystemClauseType::ReturnFromVerifyAttr => { &SystemClauseType::ReturnFromVerifyAttr => {
let e = self.e; let e = self.e;
let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells;
@@ -4326,6 +4306,7 @@ impl MachineState {
self.unify(a1, a2); self.unify(a1, a2);
} }
/*
&SystemClauseType::GetClause => { &SystemClauseType::GetClause => {
let head = self[temp_v!(1)]; let head = self[temp_v!(1)];
@@ -4343,14 +4324,14 @@ impl MachineState {
} }
}, },
Addr::Con(h) if self.heap.atom_at(h) => { Addr::Con(h) if self.heap.atom_at(h) => {
if let &HeapCellValue::Atom(ref name, _) = &self.heap[h] { if let &HeapCellValue::Atom(ref name, _) = &self.heap[h] {
indices.get_clause_subsection( indices.get_clause_subsection(
name.owning_module(), name.owning_module(),
name.clone(), name.clone(),
0, 0,
) )
} else { } else {
unreachable!() unreachable!()
} }
} }
_ => { _ => {
@@ -4372,6 +4353,7 @@ impl MachineState {
} }
} }
} }
*/
&SystemClauseType::GetCutPoint => { &SystemClauseType::GetCutPoint => {
let a1 = self[temp_v!(1)]; let a1 = self[temp_v!(1)];
let a2 = Addr::CutPoint(self.b0); let a2 = Addr::CutPoint(self.b0);
@@ -4524,7 +4506,7 @@ impl MachineState {
let term_write_result = let term_write_result =
match self.read( match self.read(
Stream::from(chars), Stream::from(chars),
indices.atom_tbl.clone(), self.atom_tbl.clone(),
&indices.op_dir, &indices.op_dir,
) { ) {
Ok(term_write_result) => { Ok(term_write_result) => {
@@ -4595,10 +4577,11 @@ impl MachineState {
let mut rand = RANDOM_STATE.borrow_mut(); let mut rand = RANDOM_STATE.borrow_mut();
rand.seed(&seed); rand.seed(&seed);
} }
&SystemClauseType::SkipMaxList => &SystemClauseType::SkipMaxList => {
if let Err(err) = self.skip_max_list() { if let Err(err) = self.skip_max_list() {
return Err(err); return Err(err);
}, }
}
&SystemClauseType::Sleep => { &SystemClauseType::Sleep => {
let time = self.store(self.deref(self[temp_v!(1)])); let time = self.store(self.deref(self[temp_v!(1)]));
@@ -4695,11 +4678,10 @@ impl MachineState {
let stream = let stream =
match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) { match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) {
Ok(tcp_stream) => { Ok(tcp_stream) => {
let socket_addr = clause_name!(socket_addr, indices.atom_tbl.clone()); let socket_addr = clause_name!(socket_addr, self.atom_tbl);
let mut stream = {
let mut stream = let tls = match self.store(self.deref(self[temp_v!(8)])) {
{ let tls = match self.store(self.deref(self[temp_v!(8)])) {
Addr::Con(h) if self.heap.atom_at(h) => { Addr::Con(h) if self.heap.atom_at(h) => {
if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] {
atom.as_str() atom.as_str()
@@ -4711,6 +4693,7 @@ impl MachineState {
unreachable!() unreachable!()
} }
}; };
match tls { match tls {
"false" => { Stream::from_tcp_stream(socket_addr, tcp_stream) } "false" => { Stream::from_tcp_stream(socket_addr, tcp_stream) }
"true" => { let connector = TlsConnector::new().unwrap(); "true" => { let connector = TlsConnector::new().unwrap();
@@ -4724,6 +4707,7 @@ impl MachineState {
_ => { unreachable!() } _ => { unreachable!() }
} }
}; };
stream.options = options; stream.options = options;
if let Some(ref alias) = &stream.options.alias { if let Some(ref alias) = &stream.options.alias {
@@ -4877,7 +4861,7 @@ impl MachineState {
match tcp_listener.accept().ok() { match tcp_listener.accept().ok() {
Some((tcp_stream, socket_addr)) => { Some((tcp_stream, socket_addr)) => {
let client = let client =
clause_name!(format!("{}", socket_addr), indices.atom_tbl); clause_name!(format!("{}", socket_addr), self.atom_tbl);
let mut tcp_stream = let mut tcp_stream =
Stream::from_tcp_stream(client.clone(), tcp_stream); Stream::from_tcp_stream(client.clone(), tcp_stream);
@@ -5226,8 +5210,13 @@ impl MachineState {
self.fail = self.structural_eq_test(); self.fail = self.structural_eq_test();
} }
&SystemClauseType::WAMInstructions => { &SystemClauseType::WAMInstructions => {
let name = self[temp_v!(1)]; let module_name = atom_from!(
let arity = self[temp_v!(2)]; self,
self.store(self.deref(self[temp_v!(1)]))
);
let name = self[temp_v!(2)];
let arity = self[temp_v!(3)];
let name = match self.store(self.deref(name)) { let name = match self.store(self.deref(name)) {
Addr::Con(h) if self.heap.atom_at(h) => { Addr::Con(h) if self.heap.atom_at(h) => {
@@ -5257,51 +5246,84 @@ impl MachineState {
} }
}; };
let first_idx = match indices let key = (name.clone(), arity.to_usize().unwrap());
.code_dir
.get(&(name.clone(), arity.to_usize().unwrap())) let first_idx = match module_name.as_str() {
{ "user" => indices.code_dir.get(&key),
Some(ref idx) if idx.local().is_some() => { _ => match indices.modules.get(&module_name) {
if let Some(idx) = idx.local() { Some(module) => module.code_dir.get(&key),
idx None => {
} else { let stub = MachineError::functor_stub(key.0, key.1);
unreachable!() let h = self.heap.h();
let err = MachineError::session_error(
h,
SessionError::from(
CompilationError::InvalidModuleResolution(
module_name
)
),
);
let err = self.error_form(err, stub);
self.throw_exception(err);
return Ok(());
} }
} },
_ => {
let arity = arity.to_usize().unwrap();
let stub = MachineError::functor_stub(name.clone(), arity);
let h = self.heap.h();
let err = MachineError::existence_error(
h,
ExistenceError::Procedure(name, arity),
);
let err = self.error_form(err, stub);
self.throw_exception(err);
return Ok(());
}
}; };
let first_idx =
match first_idx {
Some(ref idx) if idx.local().is_some() => {
if let Some(idx) = idx.local() {
idx
} else {
unreachable!()
}
}
_ => {
let arity = arity.to_usize().unwrap();
let stub = MachineError::functor_stub(name.clone(), arity);
let h = self.heap.h();
let err = MachineError::existence_error(
h,
ExistenceError::Procedure(name, arity),
);
let err = self.error_form(err, stub);
self.throw_exception(err);
return Ok(());
}
};
let mut h = self.heap.h(); let mut h = self.heap.h();
let mut functors = vec![]; let mut functors = vec![];
let mut functor_list = vec![];
walk_code( walk_code(
&code_repo.code, &code_repo.code,
first_idx, first_idx,
|instr| { |instr| {
let section = instr.to_functor(h); let old_len = functors.len();
functors.push(Addr::HeapCell(h)); instr.enqueue_functors(h, &mut functors);
let new_len = functors.len();
h += section.len(); for index in old_len .. new_len {
self.heap.extend(section.into_iter()); functor_list.push(Addr::HeapCell(h));
h += functors[index].len();
}
}, },
); );
let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter())); for functor in functors {
let listing_var = self[temp_v!(3)]; self.heap.extend(functor.into_iter());
}
let listing = Addr::HeapCell(self.heap.to_list(functor_list.into_iter()));
let listing_var = self[temp_v!(4)];
self.unify(listing, listing_var); self.unify(listing, listing_var);
} }
@@ -5831,6 +5853,53 @@ impl MachineState {
self.unify(self[temp_v!(2)], cstr); self.unify(self[temp_v!(2)], cstr);
} }
} }
&SystemClauseType::LoadLibraryAsStream => {
let library_name =
atom_from!(
self,
self.store(self.deref(self[temp_v!(1)]))
);
use crate::LIBRARIES;
match LIBRARIES.borrow().get(library_name.as_str()) {
Some(library) => {
let var_ref = Ref::HeapCell(self.heap.push(
HeapCellValue::Stream(Stream::from(*library))
));
self.bind(var_ref, self[temp_v!(2)]);
let mut path_buf = machine::current_dir();
path_buf.push("/lib");
path_buf.push(library_name.as_str());
let library_path_str = path_buf.to_str().unwrap();
let library_path =
clause_name!(library_path_str.to_string(), self.atom_tbl);
let library_path_ref = Ref::HeapCell(
self.heap.push(HeapCellValue::Atom(library_path, None))
);
self.bind(library_path_ref, self[temp_v!(3)]);
}
None => {
return Err(
self.error_form(
MachineError::existence_error(
self.heap.h(),
ExistenceError::ModuleSource(
ModuleSource::Library(library_name)
),
),
MachineError::functor_stub(clause_name!("load"), 1),
)
);
}
}
}
}; };
return_from_clause!(self.last_call, self) return_from_clause!(self.last_call, self)
@@ -5905,7 +5974,7 @@ impl MachineState {
} else { } else {
let mut avec = Vec::new(); let mut avec = Vec::new();
for attr in node.attributes() { for attr in node.attributes() {
let chars = clause_name!(String::from(attr.name()), indices.atom_tbl); let chars = clause_name!(String::from(attr.name()), self.atom_tbl);
let name = self.heap.to_unifiable( let name = self.heap.to_unifiable(
HeapCellValue::Atom(chars, None) HeapCellValue::Atom(chars, None)
); );
@@ -5926,7 +5995,7 @@ impl MachineState {
} }
let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter()));
let chars = clause_name!(String::from(node.tag_name().name()), indices.atom_tbl); let chars = clause_name!(String::from(node.tag_name().name()), self.atom_tbl);
let tag = self.heap.to_unifiable( let tag = self.heap.to_unifiable(
HeapCellValue::Atom(chars, None) HeapCellValue::Atom(chars, None)
); );
@@ -5955,7 +6024,7 @@ impl MachineState {
Some(name) => { Some(name) => {
let mut avec = Vec::new(); let mut avec = Vec::new();
for attr in node.attrs() { for attr in node.attrs() {
let chars = clause_name!(String::from(attr.0), indices.atom_tbl); let chars = clause_name!(String::from(attr.0), self.atom_tbl);
let name = self.heap.to_unifiable( let name = self.heap.to_unifiable(
HeapCellValue::Atom(chars, None) HeapCellValue::Atom(chars, None)
); );
@@ -5976,7 +6045,7 @@ impl MachineState {
} }
let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter())); let children = Addr::HeapCell(self.heap.to_list(cvec.into_iter()));
let chars = clause_name!(String::from(name), indices.atom_tbl); let chars = clause_name!(String::from(name), self.atom_tbl);
let tag = self.heap.to_unifiable( let tag = self.heap.to_unifiable(
HeapCellValue::Atom(chars, None) HeapCellValue::Atom(chars, None)
); );

View File

@@ -1,394 +0,0 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::machine::machine_indices::HeapCellValue;
use crate::machine::*;
use crate::rug::ops::Pow;
use crate::rug::Integer;
use std::cell::Cell;
use std::collections::VecDeque;
use std::iter::Rev;
use std::vec::IntoIter;
pub fn fold_by_str<I>(terms: I, mut term: Term, sym: ClauseName) -> Term
where
I: DoubleEndedIterator<Item = Term>,
{
for prec in terms.rev() {
term = Term::Clause(
Cell::default(),
sym.clone(),
vec![Box::new(prec), Box::new(term)],
None,
);
}
term
}
fn extract_from_list(
head: Box<Term>,
tail: Box<Term>,
) -> Result<Rev<IntoIter<Term>>, ParserError>
{
let mut terms = vec![*head];
let mut tail = *tail;
while let Term::Cons(_, head, next_tail) = tail {
terms.push(*head);
tail = *next_tail;
}
if let Term::Constant(_, Constant::EmptyList) = tail {
Ok(terms.into_iter().rev())
} else {
Err(ParserError::ExpectedTopLevelTerm)
}
}
#[derive(Debug)]
pub struct TermStream<'a> {
stack: Vec<Term>,
pub(crate) wam: &'a mut Machine,
parser: Parser<'a, Stream>,
pub(crate) flags: MachineFlags,
term_expansion_lens: (usize, usize),
goal_expansion_lens: (usize, usize),
top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
}
#[derive(Debug)]
pub struct ExpansionAdditionResult {
term_expansion_additions: (Predicate, VecDeque<TopLevel>),
goal_expansion_additions: (Predicate, VecDeque<TopLevel>),
}
impl ExpansionAdditionResult {
pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
let tes = mem::replace(&mut self.term_expansion_additions.0, Predicate::new());
let teqs = mem::replace(&mut self.term_expansion_additions.1, VecDeque::from(vec![]));
(tes, teqs)
}
pub fn take_goal_expansions(&mut self) -> (Predicate, VecDeque<TopLevel>) {
let ges = mem::replace(&mut self.goal_expansion_additions.0, Predicate::new());
let geqs = mem::replace(&mut self.goal_expansion_additions.1, VecDeque::from(vec![]));
(ges, geqs)
}
}
impl<'a> Drop for TermStream<'a> {
fn drop(&mut self) {
self.wam.indices.in_situ_code_dir.clear();
self.wam.indices.in_situ_module_dir.clear();
self.wam.code_repo.in_situ_code.clear();
discard_result!(self.rollback_expansion_code());
}
}
impl<'a> TermStream<'a> {
pub fn new(
src: &'a mut ParsingStream<Stream>,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
wam: &'a mut Machine,
) -> Self {
TermStream {
stack: Vec::new(),
term_expansion_lens: wam
.code_repo
.term_dir_entry_len((clause_name!("term_expansion"), 2)),
goal_expansion_lens: wam
.code_repo
.term_dir_entry_len((clause_name!("goal_expansion"), 2)),
wam,
parser: Parser::new(src, atom_tbl, flags),
flags,
top_level_terms: vec![],
}
}
#[inline]
pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> {
mem::replace(&mut self.top_level_terms, vec![])
}
#[inline]
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
match hook {
CompileTimeHook::UserTermExpansion => {
self.term_expansion_lens.0 += len;
self.term_expansion_lens.1 += queue_len;
}
CompileTimeHook::UserGoalExpansion => {
self.goal_expansion_lens.0 += len;
self.goal_expansion_lens.1 += queue_len;
}
_ => {}
}
}
#[inline]
pub fn line_num(&self) -> usize {
self.parser.line_num()
}
#[inline]
pub fn col_num(&self) -> usize {
self.parser.col_num()
}
#[inline]
pub fn update_expansion_lens(&mut self) {
let te_key = (clause_name!("term_expansion"), 2);
let ge_key = (clause_name!("goal_expansion"), 2);
let (tes_len, tes_q_len) = self.wam.code_repo.term_dir_entry_len(te_key);
self.term_expansion_lens.0 = tes_len;
self.term_expansion_lens.1 = tes_q_len;
let (ges_len, ges_q_len) = self.wam.code_repo.term_dir_entry_len(ge_key);
self.goal_expansion_lens.0 = ges_len;
self.goal_expansion_lens.1 = ges_q_len;
}
#[inline]
pub fn set_atom_tbl(&mut self, atom_tbl: TabledData<Atom>) {
self.parser.set_atom_tbl(atom_tbl);
}
#[inline]
pub fn eof(&mut self) -> Result<bool, ParserError> {
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
Ok(self.stack.is_empty() && self.parser.eof()?)
}
pub fn rollback_expansion_code(&mut self) -> Result<ExpansionAdditionResult, ParserError> {
let te_len = self.term_expansion_lens.0;
let te_queue_len = self.term_expansion_lens.1;
let ge_len = self.goal_expansion_lens.0;
let ge_queue_len = self.goal_expansion_lens.1;
let term_expansion_additions = self.wam.code_repo.truncate_terms(
(clause_name!("term_expansion"), 2),
te_len,
te_queue_len,
);
let goal_expansion_additions = self.wam.code_repo.truncate_terms(
(clause_name!("goal_expansion"), 2),
ge_len,
ge_queue_len,
);
self.wam
.code_repo
.compile_hook(CompileTimeHook::TermExpansion)?;
self.wam
.code_repo
.compile_hook(CompileTimeHook::GoalExpansion)?;
Ok(ExpansionAdditionResult {
term_expansion_additions,
goal_expansion_additions,
})
}
fn enqueue_term(&mut self, term: Term) -> Result<(), ParserError> {
match term {
Term::Cons(_, head, tail) => {
let iter = extract_from_list(head, tail)?;
Ok(self.stack.extend(iter))
}
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
Ok(self.stack.push(term))
}
_ => {
Err(ParserError::ExpectedTopLevelTerm)
}
}
}
fn parse_expansion_output(
&self,
term_string: &str,
op_dir: &OpDir,
) -> Result<Term, ParserError> {
let mut stream = parsing_stream(term_string.trim().as_bytes())?;
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
parser.read_term(composite_op!(
false,
&self.wam.indices.op_dir,
op_dir
))
}
pub fn expand_term(&mut self, term: Term, op_dir: &OpDir) -> Result<Term, ParserError> {
let mut machine_st = MachineState::new();
self.stack.push(term);
while let Some(term) = self.stack.pop() {
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) {
Some(term_string) => {
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
self.enqueue_term(term)?;
}
None => {
return Ok(term);
}
};
}
unreachable!()
}
pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> {
loop {
if let Some(term) = self.stack.pop() {
return Ok(self.expand_term(term, op_dir)?);
}
self.parser.reset();
let line_num = self.line_num();
let col_num = self.col_num();
let term = self.parser.read_term(composite_op!(
false,
&self.wam.indices.op_dir,
op_dir
))?;
// preserve a copy of the original unexpanded term for warning scans,
// if that stage is reached.
self.top_level_terms.push((term.clone(), line_num, col_num));
self.stack.push(term);
}
}
pub(super)
fn expand_goals(
&mut self,
machine_st: &mut MachineState,
op_dir: &OpDir,
mut terms: VecDeque<Term>,
) -> Result<Vec<Term>, ParserError> {
let mut results = vec![];
while let Some(term) = terms.pop_front() {
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::GoalExpansion) {
Some(term_string) => {
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
match term {
Term::Cons(_, head, tail) => {
for term in extract_from_list(head, tail)? {
terms.push_front(term);
}
}
term => terms.push_front(term),
};
}
None => results.push(term),
}
}
Ok(results)
}
}
impl MachineState {
pub(super)
fn print_with_locs(&self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
let output = PrinterOutputter::new();
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
let mut max_var_length = 0;
for var in self.heap_locs.keys() {
max_var_length = std::cmp::max(var.len(), max_var_length);
}
printer.quoted = true;
printer.numbervars = true;
// the purpose of the offset is to avoid clashes with variable
// names that might occur after the addresses in the expanded
// term are substituted with the variable names in the
// pre-expansion term. This formula ensures that all generated
// "numbervars"- style variable names will be longer than the
// keys of the var_dict, and therefore not equal to any of
// them.
printer.numbervars_offset = Integer::from(10).pow(max_var_length as u32) * 26;
printer.print_strings_as_strs = true;
printer.drop_toplevel_spec();
printer.see_all_locs();
let mut output = printer.print(addr);
output.push_char('.');
output
}
// reset the machine, but keep the heap contents as they were.
// this prevents clashes between underscored variable names in the
// same query.
fn reset_with_heap_preservation(&mut self) {
let heap = self.heap.take();
self.reset();
self.heap = heap;
}
fn try_expand_term(
&mut self,
wam: &mut Machine,
term: &Term,
hook: CompileTimeHook,
) -> Option<String> {
let term_write_result = write_term_to_heap(term, self);
let h = self.heap.h();
self[temp_v!(1)] = Addr::HeapCell(term_write_result.heap_loc);
self.heap.push(HeapCellValue::Addr(Addr::HeapCell(h)));
self[temp_v!(2)] = Addr::HeapCell(h);
let code = vec![call_clause!(ClauseType::Hook(hook), 2, 0, true)];
wam.code_repo.cached_query = code;
self.cp = LocalCodePtr::TopLevel(0, 0);
self.at_end_of_expansion = false;
self.flags.double_quotes = DoubleQuotes::Chars;
self.query_stepper(
&mut wam.indices,
&mut MachinePolicies::default(),
&mut wam.code_repo,
&mut readline::input_stream(),
&mut Stream::stdout(),
);
if self.fail || self.at_end_of_expansion {
self.reset_with_heap_preservation();
None
} else {
let TermWriteResult { var_dict, .. } = term_write_result;
self.heap_locs = var_dict;
let output = self.print_with_locs(Addr::HeapCell(h), &wam.indices.op_dir);
self.reset_with_heap_preservation();
Some(output.result())
}
}
}

149
src/machine/term_stream.rs Normal file
View File

@@ -0,0 +1,149 @@
use crate::prolog_parser::ast::*;
use crate::prolog_parser::parser::*;
use crate::machine::*;
use crate::machine::machine_errors::CompilationError;
use crate::machine::preprocessor::*;
use indexmap::IndexSet;
use std::collections::VecDeque;
use std::fmt;
pub(crate) trait TermStream : Sized {
type Evacuable;
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError>;
fn eof(&mut self) -> Result<bool, CompilationError>;
fn listing_src(&self) -> &ListingSource;
fn evacuate<'a>(loader: Loader<'a, Self>) -> Result<Self::Evacuable, SessionError>;
}
#[derive(Debug)]
pub(super) struct BootstrappingTermStream<'a> {
listing_src: ListingSource,
parser: Parser<'a, Stream>,
}
impl<'a> BootstrappingTermStream<'a> {
#[inline]
pub(super)
fn from_prolog_stream(
stream: &'a mut PrologStream,
atom_tbl: TabledData<Atom>,
flags: MachineFlags,
listing_src: ListingSource,
) -> Self {
let parser = Parser::new(stream, atom_tbl, flags);
Self { parser, listing_src }
}
}
impl<'a> TermStream for BootstrappingTermStream<'a> {
type Evacuable = CompilationTarget;
#[inline]
fn next(&mut self, op_dir: &CompositeOpDir) -> Result<Term, CompilationError> {
self.parser.reset();
self.parser.read_term(op_dir)
.map_err(CompilationError::from)
}
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
self.parser.devour_whitespace()?; // eliminate dangling comments before checking for EOF.
Ok(self.parser.eof()?)
}
#[inline]
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
fn evacuate(mut loader: Loader<Self>) -> Result<Self::Evacuable, SessionError> {
if !loader.predicates.is_empty() {
loader.compile_and_submit()?;
}
loader.load_state.retraction_info.reset(
loader.load_state.wam.code_repo.code.len(),
);
loader.load_state.remove_module_op_exports();
Ok(loader.load_state.compilation_target.take())
}
}
pub struct LiveTermStream {
pub(super) term_queue: VecDeque<Term>,
pub(super) listing_src: ListingSource,
}
impl LiveTermStream {
#[inline]
pub(super)
fn new(listing_src: ListingSource) -> Self {
Self {
term_queue: VecDeque::new(),
listing_src,
}
}
}
pub struct LoadStatePayload {
pub(super) term_stream: LiveTermStream,
pub(super) compilation_target: CompilationTarget,
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: Vec<PredicateClause>,
pub(super) clause_clauses: Vec<(Term, Term)>,
}
impl fmt::Debug for LoadStatePayload {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "LoadStatePayload")
}
}
impl LoadStatePayload {
pub(super)
fn new(wam: &Machine) -> Self {
Self {
term_stream: LiveTermStream::new(ListingSource::User),
compilation_target: CompilationTarget::default(),
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: vec![],
clause_clauses: vec![],
}
}
}
impl TermStream for LiveTermStream {
type Evacuable = LoadStatePayload;
#[inline]
fn next(&mut self, _: &CompositeOpDir) -> Result<Term, CompilationError> {
Ok(self.term_queue.pop_front().unwrap())
}
#[inline]
fn eof(&mut self) -> Result<bool, CompilationError> {
return Ok(self.term_queue.is_empty());
}
#[inline]
fn listing_src(&self) -> &ListingSource {
&self.listing_src
}
#[inline]
fn evacuate(loader: Loader<Self>) -> Result<LoadStatePayload, SessionError> {
Ok(loader.to_load_state_payload())
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -68,10 +68,18 @@ macro_rules! functor {
}); });
($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({
{ {
let arity = count_tt!($($dt) +); use crate::machine::heap::*;
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), let arity = count_tt!($($dt) +);
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ] #[allow(unused_variables, unused_mut)]
let mut addendum = Heap::new();
let mut result =
vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None),
$(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ];
result.extend(addendum.into_iter());
result
} }
}); });
($name:expr, $fixity:expr) => ( ($name:expr, $fixity:expr) => (
@@ -112,13 +120,28 @@ macro_rules! functor_term {
(number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( (number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
$e.into() $e.into()
); );
(integer($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( (integer($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Integer(Rc::new(Integer::from($e))) HeapCellValue::Integer(Rc::new(Integer::from($e)))
); );
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( (indexing_code_ptr($h:expr, $e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ({
let stub =
match $e {
IndexingCodePtr::External(o) => functor!("external", [integer(o)]),
IndexingCodePtr::Internal(o) => functor!("internal", [integer(o)]),
IndexingCodePtr::Fail => vec![HeapCellValue::Atom(clause_name!("fail"), None)],
};
let len: usize = $aux_lens.iter().sum();
let h = len + $arity + 1 + $addendum.h() + $h;
$addendum.extend(stub.into_iter());
HeapCellValue::Addr(Addr::HeapCell(h))
});
(clause_name($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom($e, None) HeapCellValue::Atom($e, None)
); );
(atom($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( (atom($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => (
HeapCellValue::Atom(clause_name!($e), None) HeapCellValue::Atom(clause_name!($e), None)
); );
(value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => ( (value($e:expr), $arity:expr, $aux_lens:expr, $addendum: ident) => (
@@ -312,14 +335,6 @@ macro_rules! jmp_call {
}; };
} }
macro_rules! try_eval_session {
($e:expr) => {
match $e {
Ok(result) => result,
Err(e) => return EvalSession::from(e),
}
};
}
macro_rules! return_from_clause { macro_rules! return_from_clause {
($lco:expr, $machine_st:expr) => {{ ($lco:expr, $machine_st:expr) => {{
if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p { if let CodePtr::VerifyAttrInterrupt(_) = $machine_st.p {
@@ -342,39 +357,21 @@ macro_rules! dir_entry {
}; };
} }
macro_rules! set_code_index {
($idx:expr, $ip:expr, $mod_name:expr) => {{
let mut idx = $idx.0.borrow_mut();
idx.0 = $ip;
idx.1 = $mod_name.clone();
}};
}
macro_rules! index_store { macro_rules! index_store {
($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => { ($code_dir:expr, $op_dir:expr, $modules:expr) => {
IndexStore { IndexStore {
atom_tbl: $atom_tbl,
code_dir: $code_dir, code_dir: $code_dir,
module_dir: ModuleDir::new(), extensible_predicates: ExtensiblePredicates::new(),
dynamic_code_dir: DynamicCodeDir::new(),
global_variables: GlobalVarDir::new(), global_variables: GlobalVarDir::new(),
in_situ_code_dir: InSituCodeDir::new(), meta_predicates: MetaPredicateDir::new(),
in_situ_module_dir: ModuleStubDir::new(),
op_dir: $op_dir,
modules: $modules, modules: $modules,
stream_aliases: StreamAliasDir::new(), op_dir: $op_dir,
streams: StreamDir::new(), streams: StreamDir::new(),
stream_aliases: StreamAliasDir::new(),
} }
}; };
} }
macro_rules! default_index_store {
($atom_tbl:expr) => {
index_store!($atom_tbl, CodeDir::new(), default_op_dir(), IndexMap::new())
};
}
macro_rules! put_constant { macro_rules! put_constant {
($lvl:expr, $cons:expr, $r:expr) => { ($lvl:expr, $cons:expr, $r:expr) => {
QueryInstruction::PutConstant($lvl, $cons, $r) QueryInstruction::PutConstant($lvl, $cons, $r)
@@ -387,6 +384,7 @@ macro_rules! get_level_and_unify {
}; };
} }
/*
macro_rules! unwind_protect { macro_rules! unwind_protect {
($e: expr, $protected: expr) => { ($e: expr, $protected: expr) => {
match $e { match $e {
@@ -398,7 +396,8 @@ macro_rules! unwind_protect {
} }
}; };
} }
*/
/*
macro_rules! discard_result { macro_rules! discard_result {
($f: expr) => { ($f: expr) => {
match $f { match $f {
@@ -406,7 +405,7 @@ macro_rules! discard_result {
} }
}; };
} }
*/
macro_rules! ar_reg { macro_rules! ar_reg {
($r: expr) => { ($r: expr) => {
ArithmeticTerm::Reg($r) ArithmeticTerm::Reg($r)
@@ -414,7 +413,7 @@ macro_rules! ar_reg {
} }
macro_rules! atom_from { macro_rules! atom_from {
($self:expr, $indices:expr, $e:expr) => { ($self:expr, $e:expr) => {
match $e { match $e {
Addr::Con(h) if $self.heap.atom_at(h) => { Addr::Con(h) if $self.heap.atom_at(h) => {
match &$self.heap[h] { match &$self.heap[h] {
@@ -427,7 +426,7 @@ macro_rules! atom_from {
} }
} }
Addr::Char(c) => { Addr::Char(c) => {
clause_name!(c.to_string(), $indices.atom_tbl.clone()) clause_name!(c.to_string(), $self.atom_tbl)
} }
_ => { _ => {
unreachable!() unreachable!()
@@ -435,3 +434,15 @@ macro_rules! atom_from {
} }
} }
} }
macro_rules! try_or_fail {
($s:expr, $e:expr) => {{
match $e {
Ok(val) => val,
Err(msg) => {
$s.throw_exception(msg);
return;
}
}
}};
}

View File

@@ -35,6 +35,7 @@ use crate::nix::sys::signal;
mod macros; mod macros;
mod allocator; mod allocator;
mod arithmetic; mod arithmetic;
mod machine;
mod codegen; mod codegen;
mod clause_types; mod clause_types;
mod debray_allocator; mod debray_allocator;
@@ -45,7 +46,6 @@ mod heap_print;
mod indexing; mod indexing;
mod instructions; mod instructions;
mod iterators; mod iterators;
mod machine;
mod read; mod read;
mod targets; mod targets;
mod write; mod write;

View File

@@ -195,7 +195,7 @@ impl MachineState {
let term = { let term = {
let mut parser = Parser::new(&mut stream, atom_tbl, self.flags); let mut parser = Parser::new(&mut stream, atom_tbl, self.flags);
parser.read_term(composite_op!(op_dir))? parser.read_term(&CompositeOpDir::new(op_dir, None))?
}; };
// 'pausing' the stream saves the pending top buffer // 'pausing' the stream saves the pending top buffer

View File

@@ -0,0 +1,44 @@
% Unsure how to handle the printing of exceptions from term & goal expansion.
'$print_message_and_fail'(Error, Culprit) :-
% writeq(error(Error, Culprit)),
% nl,
'$fail'.
term_expansion(Term, ExpandedTerm) :-
( catch(user:'$term_expansion'(Term, ExpandedTerm0),
E,
user:'$print_message_and_fail'(E, user:term_expansion)) ->
( var(ExpandedTerm0) ->
error:instantiation_error(term_expansion/2)
; ExpandedTerm0 = [_|_] ->
term_expansion_list(ExpandedTerm0, ExpandedTerm, [])
; term_expansion(ExpandedTerm0, ExpandedTerm)
)
; Term = ExpandedTerm
).
term_expansion_list([], ExpandedTerms, ExpandedTerms).
term_expansion_list([Term|Terms], ExpandedTermsHead, ExpandedTermsTail) :-
term_expansion(Term, ExpandedTerm0),
( var(ExpandedTerm0) ->
error:instantiation_error(term_expansion/2)
; ExpandedTerm0 = [_|_] ->
term_expansion_list(ExpandedTerm0, ExpandedTermsHead, ExpandedTerms0Tail),
term_expansion_list(Terms, ExpandedTerms0Tail, ExpandedTermsTail)
; ExpandedTermsHead = [ExpandedTerm0 | ExpandedTerms0Tail],
term_expansion_list(Terms, ExpandedTerms0Tail, ExpandedTermsTail)
).
goal_expansion(Goal, Module, ExpandedGoal) :-
( catch(Module:goal_expansion(Goal, ExpandedGoal0),
E,
user:'$print_message_and_fail'(E, Module:goal_expansion)) ->
( var(ExpandedGoal0) ->
error:instantiation_error(goal_expansion/2)
; goal_expansion(ExpandedGoal0, Module, ExpandedGoal)
)
; Goal = ExpandedGoal
).

View File

@@ -1,10 +1,18 @@
:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2, :- module('$toplevel', [argv/1,
argv/1]). copy_term/3,
predicate_property/2,
prolog_load_context/2]).
:- use_module(library(loader)).
:- use_module(library(charsio)). :- use_module(library(charsio)).
:- use_module(library(iso_ext)).
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(si)). :- use_module(library(si)).
:- use_module(library('$project_atts')).
:- use_module(library('$atts')).
:- dynamic(argv/1). :- dynamic(argv/1).
'$repl'([_|Args0]) :- '$repl'([_|Args0]) :-
@@ -109,9 +117,6 @@ read_and_match :-
instruction_match(Term, VarList). instruction_match(Term, VarList).
% make compile_batch, a system routine, callable.
compile_batch :- '$compile_batch'.
instruction_match(Term, VarList) :- instruction_match(Term, VarList) :-
( var(Term) -> ( var(Term) ->
throw(error(instantiation_error, repl/0)) throw(error(instantiation_error, repl/0))
@@ -119,38 +124,43 @@ instruction_match(Term, VarList) :-
!, !,
( atom(Item) -> ( atom(Item) ->
( Item == user -> ( Item == user ->
catch(compile_batch, E, print_exception_with_check(E)) catch(load(user_input), E, print_exception_with_check(E))
; consult(Item) ;
consult(Item)
) )
; ;
catch(throw(error(type_error(atom, Item), repl/0)), catch(type_error(atom, Item, repl/0),
E, E,
print_exception_with_check(E)) print_exception_with_check(E))
) )
; Term = end_of_file -> ; Term = end_of_file ->
halt halt
; submit_query_and_print_results(Term, VarList) ;
submit_query_and_print_results(Term, VarList)
). ).
:- use_module(library(iso_ext)).
% auxiliary predicates, so that using them in setup_call_cleanup/3 works submit_query_and_print_results_(Term, VarList) :-
get_b_value(B) :- '$get_b_value'(B). '$get_b_value'(B),
clear_attribute_goals :- '$clear_attribute_goals'. call(Term),
write_eqs_and_read_input(B, VarList),
!.
submit_query_and_print_results_(_, _) :-
% clear attribute goal lists, which may be populated by
% copy_term/3 prior to failure.
'$clear_attribute_goals',
write('false.'),
nl.
submit_query_and_print_results(Term0, VarList) :- submit_query_and_print_results(Term0, VarList) :-
( expand_goals(Term0, Term) -> true expand_goal(call(Term0), user, Term),
; Term0 = Term !,
),
setup_call_cleanup(bb_put('$first_answer', true), setup_call_cleanup(bb_put('$first_answer', true),
( get_b_value(B), call(Term), write_eqs_and_read_input(B, VarList), submit_query_and_print_results_(Term, VarList),
!
; % clear attribute goal lists, which may be populated by
% copy_term/3 prior to failure.
clear_attribute_goals, write('false.'), nl
),
bb_put('$first_answer', false)). bb_put('$first_answer', false)).
needs_bracketing(Value, Op) :- needs_bracketing(Value, Op) :-
catch((functor(Value, F, _), catch((functor(Value, F, _),
current_op(EqPrec, EqSpec, Op), current_op(EqPrec, EqSpec, Op),
@@ -254,12 +264,12 @@ write_eqs_and_read_input(B, VarList) :-
( B0 == B -> ( B0 == B ->
( Goals == [] -> ( Goals == [] ->
write('true.'), nl write('true.'), nl
; thread_goals(Goals, ThreadedGoals, (',')), ; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20), write_eq(ThreadedGoals, NewVarList0, 20),
write('.'), write('.'),
nl nl
) )
; thread_goals(Goals, ThreadedGoals, (',')), ; loader:thread_goals(Goals, ThreadedGoals, (',')),
write_eq(ThreadedGoals, NewVarList0, 20), write_eq(ThreadedGoals, NewVarList0, 20),
read_input(ThreadedGoals, NewVarList0) read_input(ThreadedGoals, NewVarList0)
). ).
@@ -353,133 +363,3 @@ print_exception_with_check(E) :-
% is expected to be printed instead. % is expected to be printed instead.
; print_exception(E) ; print_exception(E)
). ).
module_export(Source, PI) :-
( nonvar(PI) ->
( PI = Name / Arity ->
( var(Name) -> throw(error(instantiation_error, Source))
; integer(Arity) ->
( \+ atom(Name) -> throw(error(type_error(atom, Name), Source))
; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), Source))
; true
)
; throw(error(type_error(integer, Arity), Source))
)
; PI = op(Prec, Spec, Name) ->
( integer(Prec) ->
( \+ atom(Name) ->
throw(error(type_error(atom, Name), Source))
; Prec < 0 ->
throw(error(domain_error(not_less_than_zero, Prec), Source))
; Prec > 1200 ->
throw(error(domain_error(operator_precision, Prec), Source))
; memberchk(Spec, [xfy, yfx, xfx, fx, fy, yf, xf])
; throw(error(domain_error(operator_specification, Spec), Source))
)
; throw(error(type_error(integer, Prec), Source))
)
; throw(error(type_error(module_export, PI), Source))
)
; throw(error(instantiation_error, Source))
).
consult(Item) :-
( atom(Item) -> use_module(Item)
; throw(error(type_error(atom, Item), consult/1))
).
use_module(Module) :-
( nonvar(Module) ->
( Module = library(Filename) ->
write_term_to_chars(Filename, [], FilenameString),
'$use_module'(FilenameString)
; atom(Module) ->
'$use_module_from_file'(Module)
; throw(error(invalid_module_specifier, use_module/1))
)
; throw(error(instantiation_error, use_module/1))
).
use_module(Module, QualifiedExports) :-
( nonvar(Module) ->
( list_si(QualifiedExports) ->
maplist('$module_export'(use_module/2), QualifiedExports) ->
( Module = library(Filename) ->
write_term_to_chars(Filename, [], FilenameString),
'$use_qualified_module'(FilenameString, QualifiedExports)
; atom(Module) ->
'$use_qualified_module_from_file'(Module, QualifiedExports)
; throw(error(invalid_module_specifier, use_module/2))
)
; throw(error(type_error(list, QualifiedExports), use_module/2))
)
; throw(error(instantiation_error, use_module/2))
).
% expand goals in initialization directives.
user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
nonvar(Term0),
Term0 = (:- initialization(Goals)),
expand_goals(Goals, ExpandedGoals),
Goals \== ExpandedGoals.
module_expand_goal(UnexpandedGoals, ExpandedGoals) :-
( '$module_of'(Module, UnexpandedGoals),
'$module_exists'(Module),
Module:goal_expansion(UnexpandedGoals, ExpandedGoals),
UnexpandedGoals \== ExpandedGoals ->
true
; user:goal_expansion(UnexpandedGoals, ExpandedGoals)
).
expand_goals(UnexpandedGoals, ExpandedGoals) :-
nonvar(UnexpandedGoals),
var(ExpandedGoals),
( module_expand_goal(UnexpandedGoals, Goals) ->
true
; Goals = UnexpandedGoals
),
( Goals = (Goal0, Goals0) ->
( expand_goals(Goal0, Goal1) ->
expand_goals(Goals0, Goals1),
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
; expand_goals(Goals0, Goals1),
ExpandedGoals = (Goal0, Goals1)
)
; Goals = (Goals0 -> Goals1) ->
expand_goals(Goals0, ExpandedGoals0),
expand_goals(Goals1, ExpandedGoals1),
ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1)
; Goals = (Goals0 ; Goals1) ->
expand_goals(Goals0, ExpandedGoals0),
expand_goals(Goals1, ExpandedGoals1),
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
; Goals = (\+ Goals0) ->
expand_goals(Goals0, Goals1),
ExpandedGoals = (\+ Goals1)
; thread_goals(Goals, ExpandedGoals, (','))
; Goals = ExpandedGoals
).
thread_goals(Goals0, Goals1, Hole, Functor) :-
nonvar(Goals0),
( Goals0 = [G | Gs] ->
( Gs == [] ->
Goals1 =.. [Functor, G, Hole]
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Hole, Functor)
)
; Goals1 =.. [Functor, Goals0, Hole]
).
thread_goals(Goals0, Goals1, Functor) :-
nonvar(Goals0),
( Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
).

View File

@@ -1,5 +1,6 @@
use crate::clause_types::*; use crate::clause_types::*;
use crate::forms::*; use crate::forms::*;
use crate::indexing::IndexingCodePtr;
use crate::instructions::*; use crate::instructions::*;
use crate::machine::machine_errors::*; use crate::machine::machine_errors::*;
use crate::machine::machine_indices::*; use crate::machine::machine_indices::*;
@@ -10,14 +11,8 @@ impl fmt::Display for LocalCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p),
LocalCodePtr::InSituDirEntry(p) => write!(f, "LocalCodePtr::InSituDirEntry({})", p), LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"),
LocalCodePtr::TopLevel(cn, p) => write!(f, "LocalCodePtr::TopLevel({}, {})", cn, p), LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i),
LocalCodePtr::UserGoalExpansion(p) => {
write!(f, "LocalCodePtr::UserGoalExpansion({})", p)
}
LocalCodePtr::UserTermExpansion(p) => {
write!(f, "LocalCodePtr::UserTermExpansion({})", p)
}
} }
} }
} }
@@ -25,16 +20,50 @@ impl fmt::Display for LocalCodePtr {
impl fmt::Display for REPLCodePtr { impl fmt::Display for REPLCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
REPLCodePtr::CompileBatch => REPLCodePtr::AddDynamicPredicate =>
write!(f, "REPLCodePtr::CompileBatch"), write!(f, "REPLCodePtr::AddDynamicPredicate"),
REPLCodePtr::AddGoalExpansionClause =>
write!(f, "REPLCodePtr::AddGoalExpansionClause"),
REPLCodePtr::AddTermExpansionClause =>
write!(f, "REPLCodePtr::AddTermExpansionClause"),
REPLCodePtr::UserAssertz =>
write!(f, "REPLCodePtr::UserAssertz"),
REPLCodePtr::UserAsserta =>
write!(f, "REPLCodePtr::UserAsserta"),
REPLCodePtr::UserRetract =>
write!(f, "REPLCodePtr::UserRetract"),
REPLCodePtr::ClauseToEvacuable =>
write!(f, "REPLCodePtr::ClauseToEvacuable"),
REPLCodePtr::ConcludeLoad =>
write!(f, "REPLCodePtr::ConcludeLoad"),
REPLCodePtr::DeclareModule =>
write!(f, "REPLCodePtr::DeclareModule"),
REPLCodePtr::LoadCompiledLibrary =>
write!(f, "REPLCodePtr::LoadCompiledLibrary"),
REPLCodePtr::LoadContextSource =>
write!(f, "REPLCodePtr::LoadContextSource"),
REPLCodePtr::LoadContextFile =>
write!(f, "REPLCodePtr::LoadContextFile"),
REPLCodePtr::LoadContextDirectory =>
write!(f, "REPLCodePtr::LoadContextDirectory"),
REPLCodePtr::LoadContextModule =>
write!(f, "REPLCodePtr::LoadContextModule"),
REPLCodePtr::LoadContextStream =>
write!(f, "REPLCodePtr::LoadContextStream"),
REPLCodePtr::PopLoadContext =>
write!(f, "REPLCodePtr::PopLoadContext"),
REPLCodePtr::PopLoadStatePayload =>
write!(f, "REPLCodePtr::PopLoadStatePayload"),
REPLCodePtr::PushLoadContext =>
write!(f, "REPLCodePtr::PushLoadContext"),
REPLCodePtr::PushLoadStatePayload =>
write!(f, "REPLCodePtr::PushLoadStatePayload"),
REPLCodePtr::UseModule => REPLCodePtr::UseModule =>
write!(f, "REPLCodePtr::UseModule"), write!(f, "REPLCodePtr::UseModule"),
REPLCodePtr::UseQualifiedModule => REPLCodePtr::MetaPredicateProperty =>
write!(f, "REPLCodePtr::UseQualifiedModule"), write!(f, "REPLCodePtr::MetaPredicateProperty"),
REPLCodePtr::UseModuleFromFile => REPLCodePtr::CompilePendingPredicates =>
write!(f, "REPLCodePtr::UseModuleFromFile"), write!(f, "REPLCodePtr::CompilePendingPredicates"),
REPLCodePtr::UseQualifiedModuleFromFile =>
write!(f, "REPLCodePtr::UseQualifiedModuleFromFile")
} }
} }
} }
@@ -45,9 +74,6 @@ impl fmt::Display for IndexPtr {
&IndexPtr::DynamicUndefined => write!(f, "undefined"), &IndexPtr::DynamicUndefined => write!(f, "undefined"),
&IndexPtr::Undefined => write!(f, "undefined"), &IndexPtr::Undefined => write!(f, "undefined"),
&IndexPtr::Index(i) => write!(f, "{}", i), &IndexPtr::Index(i) => write!(f, "{}", i),
&IndexPtr::InSituDirEntry(i) => write!(f, "in_situ({})", i),
&IndexPtr::UserTermExpansion => write!(f, "user:term_expansion"),
&IndexPtr::UserGoalExpansion => write!(f, "user:goal_expansion"),
} }
} }
} }
@@ -68,17 +94,27 @@ impl fmt::Display for FactInstruction {
&FactInstruction::GetStructure(ref ct, ref arity, ref r) => { &FactInstruction::GetStructure(ref ct, ref arity, ref r) => {
write!(f, "get_structure {}/{}, {}", ct.name(), arity, r) write!(f, "get_structure {}/{}, {}", ct.name(), arity, r)
} }
&FactInstruction::GetValue(ref x, ref a) => write!(f, "get_value {}, A{}", x, a), &FactInstruction::GetValue(ref x, ref a) => {
write!(f, "get_value {}, A{}", x, a)
}
&FactInstruction::GetVariable(ref x, ref a) => { &FactInstruction::GetVariable(ref x, ref a) => {
write!(f, "fact:get_variable {}, A{}", x, a) write!(f, "fact:get_variable {}, A{}", x, a)
} }
&FactInstruction::UnifyConstant(ref constant) => { &FactInstruction::UnifyConstant(ref constant) => {
write!(f, "unify_constant {}", constant) write!(f, "unify_constant {}", constant)
} }
&FactInstruction::UnifyVariable(ref r) => write!(f, "unify_variable {}", r), &FactInstruction::UnifyVariable(ref r) => {
&FactInstruction::UnifyLocalValue(ref r) => write!(f, "unify_local_value {}", r), write!(f, "unify_variable {}", r)
&FactInstruction::UnifyValue(ref r) => write!(f, "unify_value {}", r), }
&FactInstruction::UnifyVoid(n) => write!(f, "unify_void {}", n), &FactInstruction::UnifyLocalValue(ref r) => {
write!(f, "unify_local_value {}", r)
}
&FactInstruction::UnifyValue(ref r) => {
write!(f, "unify_value {}", r)
}
&FactInstruction::UnifyVoid(n) => {
write!(f, "unify_void {}", n)
}
} }
} }
} }
@@ -141,12 +177,16 @@ impl fmt::Display for CompareTermQT {
impl fmt::Display for ClauseType { impl fmt::Display for ClauseType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&ClauseType::System(SystemClauseType::SetCutPoint(r)) => write!(f, "$set_cp({})", r), &ClauseType::System(SystemClauseType::SetCutPoint(r)) => {
&ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { write!(f, "$set_cp({})", r)
let idx = idx.0.borrow(); }
write!(f, "{}:{}/{}", idx.1, name, idx.0) &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => {
let idx = idx.0.get();
write!(f, "{}/{}", name, idx)
}
ref ct => {
write!(f, "{}", ct.name())
} }
ref ct => write!(f, "{}", ct.name()),
} }
} }
} }
@@ -158,6 +198,7 @@ impl fmt::Display for HeapCellValue {
&HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()),
&HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref), &HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref),
&HeapCellValue::Integer(ref n) => write!(f, "{}", n), &HeapCellValue::Integer(ref n) => write!(f, "{}", n),
&HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"),
&HeapCellValue::Rational(ref n) => write!(f, "{}", n), &HeapCellValue::Rational(ref n) => write!(f, "{}", n),
&HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!( &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!(
f, f,
@@ -209,6 +250,7 @@ impl fmt::Display for Addr {
&Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp), &Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp),
&Addr::Con(ref c) => write!(f, "Addr::Con({})", c), &Addr::Con(ref c) => write!(f, "Addr::Con({})", c),
&Addr::Lis(l) => write!(f, "Addr::Lis({})", l), &Addr::Lis(l) => write!(f, "Addr::Lis({})", l),
&Addr::LoadStatePayload(s) => write!(f, "Addr::LoadStatePayload({})", s),
&Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h), &Addr::AttrVar(h) => write!(f, "Addr::AttrVar({})", h),
&Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h), &Addr::HeapCell(h) => write!(f, "Addr::HeapCell({})", h),
&Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc),
@@ -244,6 +286,9 @@ impl fmt::Display for ControlInstruction {
&ControlInstruction::JmpBy(arity, offset, pvs, true) => { &ControlInstruction::JmpBy(arity, offset, pvs, true) => {
write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs) write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs)
} }
&ControlInstruction::RevJmpBy(offset) => {
write!(f, "rev_jmp_by {}", offset)
}
&ControlInstruction::Proceed => write!(f, "proceed"), &ControlInstruction::Proceed => write!(f, "proceed"),
} }
} }
@@ -262,13 +307,33 @@ impl fmt::Display for IndexedChoiceInstruction {
impl fmt::Display for ChoiceInstruction { impl fmt::Display for ChoiceInstruction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset), &ChoiceInstruction::TryMeElse(offset) =>
write!(f, "try_me_else {}", offset),
&ChoiceInstruction::DefaultRetryMeElse(offset) => { &ChoiceInstruction::DefaultRetryMeElse(offset) => {
write!(f, "retry_me_else_by_default {}", offset) write!(f, "retry_me_else_by_default {}", offset)
} }
&ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset), &ChoiceInstruction::RetryMeElse(offset) =>
&ChoiceInstruction::DefaultTrustMe => write!(f, "trust_me_by_default"), write!(f, "retry_me_else {}", offset),
&ChoiceInstruction::TrustMe => write!(f, "trust_me"), &ChoiceInstruction::DefaultTrustMe(_) =>
write!(f, "trust_me_by_default"),
&ChoiceInstruction::TrustMe(_) =>
write!(f, "trust_me"),
}
}
}
impl fmt::Display for IndexingCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IndexingCodePtr::External(o) => {
write!(f, "IndexingCodePtr::External({})", o)
}
&IndexingCodePtr::Fail => {
write!(f, "IndexingCodePtr::Fail")
}
&IndexingCodePtr::Internal(o) => {
write!(f, "IndexingCodePtr::Internal({})", o)
}
} }
} }
} }
@@ -279,11 +344,11 @@ impl fmt::Display for IndexingInstruction {
&IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => { &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => {
write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s) write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s)
} }
&IndexingInstruction::SwitchOnConstant(_, num_cs, _) => { &IndexingInstruction::SwitchOnConstant(ref constants) => {
write!(f, "switch_on_constant {}", num_cs) write!(f, "switch_on_constant {}", constants.len())
} }
&IndexingInstruction::SwitchOnStructure(_, num_ss, _) => { &IndexingInstruction::SwitchOnStructure(ref structures) => {
write!(f, "switch_on_structure {}", num_ss) write!(f, "switch_on_structure {}", structures.len())
} }
} }
} }
@@ -295,36 +360,40 @@ impl fmt::Display for SessionError {
&SessionError::ExistenceError(ref err) => { &SessionError::ExistenceError(ref err) => {
write!(f, "{}", err) write!(f, "{}", err)
} }
&SessionError::CannotOverwriteBuiltIn(ref msg) => { // &SessionError::CannotOverwriteBuiltIn(ref msg) => {
write!(f, "cannot overwrite {}", msg) // write!(f, "cannot overwrite {}", msg)
} // }
&SessionError::CannotOverwriteImport(ref msg) => { // &SessionError::CannotOverwriteImport(ref msg) => {
write!(f, "cannot overwrite import {}", msg) // write!(f, "cannot overwrite import {}", msg)
} // }
&SessionError::InvalidFileName(ref filename) => { // &SessionError::InvalidFileName(ref filename) => {
write!(f, "filename {} is invalid", filename) // write!(f, "filename {} is invalid", filename)
} // }
&SessionError::ModuleDoesNotContainExport(ref module, ref key) => { // &SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
write!( // write!(
f, // f,
"module {} does not contain claimed export {}/{}", // "module {} does not contain claimed export {}/{}",
module, // module,
key.0, // key.0,
key.1, // key.1,
) // )
} // }
&SessionError::OpIsInfixAndPostFix(_) => { &SessionError::OpIsInfixAndPostFix(_) => {
write!(f, "cannot define an op to be both postfix and infix.") write!(f, "cannot define an op to be both postfix and infix.")
} }
&SessionError::NamelessEntry => { &SessionError::NamelessEntry => {
write!(f, "the predicate head is not an atom or clause.") write!(f, "the predicate head is not an atom or clause.")
} }
&SessionError::ParserError(ref e) => { &SessionError::CompilationError(ref e) => {
write!(f, "syntax_error({})", e.as_str()) write!(f, "syntax_error({:?})", e)
} }
&SessionError::QueryCannotBeDefinedAsFact => { &SessionError::QueryCannotBeDefinedAsFact => {
write!(f, "queries cannot be defined as facts.") write!(f, "queries cannot be defined as facts.")
} }
&SessionError::ModuleCannotImportSelf(ref module_name) => {
write!(f, "modules ({}, in this case) cannot import themselves.",
module_name)
}
} }
} }
} }
@@ -364,6 +433,23 @@ impl fmt::Display for ModuleSource {
} }
} }
impl fmt::Display for IndexingLine {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
&IndexingLine::Indexing(ref indexing_instr) => {
write!(f, "{}", indexing_instr)
}
&IndexingLine::IndexedChoice(ref indexed_choice_instrs) => {
for indexed_choice_instr in indexed_choice_instrs {
write!(f, "{}", indexed_choice_instr)?;
}
Ok(())
}
}
}
}
impl fmt::Display for Line { impl fmt::Display for Line {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
@@ -372,7 +458,13 @@ impl fmt::Display for Line {
&Line::Control(ref control_instr) => write!(f, "{}", control_instr), &Line::Control(ref control_instr) => write!(f, "{}", control_instr),
&Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr), &Line::Cut(ref cut_instr) => write!(f, "{}", cut_instr),
&Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr), &Line::Fact(ref fact_instr) => write!(f, "{}", fact_instr),
&Line::Indexing(ref indexing_instr) => write!(f, "{}", indexing_instr), &Line::IndexingCode(ref indexing_instrs) => {
for indexing_instr in indexing_instrs {
write!(f, "{}", indexing_instr)?;
}
Ok(())
}
&Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr), &Line::IndexedChoice(ref indexed_choice_instr) => write!(f, "{}", indexed_choice_instr),
&Line::Query(ref query_instr) => write!(f, "{}", query_instr), &Line::Query(ref query_instr) => write!(f, "{}", query_instr),
} }