add multifile and module scoped predicates

This commit is contained in:
Mark Thom
2020-02-02 22:13:14 -07:00
parent 668c9489c9
commit 740bd528c4
18 changed files with 1058 additions and 385 deletions

6
Cargo.lock generated
View File

@@ -311,8 +311,7 @@ dependencies = [
[[package]] [[package]]
name = "prolog_parser" name = "prolog_parser"
version = "0.8.37" version = "0.8.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lexical 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -447,7 +446,7 @@ dependencies = [
"nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-rug-adapter 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"prolog_parser 0.8.37 (registry+https://github.com/rust-lang/crates.io-index)", "prolog_parser 0.8.38",
"ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ref_thread_local 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rug 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 5.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -590,7 +589,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6" "checksum num-traits 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "443c53b3c3531dfcbfa499d8893944db78474ad7a1d87fa2d94d1a2231693ac6"
"checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d" "checksum ordered-float 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7eb5259643245d3f292c7a146b2df53bba24d7eab159410e648eb73dc164669d"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" "checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
"checksum prolog_parser 0.8.37 (registry+https://github.com/rust-lang/crates.io-index)" = "cb3da90085db170f1045f7d6851da12400ab205af9ec2acaa5ee42ab45a25dd8"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"

View File

@@ -24,7 +24,7 @@ libc = "0.2.62"
nix = "0.15.0" nix = "0.15.0"
num-rug-adapter = { optional = true, version = "0.1.1" } num-rug-adapter = { optional = true, version = "0.1.1" }
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = { version = "0.8.37", default-features = false } prolog_parser = { version = "0.8.38", 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 = "5.0.3" rustyline = "5.0.3"

View File

@@ -31,26 +31,6 @@ pub enum TopLevel {
} }
impl TopLevel { impl TopLevel {
pub fn name(&self) -> Option<ClauseName> {
match self {
&TopLevel::Declaration(_) => None,
&TopLevel::Fact(ref term, ..) => term.name(),
&TopLevel::Predicate(ref clauses) => clauses.0.first().and_then(|ref term| term.name()),
&TopLevel::Query(_) => None,
&TopLevel::Rule(Rule { ref head, .. }, ..) => Some(head.0.clone()),
}
}
pub fn arity(&self) -> usize {
match self {
&TopLevel::Declaration(_) => 0,
&TopLevel::Fact(ref term, ..) => term.arity(),
&TopLevel::Predicate(ref clauses) => clauses.0.first().map(|t| t.arity()).unwrap_or(0),
&TopLevel::Query(_) => 0,
&TopLevel::Rule(Rule { ref head, .. }, ..) => head.1.len(),
}
}
pub fn is_end_of_file_atom(&self) -> bool { pub fn is_end_of_file_atom(&self) -> bool {
match self { match self {
&TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => { &TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => {
@@ -159,6 +139,190 @@ impl ListingSource {
} }
} }
fn resolved_term_and_module(term: &Term) -> Option<(ClauseName, ClauseName)>
{
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 {
match clauses.first() {
Some(ref cl) => {
self.name_and_module() == cl.name_and_module() && self.arity() == cl.arity()
}
None => {
true
}
}
}
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>;
fn arity(&self) -> usize;
}
/* Of course '$current_module$' isn't the name of the current
* module. It'll do if no module is explicitly specified through
* (:)/2.
*/
impl ClauseConsistency for Term {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>
{
match self {
Term::Clause(_, ref name, ref terms, _) =>
match name.as_str() {
":-" => {
match terms.len() {
1 => None, // a declaration.
2 => resolved_term_and_module(&terms[0]),
_ => Some((name.owning_module(), clause_name!(":-"))),
}
}
_ => {
resolved_term_and_module(self)
}
},
Term::Constant(_, Constant::Atom(ref name, _)) => {
Some((name.owning_module(), name.clone()))
}
_ => {
None
}
}
}
fn arity(&self) -> usize {
match self {
Term::Clause(_, ref name, ref terms, _) =>
match name.as_str() {
":-" => {
match terms.len() {
1 => 0,
2 => resolved_term_arity(&terms[0]),
_ => terms.len(),
}
}
_ => {
resolved_term_arity(self)
}
},
_ => {
0
}
}
}
}
impl ClauseConsistency for Rule {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
Some((self.head.0.owning_module(), self.head.0.clone()))
}
fn arity(&self) -> usize {
self.head.1.len()
}
}
impl ClauseConsistency for PredicateClause {
fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> {
match self {
&PredicateClause::Fact(ref term, ..) => {
term.name_and_module()
.map(|(_, name)| (name.owning_module(), name))
}
&PredicateClause::Rule(ref rule, ..) => {
rule.name_and_module()
}
}
}
fn arity(&self) -> usize {
match self {
&PredicateClause::Fact(ref term, ..) => {
term.arity()
}
&PredicateClause::Rule(ref rule, ..) => {
rule.arity()
}
}
}
}
impl ClauseConsistency for Predicate {
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>); pub type CompiledResult = (Predicate, VecDeque<TopLevel>);
#[derive(Clone)] #[derive(Clone)]
@@ -177,8 +341,24 @@ impl PredicateClause {
pub fn arity(&self) -> usize { pub fn arity(&self) -> usize {
match self { match self {
&PredicateClause::Fact(ref term, ..) => term.arity(), &PredicateClause::Fact(ref term, ..) => {
&PredicateClause::Rule(ref rule, ..) => rule.head.1.len(), term.arity()
}
&PredicateClause::Rule(ref rule, ..) => {
if rule.head.0.as_str() == ":" && rule.head.1.len() == 2 {
match (rule.head.1)[0].as_ref() {
&Term::Constant(_, Constant::Atom(..)) => {
}
_ => {
return 2;
}
}
(rule.head.1)[1].arity()
} else {
rule.head.1.len()
}
}
} }
} }
@@ -196,6 +376,14 @@ pub enum ModuleSource {
File(ClauseName), File(ClauseName),
} }
pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator.
#[derive(Clone)]
pub enum MultiFileIndicator {
LocalScoped(ClauseName, usize), // name, arity
ModuleScoped(ScopedPredicateKey),
}
#[derive(Clone)] #[derive(Clone)]
pub enum Declaration { pub enum Declaration {
Dynamic(ClauseName, usize), // name, arity Dynamic(ClauseName, usize), // name, arity
@@ -203,7 +391,7 @@ pub enum Declaration {
Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>), Hook(CompileTimeHook, PredicateClause, VecDeque<TopLevel>),
ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal ModuleInitialization(Vec<QueryTerm>, VecDeque<TopLevel>), // goal
Module(ModuleDecl), Module(ModuleDecl),
MultiFile(ClauseName, usize), MultiFile(MultiFileIndicator),
NonCountedBacktracking(ClauseName, usize), // name, arity NonCountedBacktracking(ClauseName, usize), // name, arity
Op(OpDecl), Op(OpDecl),
UseModule(ModuleSource), UseModule(ModuleSource),
@@ -314,11 +502,11 @@ pub fn fetch_op_spec(
op_dir: &OpDir, op_dir: &OpDir,
) -> Option<SharedOpDesc> { ) -> Option<SharedOpDesc> {
if let Some(ref op_desc) = &spec { if let Some(ref op_desc) = &spec {
if op_desc.arity() != arity { if op_desc.arity() != arity {
/* it's possible to extend operator functors with /* it's possible to extend operator functors with
* additional terms. When that happens, * additional terms. When that happens,
* void the op_spec by returning None. */ * void the op_spec by returning None. */
return None; return None;
} }
} }
@@ -358,7 +546,7 @@ pub type ModuleDir = IndexMap<ClauseName, Module>;
#[derive(Clone, PartialEq)] #[derive(Clone, PartialEq)]
pub enum ModuleExport { pub enum ModuleExport {
OpDecl(OpDecl), OpDecl(OpDecl),
PredicateKey(PredicateKey), PredicateKey(PredicateKey),
} }
#[derive(Clone)] #[derive(Clone)]

View File

@@ -44,6 +44,17 @@ phrase_(phrase(NonTerminal), S0, S) :-
phrase_([T|Ts], S0, S) :- phrase_([T|Ts], S0, S) :-
append([T|Ts], S, S0). append([T|Ts], S, S0).
% The same version of the below two dcg_rule clauses, but with module scoping.
dcg_rule(( M:NonTerminal, Terminals --> GRBody ), ( M:Head :- Body )) :-
dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S1, Goal1),
dcg_terminals(Terminals, S, S1, Goal2),
Body = ( Goal1, Goal2 ).
dcg_rule(( M:NonTerminal --> GRBody ), ( M:Head :- Body )) :-
NonTerminal \= ( _, _ ),
dcg_non_terminal(NonTerminal, S0, S, Head),
dcg_body(GRBody, S0, S, Body).
% This program uses append/3 as defined in the Prolog prologue. % This program uses append/3 as defined in the Prolog prologue.
% Expands a DCG rule into a Prolog rule, when no error condition applies. % Expands a DCG rule into a Prolog rule, when no error condition applies.
dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :- dcg_rule(( NonTerminal, Terminals --> GRBody ), ( Head :- Body )) :-

View File

@@ -9,7 +9,10 @@ use crate::prolog::machine::compile::*;
use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use indexmap::IndexSet;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::mem;
pub struct CodeRepo { pub struct CodeRepo {
pub(super) cached_query: Code, pub(super) cached_query: Code,
@@ -59,11 +62,13 @@ impl CodeRepo {
.unwrap_or((Predicate::new(), VecDeque::from(vec![]))) .unwrap_or((Predicate::new(), VecDeque::from(vec![])))
} }
pub fn add_in_situ_result( pub(crate) fn add_in_situ_result(
&mut self, &mut self,
result: &CompiledResult, result: &CompiledResult,
in_situ_code_dir: &mut InSituCodeDir, in_situ_code_dir: &mut InSituCodeDir,
in_situ_module_dir: &mut ModuleStubDir,
flags: MachineFlags, flags: MachineFlags,
non_counted_bt_preds: &IndexSet<PredicateKey>,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let (ref decl, ref queue) = result; let (ref decl, ref queue) = result;
let (name, arity) = decl let (name, arity) = decl
@@ -75,17 +80,26 @@ impl CodeRepo {
}) })
.ok_or(SessionError::NamelessEntry)?; .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(); let p = self.in_situ_code.len();
in_situ_code_dir.insert((name, arity), p);
let mut cg = CodeGenerator::<DebrayAllocator>::new(true, flags); match in_situ_module_dir.get_mut(&module_name) {
// clone the decl to avoid the need to wipe its register cells later. Some(ref mut module_stub) if name.has_table(&module_stub.atom_tbl) => {
let mut decl_code = cg.compile_predicate(&decl.0.clone())?; module_stub.in_situ_code_dir.insert((name, arity), p);
}
_ => {
in_situ_code_dir.insert((name, arity), p);
}
}
compile_appendix(&mut decl_code, queue, true, flags)?; let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt, flags);
let mut decl_code = cg.compile_predicate(&decl.0)?;
self.in_situ_code.extend(decl_code.into_iter()); compile_appendix(&mut decl_code, queue, non_counted_bt, flags)?;
Ok(())
Ok(self.in_situ_code.extend(decl_code.into_iter()))
} }
#[inline] #[inline]
@@ -93,6 +107,11 @@ impl CodeRepo {
self.cached_query.len() 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) fn lookup_instr<'a>( pub(super) fn lookup_instr<'a>(
&'a self, &'a self,
last_call: bool, last_call: bool,

View File

@@ -0,0 +1,81 @@
use crate::prolog::instructions::*;
use std::collections::VecDeque;
fn scan_for_trust_me(code: &Code, jmp_offsets: &mut VecDeque<usize>, after_idx: &mut usize) {
for (idx, instr) in code[*after_idx..].iter().enumerate() {
match instr {
&Line::Choice(ChoiceInstruction::TrustMe)
| &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
*after_idx += idx;
return;
}
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
jmp_offsets.push_back(*after_idx + idx + offset)
}
_ => {}
}
}
}
fn capture_next_range(code: &Code, queue: &mut VecDeque<usize>, last_idx: &mut usize) {
loop {
match &code[*last_idx] {
&Line::Choice(ChoiceInstruction::TryMeElse(..))
| &Line::IndexedChoice(IndexedChoiceInstruction::Try(..)) => {
*last_idx += 1;
scan_for_trust_me(code, queue, 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
* begin in code at the offset p. Each instruction is passed to the
* walker function.
*/
pub fn walk_code(code: &Code, p: usize, mut walker: impl FnMut(&Line))
{
let mut queue = VecDeque::from(vec![p]);
while let Some(first_idx) = queue.pop_front() {
let mut last_idx = first_idx;
capture_next_range(code, &mut queue, &mut last_idx);
for instr in &code[first_idx .. last_idx + 1] {
walker(instr);
}
}
}
/* A function for code walking that might result in modification to
* the code. Otherwise identical to walk_code.
*/
pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line))
{
let mut queue = VecDeque::from(vec![p]);
while let Some(first_idx) = queue.pop_front() {
let mut last_idx = first_idx;
capture_next_range(code, &mut queue, &mut last_idx);
for instr in &mut code[first_idx .. last_idx + 1] {
walker(instr);
}
}
}

View File

@@ -7,6 +7,7 @@ use crate::prolog::debray_allocator::*;
use crate::prolog::forms::*; use crate::prolog::forms::*;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::iterators::*; use crate::prolog::iterators::*;
use crate::prolog::machine::code_walker::*;
use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::term_expansion::ExpansionAdditionResult; use crate::prolog::machine::term_expansion::ExpansionAdditionResult;
@@ -367,24 +368,36 @@ fn compile_into_module_impl<R: Read>(
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?; wam.code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?;
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?; wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
let results = compiler.gather_items(wam, src, &mut indices)?; let mut results = compiler.gather_items(wam, src, &mut indices)?;
let module_code =
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?;
let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len(), module_name.clone()); compiler.adapt_in_situ_code(
results.worker_results,
wam,
&mut indices.code_dir,
&mut indices.module_dir,
&mut results.in_situ_code,
&results.in_situ_code_dir,
&results.in_situ_module_dir,
)?;
let mut clause_code_generator = ClauseCodeGenerator::new(
results.in_situ_code.len(),
module_name.clone()
);
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?; clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
let top_level_term_dir = results.top_level_term_dirs.consolidate(); let top_level_term_dir = results.top_level_term_dirs.consolidate();
add_module_code( add_module(
wam, wam,
compiler.module.take().unwrap(), compiler.module.take().unwrap(),
module_code,
indices, indices,
top_level_term_dir, top_level_term_dir,
); );
wam.code_repo.code.extend(results.in_situ_code.into_iter());
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map); clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
Ok(compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo)) Ok(compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo))
@@ -399,6 +412,9 @@ pub struct GatherResult {
top_level_terms: Vec<(Term, usize, usize)>, top_level_terms: Vec<(Term, usize, usize)>,
top_level_term_dirs: TermDirQuantum, top_level_term_dirs: TermDirQuantum,
module_term_dirs: TermDirQuantum, module_term_dirs: TermDirQuantum,
in_situ_code_dir: InSituCodeDir,
in_situ_code: Code,
in_situ_module_dir: ModuleStubDir,
} }
pub struct ClauseCodeGenerator { pub struct ClauseCodeGenerator {
@@ -490,8 +506,24 @@ impl ClauseCodeGenerator {
} }
} }
fn insert_or_refresh_term_dir_quantum(
term_dir: &TermDir,
key: PredicateKey,
term_dirs: &mut TermDirQuantum
) {
match term_dir.get(&key) {
Some((ref preds, ref queue)) => {
let entry = TermDirQuantumEntry::from(preds, queue);
term_dirs.insert_or_refresh(key, entry);
}
None => {
let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new());
term_dirs.insert_or_refresh(key, entry);
}
}
}
pub struct ListingCompiler { pub struct ListingCompiler {
non_counted_bt_preds: IndexSet<PredicateKey>,
module: Option<Module>, module: Option<Module>,
user_term_dir: TermDir, user_term_dir: TermDir,
orig_term_expansion_lens: (usize, usize), orig_term_expansion_lens: (usize, usize),
@@ -501,23 +533,22 @@ pub struct ListingCompiler {
listing_src: ListingSource, // a file? a module? listing_src: ListingSource, // a file? a module?
} }
fn add_toplevel_code( fn add_toplevel(
wam: &mut Machine, wam: &mut Machine,
code: Code,
indices: IndexStore, indices: IndexStore,
term_dir: TermDir, term_dir: TermDir,
) { ) {
wam.add_batched_code(code, indices.code_dir); wam.add_batched_code_dir(indices.code_dir);
wam.add_batched_ops(indices.op_dir); wam.add_batched_ops(indices.op_dir);
wam.add_in_situ_module_dir(indices.module_dir);
wam.code_repo.term_dir.extend(term_dir.into_iter()); wam.code_repo.term_dir.extend(term_dir.into_iter());
} }
#[inline] #[inline]
fn add_module_code( fn add_module(
wam: &mut Machine, wam: &mut Machine,
mut module: Module, mut module: Module,
code: Code,
indices: IndexStore, indices: IndexStore,
term_dir: TermDir, term_dir: TermDir,
) { ) {
@@ -525,7 +556,8 @@ fn add_module_code(
module.op_dir.extend(indices.op_dir.into_iter()); module.op_dir.extend(indices.op_dir.into_iter());
module.term_dir.extend(term_dir.into_iter()); module.term_dir.extend(term_dir.into_iter());
wam.add_module(module, code); wam.add_in_situ_module_dir(indices.module_dir);
wam.add_module(module);
} }
fn add_non_module_code( fn add_non_module_code(
@@ -540,7 +572,8 @@ fn add_non_module_code(
let mut clause_code_generator = ClauseCodeGenerator::new(code.len(), clause_name!("user")); let mut clause_code_generator = ClauseCodeGenerator::new(code.len(), clause_name!("user"));
clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?; clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?;
add_toplevel_code(wam, code, indices, term_dir); add_toplevel(wam, indices, term_dir);
wam.code_repo.code.extend(code.into_iter());
clause_code_generator.add_clause_code(wam, dynamic_clause_map); clause_code_generator.add_clause_code(wam, dynamic_clause_map);
Ok(()) Ok(())
@@ -580,7 +613,6 @@ impl ListingCompiler {
listing_src: ListingSource, listing_src: ListingSource,
) -> Self { ) -> Self {
ListingCompiler { ListingCompiler {
non_counted_bt_preds: IndexSet::new(),
module: None, module: None,
user_term_dir: TermDir::new(), user_term_dir: TermDir::new(),
orig_term_expansion_lens: code_repo orig_term_expansion_lens: code_repo
@@ -593,31 +625,37 @@ impl ListingCompiler {
} }
} }
/* /* Replace calls to self with a localized index cell, not
Replace calls to self with a localized index cell, not available to the global CodeIndex. * available to the global CodeIndex. This is done to implement
This is done to implement logical update semantics for dynamic database updates. * logical update semantics for dynamic database updates.
*/ */
fn localize_self_calls(&mut self, name: ClauseName, arity: usize, code: &mut Code, p: usize) { fn localize_self_calls(&mut self, key: PredicateKey, code: &mut Code, p: usize, target_p: usize)
let self_idx = CodeIndex::default(); {
set_code_index!(self_idx, IndexPtr::Index(p), self.get_module_name()); let (name, arity) = key;
for instr in code.iter_mut() { let self_idx = CodeIndex::default();
if let &mut Line::Control(ControlInstruction::CallClause(ref mut ct, ..)) = instr { set_code_index!(self_idx, IndexPtr::Index(target_p), self.get_module_name());
match ct {
&mut ClauseType::Named(ref ct_name, ct_arity, ref mut idx) walk_code_mut(code, p, |instr|
if ct_name == &name && arity == ct_arity => match instr {
{ Line::Control(ControlInstruction::CallClause(ref mut ct, ..)) => {
*idx = self_idx.clone(); match ct {
ClauseType::Named(ref ct_name, ct_arity, ref mut idx)
if ct_name == &name && arity == *ct_arity =>
{
*idx = self_idx.clone();
}
ClauseType::Op(ref op_name, ref shared_op_desc, ref mut idx)
if op_name == &name && shared_op_desc.arity() == arity =>
{
*idx = self_idx.clone();
}
_ => {}
} }
&mut ClauseType::Op(ref op_name, ref shared_op_desc, ref mut idx)
if op_name == &name && shared_op_desc.arity() == arity =>
{
*idx = self_idx.clone();
}
_ => {}
} }
} _ => {}
} },
);
} }
fn use_module( fn use_module(
@@ -707,45 +745,103 @@ impl ListingCompiler {
.map_err(SessionError::from) .map_err(SessionError::from)
} }
pub(crate) fn generate_code( fn set_code_index(
&mut self,
wam: &Machine,
key: PredicateKey,
in_situ_code: &mut Code,
code_dir: &mut CodeDir,
in_situ_code_dir: &InSituCodeDir,
decl: PredicateCompileQueue,
) -> Result<(), SessionError> {
let p = wam.code_repo.code.len();
let idx = code_dir
.entry(key.clone())
.or_insert(CodeIndex::default());
Ok(match in_situ_code_dir.get(&key) {
Some(in_situ_p) => {
set_code_index!(idx, IndexPtr::Index(p + *in_situ_p), self.get_module_name());
self.localize_self_calls(key, in_situ_code, *in_situ_p, p + *in_situ_p);
}
None => {
let flags = wam.machine_flags();
let (decl, queue) = decl;
let mut cg = CodeGenerator::<DebrayAllocator>::new(false, flags);
let mut decl_code = cg.compile_predicate(&decl.0)?;
compile_appendix(&mut decl_code, &queue, false, flags)?;
let in_situ_p = in_situ_code.len();
in_situ_code.extend(decl_code.into_iter());
set_code_index!(idx, IndexPtr::Index(p + in_situ_p), self.get_module_name());
self.localize_self_calls(key, in_situ_code, in_situ_p, p + in_situ_p);
}
})
}
fn adapt_in_situ_code(
&mut self, &mut self,
decls: Vec<PredicateCompileQueue>, decls: Vec<PredicateCompileQueue>,
wam: &Machine, wam: &Machine,
code_dir: &mut CodeDir, code_dir: &mut CodeDir,
code_offset: usize, module_dir: &mut ModuleDir,
) -> Result<Code, SessionError> { in_situ_code: &mut Code,
let mut code = vec![]; in_situ_code_dir: &InSituCodeDir,
in_situ_module_dir: &ModuleStubDir,
for (decl, queue) in decls { ) -> Result<(), SessionError> {
let (name, arity) = decl for decl in decls {
let key = decl.0
.predicate_indicator() .predicate_indicator()
.ok_or(SessionError::NamelessEntry)?; .ok_or(SessionError::NamelessEntry)?;
let non_counted_bt = self.non_counted_bt_preds.contains(&(name.clone(), arity));
let p = code.len() + wam.code_repo.code.len() + code_offset; let (name, _arity) = key.clone();
let mut cg = CodeGenerator::<DebrayAllocator>::new(non_counted_bt, wam.machine_flags()); let module_name = name.owning_module();
let decl = TopLevel::Predicate(decl); match in_situ_module_dir.get(&module_name) {
let mut decl_code = compile_relation(&mut cg, &decl)?; Some(ref module_stub) if name.has_table(&module_stub.atom_tbl) => {
let module =
module_dir.entry(module_name.clone())
.or_insert_with(|| {
let module_decl = ModuleDecl {
name: module_name.clone(),
exports: vec![]
};
compile_appendix(&mut decl_code, &queue, non_counted_bt, wam.machine_flags())?; Module::new(
module_decl,
module_stub.atom_tbl.clone(),
self.listing_src.clone(),
)
});
let idx = code_dir self.set_code_index(
.entry((name.clone(), arity)) wam,
.or_insert(CodeIndex::default()); key,
in_situ_code,
set_code_index!(idx, IndexPtr::Index(p), self.get_module_name()); &mut module.code_dir,
&module_stub.in_situ_code_dir,
self.localize_self_calls(name, arity, &mut decl_code, p); decl,
code.extend(decl_code.into_iter()); )?;
}
_ => {
self.set_code_index(
wam,
key,
in_situ_code,
code_dir,
in_situ_code_dir,
decl,
)?;
}
}
} }
Ok(code) Ok(())
}
fn add_non_counted_bt_flag(&mut self, name: ClauseName, arity: usize) {
self.non_counted_bt_preds.insert((name, arity));
} }
fn add_term_dir_terms( fn add_term_dir_terms(
@@ -822,6 +918,7 @@ impl ListingCompiler {
wam: &mut Machine, wam: &mut Machine,
indices: &mut IndexStore, indices: &mut IndexStore,
flags: MachineFlags, flags: MachineFlags,
non_counted_bt_preds: &mut IndexSet<PredicateKey>,
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
match decl { match decl {
Declaration::Dynamic(..) => { Declaration::Dynamic(..) => {
@@ -872,7 +969,8 @@ impl ListingCompiler {
Ok(()) Ok(())
} }
Declaration::NonCountedBacktracking(name, arity) => { Declaration::NonCountedBacktracking(name, arity) => {
Ok(self.add_non_counted_bt_flag(name, arity)) non_counted_bt_preds.insert((name, arity));
Ok(())
} }
Declaration::Op(op_decl) => { Declaration::Op(op_decl) => {
self.submit_op(wam, indices, &op_decl) self.submit_op(wam, indices, &op_decl)
@@ -929,50 +1027,35 @@ impl ListingCompiler {
fn setup_multifile_decl<R: Read>( fn setup_multifile_decl<R: Read>(
&self, &self,
name: ClauseName, indicator: MultiFileIndicator,
arity: usize, worker: &mut TopLevelBatchWorker<R>,
worker: &mut TopLevelBatchWorker<R>
) -> Result<(), SessionError> { ) -> Result<(), SessionError> {
let module_name = name.owning_module(); match indicator {
MultiFileIndicator::LocalScoped(name, arity) => {
let term_dir = &worker.term_stream.wam.code_repo.term_dir;
let key = (name, arity);
let term_dirs = &mut worker.term_dirs;
let term_dir = match module_name.as_str() { insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
"user" => {
&worker.term_stream.wam.code_repo.term_dir
} }
_ => { MultiFileIndicator::ModuleScoped((module_name, key)) => {
if let Some(ref module) = self.module { match worker.term_stream.wam.indices.modules.get(&module_name) {
&module.term_dir Some(ref module) => {
} else { let term_dir = &module.term_dir;
match worker.term_stream.wam.indices.modules.get(&module_name) { let term_dirs = worker.intra_module_term_dirs
Some(ref module) => { .entry(module_name)
&module.term_dir .or_insert(TermDirQuantum::new());
}
None => { insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs);
return Err(SessionError::ModuleNotFound); }
} None => {
return Err(SessionError::ModuleNotFound);
} }
} }
} }
}; };
Ok(match term_dir.get(&(name.clone(), arity)) { Ok(())
Some((ref preds, ref queue)) => {
let (preds, queue) = (preds.clone(), queue.clone());
worker.term_dirs.set_old(
(name.clone(), arity),
preds,
queue,
);
}
None => {
worker.term_dirs.set_old(
(name.clone(), arity),
Predicate::new(),
VecDeque::new(),
);
}
})
} }
fn process_and_commit_decl<R: Read>( fn process_and_commit_decl<R: Read>(
@@ -1001,8 +1084,8 @@ impl ListingCompiler {
&Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() => { &Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() => {
worker.term_stream.incr_expansion_lens(hook, 1, queue.len()) worker.term_stream.incr_expansion_lens(hook, 1, queue.len())
} }
&Declaration::MultiFile(ref name, arity) => { &Declaration::MultiFile(ref indicator) => {
self.setup_multifile_decl(name.clone(), arity, worker)?; self.setup_multifile_decl(indicator.clone(), worker)?;
} }
&Declaration::UseModule(_) | &Declaration::UseQualifiedModule(..) => { &Declaration::UseModule(_) | &Declaration::UseQualifiedModule(..) => {
update_expansion_lengths = true update_expansion_lengths = true
@@ -1010,7 +1093,13 @@ impl ListingCompiler {
_ => {} _ => {}
}; };
let result = self.process_decl(decl, &mut worker.term_stream.wam, indices, flags); let result = self.process_decl(
decl,
&mut worker.term_stream.wam,
indices,
flags,
&mut worker.non_counted_bt_preds,
);
if update_expansion_lengths { if update_expansion_lengths {
worker.term_stream.update_expansion_lens(); worker.term_stream.update_expansion_lens();
@@ -1018,7 +1107,7 @@ impl ListingCompiler {
result result
} }
pub(crate) fn gather_items<R: Read>( pub(crate) fn gather_items<R: Read>(
&mut self, &mut self,
wam: &mut Machine, wam: &mut Machine,
@@ -1040,10 +1129,11 @@ impl ListingCompiler {
mem::swap(&mut worker.results, &mut toplevel_results); mem::swap(&mut worker.results, &mut toplevel_results);
worker.in_module = true; worker.in_module = true;
self.process_and_commit_decl(decl, &mut worker, indices, flags)?; self.process_and_commit_decl(decl, &mut worker, indices, flags)?;
if let Some(ref module) = &self.module { if let Some(ref module) = &self.module {
worker.term_stream.set_atom_tbl(module.atom_tbl.clone()); worker.term_stream.set_atom_tbl(module.atom_tbl.clone());
top_level_term_dirs = mem::replace( top_level_term_dirs = mem::replace(
&mut worker.term_dirs, &mut worker.term_dirs,
TermDirQuantum::new(), TermDirQuantum::new(),
@@ -1056,7 +1146,7 @@ impl ListingCompiler {
} }
} }
let addition_results = worker.term_stream.rollback_expansion_code()?; let addition_results = worker.term_stream.rollback_expansion_code()?;
let module_term_dirs = if self.module.is_some() { let module_term_dirs = if self.module.is_some() {
worker.term_dirs worker.term_dirs
@@ -1064,7 +1154,7 @@ impl ListingCompiler {
top_level_term_dirs = worker.term_dirs; top_level_term_dirs = worker.term_dirs;
TermDirQuantum::new() TermDirQuantum::new()
}; };
Ok(GatherResult { Ok(GatherResult {
worker_results: worker.results, worker_results: worker.results,
dynamic_clause_map: worker.dynamic_clause_map, dynamic_clause_map: worker.dynamic_clause_map,
@@ -1074,6 +1164,9 @@ impl ListingCompiler {
top_level_terms: worker.term_stream.top_level_terms(), top_level_terms: worker.term_stream.top_level_terms(),
top_level_term_dirs, top_level_term_dirs,
module_term_dirs, module_term_dirs,
in_situ_code_dir: worker.term_stream.wam.indices.take_in_situ_code_dir(),
in_situ_code: worker.term_stream.wam.code_repo.take_in_situ_code(),
in_situ_module_dir: worker.term_stream.wam.indices.take_in_situ_module_dir(),
}) })
} }
@@ -1119,18 +1212,29 @@ fn compile_work_impl(
let top_level_term_dir = results.top_level_term_dirs.consolidate(); let top_level_term_dir = results.top_level_term_dirs.consolidate();
let module_term_dir = results.module_term_dirs.consolidate(); let module_term_dir = results.module_term_dirs.consolidate();
let module_code = compiler.generate_code( let mut code = results.in_situ_code;
let in_situ_code_dir = results.in_situ_code_dir;
let in_situ_module_dir = results.in_situ_module_dir;
compiler.adapt_in_situ_code(
results.worker_results, results.worker_results,
wam, wam,
&mut indices.code_dir, &mut indices.code_dir,
0 &mut indices.module_dir,
&mut code,
&in_situ_code_dir,
&in_situ_module_dir,
)?; )?;
let toplvl_code = compiler.generate_code( compiler.adapt_in_situ_code(
results.toplevel_results, results.toplevel_results,
wam, wam,
&mut results.toplevel_indices.code_dir, &mut results.toplevel_indices.code_dir,
module_code.len() &mut indices.module_dir,
&mut code,
&in_situ_code_dir,
&in_situ_module_dir,
)?; )?;
if let Some(ref mut module) = &mut compiler.module { if let Some(ref mut module) = &mut compiler.module {
@@ -1154,8 +1258,7 @@ fn compile_work_impl(
} }
let mut clause_code_generator = let mut clause_code_generator =
ClauseCodeGenerator::new(module_code.len() + toplvl_code.len(), ClauseCodeGenerator::new(code.len(), module.module_decl.name.clone());
module.module_decl.name.clone());
wam.check_toplevel_code(&results.toplevel_indices)?; wam.check_toplevel_code(&results.toplevel_indices)?;
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?; clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
@@ -1165,23 +1268,25 @@ fn compile_work_impl(
} }
if module.is_impromptu_module { if module.is_impromptu_module {
add_module_code(wam, module, module_code, indices, module_term_dir); add_module(wam, module, indices, module_term_dir);
let module = wam.indices.take_module(compiler.listing_src.name()).unwrap(); let module = wam.indices.take_module(compiler.listing_src.name()).unwrap();
wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?; wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?;
wam.indices.insert_module(module); wam.indices.insert_module(module);
} else { } else {
add_module_code(wam, module, module_code, indices, module_term_dir); add_module(wam, module, indices, module_term_dir);
} }
add_toplevel_code(wam, toplvl_code, results.toplevel_indices, top_level_term_dir); add_toplevel(wam, results.toplevel_indices, top_level_term_dir);
wam.code_repo.code.extend(code.into_iter());
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map); clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
} else { } else {
add_non_module_code( add_non_module_code(
wam, wam,
results.dynamic_clause_map, results.dynamic_clause_map,
module_code, code,
indices, indices,
top_level_term_dir, top_level_term_dir,
)?; )?;
@@ -1231,14 +1336,24 @@ pub fn compile_special_form<R: Read>(
setup_indices(wam, clause_name!("builtins"), &mut indices)?; setup_indices(wam, clause_name!("builtins"), &mut indices)?;
let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src); let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src);
let results = compiler.gather_items(wam, src, &mut indices)?; let mut results = compiler.gather_items(wam, src, &mut indices)?;
compiler.adapt_in_situ_code(
results.worker_results,
wam,
&mut indices.code_dir,
&mut indices.module_dir,
&mut results.in_situ_code,
&results.in_situ_code_dir,
&results.in_situ_module_dir,
)?;
let code = compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?;
let p = wam.code_repo.code.len(); let p = wam.code_repo.code.len();
let top_level_term_dir = results.top_level_term_dirs.consolidate(); let top_level_term_dir = results.top_level_term_dirs.consolidate();
add_toplevel_code(wam, code, indices, top_level_term_dir); add_toplevel(wam, indices, top_level_term_dir);
wam.code_repo.code.extend(results.in_situ_code.into_iter());
Ok(p) Ok(p)
} }

View File

@@ -1,6 +1,7 @@
use prolog_parser::ast::*; use prolog_parser::ast::*;
use prolog_parser::string_list::*; use prolog_parser::string_list::*;
use crate::prolog::forms::PredicateKey;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*; use crate::prolog::machine::machine_state::*;
use crate::prolog::rug::Integer; use crate::prolog::rug::Integer;
@@ -134,7 +135,7 @@ impl MachineError {
SessionError::InvalidFileName(filename) => { SessionError::InvalidFileName(filename) => {
Self::existence_error(h, ExistenceError::Module(filename)) Self::existence_error(h, ExistenceError::Module(filename))
} }
SessionError::ModuleDoesNotContainExport => Self::permission_error( SessionError::ModuleDoesNotContainExport(..) => Self::permission_error(
PermissionError::Access, PermissionError::Access,
"private_procedure", "private_procedure",
clause_name!("module_does_not_contain_claimed_export"), clause_name!("module_does_not_contain_claimed_export"),
@@ -533,7 +534,7 @@ pub enum SessionError {
CannotOverwriteBuiltIn(ClauseName), CannotOverwriteBuiltIn(ClauseName),
CannotOverwriteImport(ClauseName), CannotOverwriteImport(ClauseName),
InvalidFileName(ClauseName), InvalidFileName(ClauseName),
ModuleDoesNotContainExport, ModuleDoesNotContainExport(ClauseName, PredicateKey),
ModuleNotFound, ModuleNotFound,
NamelessEntry, NamelessEntry,
OpIsInfixAndPostFix(ClauseName), OpIsInfixAndPostFix(ClauseName),

View File

@@ -214,6 +214,7 @@ impl HeapCellValue {
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, Undefined,
InSituDirEntry(usize),
Index(usize), Index(usize),
UserGoalExpansion, UserGoalExpansion,
UserTermExpansion UserTermExpansion
@@ -223,6 +224,11 @@ pub enum IndexPtr {
pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>); pub struct CodeIndex(pub Rc<RefCell<(IndexPtr, ClauseName)>>);
impl CodeIndex { impl CodeIndex {
#[inline]
pub fn new(ptr: IndexPtr, module_name: ClauseName) -> Self {
CodeIndex(Rc::new(RefCell::new(( ptr, module_name ))))
}
#[inline] #[inline]
pub fn is_undefined(&self) -> bool { pub fn is_undefined(&self) -> bool {
let index_ptr = &self.0.borrow().0; let index_ptr = &self.0.borrow().0;
@@ -540,17 +546,36 @@ impl Default for DynamicPredicateInfo {
} }
pub type InSituCodeDir = IndexMap<PredicateKey, usize>; pub type InSituCodeDir = IndexMap<PredicateKey, usize>;
// key type: module name, predicate indicator. // key type: module name, predicate indicator.
pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>; pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>;
pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>; pub type GlobalVarDir = IndexMap<ClauseName, (Ball, Option<usize>)>;
pub(crate) struct ModuleStub {
pub(crate) atom_tbl: TabledData<Atom>,
pub(crate) in_situ_code_dir: InSituCodeDir,
}
impl 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 struct IndexStore { pub struct IndexStore {
pub(super) atom_tbl: TabledData<Atom>, pub(super) atom_tbl: TabledData<Atom>,
pub(super) code_dir: CodeDir, pub(super) code_dir: CodeDir,
pub(super) module_dir: ModuleDir,
pub(super) dynamic_code_dir: DynamicCodeDir, pub(super) dynamic_code_dir: DynamicCodeDir,
pub(super) global_variables: GlobalVarDir, pub(super) global_variables: GlobalVarDir,
pub(super) in_situ_code_dir: InSituCodeDir, pub(super) in_situ_code_dir: InSituCodeDir,
pub(super) in_situ_module_dir: ModuleStubDir,
pub(super) modules: ModuleDir, pub(super) modules: ModuleDir,
pub(super) op_dir: OpDir, pub(super) op_dir: OpDir,
} }
@@ -607,6 +632,16 @@ impl IndexStore {
self.dynamic_code_dir.get(&(module, name, arity)).cloned() self.dynamic_code_dir.get(&(module, name, arity)).cloned()
} }
#[inline]
pub(crate) fn take_in_situ_module_dir(&mut self) -> ModuleStubDir {
mem::replace(&mut self.in_situ_module_dir, ModuleStubDir::new())
}
#[inline]
pub fn take_in_situ_code_dir(&mut self) -> InSituCodeDir {
mem::replace(&mut self.in_situ_code_dir, InSituCodeDir::new())
}
#[inline] #[inline]
pub fn take_module(&mut self, name: ClauseName) -> Option<Module> { pub fn take_module(&mut self, name: ClauseName) -> Option<Module> {
self.modules.swap_remove(&name) self.modules.swap_remove(&name)
@@ -622,12 +657,13 @@ impl IndexStore {
IndexStore { IndexStore {
atom_tbl: TabledData::new(Rc::new("user".to_string())), atom_tbl: TabledData::new(Rc::new("user".to_string())),
code_dir: CodeDir::new(), code_dir: CodeDir::new(),
module_dir: ModuleDir::new(),
dynamic_code_dir: DynamicCodeDir::new(), dynamic_code_dir: DynamicCodeDir::new(),
global_variables: GlobalVarDir::new(), global_variables: GlobalVarDir::new(),
in_situ_code_dir: InSituCodeDir::new(), in_situ_code_dir: InSituCodeDir::new(),
in_situ_module_dir: ModuleStubDir::new(),
op_dir: default_op_dir(), op_dir: default_op_dir(),
modules: ModuleDir::new(), modules: ModuleDir::new(),
// parsing_stream: readline::parsing_stream(String::new())
} }
} }
@@ -680,6 +716,77 @@ impl IndexStore {
pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>; pub type CodeDir = BTreeMap<PredicateKey, CodeIndex>;
pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>; pub type TermDir = IndexMap<PredicateKey, (Predicate, VecDeque<TopLevel>)>;
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
}
}
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(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)] #[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
pub enum CompileTimeHook { pub enum CompileTimeHook {
GoalExpansion, GoalExpansion,

View File

@@ -372,6 +372,15 @@ impl MachineState {
return Ok(()); 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(());
}
_ => {} _ => {}
} }
} }
@@ -384,19 +393,21 @@ impl MachineState {
} }
} }
fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<usize> { fn try_in_situ_lookup(name: ClauseName, arity: usize, indices: &IndexStore) -> Option<usize>
{
match indices.in_situ_code_dir.get(&(name.clone(), arity)) { match indices.in_situ_code_dir.get(&(name.clone(), arity)) {
Some(p) => Some(*p), Some(p) => Some(*p),
None => match indices.code_dir.get(&(name, arity)) { None =>
Some(ref idx) => { match indices.code_dir.get(&(name, arity)) {
if let &IndexPtr::Index(p) = &idx.0.borrow().0 { Some(ref idx) => {
Some(p) if let IndexPtr::Index(p) = idx.0.borrow().0 {
} else { Some(p)
None } else {
None
}
} }
} _ => None,
_ => None, },
},
} }
} }
@@ -633,10 +644,12 @@ pub(crate) trait CallPolicy: Any {
indices: &IndexStore, indices: &IndexStore,
) -> CallResult { ) -> CallResult {
match idx.0.borrow().0 { match idx.0.borrow().0 {
IndexPtr::DynamicUndefined => IndexPtr::DynamicUndefined => {
machine_st.fail = true, machine_st.fail = true;
IndexPtr::Undefined => }
return try_in_situ(machine_st, name, arity, indices, false), IndexPtr::Undefined => {
return try_in_situ(machine_st, name, arity, indices, false);
}
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))
} }
@@ -646,6 +659,9 @@ pub(crate) trait CallPolicy: Any {
IndexPtr::UserGoalExpansion => { IndexPtr::UserGoalExpansion => {
machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0)); machine_st.call_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
} }
IndexPtr::InSituDirEntry(p) => {
machine_st.call_at_index(arity, LocalCodePtr::InSituDirEntry(p));
}
} }
Ok(()) Ok(())
@@ -673,6 +689,9 @@ pub(crate) trait CallPolicy: Any {
IndexPtr::UserGoalExpansion => { IndexPtr::UserGoalExpansion => {
machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0)); machine_st.execute_at_index(arity, LocalCodePtr::UserGoalExpansion(0));
} }
IndexPtr::InSituDirEntry(p) => {
machine_st.execute_at_index(arity, LocalCodePtr::InSituDirEntry(p));
}
} }
Ok(()) Ok(())

View File

@@ -10,6 +10,7 @@ use crate::prolog::read::*;
mod attributed_variables; mod attributed_variables;
pub(super) mod code_repo; pub(super) mod code_repo;
pub mod code_walker;
pub mod compile; pub mod compile;
mod copier; mod copier;
mod dynamic_database; mod dynamic_database;
@@ -109,11 +110,33 @@ impl SubModuleUser for IndexStore {
fn get_code_index(&self, key: PredicateKey, module_name: ClauseName) -> Option<CodeIndex> { fn get_code_index(&self, key: PredicateKey, module_name: ClauseName) -> Option<CodeIndex> {
match module_name.as_str() { match module_name.as_str() {
"user" | "builtin" => self.code_dir.get(&key).cloned(), "user" => {
_ => self self.code_dir.get(&key).cloned()
.modules }
.get(&module_name) _ => {
.and_then(|ref module| module.code_dir.get(&key).cloned().map(CodeIndex::from)) match self.in_situ_module_dir.get(&module_name) {
Some(ref module_stub) => {
match module_stub.in_situ_code_dir.get(&key) {
Some(p) => {
return Some(CodeIndex::new(
IndexPtr::InSituDirEntry(*p),
module_name.clone()
));
}
None => {
}
}
}
None => {
}
};
self.modules
.get(&module_name)
.and_then(|ref module| {
module.code_dir.get(&key).cloned()
})
}
} }
} }
@@ -333,7 +356,7 @@ impl Machine {
default_index_store!(atom_tbl.clone()), default_index_store!(atom_tbl.clone()),
true, true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("builtins.pl"), clause_name!("builtins.pl"),
lib_path.clone(), lib_path.clone(),
), ),
); );
@@ -348,7 +371,7 @@ impl Machine {
); );
compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true, compile_user_module(&mut wam, parsing_stream(LISTS.as_bytes()), true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("lists"), clause_name!("lists"),
lib_path.clone(), lib_path.clone(),
), ),
); );
@@ -360,7 +383,7 @@ impl Machine {
); );
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true, compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
ListingSource::from_file_and_path( ListingSource::from_file_and_path(
clause_name!("si"), clause_name!("si"),
lib_path.clone(), lib_path.clone(),
) )
); );
@@ -418,10 +441,10 @@ impl Machine {
Ok(()) Ok(())
} }
pub fn add_batched_code(&mut self, code: Code, code_dir: CodeDir) { pub(crate) fn add_batched_code_dir(&mut self, code_dir: CodeDir) {
// error detection has finished, so update the master index of keys. // error detection has finished, so update the master index of keys.
for (key, idx) in code_dir { for (key, idx) in code_dir {
if let Some(ref mut master_idx) = self.indices.code_dir.get_mut(&key) { if let Some(ref master_idx) = self.indices.code_dir.get(&key) {
// ensure we don't double borrow if master_idx == idx. // ensure we don't double borrow if master_idx == idx.
// we don't need to modify anything in that case. // we don't need to modify anything in that case.
if !Rc::ptr_eq(&master_idx.0, &idx.0) { if !Rc::ptr_eq(&master_idx.0, &idx.0) {
@@ -433,21 +456,37 @@ impl Machine {
self.indices.code_dir.insert(key, idx); self.indices.code_dir.insert(key, idx);
} }
self.code_repo.code.extend(code.into_iter());
} }
#[inline] #[inline]
pub fn add_batched_ops(&mut self, op_dir: OpDir) { pub(crate) fn add_batched_ops(&mut self, op_dir: OpDir) {
self.indices.op_dir.extend(op_dir.into_iter()); self.indices.op_dir.extend(op_dir.into_iter());
} }
pub(crate) fn add_in_situ_module_dir(&mut self, module_dir: ModuleDir) {
for (module_name, module_skeleton) in module_dir {
match self.indices.modules.get_mut(&module_name) {
Some(ref mut module) => {
for (key, idx) in module_skeleton.code_dir {
if let Some(existing_idx) = module.code_dir.get(&key) {
set_code_index!(existing_idx, idx.0.borrow().0, module_name.clone());
} else {
module.code_dir.insert(key, idx);
}
}
}
None => {
self.add_module(module_skeleton);
}
}
}
}
#[inline] #[inline]
pub fn add_module(&mut self, module: Module, code: Code) { pub fn add_module(&mut self, module: Module) {
self.indices self.indices
.modules .modules
.insert(module.module_decl.name.clone(), module); .insert(module.module_decl.name.clone(), module);
self.code_repo.code.extend(code.into_iter());
} }
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {

View File

@@ -231,8 +231,13 @@ where
continue; continue;
} }
if !user.import_decl(name, arity, submodule) { if !user.import_decl(name.clone(), arity, submodule) {
return Err(SessionError::ModuleDoesNotContainExport); let submodule_name = submodule.module_decl.name.clone();
return Err(SessionError::ModuleDoesNotContainExport(
submodule_name,
(name, arity)
));
} }
}, },
ModuleExport::OpDecl(op_decl) => { ModuleExport::OpDecl(op_decl) => {
@@ -266,8 +271,13 @@ pub fn use_module<User: SubModuleUser>(
for export in submodule.module_decl.exports.iter().cloned() { for export in submodule.module_decl.exports.iter().cloned() {
match export { match export {
ModuleExport::PredicateKey((name, arity)) => { ModuleExport::PredicateKey((name, arity)) => {
if !user.import_decl(name, arity, submodule) { if !user.import_decl(name.clone(), arity, submodule) {
return Err(SessionError::ModuleDoesNotContainExport); let submodule_name = submodule.module_decl.name.clone();
return Err(SessionError::ModuleDoesNotContainExport(
submodule_name,
(name, arity)
));
} }
} }
ModuleExport::OpDecl(op_decl) => { ModuleExport::OpDecl(op_decl) => {

View File

@@ -9,6 +9,7 @@ use crate::prolog::heap_print::*;
use crate::prolog::instructions::*; use crate::prolog::instructions::*;
use crate::prolog::machine::code_repo::CodeRepo; use crate::prolog::machine::code_repo::CodeRepo;
use crate::prolog::machine::copier::*; use crate::prolog::machine::copier::*;
use crate::prolog::machine::code_walker::*;
use crate::prolog::machine::machine_errors::*; use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*; use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*; use crate::prolog::machine::machine_state::*;
@@ -21,7 +22,6 @@ use crate::ref_thread_local::RefThreadLocal;
use indexmap::{IndexMap, IndexSet}; use indexmap::{IndexMap, IndexSet};
use std::collections::VecDeque;
use std::io::{stdin, stdout, Write}; use std::io::{stdin, stdout, Write};
use std::iter::once; use std::iter::once;
use std::mem; use std::mem;
@@ -68,22 +68,6 @@ impl BrentAlgState {
} }
} }
fn scan_for_trust_me(code: &Code, jmp_offsets: &mut VecDeque<usize>, after_idx: &mut usize) {
for (idx, instr) in code[*after_idx..].iter().enumerate() {
match instr {
&Line::Choice(ChoiceInstruction::TrustMe)
| &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => {
*after_idx += idx;
return;
}
&Line::Control(ControlInstruction::JmpBy(_, offset, ..)) => {
jmp_offsets.push_back(*after_idx + idx + offset)
}
_ => {}
}
}
}
fn is_builtin_predicate(name: &ClauseName) -> bool { fn is_builtin_predicate(name: &ClauseName) -> bool {
let in_builtins = name.owning_module().as_str() == "builtins"; let in_builtins = name.owning_module().as_str() == "builtins";
let hidden_name = name.as_str().starts_with("$"); let hidden_name = name.as_str().starts_with("$");
@@ -537,49 +521,6 @@ impl MachineState {
self.unify(attr_goals, target); self.unify(attr_goals, target);
} }
fn create_instruction_functors(&mut self, code: &Code, first_idx: usize) -> Vec<Addr> {
let mut queue = VecDeque::new();
let mut functors = vec![];
let mut h = self.heap.h;
queue.push_back(first_idx);
while let Some(first_idx) = queue.pop_front() {
let mut last_idx = first_idx;
loop {
match &code[last_idx] {
&Line::Choice(ChoiceInstruction::TryMeElse(..))
| &Line::IndexedChoice(IndexedChoiceInstruction::Try(..)) => {
last_idx += 1;
scan_for_trust_me(code, &mut queue, &mut 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,
};
}
for instr in &code[first_idx..last_idx + 1] {
let section = instr.to_functor(h);
functors.push(Addr::HeapCell(h));
h += section.len();
self.heap.extend(section.into_iter());
}
}
functors
}
fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr { fn call_continuation_chunk(&mut self, chunk: Addr, return_p: LocalCodePtr) -> LocalCodePtr {
let chunk = self.store(self.deref(chunk)); let chunk = self.store(self.deref(chunk));
@@ -2382,7 +2323,21 @@ impl MachineState {
} }
}; };
let functors = self.create_instruction_functors(&code_repo.code, first_idx); let mut h = self.heap.h;
let mut functors = vec![];
walk_code(
&code_repo.code,
first_idx,
|instr| {
let section = instr.to_functor(h);
functors.push(Addr::HeapCell(h));
h += section.len();
self.heap.extend(section.into_iter());
},
);
let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter())); let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter()));
let listing_var = self[temp_v!(3)].clone(); let listing_var = self[temp_v!(3)].clone();

View File

@@ -73,11 +73,10 @@ pub struct TermStream<'a, R: Read> {
stack: Vec<Term>, stack: Vec<Term>,
pub(crate) wam: &'a mut Machine, pub(crate) wam: &'a mut Machine,
parser: Parser<'a, R>, parser: Parser<'a, R>,
in_module: bool,
pub(crate) flags: MachineFlags, pub(crate) flags: MachineFlags,
term_expansion_lens: (usize, usize), term_expansion_lens: (usize, usize),
goal_expansion_lens: (usize, usize), goal_expansion_lens: (usize, usize),
top_level_terms: Vec<(Term, usize, usize)> // term, line_num, col_num. top_level_terms: Vec<(Term, usize, usize)>, // term, line_num, col_num.
} }
pub struct ExpansionAdditionResult { pub struct ExpansionAdditionResult {
@@ -104,6 +103,8 @@ impl ExpansionAdditionResult {
impl<'a, R: Read> Drop for TermStream<'a, R> { impl<'a, R: Read> Drop for TermStream<'a, R> {
fn drop(&mut self) { fn drop(&mut self) {
self.wam.indices.in_situ_code_dir.clear(); self.wam.indices.in_situ_code_dir.clear();
self.wam.indices.in_situ_module_dir.clear();
self.wam.code_repo.in_situ_code.clear(); self.wam.code_repo.in_situ_code.clear();
discard_result!(self.rollback_expansion_code()); discard_result!(self.rollback_expansion_code());
} }
@@ -126,9 +127,8 @@ impl<'a, R: Read> TermStream<'a, R> {
.term_dir_entry_len((clause_name!("goal_expansion"), 2)), .term_dir_entry_len((clause_name!("goal_expansion"), 2)),
wam, wam,
parser: Parser::new(src, atom_tbl, flags), parser: Parser::new(src, atom_tbl, flags),
in_module: false,
flags, flags,
top_level_terms: vec![] top_level_terms: vec![],
} }
} }
@@ -226,8 +226,12 @@ impl<'a, R: Read> TermStream<'a, R> {
let iter = extract_from_list(head, tail)?; let iter = extract_from_list(head, tail)?;
Ok(self.stack.extend(iter)) Ok(self.stack.extend(iter))
} }
Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => Ok(self.stack.push(term)), Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => {
_ => Err(ParserError::ExpectedTopLevelTerm), Ok(self.stack.push(term))
}
_ => {
Err(ParserError::ExpectedTopLevelTerm)
}
} }
} }
@@ -240,26 +244,36 @@ impl<'a, R: Read> TermStream<'a, R> {
let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags); let mut parser = Parser::new(&mut stream, self.parser.get_atom_tbl(), self.flags);
parser.read_term(composite_op!( parser.read_term(composite_op!(
self.in_module, false,
&self.wam.indices.op_dir, &self.wam.indices.op_dir,
op_dir op_dir
)) ))
} }
pub fn read_term(&mut self, op_dir: &OpDir) -> Result<Term, ParserError> { pub fn expand_term(&mut self, term: Term, op_dir: &OpDir) -> Result<Term, ParserError> {
let mut machine_st = MachineState::new(); 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 { loop {
while let Some(term) = self.stack.pop() { if let Some(term) = self.stack.pop() {
match machine_st.try_expand_term(self.wam, &term, CompileTimeHook::TermExpansion) { return Ok(self.expand_term(term, op_dir)?);
Some(term_string) => {
let term = self.parse_expansion_output(term_string.as_str(), op_dir)?;
self.enqueue_term(term)?
}
None => {
return Ok(term);
}
};
} }
self.parser.reset(); self.parser.reset();
@@ -268,7 +282,7 @@ impl<'a, R: Read> TermStream<'a, R> {
let col_num = self.col_num(); let col_num = self.col_num();
let term = self.parser.read_term(composite_op!( let term = self.parser.read_term(composite_op!(
self.in_module, false,
&self.wam.indices.op_dir, &self.wam.indices.op_dir,
op_dir op_dir
))?; ))?;

View File

@@ -15,6 +15,7 @@ use std::cell::Cell;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::io::Read; use std::io::Read;
use std::mem; use std::mem;
use std::ops::DerefMut;
use std::rc::Rc; use std::rc::Rc;
enum IndexSource<'a, T> { enum IndexSource<'a, T> {
@@ -108,6 +109,31 @@ impl<'a, 'b, 'c, R: Read> CompositeIndices<'a, 'b, 'c, R> {
ct => ct, ct => ct,
} }
} }
fn add_in_situ_module_info(&mut self, module_name: ClauseName, term: &mut Term)
{
let atom_tbl =
match self.term_stream.wam.indices.in_situ_module_dir.get(&module_name) {
Some(ref module_stub) => module_stub.atom_tbl.clone(),
None => {
let atom_tbl = match self.term_stream.wam.indices.modules.get(&module_name) {
Some(ref module) => module.atom_tbl.clone(),
None => TabledData::new(module_name.to_rc()),
};
self.term_stream.wam.indices.in_situ_module_dir.insert(
module_name.clone(),
ModuleStub::new(atom_tbl.clone()),
);
atom_tbl
}
};
if let Some(name) = term.name() {
term.set_name(name.with_table(atom_tbl));
}
}
} }
fn as_compile_time_hook( fn as_compile_time_hook(
@@ -196,7 +222,8 @@ fn setup_op_decl(
to_op_decl(prec, spec.as_str(), name) to_op_decl(prec, spec.as_str(), name)
} }
fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError> { fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserError>
{
match term { match term {
Term::Clause(_, ref name, ref mut terms, Some(_)) Term::Clause(_, ref name, ref mut terms, Some(_))
if name.as_str() == "/" && terms.len() == 2 => if name.as_str() == "/" && terms.len() == 2 =>
@@ -221,6 +248,28 @@ fn setup_predicate_indicator(term: &mut Term) -> Result<PredicateKey, ParserErro
} }
} }
fn setup_scoped_predicate_indicator(term: &mut Term) -> Result<ScopedPredicateKey, ParserError>
{
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(ParserError::InvalidModuleExport)?;
let key = setup_predicate_indicator(&mut predicate_indicator)?;
Ok((module_name, key))
}
_ => Err(ParserError::InvalidModuleExport),
}
}
fn setup_module_export( fn setup_module_export(
mut term: Term, mut term: Term,
atom_tbl: TabledData<Atom>, atom_tbl: TabledData<Atom>,
@@ -327,19 +376,8 @@ fn setup_qualified_import(
} }
} }
fn is_consistent( fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
name: Option<ClauseName>,
arity: usize,
clauses: &Vec<PredicateClause>,
) -> bool
{ {
match clauses.first() {
Some(ref cl) => name == cl.name() && arity == cl.arity(),
None => true,
}
}
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError> {
let mut clauses: Vec<PredicateClause> = vec![]; let mut clauses: Vec<PredicateClause> = vec![];
while let Some(tl) = tls.pop_front() { while let Some(tl) = tls.pop_front() {
@@ -347,20 +385,21 @@ fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError>
TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl), TopLevel::Query(_) if clauses.is_empty() && tls.is_empty() => return Ok(tl),
TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl), TopLevel::Declaration(_) if clauses.is_empty() => return Ok(tl),
TopLevel::Query(_) => return Err(ParserError::InconsistentEntry), TopLevel::Query(_) => return Err(ParserError::InconsistentEntry),
TopLevel::Fact(..) if is_consistent(tl.name(), tl.arity(), &clauses) => TopLevel::Fact(..) => {
if let TopLevel::Fact(fact, line_num, col_num) = tl { if let TopLevel::Fact(fact, line_num, col_num) = tl {
let clause = PredicateClause::Fact(fact, line_num, col_num); let clause = PredicateClause::Fact(fact, line_num, col_num);
clauses.push(clause); clauses.push(clause);
}, }
TopLevel::Rule(..) if is_consistent(tl.name(), tl.arity(), &clauses) => { }
TopLevel::Rule(..) => {
if let TopLevel::Rule(rule, line_num, col_num) = tl { if let TopLevel::Rule(rule, line_num, col_num) = tl {
let clause = PredicateClause::Rule(rule, line_num, col_num); let clause = PredicateClause::Rule(rule, line_num, col_num);
clauses.push(clause); clauses.push(clause);
} }
} }
TopLevel::Predicate(_) if is_consistent(tl.name(), tl.arity(), &clauses) => { TopLevel::Predicate(..) => {
if let TopLevel::Predicate(pred) = tl { if let TopLevel::Predicate(predicate) = tl {
clauses.extend(pred.clauses().into_iter()) clauses.extend(predicate.clauses().into_iter())
} }
} }
_ => { _ => {
@@ -442,6 +481,7 @@ fn check_for_internal_if_then(terms: &mut Vec<Term>) {
} }
let tail_term = conq_terms.pop_back().unwrap(); let tail_term = conq_terms.pop_back().unwrap();
terms.push(fold_by_str( terms.push(fold_by_str(
conq_terms.into_iter(), conq_terms.into_iter(),
tail_term, tail_term,
@@ -477,6 +517,78 @@ fn flatten_hook(mut term: Term) -> Term {
term term
} }
fn draw_from_term_dir_impl(
term_dir: &TermDir,
term_dirs: &mut TermDirQuantum,
key: &PredicateKey,
preds: &mut Vec<PredicateClause>,
queue: &mut VecDeque<TopLevel>
) {
if let Some(entry) = term_dirs.get_mut(key) {
if entry.is_fresh {
entry.is_fresh = false;
(entry.new_terms.0).0.extend(preds.drain(0 ..));
entry.new_terms.1.extend(queue.drain(0 ..));
*preds = (entry.old_terms.0).0
.iter()
.cloned()
.chain((entry.new_terms.0).0.iter().cloned())
.collect();
*queue = entry.old_terms.1
.iter()
.cloned()
.chain(entry.new_terms.1.iter().cloned())
.collect();
} else {
*entry = TermDirQuantumEntry::new();
}
} else if term_dir.contains_key(key) {
let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new());
term_dirs.insert(key.clone(), entry);
}
}
fn draw_from_term_dir<R: Read>(
indices: &CompositeIndices<R>,
intra_module_term_dirs: &mut IndexMap<ClauseName, TermDirQuantum>,
top_level_term_dirs: &mut TermDirQuantum,
key: &PredicateKey,
preds: &mut Vec<PredicateClause>,
queue: &mut VecDeque<TopLevel>,
) {
let module = key.0.owning_module();
// aaarghhh..
match indices.term_stream.wam.indices.in_situ_module_dir.get(&module) {
// modify module_stub to do this right.
Some(ref module_stub) if key.0.has_table(&module_stub.atom_tbl) => {
if let Some(ref mut term_dirs) = intra_module_term_dirs.get_mut(&module) {
if let Some(ref module) = indices.term_stream.wam.indices.modules.get(&module) {
return draw_from_term_dir_impl(
&module.term_dir,
term_dirs,
key,
preds,
queue,
);
}
}
}
_ => {}
}
draw_from_term_dir_impl(
&indices.term_stream.wam.code_repo.term_dir,
top_level_term_dirs,
key,
preds,
queue,
);
}
fn setup_declaration<'a, 'b, 'c, R: Read>( fn setup_declaration<'a, 'b, 'c, R: Read>(
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c, R>,
flags: MachineFlags, flags: MachineFlags,
@@ -509,8 +621,17 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
Ok(Declaration::NonCountedBacktracking(name, arity)) Ok(Declaration::NonCountedBacktracking(name, arity))
} }
("multifile", 1) => { ("multifile", 1) => {
let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; let mut term = *terms.pop().unwrap();
Ok(Declaration::MultiFile(name, arity))
match setup_predicate_indicator(&mut term) {
Ok((name, arity)) =>
Ok(Declaration::MultiFile(MultiFileIndicator::LocalScoped(name, arity))),
_ =>
setup_scoped_predicate_indicator(&mut term)
.map(|key| {
Declaration::MultiFile(MultiFileIndicator::ModuleScoped(key))
})
}
} }
("use_module", 1) => { ("use_module", 1) => {
Ok(Declaration::UseModule(setup_use_module_decl(terms)?)) Ok(Declaration::UseModule(setup_use_module_decl(terms)?))
@@ -870,6 +991,34 @@ impl RelationWorker {
)?)) )?))
} }
fn compact_module_scoped_head<'a, 'b, 'c, R: Read>(
&self,
term: &mut Term,
indices: &mut CompositeIndices<'a, 'b, 'c, R>,
) {
let inner_term = match term {
Term::Clause(_, ref name, ref mut inner_terms, _)
if name.as_str() == ":" && inner_terms.len() == 2 => {
let module_name = match inner_terms[0].as_ref() {
&Term::Constant(_, Constant::Atom(ref module, _)) => {
module.clone()
}
_ => {
return;
}
};
indices.add_in_situ_module_info(module_name, inner_terms[1].deref_mut());
*inner_terms.pop().unwrap()
}
_ => {
return;
}
};
*term = inner_term;
}
fn try_term_to_tl<'a, 'b, 'c, R: Read>( fn try_term_to_tl<'a, 'b, 'c, R: Read>(
&mut self, &mut self,
indices: &mut CompositeIndices<'a, 'b, 'c, R>, indices: &mut CompositeIndices<'a, 'b, 'c, R>,
@@ -877,7 +1026,7 @@ impl RelationWorker {
blocks_cuts: bool, blocks_cuts: bool,
) -> Result<TopLevel, ParserError> { ) -> Result<TopLevel, ParserError> {
match term { match term {
Term::Clause(r, name, terms, fixity) => { Term::Clause(r, name, mut terms, fixity) => {
if let Some(hook) = is_compile_time_hook(&name, &terms) { if let Some(hook) = is_compile_time_hook(&name, &terms) {
let term = Term::Clause(r, name, terms, fixity); let term = Term::Clause(r, name, terms, fixity);
let (hook, clause, queue) = self.setup_hook(hook, indices, term)?; let (hook, clause, queue) = self.setup_hook(hook, indices, term)?;
@@ -888,6 +1037,8 @@ impl RelationWorker {
} else if name.as_str() == "?-" { } else if name.as_str() == "?-" {
self.try_term_to_query(indices, terms, blocks_cuts) self.try_term_to_query(indices, terms, blocks_cuts)
} else if name.as_str() == ":-" && terms.len() == 2 { } else if name.as_str() == ":-" && terms.len() == 2 {
self.compact_module_scoped_head(&mut terms[0], indices);
Ok(TopLevel::Rule(self.setup_rule( Ok(TopLevel::Rule(self.setup_rule(
indices, indices,
terms, terms,
@@ -898,11 +1049,14 @@ impl RelationWorker {
Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms, Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms,
self.line_num, self.col_num)?)) self.line_num, self.col_num)?))
} else { } else {
let term = Term::Clause(r, name, terms, fixity); let mut term = Term::Clause(r, name, terms, fixity);
self.compact_module_scoped_head(&mut term, indices);
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)) Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num))
} }
} }
term => Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)), term =>
Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)),
} }
} }
@@ -949,68 +1103,15 @@ pub type DynamicClause = Vec<(Term, Term)>;
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>; pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>;
pub struct TermDirQuantum {
old_term_dir: TermDir,
new_term_dir: TermDir,
}
impl TermDirQuantum {
pub fn new() -> Self {
Self {
old_term_dir: TermDir::new(),
new_term_dir: TermDir::new()
}
}
#[inline]
fn get_old(&self, name: ClauseName, arity: usize) -> Option<&(Predicate, VecDeque<TopLevel>)>
{
self.old_term_dir.get(&(name, arity))
}
#[inline]
fn add_new(
&mut self,
key: PredicateKey,
preds: &mut Vec<PredicateClause>,
queue: VecDeque<TopLevel>
) {
let preds = Predicate(mem::replace(preds, vec![]));
self.new_term_dir.insert(key, (preds, queue));
}
pub fn consolidate(self) -> TermDir {
let mut term_dir = self.old_term_dir;
for (key, (preds, queue)) in self.new_term_dir {
let (prev_preds, prev_queue) =
term_dir.entry(key).or_insert((Predicate::new(), VecDeque::new()));
prev_preds.0.extend(preds.0.into_iter());
prev_queue.extend(queue.into_iter());
}
term_dir
}
#[inline]
pub fn set_old(
&mut self,
key: PredicateKey,
pred: Predicate,
queue: VecDeque<TopLevel>
) {
self.old_term_dir.insert(key, (pred, queue));
}
}
pub struct TopLevelBatchWorker<'a, R: Read> { pub struct TopLevelBatchWorker<'a, R: Read> {
pub(crate) term_stream: TermStream<'a, R>, pub(crate) term_stream: TermStream<'a, R>,
rel_worker: RelationWorker, rel_worker: RelationWorker,
pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>, pub(crate) results: Vec<(Predicate, VecDeque<TopLevel>)>,
pub(crate) dynamic_clause_map: DynamicClauseMap, pub(crate) dynamic_clause_map: DynamicClauseMap,
pub(crate) in_module: bool, pub(crate) in_module: bool,
pub(crate) term_dirs: TermDirQuantum pub(crate) term_dirs: TermDirQuantum,
pub(crate) intra_module_term_dirs: IndexMap<ClauseName, TermDirQuantum>,
pub(crate) non_counted_bt_preds: IndexSet<PredicateKey>,
} }
impl<'a, R: Read> TopLevelBatchWorker<'a, R> { impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
@@ -1032,6 +1133,8 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
dynamic_clause_map: IndexMap::new(), dynamic_clause_map: IndexMap::new(),
in_module: false, in_module: false,
term_dirs: TermDirQuantum::new(), term_dirs: TermDirQuantum::new(),
intra_module_term_dirs: IndexMap::new(),
non_counted_bt_preds: IndexSet::new(),
} }
} }
@@ -1064,32 +1167,31 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
let mut indices = CompositeIndices::new( let mut indices = CompositeIndices::new(
&mut self.term_stream, &mut self.term_stream,
IndexSource::Local(indices), IndexSource::Local(indices),
if self.in_module { None } else { Some(IndexSource::TermStream) } if self.in_module { None } else { Some(IndexSource::TermStream) },
); );
let (name, arity) = (preds[0].name().unwrap(), preds[0].arity()); let key = (preds[0].name().unwrap(), preds[0].arity());
let (mut prev_preds, mut prev_queue) = let mut preds = mem::replace(preds, vec![]);
match self.term_dirs.get_old(name.clone(), arity).cloned() { let mut queue = self.rel_worker.parse_queue(&mut indices)?;
Some((preds, queue)) => (preds, queue),
None => (Predicate::new(), VecDeque::new()),
};
let queue = self.rel_worker.parse_queue(&mut indices)?; draw_from_term_dir(
&indices,
&mut self.intra_module_term_dirs,
&mut self.term_dirs,
&key,
&mut preds,
&mut queue,
);
prev_preds.0.extend(preds.iter().cloned()); let result = (Predicate(preds), queue);
prev_queue.extend(queue.iter().cloned());
let result = (prev_preds, prev_queue);
self.term_dirs.add_new((name, arity), preds, queue);
let in_situ_code_dir = &mut indices.term_stream.wam.indices.in_situ_code_dir;
indices.term_stream.wam.code_repo.add_in_situ_result( indices.term_stream.wam.code_repo.add_in_situ_result(
&result, &result,
in_situ_code_dir, &mut indices.term_stream.wam.indices.in_situ_code_dir,
&mut indices.term_stream.wam.indices.in_situ_module_dir,
indices.term_stream.flags, indices.term_stream.flags,
&self.non_counted_bt_preds,
)?; )?;
Ok(self.results.push(result)) Ok(self.results.push(result))
@@ -1120,12 +1222,18 @@ impl<'a, R: Read> TopLevelBatchWorker<'a, R> {
while !self.term_stream.eof()? { while !self.term_stream.eof()? {
let term = self.term_stream.read_term(&indices.op_dir)?; let term = self.term_stream.read_term(&indices.op_dir)?;
// if is_consistent is false, preds is non-empty. // if is_consistent is false, preds is non-empty.
if !is_consistent(term.predicate_name(), term.predicate_arity(), &preds) { let term = if !term.is_consistent(&preds) {
self.process_result(indices, &mut preds)?; self.process_result(indices, &mut preds)?;
self.take_dynamic_clauses(); self.take_dynamic_clauses();
}
// expand the term after the addition of the previous
// predicate.
self.term_stream.expand_term(term, &indices.op_dir)?
} else {
term
};
let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?; let (mut tl, new_rel_worker) = self.try_term_to_tl(indices, term)?;

View File

@@ -241,11 +241,13 @@ macro_rules! index_store {
IndexStore { IndexStore {
atom_tbl: $atom_tbl, atom_tbl: $atom_tbl,
code_dir: $code_dir, code_dir: $code_dir,
module_dir: ModuleDir::new(),
dynamic_code_dir: DynamicCodeDir::new(), dynamic_code_dir: DynamicCodeDir::new(),
global_variables: GlobalVarDir::new(), global_variables: GlobalVarDir::new(),
in_situ_code_dir: InSituCodeDir::new(), in_situ_code_dir: InSituCodeDir::new(),
in_situ_module_dir: ModuleStubDir::new(),
op_dir: $op_dir, op_dir: $op_dir,
modules: $modules, modules: $modules,
} }
}; };
} }

View File

@@ -243,7 +243,6 @@ user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
expand_goals(Goals, ExpandedGoals), expand_goals(Goals, ExpandedGoals),
Goals \== ExpandedGoals. Goals \== ExpandedGoals.
'$module_expand_goal'(UnexpandedGoals, ExpandedGoals) :- '$module_expand_goal'(UnexpandedGoals, ExpandedGoals) :-
( '$module_of'(Module, UnexpandedGoals), ( '$module_of'(Module, UnexpandedGoals),
'$module_exists'(Module), '$module_exists'(Module),

View File

@@ -45,6 +45,7 @@ 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::UserTermExpansion => write!(f, "user:term_expansion"),
&IndexPtr::UserGoalExpansion => write!(f, "user:goal_expansion"), &IndexPtr::UserGoalExpansion => write!(f, "user:goal_expansion"),
} }
@@ -261,8 +262,14 @@ impl fmt::Display for SessionError {
write!(f, "filename {} is invalid", filename) write!(f, "filename {} is invalid", filename)
} }
&SessionError::ModuleNotFound => write!(f, "module not found."), &SessionError::ModuleNotFound => write!(f, "module not found."),
&SessionError::ModuleDoesNotContainExport => { &SessionError::ModuleDoesNotContainExport(ref module, ref key) => {
write!(f, "module does not contain claimed export.") write!(
f,
"module {} does not contain claimed export {}/{}",
module,
key.0,
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.")