diff --git a/Cargo.lock b/Cargo.lock index 21afb6e7..6c55c9ba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -509,6 +509,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "markup5ever" version = "0.8.1" @@ -869,7 +878,7 @@ dependencies = [ ] [[package]] -name = "prolog_parser" +name = "prolog_parser_rebis" version = "0.8.68" dependencies = [ "lexical", @@ -1212,7 +1221,7 @@ dependencies = [ "num-rug-adapter", "openssl", "ordered-float", - "prolog_parser", + "prolog_parser_rebis", "ref_thread_local", "ring", "ripemd160", @@ -1221,6 +1230,7 @@ dependencies = [ "rustyline", "select", "sha3", + "slice-deque", "sodiumoxide", "unicode_reader", ] @@ -1346,6 +1356,17 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" +[[package]] +name = "slice-deque" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ef6ee280cdefba6d2d0b4b78a84a1c1a3f3a4cec98c2d4231c8bc225de0f25" +dependencies = [ + "libc", + "mach", + "winapi 0.3.9", +] + [[package]] name = "smallvec" version = "1.6.1" diff --git a/Cargo.toml b/Cargo.toml index 3ba2a6c7..c49eebcf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,8 +18,8 @@ members = ["crates/prolog_parser"] indexmap = "1.0.2" [features] -default = ["rug", "prolog_parser/rug"] -num = ["num-rug-adapter", "prolog_parser/num"] +default = ["rug", "prolog_parser_rebis/rug"] +num = ["num-rug-adapter", "prolog_parser_rebis/num"] [dependencies] cpu-time = "1.0.0" @@ -35,7 +35,7 @@ libc = "0.2.62" nix = "0.15.0" num-rug-adapter = { optional = true, version = "0.1.4" } ordered-float = "0.5.0" -prolog_parser = { path = "./crates/prolog_parser", default-features = false } +prolog_parser_rebis = { path = "./crates/prolog_parser", default-features = false } ref_thread_local = "0.0.0" rug = { version = "1.4.0", optional = true } rustyline = "7.0.0" @@ -51,3 +51,4 @@ select = "0.4.3" roxmltree = "0.11.0" base64 = "0.12.3" sodiumoxide = "0.2.6" +slice-deque = "0.3.0" diff --git a/README.md b/README.md index 8151a333..985ae4a0 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,36 @@ programming, which is itself written in a high-level language. ![Scryer Logo: Cryer](logo/scryer.png) +## Rebis Development Branch + +This is the Rebis development branch, which is planned to converge on +version 0.9.0 of Scryer Prolog. As Rebis progresses to completion, it +will absorb contributions made to complementary parts of the master +branch. As such, it is now the bleeding edge version of Scryer. + +The major contribution of Rebis is the transition to a predicate-based +module system from the atom-based module system of the master +branch. Much of the compilation procedure has been ported from Rust to +Prolog, and is laid out in the files `loader.[rs|pl]`. + +A minimalized bootstrapping procedure written entirely in Rust is used +to load `loader.pl` and several preliminary libraries into Scryer, +which is called from `toplevel.pl` to compile and load new modules. + +Some established features of Scryer have been temporarily disrupted by +Rebis' sweeping changes: + +* Logical update semantics must be re-implemented, although +`asserta/1`, `assertz/1`, `retract/1`, and `clause/2` otherwise +work as expected using the new incremental clause compilation of +`compile.rs`. + +* Metacalls in several libraries must be modified to use the new +predicate-based module system. + +* `multifile` declarations are no longer supported by the Rust loader. +The current plan is to re-implement them mostly in Prolog. + ## Phase 1 Produce an implementation of the Warren Abstract Machine in Rust, done diff --git a/build.rs b/build.rs index a9ec444e..aaa876ab 100644 --- a/build.rs +++ b/build.rs @@ -11,6 +11,7 @@ fn find_prolog_files(libraries: &mut File, prefix: &str, current_dir: &Path) { Ok(entries) => entries, Err(_) => return, }; + for entry in entries.filter_map(Result::ok).map(|e| e.path()) { if entry.is_dir() { 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 = String::from_utf8(fs::read(&entry).unwrap()).unwrap(); let name = entry.file_stem().unwrap().to_str().unwrap(); + let line = format!( " m.insert(\"{}\",\n{:?});\n", prefix.to_owned() + name, diff --git a/crates/prolog_parser/Cargo.toml b/crates/prolog_parser/Cargo.toml index 05bfc24d..dfdc5a32 100644 --- a/crates/prolog_parser/Cargo.toml +++ b/crates/prolog_parser/Cargo.toml @@ -1,9 +1,9 @@ [package] -name = "prolog_parser" +name = "prolog_parser_rebis" version = "0.8.68" authors = ["Mark Thom "] -repository = "https://github.com/mthom/scryer-prolog" -description = " An operator precedence parser for scryer-prolog, an up and coming ISO Prolog implementation." +repository = "https://github.com/mthom/prolog_parser" +description = " An operator precedence parser for the Rebis development version of Scryer Prolog, an up and coming ISO Prolog implementation." license = "BSD-3-Clause" [dependencies] diff --git a/crates/prolog_parser/src/ast.rs b/crates/prolog_parser/src/ast.rs index 5f7905a3..d337e9c7 100644 --- a/crates/prolog_parser/src/ast.rs +++ b/crates/prolog_parser/src/ast.rs @@ -1,5 +1,5 @@ -use ordered_float::*; use rug::{Integer, Rational}; +use ordered_float::*; use tabled_rc::*; use put_back_n::*; @@ -10,6 +10,7 @@ use std::collections::HashMap; use std::fmt; use std::hash::{Hash, Hasher}; use std::io::{Bytes, Error as IOError, Read}; +use std::ops::Deref; use std::rc::Rc; use std::vec::Vec; @@ -26,140 +27,112 @@ pub const MAX_ARITY: usize = 1023; pub const XFX: u32 = 0x0001; pub const XFY: u32 = 0x0002; pub const YFX: u32 = 0x0004; -pub const XF: u32 = 0x0010; -pub const YF: u32 = 0x0020; -pub const FX: u32 = 0x0040; -pub const FY: u32 = 0x0080; +pub const XF: u32 = 0x0010; +pub const YF: u32 = 0x0020; +pub const FX: u32 = 0x0040; +pub const FY: u32 = 0x0080; pub const DELIMITER: u32 = 0x0100; -pub const TERM: u32 = 0x1000; +pub const TERM: u32 = 0x1000; pub const LTERM: u32 = 0x3000; pub const NEGATIVE_SIGN: u32 = 0x0200; #[macro_export] macro_rules! clause_name { - ($name: expr, $tbl: expr) => { + ($name: expr, $tbl: expr) => ( ClauseName::User(TabledRc::new($name, $tbl.clone())) - }; - ($name: expr) => { + ) ; + ($name: expr) => ( ClauseName::BuiltIn($name) - }; + ) } #[macro_export] macro_rules! atom { - ($e:expr, $tbl:expr) => { + ($e:expr, $tbl:expr) => ( Constant::Atom(ClauseName::User(tabled_rc!($e, $tbl)), None) - }; - ($e:expr) => { + ); + ($e:expr) => ( Constant::Atom(clause_name!($e), None) - }; + ) } #[macro_export] macro_rules! rc_atom { - ($e:expr) => { + ($e:expr) => ( Rc::new(String::from($e)) - }; + ) } macro_rules! is_term { - ($x:expr) => { - ($x & TERM) != 0 - }; + ($x:expr) => ( ($x & TERM) != 0 ) } macro_rules! is_lterm { - ($x:expr) => { - ($x & LTERM) != 0 - }; + ($x:expr) => ( ($x & LTERM) != 0 ) } macro_rules! is_op { - ($x:expr) => { - $x & (XF | YF | FX | FY | XFX | XFY | YFX) != 0 - }; + ($x:expr) => ( $x & (XF | YF | FX | FY | XFX | XFY | YFX) != 0 ) } macro_rules! is_negate { - ($x:expr) => { - ($x & NEGATIVE_SIGN) != 0 - }; + ($x:expr) => ( ($x & NEGATIVE_SIGN) != 0 ) } #[macro_export] macro_rules! is_prefix { - ($x:expr) => { - $x & (FX | FY) != 0 - }; + ($x:expr) => ( $x & (FX | FY) != 0 ) } #[macro_export] macro_rules! is_postfix { - ($x:expr) => { - $x & (XF | YF) != 0 - }; + ($x:expr) => ( $x & (XF | YF) != 0 ) } #[macro_export] macro_rules! is_infix { - ($x:expr) => { - ($x & (XFX | XFY | YFX)) != 0 - }; + ($x:expr) => ( ($x & (XFX | XFY | YFX)) != 0 ) } #[macro_export] macro_rules! is_xfx { - ($x:expr) => { - ($x & XFX) != 0 - }; + ($x:expr) => ( ($x & XFX) != 0 ) } #[macro_export] macro_rules! is_xfy { - ($x:expr) => { - ($x & XFY) != 0 - }; + ($x:expr) => ( ($x & XFY) != 0 ) } #[macro_export] macro_rules! is_yfx { - ($x:expr) => { - ($x & YFX) != 0 - }; + ($x:expr) => ( ($x & YFX) != 0 ) } #[macro_export] macro_rules! is_yf { - ($x:expr) => { - ($x & YF) != 0 - }; + ($x:expr) => ( ($x & YF) != 0 ) } #[macro_export] macro_rules! is_xf { - ($x:expr) => { - ($x & XF) != 0 - }; + ($x:expr) => ( ($x & XF) != 0 ) } #[macro_export] macro_rules! is_fx { - ($x:expr) => { - ($x & FX) != 0 - }; + ($x:expr) => ( ($x & FX) != 0 ) } #[macro_export] macro_rules! is_fy { - ($x:expr) => { - ($x & FY) != 0 - }; + ($x:expr) => ( ($x & FY) != 0 ) } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum RegType { Perm(usize), - Temp(usize), + Temp(usize) } impl Default for RegType { @@ -171,14 +144,14 @@ impl Default for RegType { impl RegType { pub fn reg_num(self) -> usize { match self { - RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num, + RegType::Perm(reg_num) | RegType::Temp(reg_num) => reg_num } } pub fn is_perm(self) -> bool { match self { RegType::Perm(_) => true, - _ => false, + _ => false } } } @@ -187,7 +160,7 @@ impl fmt::Display for RegType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { &RegType::Perm(val) => write!(f, "Y{}", val), - &RegType::Temp(val) => write!(f, "X{}", val), + &RegType::Temp(val) => write!(f, "X{}", val) } } } @@ -195,13 +168,13 @@ impl fmt::Display for RegType { #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum VarReg { ArgAndNorm(RegType, usize), - Norm(RegType), + Norm(RegType) } impl VarReg { pub fn norm(self) -> RegType { match self { - VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg, + VarReg::ArgAndNorm(reg, _) | VarReg::Norm(reg) => reg } } } @@ -211,8 +184,10 @@ impl fmt::Display for VarReg { match self { &VarReg::Norm(RegType::Perm(reg)) => write!(f, "Y{}", reg), &VarReg::Norm(RegType::Temp(reg)) => write!(f, "X{}", reg), - &VarReg::ArgAndNorm(RegType::Perm(reg), arg) => write!(f, "Y{} A{}", reg, arg), - &VarReg::ArgAndNorm(RegType::Temp(reg), arg) => write!(f, "X{} A{}", reg, arg), + &VarReg::ArgAndNorm(RegType::Perm(reg), arg) => + write!(f, "Y{} A{}", reg, arg), + &VarReg::ArgAndNorm(RegType::Temp(reg), arg) => + write!(f, "X{} A{}", reg, arg) } } } @@ -225,30 +200,28 @@ impl Default for VarReg { #[macro_export] macro_rules! temp_v { - ($x:expr) => { + ($x:expr) => ( RegType::Temp($x) - }; + ) } #[macro_export] macro_rules! perm_v { - ($x:expr) => { + ($x:expr) => ( RegType::Perm($x) - }; + ) } #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] pub enum GenContext { - Head, - Mid(usize), - Last(usize), // Mid & Last: chunk_num + Head, Mid(usize), Last(usize) // Mid & Last: chunk_num } impl GenContext { pub fn chunk_num(self) -> usize { match self { GenContext::Head => 0, - GenContext::Mid(cn) | GenContext::Last(cn) => cn, + GenContext::Mid(cn) | GenContext::Last(cn) => cn } } } @@ -256,22 +229,17 @@ impl GenContext { pub type OpDirKey = (ClauseName, Fixity); #[derive(Debug, Clone)] -pub struct OpDirValue(pub SharedOpDesc, pub ClauseName); +pub struct OpDirValue(pub SharedOpDesc); impl OpDirValue { - pub fn new(spec: Specifier, priority: usize, module_name: ClauseName) -> Self { - OpDirValue(SharedOpDesc::new(priority, spec), module_name) + pub fn new(spec: Specifier, priority: usize) -> Self { + OpDirValue(SharedOpDesc::new(priority, spec)) } #[inline] pub fn shared_op_desc(&self) -> SharedOpDesc { self.0.clone() } - - #[inline] - pub fn owning_module(&self) -> ClauseName { - self.1.clone() - } } // name and fixity -> operator type and precedence. @@ -279,22 +247,18 @@ pub type OpDir = HashMap; #[derive(Debug, Clone, Copy)] pub struct MachineFlags { - pub double_quotes: DoubleQuotes, + pub double_quotes: DoubleQuotes } impl Default for MachineFlags { fn default() -> Self { - MachineFlags { - double_quotes: DoubleQuotes::default(), - } + MachineFlags { double_quotes: DoubleQuotes::default() } } } #[derive(Debug, Clone, Copy)] pub enum DoubleQuotes { - Atom, - Chars, - Codes, + Atom, Chars, Codes } impl DoubleQuotes { @@ -330,118 +294,78 @@ impl Default for DoubleQuotes { } pub fn default_op_dir() -> OpDir { - let module_name = clause_name!("builtins"); let mut op_dir = OpDir::new(); - op_dir.insert( - (clause_name!(":-"), Fixity::In), - OpDirValue::new(XFX, 1200, module_name.clone()), - ); - op_dir.insert( - (clause_name!(":-"), Fixity::Pre), - OpDirValue::new(FX, 1200, module_name.clone()), - ); - op_dir.insert( - (clause_name!("?-"), Fixity::Pre), - OpDirValue::new(FX, 1200, module_name.clone()), - ); - op_dir.insert( - (clause_name!(","), Fixity::In), - OpDirValue::new(XFY, 1000, module_name.clone()), - ); + op_dir.insert((clause_name!(":-"), Fixity::In), OpDirValue::new(XFX, 1200)); + op_dir.insert((clause_name!(":-"), Fixity::Pre), OpDirValue::new(FX, 1200)); + op_dir.insert((clause_name!("?-"), Fixity::Pre), OpDirValue::new(FX, 1200)); + op_dir.insert((clause_name!(","), Fixity::In), OpDirValue::new(XFY, 1000)); op_dir } -#[derive(PartialEq, Debug, Clone)] +#[derive(Debug, Clone)] pub enum ArithmeticError { NonEvaluableFunctor(Constant, usize), - UninstantiatedVar, + UninstantiatedVar } #[derive(Debug)] pub enum ParserError { - Arithmetic(ArithmeticError), BackQuotedString(usize, usize), - BadPendingByte, - CannotParseCyclicTerm, UnexpectedChar(char, usize, usize), UnexpectedEOF, IO(IOError), - ExpectedRel, - ExpectedTopLevelTerm, - InadmissibleFact, - InadmissibleQueryTerm, IncompleteReduction(usize, usize), - InconsistentEntry, - InvalidDoubleQuotesDecl, - InvalidHook, - InvalidModuleDecl, - InvalidModuleExport, - InvalidRuleHead, - InvalidUseModuleDecl, - InvalidModuleResolution, InvalidSingleQuotedCharacter(char), MissingQuote(usize, usize), NonPrologChar(usize, usize), ParseBigInt(usize, usize), - ParseFloat(usize, usize), - Utf8Error(usize, usize), + Utf8Error(usize, usize) } impl ParserError { pub fn line_and_col_num(&self) -> Option<(usize, usize)> { match self { &ParserError::BackQuotedString(line_num, col_num) - | &ParserError::UnexpectedChar(_, line_num, col_num) - | &ParserError::IncompleteReduction(line_num, col_num) - | &ParserError::MissingQuote(line_num, col_num) - | &ParserError::NonPrologChar(line_num, col_num) - | &ParserError::ParseBigInt(line_num, col_num) - | &ParserError::ParseFloat(line_num, col_num) - | &ParserError::Utf8Error(line_num, col_num) => Some((line_num, col_num)), - _ => None, + | &ParserError::UnexpectedChar(_, line_num, col_num) + | &ParserError::IncompleteReduction(line_num, col_num) + | &ParserError::MissingQuote(line_num, col_num) + | &ParserError::NonPrologChar(line_num, col_num) + | &ParserError::ParseBigInt(line_num, col_num) + | &ParserError::Utf8Error(line_num, col_num) => + Some((line_num, col_num)), + _ => + None } } pub fn as_str(&self) -> &'static str { match self { - &ParserError::Arithmetic(..) => "arithmetic_error", - &ParserError::BackQuotedString(..) => "back_quoted_string", - &ParserError::BadPendingByte => "bad_pending_byte", - &ParserError::UnexpectedChar(..) => "unexpected_char", - &ParserError::UnexpectedEOF => "unexpected_end_of_file", - &ParserError::ExpectedRel => "expected_relation", - &ParserError::ExpectedTopLevelTerm => "expected_atom_or_cons_or_clause", - &ParserError::InadmissibleFact => "inadmissible_fact", - &ParserError::InadmissibleQueryTerm => "inadmissible_query_term", - &ParserError::IncompleteReduction(..) => "incomplete_reduction", - &ParserError::InconsistentEntry => "inconsistent_entry", - &ParserError::InvalidDoubleQuotesDecl => "invalid_double_quotes_declaration", - &ParserError::InvalidHook => "invalid_hook", - &ParserError::InvalidModuleDecl => "invalid_module_declaration", - &ParserError::InvalidModuleExport => "invalid_module_export", - &ParserError::InvalidModuleResolution => "invalid_module_resolution", - &ParserError::InvalidRuleHead => "invalid_head_of_rule", - &ParserError::InvalidUseModuleDecl => "invalid_use_module_declaration", - &ParserError::InvalidSingleQuotedCharacter(..) => "invalid_single_quoted_character", - &ParserError::IO(_) => "input_output_error", - &ParserError::MissingQuote(..) => "missing_quote", - &ParserError::NonPrologChar(..) => "non_prolog_character", - &ParserError::ParseBigInt(..) => "cannot_parse_big_int", - &ParserError::ParseFloat(..) => "cannot_parse_float", - &ParserError::Utf8Error(..) => "utf8_conversion_error", - &ParserError::CannotParseCyclicTerm => "cannot_parse_cyclic_term", + &ParserError::BackQuotedString(..) => + "back_quoted_string", + &ParserError::UnexpectedChar(..) => + "unexpected_char", + &ParserError::UnexpectedEOF => + "unexpected_end_of_file", + &ParserError::IncompleteReduction(..) => + "incomplete_reduction", + &ParserError::InvalidSingleQuotedCharacter(..) => + "invalid_single_quoted_character", + &ParserError::IO(_) => + "input_output_error", + &ParserError::MissingQuote(..) => + "missing_quote", + &ParserError::NonPrologChar(..) => + "non_prolog_character", + &ParserError::ParseBigInt(..) => + "cannot_parse_big_int", + &ParserError::Utf8Error(..) => + "utf8_conversion_error", } } } -impl From for ParserError { - fn from(err: ArithmeticError) -> ParserError { - ParserError::Arithmetic(err) - } -} - impl From for ParserError { fn from(err: IOError) -> ParserError { ParserError::IO(err) @@ -458,11 +382,39 @@ impl From<&IOError> for ParserError { } } + +#[derive(Debug, Clone, Copy)] +pub struct CompositeOpDir<'a, 'b> { + pub primary_op_dir: Option<&'b OpDir>, + pub secondary_op_dir: &'a OpDir, +} + +impl<'a, 'b> CompositeOpDir<'a, 'b> +{ + #[inline] + pub fn new(secondary_op_dir: &'a OpDir, primary_op_dir: Option<&'b OpDir>) -> Self { + CompositeOpDir { primary_op_dir, secondary_op_dir } + } + + #[inline] + pub(crate) + fn get(&self, name: ClauseName, fixity: Fixity) -> Option<&OpDirValue> + { + let entry = + if let Some(ref primary_op_dir) = &self.primary_op_dir { + primary_op_dir.get(&(name.clone(), fixity)) + } else { + None + }; + + entry.or_else(move || self.secondary_op_dir.get(&(name, fixity))) + } +} + + #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] pub enum Fixity { - In, - Post, - Pre, + In, Post, Pre } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] @@ -509,6 +461,15 @@ impl SharedOpDesc { } } +impl Deref for SharedOpDesc { + type Target = Cell<(usize, Specifier)>; + + #[inline] + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} + // this ensures that SharedOpDesc (which is not consistently placed in // every atom!) doesn't affect the value of an atom hash. If // SharedOpDesc values are to be indexed, a BTreeMap or BTreeSet @@ -535,21 +496,28 @@ pub enum Constant { impl fmt::Display for Constant { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &Constant::Atom(ref atom, _) => { + &Constant::Atom(ref atom, _) => if atom.as_str().chars().any(|c| "`.$'\" ".contains(c)) { write!(f, "'{}'", atom.as_str()) } else { write!(f, "{}", atom.as_str()) - } - } - &Constant::Char(c) => write!(f, "'{}'", c as u32), - &Constant::EmptyList => write!(f, "[]"), - &Constant::Fixnum(n) => write!(f, "{}", n), - &Constant::Integer(ref n) => write!(f, "{}", n), - &Constant::Rational(ref n) => write!(f, "{}", n), - &Constant::Float(ref n) => write!(f, "{}", n), - &Constant::String(ref s) => write!(f, "\"{}\"", &s), - &Constant::Usize(integer) => write!(f, "u{}", integer), + }, + &Constant::Char(c) => + write!(f, "'{}'", c as u32), + &Constant::EmptyList => + write!(f, "[]"), + &Constant::Fixnum(n) => + write!(f, "{}", n), + &Constant::Integer(ref n) => + write!(f, "{}", n), + &Constant::Rational(ref n) => + write!(f, "{}", n), + &Constant::Float(ref n) => + write!(f, "{}", n), + &Constant::String(ref s) => + write!(f, "\"{}\"", &s), + &Constant::Usize(integer) => + write!(f, "u{}", integer), } } } @@ -558,27 +526,37 @@ impl PartialEq for Constant { fn eq(&self, other: &Constant) -> bool { match (self, other) { (&Constant::Atom(ref atom, _), &Constant::Char(c)) - | (&Constant::Char(c), &Constant::Atom(ref atom, _)) => { - atom.is_char() && Some(c) == atom.as_str().chars().next() - } - (&Constant::Atom(ref a1, _), &Constant::Atom(ref a2, _)) => a1.as_str() == a2.as_str(), - (&Constant::Char(c1), &Constant::Char(c2)) => c1 == c2, - (&Constant::Fixnum(n1), &Constant::Fixnum(n2)) => n1 == n2, - (&Constant::Fixnum(n1), &Constant::Integer(ref n2)) - | (&Constant::Integer(ref n2), &Constant::Fixnum(n1)) => { + | (&Constant::Char(c), &Constant::Atom(ref atom, _)) => { + atom.is_char() && Some(c) == atom.as_str().chars().next() + }, + (&Constant::Atom(ref a1, _), &Constant::Atom(ref a2, _)) => + a1.as_str() == a2.as_str(), + (&Constant::Char(c1), &Constant::Char(c2)) => + c1 == c2, + (&Constant::Fixnum(n1), &Constant::Fixnum(n2)) => + n1 == n2, + (&Constant::Fixnum(n1), &Constant::Integer(ref n2)) | + (&Constant::Integer(ref n2), &Constant::Fixnum(n1)) => { if let Some(n2) = n2.to_isize() { n1 == n2 } else { false } } - (&Constant::Integer(ref n1), &Constant::Integer(ref n2)) => n1 == n2, - (&Constant::Rational(ref n1), &Constant::Rational(ref n2)) => n1 == n2, - (&Constant::Float(ref n1), &Constant::Float(ref n2)) => n1 == n2, - (&Constant::String(ref s1), &Constant::String(ref s2)) => &s1 == &s2, - (&Constant::EmptyList, &Constant::EmptyList) => true, - (&Constant::Usize(u1), &Constant::Usize(u2)) => u1 == u2, - _ => false, + (&Constant::Integer(ref n1), &Constant::Integer(ref n2)) => + n1 == n2, + (&Constant::Rational(ref n1), &Constant::Rational(ref n2)) => + n1 == n2, + (&Constant::Float(ref n1), &Constant::Float(ref n2)) => + n1 == n2, + (&Constant::String(ref s1), &Constant::String(ref s2)) => { + &s1 == &s2 + } + (&Constant::EmptyList, &Constant::EmptyList) => + true, + (&Constant::Usize(u1), &Constant::Usize(u2)) => + u1 == u2, + _ => false } } } @@ -589,7 +567,7 @@ impl Constant { pub fn to_atom(self) -> Option { match self { Constant::Atom(a, _) => Some(a.defrock_brackets()), - _ => None, + _ => None } } } @@ -597,7 +575,7 @@ impl Constant { #[derive(Debug, Clone)] pub enum ClauseName { BuiltIn(&'static str), - User(TabledRc), + User(TabledRc) } impl fmt::Display for ClauseName { @@ -644,12 +622,10 @@ impl ClauseName { match self { &ClauseName::User(ref name) => { let module = name.owning_module(); - ClauseName::User(TabledRc { - atom: module.clone(), - table: TabledData::new(module), - }) - } - _ => clause_name!("user"), + ClauseName::User(TabledRc { atom: module.clone(), + table: TabledData::new(module) }) + }, + _ => clause_name!("user") } } @@ -657,7 +633,7 @@ impl ClauseName { pub fn to_rc(&self) -> Rc { match self { &ClauseName::BuiltIn(s) => Rc::new(s.to_string()), - &ClauseName::User(ref rc) => rc.inner(), + &ClauseName::User(ref rc) => rc.inner() } } @@ -690,7 +666,9 @@ impl ClauseName { false } } - ClauseName::User(ref name) => other.has_table(&name.table), + ClauseName::User(ref name) => { + other.has_table(&name.table) + } } } @@ -698,7 +676,7 @@ impl ClauseName { pub fn as_str(&self) -> &str { match self { &ClauseName::BuiltIn(s) => s, - &ClauseName::User(ref name) => name.as_ref(), + &ClauseName::User(ref name) => name.as_ref() } } @@ -710,17 +688,17 @@ impl ClauseName { pub fn defrock_brackets(self) -> Self { fn defrock_brackets(s: &str) -> &str { if s.starts_with('(') && s.ends_with(')') { - &s[1..s.len() - 1] + &s[1 .. s.len() - 1] } else { s } } match self { - ClauseName::BuiltIn(s) => ClauseName::BuiltIn(defrock_brackets(s)), - ClauseName::User(s) => { + ClauseName::BuiltIn(s) => + ClauseName::BuiltIn(defrock_brackets(s)), + ClauseName::User(s) => ClauseName::User(tabled_rc!(defrock_brackets(s.as_str()).to_owned(), s.table)) - } } } } @@ -735,15 +713,10 @@ impl AsRef for ClauseName { #[derive(Debug, PartialEq, Eq, Clone)] pub enum Term { AnonVar, - Clause( - Cell, - ClauseName, - Vec>, - Option, - ), + Clause(Cell, ClauseName, Vec>, Option), Cons(Cell, Box, Box), Constant(Cell, Constant), - Var(Cell, Rc), + Var(Cell, Rc) } impl Term { @@ -751,29 +724,30 @@ impl Term { match self { &Term::Clause(_, _, _, ref spec) => spec.clone(), &Term::Constant(_, Constant::Atom(_, ref spec)) => spec.clone(), - _ => None, + _ => None } } pub fn to_constant(self) -> Option { match self { Term::Constant(_, c) => Some(c), - _ => None, + _ => None } } pub fn first_arg(&self) -> Option<&Term> { match self { - &Term::Clause(_, _, ref terms, _) => terms.first().map(|bt| bt.as_ref()), - _ => None, + &Term::Clause(_, _, ref terms, _) => + terms.first().map(|bt| bt.as_ref()), + _ => None } } pub fn set_name(&mut self, new_name: ClauseName) { match self { Term::Constant(_, Constant::Atom(ref mut atom, _)) - | Term::Clause(_, ref mut atom, ..) => { - *atom = new_name; + | Term::Clause(_, ref mut atom, ..) => { + *atom = new_name; } _ => {} } @@ -781,62 +755,20 @@ impl Term { pub fn name(&self) -> Option { match self { - &Term::Constant(_, Constant::Atom(ref atom, _)) | &Term::Clause(_, ref atom, ..) => { - Some(atom.clone()) - } - _ => None, + &Term::Constant(_, Constant::Atom(ref atom, _)) + | &Term::Clause(_, ref atom, ..) => Some(atom.clone()), + _ => None } } pub fn arity(&self) -> usize { match self { &Term::Clause(_, _, ref child_terms, ..) => child_terms.len(), - _ => 0, + _ => 0 } } } -#[derive(Debug, Clone, Copy)] -pub struct CompositeOp<'a, 'b> { - pub op_dir: &'a OpDir, - pub static_op_dir: Option<&'b OpDir>, -} - -#[macro_export] -macro_rules! composite_op { - ($include_machine_p:expr, $op_dir:expr, $machine_op_dir:expr) => { - CompositeOp { - op_dir: $op_dir, - static_op_dir: if !$include_machine_p { - Some($machine_op_dir) - } else { - None - }, - } - }; - ($op_dir:expr) => { - CompositeOp { - op_dir: $op_dir, - static_op_dir: None, - } - }; -} - -impl<'a, 'b> CompositeOp<'a, 'b> { - #[inline] - pub(crate) fn get(&self, name: ClauseName, fixity: Fixity) -> Option { - let entry = if let Some(ref static_op_dir) = &self.static_op_dir { - static_op_dir.get(&(name.clone(), fixity)) - } else { - None - }; - - entry - .or_else(move || self.op_dir.get(&(name, fixity))) - .cloned() - } -} - fn unfold_by_str_once(term: &mut Term, s: &str) -> Option<(Term, Term)> { if let &mut Term::Clause(_, ref name, ref mut subterms, _) = term { if name.as_str() == s && subterms.len() == 2 { diff --git a/crates/prolog_parser/src/parser.rs b/crates/prolog_parser/src/parser.rs index dd665c26..19fd7912 100644 --- a/crates/prolog_parser/src/parser.rs +++ b/crates/prolog_parser/src/parser.rs @@ -46,24 +46,24 @@ struct TokenDesc { } pub -fn get_clause_spec(name: ClauseName, arity: usize, op_dir: CompositeOp) -> Option +fn get_clause_spec(name: ClauseName, arity: usize, op_dir: &CompositeOpDir) -> Option { match arity { 1 => { /* This is a clause with an operator principal functor. Prefix operators are supposed over post. */ - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Pre) { - return Some(cell); + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { + return Some(cell.clone()); } - if let Some(OpDirValue(cell, _)) = op_dir.get(name, Fixity::Post) { - return Some(cell); + if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::Post) { + return Some(cell.clone()); } }, 2 => - if let Some(OpDirValue(cell, _)) = op_dir.get(name, Fixity::In) { - return Some(cell); + if let Some(OpDirValue(cell)) = op_dir.get(name, Fixity::In) { + return Some(cell.clone()); }, _ => {} }; @@ -71,11 +71,11 @@ fn get_clause_spec(name: ClauseName, arity: usize, op_dir: CompositeOp) -> Optio None } -pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option +pub fn get_op_desc(name: ClauseName, op_dir: &CompositeOpDir) -> Option { let mut op_desc = OpDesc { pre: 0, inf: 0, post: 0, spec: 0 }; - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Pre) { + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Pre) { let (pri, spec) = cell.get(); if pri > 0 { @@ -86,7 +86,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option } } - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::Post) { + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::Post) { let (pri, spec) = cell.get(); if pri > 0 { @@ -95,7 +95,7 @@ pub fn get_desc(name: ClauseName, op_dir: CompositeOp) -> Option } } - if let Some(OpDirValue(cell, _)) = op_dir.get(name.clone(), Fixity::In) { + if let Some(OpDirValue(cell)) = op_dir.get(name.clone(), Fixity::In) { let (pri, spec) = cell.get(); if pri > 0 { @@ -319,7 +319,7 @@ impl<'a, R: Read> Parser<'a, R> { } fn promote_atom_op(&mut self, atom: ClauseName, priority: usize, assoc: u32, - op_dir_val: Option) + op_dir_val: Option<&OpDirValue>) { let spec = op_dir_val.map(|op_dir_val| op_dir_val.shared_op_desc()); @@ -454,7 +454,7 @@ impl<'a, R: Read> Parser<'a, R> { None } - fn reduce_term(&mut self, op_dir: CompositeOp) -> bool + fn reduce_term(&mut self, op_dir: &CompositeOpDir) -> bool { if self.stack.is_empty() { return false; @@ -687,12 +687,18 @@ impl<'a, R: Read> Parser<'a, R> { let term = match self.terms.pop() { Some(term) => term, - _ => return Err(ParserError::IncompleteReduction(self.lexer.line_num, - self.lexer.col_num)) + _ => return Err(ParserError::IncompleteReduction( + self.lexer.line_num, + self.lexer.col_num, + )) }; - self.terms.push(Term::Clause(Cell::default(), clause_name!("{}"), - vec![Box::new(term)], None)); + self.terms.push(Term::Clause( + Cell::default(), + clause_name!("{}"), + vec![Box::new(term)], + None + )); return Ok(true); } @@ -738,8 +744,8 @@ impl<'a, R: Read> Parser<'a, R> { } } - fn shift_op(&mut self, name: ClauseName, op_dir: CompositeOp) -> Result { - if let Some(OpDesc { pre, inf, post, spec }) = get_desc(name.clone(), op_dir) { + fn shift_op(&mut self, name: ClauseName, op_dir: &CompositeOpDir) -> Result { + if let Some(OpDesc { pre, inf, post, spec }) = get_op_desc(name.clone(), op_dir) { if (pre > 0 && inf + post > 0) || is_negate!(spec) { match self.tokens.last().ok_or(ParserError::UnexpectedEOF)? { // do this when layout hasn't been inserted, @@ -752,8 +758,12 @@ impl<'a, R: Read> Parser<'a, R> { let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; let op_dir_val = op_dir.get(name.clone(), fixity); - self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF), - op_dir_val); + self.promote_atom_op( + name, + inf + post, + spec & (XFX | XFY | YFX | YF | XF), + op_dir_val, + ); }, _ => { self.reduce_op(inf + post); @@ -764,9 +774,12 @@ impl<'a, R: Read> Parser<'a, R> { let fixity = if inf > 0 { Fixity::In } else { Fixity::Post }; let op_dir_val = op_dir.get(name.clone(), fixity); - self.promote_atom_op(name, inf + post, - spec & (XFX | XFY | YFX | XF | YF), - op_dir_val); + self.promote_atom_op( + name, + inf + post, + spec & (XFX | XFY | YFX | XF | YF), + op_dir_val, + ); } else { let op_dir_val = op_dir.get(name.clone(), Fixity::Pre); self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN), op_dir_val); @@ -778,14 +791,16 @@ impl<'a, R: Read> Parser<'a, R> { } } } else { - let op_dir_val = op_dir.get(name.clone(), - if pre + inf == 0 { - Fixity::Post - } else if post + pre == 0 { - Fixity::In - } else { - Fixity::Pre - }); + let op_dir_val = op_dir.get( + name.clone(), + if pre + inf == 0 { + Fixity::Post + } else if post + pre == 0 { + Fixity::In + } else { + Fixity::Pre + }, + ); self.reduce_op(pre + inf + post); // only one non-zero priority among these. self.promote_atom_op(name, pre + inf + post, spec, op_dir_val); @@ -843,7 +858,7 @@ impl<'a, R: Read> Parser<'a, R> { self.shift(Token::Constant(constr(n)), 0, TERM); } - fn shift_token(&mut self, token: Token, op_dir: CompositeOp) -> Result<(), ParserError> { + fn shift_token(&mut self, token: Token, op_dir: &CompositeOpDir) -> Result<(), ParserError> { fn negate_rc(mut t: Rc) -> Rc { match Rc::get_mut(&mut t) { Some(t) => { @@ -909,7 +924,7 @@ impl<'a, R: Read> Parser<'a, R> { /* '|' as an operator must have priority > 1000 and can only be infix. * See: http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#Res_A78 */ - let (priority, spec) = get_desc(clause_name!("|"), op_dir) + let (priority, spec) = get_op_desc(clause_name!("|"), op_dir) .map(|OpDesc { inf, spec, .. }| (inf, spec)) .unwrap_or((1000, DELIMITER)); @@ -942,7 +957,7 @@ impl<'a, R: Read> Parser<'a, R> { self.lexer.eof() } - pub fn read_term(&mut self, op_dir: CompositeOp) -> Result + pub fn read_term(&mut self, op_dir: &CompositeOpDir) -> Result { self.tokens = read_tokens(&mut self.lexer)?; @@ -966,7 +981,7 @@ impl<'a, R: Read> Parser<'a, R> { } } - pub fn read(&mut self, op_dir: CompositeOp) -> Result, ParserError> + pub fn read(&mut self, op_dir: &CompositeOpDir) -> Result, ParserError> { let mut terms = Vec::new(); diff --git a/src/allocator.rs b/src/allocator.rs index 9034efc5..f2b2cd0c 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::fixtures::*; use crate::forms::*; diff --git a/src/arithmetic.rs b/src/arithmetic.rs index c4cefafe..1231dfa6 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::clause_types::*; use crate::fixtures::*; diff --git a/src/clause_types.rs b/src/clause_types.rs index dbaefb69..4c39d5d6 100644 --- a/src/clause_types.rs +++ b/src/clause_types.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::forms::Number; use crate::machine::machine_indices::*; @@ -150,11 +150,11 @@ impl InlinedClauseType { #[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum SystemClauseType { - AbolishClause, - AbolishModuleClause, - AssertDynamicPredicateToBack, - AssertDynamicPredicateToFront, - AtEndOfExpansion, + // AbolishClause, + // AbolishModuleClause, + // AssertDynamicPredicateToBack, + // AssertDynamicPredicateToFront, + // AtEndOfExpansion, AtomChars, AtomCodes, AtomLength, @@ -189,8 +189,8 @@ pub enum SystemClauseType { DynamicModuleResolution(usize), EnqueueAttributeGoal, EnqueueAttributedVar, - ExpandGoal, - ExpandTerm, +// ExpandGoal, +// ExpandTerm, FetchGlobalVar, FetchGlobalVarWithOffset, FirstStream, @@ -207,16 +207,16 @@ pub enum SystemClauseType { GetAttrVarQueueDelimiter, GetAttrVarQueueBeyond, GetBValue, - GetClause, +// GetClause, GetContinuationChunk, - GetModuleClause, +// GetModuleClause, GetNextDBRef, GetNextOpDBRef, IsPartialString, LookupDBRef, LookupOpDBRef, Halt, - ModuleHeadIsDynamic, +// ModuleHeadIsDynamic, GetLiftedHeapFromOffset, GetLiftedHeapFromOffsetDiff, GetSCCCleaner, @@ -224,11 +224,11 @@ pub enum SystemClauseType { InstallSCCCleaner, InstallInferenceCounter, LiftedHeapLength, - ModuleAssertDynamicPredicateToFront, - ModuleAssertDynamicPredicateToBack, + LoadLibraryAsStream, + // ModuleAssertDynamicPredicateToFront, + // ModuleAssertDynamicPredicateToBack, ModuleExists, - ModuleOf, - ModuleRetractClause, + // ModuleRetractClause, NextEP, NoSuchPredicate, NumberToChars, @@ -254,7 +254,7 @@ pub enum SystemClauseType { ResetContinuationMarker, ResetGlobalVarAtKey, ResetGlobalVarAtOffset, - RetractClause, + // RetractClause, RestoreCutPolicy, SetCutPoint(RegType), SetInput, @@ -324,11 +324,11 @@ pub enum SystemClauseType { impl SystemClauseType { pub fn name(&self) -> ClauseName { match self { - &SystemClauseType::AbolishClause => clause_name!("$abolish_clause"), - &SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"), - &SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"), - &SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"), - &SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"), + // &SystemClauseType::AbolishClause => clause_name!("$abolish_clause"), + // &SystemClauseType::AbolishModuleClause => clause_name!("$abolish_module_clause"), + // &SystemClauseType::AssertDynamicPredicateToBack => clause_name!("$assertz"), + // &SystemClauseType::AssertDynamicPredicateToFront => clause_name!("$asserta"), + // &SystemClauseType::AtEndOfExpansion => clause_name!("$at_end_of_expansion"), &SystemClauseType::AtomChars => clause_name!("$atom_chars"), &SystemClauseType::AtomCodes => clause_name!("$atom_codes"), &SystemClauseType::AtomLength => clause_name!("$atom_length"), @@ -356,17 +356,52 @@ impl SystemClauseType { &SystemClauseType::WorkingDirectory => clause_name!("$working_directory"), &SystemClauseType::PathCanonical => clause_name!("$path_canonical"), &SystemClauseType::FileTime => clause_name!("$file_time"), - &SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"), - &SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"), - &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => { - clause_name!("$use_qualified_module") - } - &SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile) => { - clause_name!("$use_module_from_file") - } - &SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile) => { - clause_name!("$use_qualified_module_from_file") - } + &SystemClauseType::REPL(REPLCodePtr::AddDynamicPredicate) => + clause_name!("$add_dynamic_predicate"), + &SystemClauseType::REPL(REPLCodePtr::AddGoalExpansionClause) => + clause_name!("$add_goal_expansion_clause"), + &SystemClauseType::REPL(REPLCodePtr::AddTermExpansionClause) => + clause_name!("$add_term_expansion_clause"), + &SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable) => + clause_name!("$clause_to_evacuable"), + &SystemClauseType::REPL(REPLCodePtr::ConcludeLoad) => + 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::BuiltInProperty) => + clause_name!("$cpp_built_in_property"), + &SystemClauseType::REPL(REPLCodePtr::CompilePendingPredicates) => + clause_name!("$compile_pending_predicates"), &SystemClauseType::Close => clause_name!("$close"), &SystemClauseType::CopyToLiftedHeap => clause_name!("$copy_to_lh"), &SystemClauseType::DeleteAttribute => clause_name!("$del_attr_non_head"), @@ -374,12 +409,9 @@ impl SystemClauseType { &SystemClauseType::DynamicModuleResolution(_) => clause_name!("$module_call"), &SystemClauseType::EnqueueAttributeGoal => clause_name!("$enqueue_attribute_goal"), &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::FetchGlobalVarWithOffset => { - clause_name!("$fetch_global_var_with_offset") - } + &SystemClauseType::FetchGlobalVarWithOffset => + clause_name!("$fetch_global_var_with_offset"), &SystemClauseType::FirstStream => clause_name!("$first_stream"), &SystemClauseType::FlushOutput => clause_name!("$flush_output"), &SystemClauseType::GetByte => clause_name!("$get_byte"), @@ -405,13 +437,13 @@ impl SystemClauseType { clause_name!("$get_lh_from_offset_diff") } &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::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"), &SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"), &SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"), &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::Halt => clause_name!("$halt"), &SystemClauseType::HeadIsDynamic => clause_name!("$head_is_dynamic"), @@ -430,15 +462,14 @@ impl SystemClauseType { &SystemClauseType::Maybe => clause_name!("maybe"), &SystemClauseType::CpuNow => clause_name!("$cpu_now"), &SystemClauseType::CurrentTime => clause_name!("$current_time"), - &SystemClauseType::ModuleAssertDynamicPredicateToFront => { - clause_name!("$module_asserta") - } - &SystemClauseType::ModuleAssertDynamicPredicateToBack => { - clause_name!("$module_assertz") - } - &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"), + // &SystemClauseType::ModuleAssertDynamicPredicateToFront => { + // clause_name!("$module_asserta") + // } + // &SystemClauseType::ModuleAssertDynamicPredicateToBack => { + // clause_name!("$module_assertz") + // } +// &SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"), &SystemClauseType::ModuleExists => clause_name!("$module_exists"), - &SystemClauseType::ModuleOf => clause_name!("$module_of"), &SystemClauseType::NextStream => clause_name!("$next_stream"), &SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"), &SystemClauseType::NumberToChars => clause_name!("$number_to_chars"), @@ -483,14 +514,13 @@ impl SystemClauseType { &SystemClauseType::GetCutPoint => clause_name!("$get_cp"), &SystemClauseType::GetCurrentBlock => clause_name!("$get_current_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::ReadQueryTerm => clause_name!("$read_query_term"), &SystemClauseType::ReadTerm => clause_name!("$read_term"), &SystemClauseType::ReadTermFromChars => clause_name!("$read_term_from_chars"), &SystemClauseType::ResetGlobalVarAtKey => clause_name!("$reset_global_var_at_key"), &SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"), - &SystemClauseType::RetractClause => clause_name!("$retract_clause"), &SystemClauseType::ResetBlock => clause_name!("$reset_block"), &SystemClauseType::ResetContinuationMarker => clause_name!("$reset_cont_marker"), &SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"), @@ -533,22 +563,27 @@ impl SystemClauseType { &SystemClauseType::SetEnv => clause_name!("$setenv"), &SystemClauseType::UnsetEnv => clause_name!("$unsetenv"), &SystemClauseType::CharsBase64 => clause_name!("$chars_base64"), + &SystemClauseType::LoadLibraryAsStream => clause_name!("$load_library_as_stream"), } } pub fn from(name: &str, arity: usize) -> Option { match (name, arity) { - ("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause), - ("$at_end_of_expansion", 0) => Some(SystemClauseType::AtEndOfExpansion), + // ("$abolish_clause", 2) => Some(SystemClauseType::AbolishClause), + ("$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_codes", 2) => Some(SystemClauseType::AtomCodes), ("$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), - ("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront), - ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), - ("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront), - ("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack), + // ("$module_asserta", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToFront), + // ("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack), ("$call_continuation", 1) => Some(SystemClauseType::CallContinuation), ("$char_code", 2) => Some(SystemClauseType::CharCode), ("$char_type", 2) => Some(SystemClauseType::CharType), @@ -559,7 +594,6 @@ impl SystemClauseType { ("$copy_term_without_attr_vars", 2) => Some(SystemClauseType::CopyTermWithoutAttrVars), ("$create_partial_string", 3) => Some(SystemClauseType::CreatePartialString), ("$check_cp", 1) => Some(SystemClauseType::CheckCutPoint), - ("$compile_batch", 0) => Some(SystemClauseType::REPL(REPLCodePtr::CompileBatch)), ("$copy_to_lh", 2) => Some(SystemClauseType::CopyToLiftedHeap), ("$close", 2) => Some(SystemClauseType::Close), ("$current_hostname", 1) => Some(SystemClauseType::CurrentHostname), @@ -582,8 +616,8 @@ impl SystemClauseType { ("$peek_char", 2) => Some(SystemClauseType::PeekChar), ("$peek_code", 2) => Some(SystemClauseType::PeekCode), ("$is_partial_string", 1) => Some(SystemClauseType::IsPartialString), - ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), - ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), +// ("$expand_term", 2) => Some(SystemClauseType::ExpandTerm), +// ("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal), ("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar), ("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset), ("$get_byte", 2) => Some(SystemClauseType::GetByte), @@ -615,14 +649,14 @@ impl SystemClauseType { } ("$get_attr_list", 2) => Some(SystemClauseType::GetAttributedVariableList), ("$get_b_value", 1) => Some(SystemClauseType::GetBValue), - ("$get_clause", 2) => Some(SystemClauseType::GetClause), - ("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause), +// ("$get_clause", 2) => Some(SystemClauseType::GetClause), +// ("$get_module_clause", 3) => Some(SystemClauseType::GetModuleClause), ("$get_lh_from_offset", 2) => Some(SystemClauseType::GetLiftedHeapFromOffset), ("$get_lh_from_offset_diff", 3) => Some(SystemClauseType::GetLiftedHeapFromOffsetDiff), ("$get_double_quotes", 1) => Some(SystemClauseType::GetDoubleQuotes), ("$get_scc_cleaner", 1) => Some(SystemClauseType::GetSCCCleaner), ("$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_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter), ("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength), @@ -630,10 +664,9 @@ impl SystemClauseType { ("$cpu_now", 1) => Some(SystemClauseType::CpuNow), ("$current_time", 1) => Some(SystemClauseType::CurrentTime), ("$module_exists", 1) => Some(SystemClauseType::ModuleExists), - ("$module_of", 2) => Some(SystemClauseType::ModuleOf), - ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause), - ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic), - ("$no_such_predicate", 1) => Some(SystemClauseType::NoSuchPredicate), + // ("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause), + // ("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic), + ("$no_such_predicate", 2) => Some(SystemClauseType::NoSuchPredicate), ("$number_to_chars", 2) => Some(SystemClauseType::NumberToChars), ("$number_to_codes", 2) => Some(SystemClauseType::NumberToCodes), ("$op", 3) => Some(SystemClauseType::OpDeclaration), @@ -667,7 +700,7 @@ impl SystemClauseType { ("$reset_cont_marker", 0) => Some(SystemClauseType::ResetContinuationMarker), ("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey), ("$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), ("$set_ball", 1) => Some(SystemClauseType::SetBall), ("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))), @@ -697,15 +730,17 @@ impl SystemClauseType { ("$working_directory", 2) => Some(SystemClauseType::WorkingDirectory), ("$path_canonical", 2) => Some(SystemClauseType::PathCanonical), ("$file_time", 3) => Some(SystemClauseType::FileTime), - ("$use_module", 1) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), - ("$use_module_from_file", 1) => - Some(SystemClauseType::REPL(REPLCodePtr::UseModuleFromFile)), - ("$use_qualified_module", 2) => - Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule)), - ("$use_qualified_module_from_file", 2) => - Some(SystemClauseType::REPL(REPLCodePtr::UseQualifiedModuleFromFile)), + ("$clause_to_evacuable", 3) => Some(SystemClauseType::REPL(REPLCodePtr::ClauseToEvacuable)), + ("$conclude_load", 1) => Some(SystemClauseType::REPL(REPLCodePtr::ConcludeLoad)), + ("$use_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::UseModule)), + ("$declare_module", 3) => Some(SystemClauseType::REPL(REPLCodePtr::DeclareModule)), + ("$load_compiled_library", 2) => Some(SystemClauseType::REPL(REPLCodePtr::LoadCompiledLibrary)), + ("$push_load_state_payload", 1) => Some(SystemClauseType::REPL(REPLCodePtr::PushLoadStatePayload)), + ("$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), - ("$wam_instructions", 3) => Some(SystemClauseType::WAMInstructions), + ("$wam_instructions", 4) => Some(SystemClauseType::WAMInstructions), ("$write_term", 7) => Some(SystemClauseType::WriteTerm), ("$write_term_to_chars", 7) => Some(SystemClauseType::WriteTermToChars), ("$scryer_prolog_version", 1) => Some(SystemClauseType::ScryerPrologVersion), @@ -727,6 +762,18 @@ impl SystemClauseType { ("$setenv", 2) => Some(SystemClauseType::SetEnv), ("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv), ("$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", 4) => Some(SystemClauseType::REPL(REPLCodePtr::MetaPredicateProperty)), + ("$cpp_built_in_property", 2) => Some(SystemClauseType::REPL(REPLCodePtr::BuiltInProperty)), + ("$compile_pending_predicates", 1) => Some(SystemClauseType::REPL(REPLCodePtr::CompilePendingPredicates)), _ => None, } } @@ -754,7 +801,6 @@ pub enum BuiltInClauseType { pub enum ClauseType { BuiltIn(BuiltInClauseType), CallN, - Hook(CompileTimeHook), Inlined(InlinedClauseType), Named(ClauseName, usize, CodeIndex), // name, arity, index. Op(ClauseName, SharedOpDesc, CodeIndex), @@ -818,7 +864,6 @@ impl ClauseType { match self { &ClauseType::BuiltIn(ref built_in) => built_in.name(), &ClauseType::CallN => clause_name!("call"), - &ClauseType::Hook(ref hook) => hook.name(), &ClauseType::Inlined(ref inlined) => clause_name!(inlined.name()), &ClauseType::Op(ref name, ..) => name.clone(), &ClauseType::Named(ref name, ..) => name.clone(), diff --git a/src/codegen.rs b/src/codegen.rs index d260cfa0..f2a1c5ab 100644 --- a/src/codegen.rs +++ b/src/codegen.rs @@ -1,5 +1,6 @@ /// Code generation to WAM-like instructions. -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::tabled_rc::TabledData; use crate::allocator::*; use crate::arithmetic::*; @@ -9,20 +10,32 @@ use crate::forms::*; use crate::indexing::*; use crate::instructions::*; use crate::iterators::*; -use crate::machine::machine_indices::*; use crate::targets::*; +use crate::machine::machine_errors::*; + use crate::indexmap::{IndexMap, IndexSet}; use std::cell::Cell; +use std::collections::VecDeque; use std::rc::Rc; -use std::vec::Vec; -#[derive(Debug)] -pub struct CodeGenerator { - marker: TermMarker, - pub var_count: IndexMap, usize>, - non_counted_bt: bool, +#[inline] +pub fn trust_me(non_counted_bt: bool) -> ChoiceInstruction { + if non_counted_bt { + ChoiceInstruction::DefaultTrustMe(0) + } 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)] @@ -97,17 +110,46 @@ impl<'a> ConjunctInfo<'a> { } } -impl<'a, TermMarker: Allocator<'a>> CodeGenerator { - pub fn new(non_counted_bt: bool) -> Self { - CodeGenerator { - marker: Allocator::new(), - var_count: IndexMap::new(), +#[derive(Clone, Copy, Debug)] +pub struct CodeGenSettings { + pub is_extensible: bool, + pub non_counted_bt: bool, +} + +impl CodeGenSettings { + #[inline] + pub fn new(is_extensible: bool, non_counted_bt: bool) -> Self { + CodeGenSettings { + is_extensible, non_counted_bt, } } +} - pub fn take_vars(self) -> AllocVarDict { - self.marker.take_bindings() +#[derive(Debug)] +pub struct CodeGenerator { + atom_tbl: TabledData, + marker: TermMarker, + pub var_count: IndexMap, usize>, + non_counted_bt: bool, + is_extensible: bool, + pub skeleton: PredicateSkeleton, + pub jmp_by_locs: Vec, + global_jmp_by_locs_offset: usize, +} + +impl<'a, TermMarker: Allocator<'a>> CodeGenerator { + pub fn new(atom_tbl: TabledData, 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>>(&mut self, iter: Iter) { @@ -337,16 +379,20 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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 { - &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) => { - 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) => { - 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 { match code.last_mut() { Some(&mut Line::Control(ref mut ctrl)) => match ctrl { &mut ControlInstruction::CallClause(_, _, _, ref mut last_call, _) => { - *last_call = true + *last_call = true; } &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 @@ -377,7 +429,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { terms: &'a Vec>, term_loc: GenContext, code: &mut Code, - ) -> Result<(), ParserError> { + ) -> Result<(), CompilationError> { match ct { &InlinedClauseType::CompareNumber(cmp, ..) => { self.marker.reset_arg(2); @@ -553,7 +605,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { code: &mut Code, term_loc: GenContext, use_default_call_policy: bool, - ) -> Result<(), ParserError> { + ) -> Result<(), CompilationError> { let (mut acode, at) = self.call_arith_eval(terms[1].as_ref(), 1)?; code.append(&mut acode); @@ -656,7 +708,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { conjunct_info: &ConjunctInfo<'a>, code: &mut Code, is_exposed: bool, - ) -> Result<(), ParserError> { + ) -> Result<(), CompilationError> { for (chunk_num, _, terms) in iter.rule_body_iter() { for (i, term) in terms.iter().enumerate() { let term_loc = if i + 1 < terms.len() { @@ -669,18 +721,24 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { &QueryTerm::GetLevelAndUnify(ref cell, ref var) => { self.compile_get_level_and_unify(code, cell, var.clone(), term_loc) } - &QueryTerm::UnblockedCut(ref cell) => self.compile_unblocked_cut(code, cell), - &QueryTerm::BlockedCut => code.push(if chunk_num == 0 { - Line::Cut(CutInstruction::NeckCut) - } else { - Line::Cut(CutInstruction::Cut(perm_v!(1))) - }), + &QueryTerm::UnblockedCut(ref cell) => { + self.compile_unblocked_cut(code, cell) + } + &QueryTerm::BlockedCut => { + code.push(if chunk_num == 0 { + Line::Cut(CutInstruction::NeckCut) + } else { + Line::Cut(CutInstruction::Cut(perm_v!(1))) + }) + } &QueryTerm::Clause( _, ClauseType::BuiltIn(BuiltInClauseType::Is(..)), ref terms, 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, _) => { self.compile_inlined(ct, terms, term_loc, code)? } @@ -714,7 +772,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - 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. match toc { &QueryTerm::BlockedCut | &QueryTerm::UnblockedCut(..) => code.push(proceed!()), @@ -726,11 +784,19 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { let dealloc_index = Self::lco(code); 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)); } } - pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result { + pub fn compile_rule<'b: 'a>(&mut self, rule: &'b Rule) -> Result { let iter = ChunkedIterator::from_rule(rule); let conjunct_info = self.collect_var_data(iter); @@ -739,7 +805,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { ref clauses, } = rule; - let mut code = Vec::new(); + let mut code = Code::new(); self.marker.reset_at_head(args); self.compile_seq_prelude(&conjunct_info, &mut code); @@ -761,8 +827,8 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { self.compile_seq(iter, &conjunct_info, &mut code, false)?; 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) } @@ -836,10 +902,11 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { } } - 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) -> Result { +/* + pub fn compile_query(&mut self, query: &'a Vec) -> Result { let iter = ChunkedIterator::from_term_sequence(query); let conjunct_info = self.collect_var_data(iter); @@ -857,6 +924,16 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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. fn first_instantiated_index(clauses: &[PredicateClause]) -> Option { @@ -925,48 +1002,50 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { 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>( &mut self, clauses: &'b [PredicateClause], optimal_index: usize, - ) -> Result { - let mut code_body = Vec::new(); - let mut code_offsets = CodeOffsets::new(); + ) -> Result { + let mut code = VecDeque::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() { self.marker.reset(); - let mut clause_code = match *clause { - PredicateClause::Fact(ref fact, ..) => self.compile_fact(fact), - PredicateClause::Rule(ref rule, ..) => self.compile_rule(rule)?, + let mut clause_index_info = ClauseIndexInfo::new(code.len()); + self.global_jmp_by_locs_offset = self.jmp_by_locs.len(); + + 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 { 0 => ChoiceInstruction::TryMeElse(clause_code.len() + 1), - _ if i == num_clauses - 1 => self.trust_me(), - _ => self.retry_me_else(clause_code.len() + 1), + _ if i == clauses.len() - 1 => trust_me(self.non_counted_bt), + _ => 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() { @@ -976,47 +1055,86 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator { }, None => None, }; + if let Some(arg) = arg { - let index = code_body.len(); - code_offsets.index_term(arg, index); + let index = code.len(); + 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(); - code_offsets.add_indices(&mut code, code_body, optimal_index + 1); + let index_code = code_offsets.compute_indices(skip_stub_try_me_else); + 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>( &mut self, clauses: &'b Vec, - ) -> Result { - let mut code = Vec::new(); + ) -> Result { + let mut code = Code::new(); + let optimal_index = match Self::first_instantiated_index(&clauses) { Some(index) => index, None => 0, // Default to first argument indexing. }; + let split_pred = Self::split_predicate(&clauses, optimal_index); let multi_seq = split_pred.len() > 1; for (l, r) in split_pred { - let mut code_segment = - self.compile_pred_subseq(&clauses[l..r], optimal_index)?; + let skel_lower_bound = self.skeleton.clauses.len(); + let code_segment = self.compile_pred_subseq(&clauses[l .. r], optimal_index)?; + let clause_start_offset = code.len(); if multi_seq { let choice = match l { 0 => ChoiceInstruction::TryMeElse(code_segment.len() + 1), - _ if r == clauses.len() => self.trust_me(), - _ => self.retry_me_else(code_segment.len() + 1), + _ if r == clauses.len() => trust_me(self.non_counted_bt), + _ => retry_me_else(code_segment.len() + 1, self.non_counted_bt), }; 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) diff --git a/src/debray_allocator.rs b/src/debray_allocator.rs index 9e129828..3c69bda2 100644 --- a/src/debray_allocator.rs +++ b/src/debray_allocator.rs @@ -1,6 +1,6 @@ use crate::indexmap::IndexMap; -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::allocator::*; use crate::fixtures::*; diff --git a/src/fixtures.rs b/src/fixtures.rs index 907c9227..d9034562 100644 --- a/src/fixtures.rs +++ b/src/fixtures.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::forms::*; use crate::instructions::*; diff --git a/src/forms.rs b/src/forms.rs index b99897a1..c039e603 100644 --- a/src/forms.rs +++ b/src/forms.rs @@ -1,6 +1,5 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::parser::OpDesc; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::parser::OpDesc; use crate::clause_types::*; use crate::machine::machine_errors::*; @@ -8,15 +7,19 @@ use crate::machine::machine_indices::*; use crate::ordered_float::OrderedFloat; use crate::rug::{Integer, Rational}; -use crate::indexmap::IndexMap; +use crate::indexmap::{IndexMap, IndexSet}; + +use slice_deque::*; use std::cell::Cell; -use std::collections::VecDeque; +use std::ops::AddAssign; use std::path::PathBuf; use std::rc::Rc; pub type PredicateKey = (ClauseName, usize); // name, arity. +pub type Predicate = Vec; + // vars of predicate, toplevel offset. Vec is always a vector // of vars (we get their adjoining cells this way). pub type JumpStub = Vec; @@ -24,19 +27,24 @@ pub type JumpStub = Vec; #[derive(Debug, Clone)] pub enum TopLevel { Declaration(Declaration), - Fact(Term, usize, usize), // Term, line_num, col_num + Fact(Term), // Term, line_num, col_num Predicate(Predicate), Query(Vec), - Rule(Rule, usize, usize), // Rule, line_num, col_num + Rule(Rule), // Rule, line_num, col_num } -impl TopLevel { - pub fn is_end_of_file_atom(&self) -> bool { +#[derive(Debug, Clone, Copy)] +pub enum AppendOrPrepend { + Append, + Prepend +} + +impl AppendOrPrepend { + #[inline] + pub fn is_append(self) -> bool { match self { - &TopLevel::Fact(Term::Constant(_, Constant::Atom(ref name, _)), ..) => { - return name.as_str() == "end_of_file" - } - _ => false, + AppendOrPrepend::Append => true, + AppendOrPrepend::Prepend => false, } } } @@ -91,30 +99,9 @@ pub struct Rule { pub clauses: Vec, } -#[derive(Debug, Clone)] -pub struct Predicate(pub Vec); - -impl Predicate { - #[inline] - pub fn new() -> Self { - Predicate(vec![]) - } - - #[inline] - pub fn clauses(self) -> Vec { - 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)] +#[derive(Clone, Debug, Hash)] pub enum ListingSource { + DynamicallyGenerated, File(ClauseName, PathBuf), // filename, path User, } @@ -123,98 +110,13 @@ impl ListingSource { pub fn from_file_and_path(filename: ClauseName, path_buf: PathBuf) -> Self { 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)> -{ - 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 { +pub trait ClauseInfo { fn is_consistent(&self, clauses: &Vec) -> bool { match clauses.first() { - Some(ref cl) => { - self.name_and_module() == cl.name_and_module() && self.arity() == cl.arity() + Some(cl) => { + self.name() == cl.name() && self.arity() == cl.arity() } None => { true @@ -222,33 +124,29 @@ pub trait ClauseConsistency { } } - fn name_and_module(&self) -> Option<(ClauseName, ClauseName)>; + fn name(&self) -> Option; 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)> - { +impl ClauseInfo for Term { + fn name(&self) -> Option { match self { - Term::Clause(_, ref name, ref terms, _) => + 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!(":-"))), + 2 => terms[0].name(), + _ => Some(clause_name!(":-")), } } _ => { - resolved_term_and_module(self) + Some(name.clone()) } - }, + } + } Term::Constant(_, Constant::Atom(ref name, _)) => { - Some((name.owning_module(), name.clone())) + Some(name.clone()) } _ => { None @@ -263,12 +161,12 @@ impl ClauseConsistency for Term { ":-" => { match terms.len() { 1 => 0, - 2 => resolved_term_arity(&terms[0]), + 2 => terms[0].arity(), _ => terms.len(), } } _ => { - resolved_term_arity(self) + terms.len() } }, _ => { @@ -278,9 +176,9 @@ impl ClauseConsistency for Term { } } -impl ClauseConsistency for Rule { - fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> { - Some((self.head.0.owning_module(), self.head.0.clone())) +impl ClauseInfo for Rule { + fn name(&self) -> Option { + Some(self.head.0.clone()) } fn arity(&self) -> usize { @@ -288,15 +186,14 @@ impl ClauseConsistency for Rule { } } -impl ClauseConsistency for PredicateClause { - fn name_and_module(&self) -> Option<(ClauseName, ClauseName)> { +impl ClauseInfo for PredicateClause { + fn name(&self) -> Option { match self { &PredicateClause::Fact(ref term, ..) => { - term.name_and_module() - .map(|(_, name)| (name.owning_module(), name)) + term.name() } &PredicateClause::Rule(ref rule, ..) => { - rule.name_and_module() + rule.name() } } } @@ -313,22 +210,12 @@ impl ClauseConsistency for PredicateClause { } } -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); +// pub type CompiledResult = (Predicate, VecDeque); #[derive(Debug, Clone)] pub enum PredicateClause { - Fact(Term, usize, usize), // Term, line number, column number. - Rule(Rule, usize, usize), // Term, line number, column number. + Fact(Term), + Rule(Rule), } impl PredicateClause { @@ -401,66 +288,60 @@ impl ModuleSource { } } -pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator. +// pub type ScopedPredicateKey = (ClauseName, PredicateKey); // module name, predicate indicator. +/* #[derive(Debug, Clone)] pub enum MultiFileIndicator { LocalScoped(ClauseName, usize), // name, arity ModuleScoped(ScopedPredicateKey), } +*/ + +#[derive(Clone, Copy, Hash, Debug)] +pub enum MetaSpec { + Minus, + Plus, + Either, + RequiresExpansionWithArgument(usize), +} #[derive(Debug, Clone)] pub enum Declaration { - Dynamic(ClauseName, usize), // name, arity - EndOfFile, - Hook(CompileTimeHook, PredicateClause, VecDeque), - ModuleInitialization(Vec, VecDeque), // goal + Dynamic(ClauseName, usize), + MetaPredicate(ClauseName, ClauseName, Vec), // module name, name, meta-specs Module(ModuleDecl), - MultiFile(MultiFileIndicator), NonCountedBacktracking(ClauseName, usize), // name, arity Op(OpDecl), - SetPrologFlag(DoubleQuotes), UseModule(ModuleSource), - UseQualifiedModule(ModuleSource, Vec), + UseQualifiedModule(ModuleSource, IndexSet), } -impl Declaration { - #[inline] - pub fn is_module_decl(&self) -> bool { - if let &Declaration::Module(_) = self { - true - } else { - false - } - } - - #[inline] - pub fn is_end_of_file(&self) -> bool { - if let &Declaration::EndOfFile = self { - true - } else { - false - } - } +#[derive(Debug, Clone, Eq, Hash, PartialEq, Ord, PartialOrd)] +pub struct OpDecl { + pub prec: usize, + pub spec: Specifier, + pub name: ClauseName } -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] -pub struct OpDecl(pub usize, pub Specifier, pub ClauseName); - impl OpDecl { #[inline] - pub fn name(&self) -> ClauseName { - self.2.clone() + pub fn new(prec: usize, spec: Specifier, name: ClauseName) -> Self { + Self { prec, spec, name } } #[inline] - pub fn remove(&self, op_dir: &mut OpDir) { - self.insert_into_op_dir(clause_name!(""), op_dir, 0); + pub fn remove(&mut self, op_dir: &mut OpDir) { + let prec = self.prec; + self.prec = 0; + + self.insert_into_op_dir(op_dir); + self.prec = prec; } #[inline] pub fn fixity(&self) -> Fixity { - match self.1 { + match self.spec { XFY | XFX | YFX => Fixity::In, XF | YF => Fixity::Post, FX | FY => Fixity::Pre, @@ -468,29 +349,27 @@ impl OpDecl { } } - pub fn insert_into_op_dir(&self, module: ClauseName, op_dir: &mut OpDir, prec: usize) { - let (spec, name) = (self.1, self.2.clone()); + pub fn insert_into_op_dir(&self, op_dir: &mut OpDir) -> Option<(usize, Specifier)> { + let key = (self.name.clone(), self.fixity()); - let fixity = self.fixity(); - - match op_dir.get(&(name.clone(), fixity)) { + match op_dir.get(&key) { Some(cell) => { - cell.shared_op_desc().set(prec, spec); - return; + return Some(cell.shared_op_desc().replace((self.prec, self.spec))); + } + 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( &self, - module: ClauseName, existing_desc: Option, op_dir: &mut OpDir, ) -> 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 let Some(desc) = existing_desc { @@ -508,7 +387,8 @@ impl OpDecl { } } - Ok(self.insert_into_op_dir(module, op_dir, prec)) + self.insert_into_op_dir(op_dir); + Ok(()) } } @@ -547,7 +427,7 @@ pub fn fetch_op_spec( match arity { 2 => op_dir .get(&(name, Fixity::In)) - .and_then(|OpDirValue(spec, _)| { + .and_then(|OpDirValue(spec)| { if spec.prec() > 0 { Some(spec.clone()) } else { @@ -555,15 +435,15 @@ pub fn fetch_op_spec( } }), 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 { return Some(spec.clone()); } } op_dir - .get(&(name, Fixity::Post)) - .and_then(|OpDirValue(spec, _)| { + .get(&(name.clone(), Fixity::Post)) + .and_then(|OpDirValue(spec)| { if spec.prec() > 0 { Some(spec.clone()) } else { @@ -579,7 +459,7 @@ pub fn fetch_op_spec( pub type ModuleDir = IndexMap; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, Eq, Hash, PartialEq)] pub enum ModuleExport { OpDecl(OpDecl), PredicateKey(PredicateKey), @@ -593,21 +473,32 @@ pub struct ModuleDecl { #[derive(Debug)] pub struct Module { - pub atom_tbl: TabledData, pub module_decl: ModuleDecl, pub code_dir: CodeDir, pub op_dir: OpDir, - pub term_dir: TermDir, // this contains multifile predicates. - pub term_expansions: (Predicate, VecDeque), - pub goal_expansions: (Predicate, VecDeque), - pub user_term_expansions: (Predicate, VecDeque), // term expansions inherited from the user scope. - pub user_goal_expansions: (Predicate, VecDeque), // same for goal_expansions. - pub local_term_expansions: (Predicate, VecDeque), // expansions local to the module. - pub local_goal_expansions: (Predicate, VecDeque), - pub inserted_expansions: bool, // has the module been successfully inserted into toplevel?? + pub meta_predicates: MetaPredicateDir, + pub extensible_predicates: IndexMap, pub is_impromptu_module: bool, 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)] pub enum Number { @@ -715,3 +606,154 @@ impl Number { } } } + +#[derive(Debug, Clone)] +pub enum OptArgIndexKey { + Constant(usize, usize, Constant, Vec), // 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 { + 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 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, + pub clause_clause_locs: SliceDeque, +} + +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, + } + } + */ +} diff --git a/src/heap_iter.rs b/src/heap_iter.rs index a541d12f..44541237 100644 --- a/src/heap_iter.rs +++ b/src/heap_iter.rs @@ -45,10 +45,13 @@ impl<'a> HCPreOrderIterator<'a> { | HeapCellValue::Integer(_) | HeapCellValue::Rational(_) => { Addr::Con(h) } + HeapCellValue::LoadStatePayload(_) => { + Addr::LoadStatePayload(h) + } HeapCellValue::Stream(_) => { Addr::Stream(h) } - &HeapCellValue::TcpListener(_) => { + HeapCellValue::TcpListener(_) => { Addr::TcpListener(h) } } @@ -175,13 +178,17 @@ impl<'a> Iterator for HCPostOrderIterator<'a> { } &HeapCellValue::Addr(Addr::PStrLocation(h, n)) => { match &self.machine_st.heap[h] { - &HeapCellValue::PartialString(ref pstr, _) => { + &HeapCellValue::PartialString(..) => {// ref pstr, _) => { + /* let c = pstr.range_from(n ..).next().unwrap(); let next_n = n + c.len_utf8(); 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!() diff --git a/src/heap_print.rs b/src/heap_print.rs index 2a51fa91..29530fa5 100644 --- a/src/heap_print.rs +++ b/src/heap_print.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::clause_types::*; use crate::forms::*; @@ -402,6 +402,7 @@ pub fn requires_space(atom: &str, op: &str) -> bool { } } +/* fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict { machine_st .heap_locs @@ -414,6 +415,7 @@ fn reverse_heap_locs<'a>(machine_st: &'a MachineState) -> ReverseHeapVarDict { }) .collect() } +*/ fn non_quoted_graphic_token>(mut iter: Iter, c: char) -> bool { if c == '/' { @@ -503,7 +505,7 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { max_depth: 0, } } - +/* pub fn from_heap_locs( machine_st: &'a MachineState, op_dir: &'a OpDir, @@ -520,17 +522,20 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> { printer } - +*/ +/* pub fn drop_toplevel_spec(&mut self) { self.toplevel_spec = None; } - +*/ +/* #[inline] pub fn see_all_locs(&mut self) { for key in self.heap_locs.keys().cloned() { self.printed_vars.insert(key); } } +*/ #[inline] 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) { match self.op_dir.get(&(clause_name!("rdiv"), Fixity::In)) { - Some(OpDirValue(ref spec, _)) => { + Some(OpDirValue(ref spec)) => { if add_brackets { self.state_stack.push(TokenOrRedirect::Close); } diff --git a/src/indexing.rs b/src/indexing.rs index bf5403bf..9359e18c 100644 --- a/src/indexing.rs +++ b/src/indexing.rs @@ -1,203 +1,1090 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::tabled_rc::*; +use crate::forms::*; use crate::instructions::*; -use crate::rug::Integer; use crate::indexmap::IndexMap; +use crate::rug::Integer; + +use slice_deque::{sdeq, SliceDeque}; -use std::collections::VecDeque; use std::convert::TryFrom; use std::hash::Hash; +use std::iter::once; use std::rc::Rc; #[derive(Debug, Clone, Copy)] -enum IntIndex { - External(usize), +pub enum IndexingCodePtr { + External(usize), // the index points past the indexing instruction prelude. Fail, - Internal(usize), + Internal(usize), // the index points into the indexing instruction prelude. +} + +impl IndexingCodePtr { + #[inline] + fn is_internal(self) -> bool { + if let IndexingCodePtr::Internal(_) = self { + true + } else { + false + } + } +} + +#[derive(Debug, Clone, Copy)] +enum OptArgIndexKeyType { + Structure, + Constant, + List, +} + +impl OptArgIndexKey { + #[inline] + fn has_key_type(&self, key_type: OptArgIndexKeyType) -> bool { + match (self, key_type) { + (OptArgIndexKey::Constant(..), OptArgIndexKeyType::Constant) | + (OptArgIndexKey::Structure(..), OptArgIndexKeyType::Structure) | + (OptArgIndexKey::List(..), OptArgIndexKeyType::List) => { + true + } + _ => { + false + } + } + } +} + +#[inline] +fn search_skeleton_for_first_key_type( + skeleton: &[ClauseIndexInfo], + key_type: OptArgIndexKeyType, + append_or_prepend: AppendOrPrepend, +) -> Option<&OptArgIndexKey> { + if append_or_prepend.is_append() { + for clause_index_info in skeleton.iter().rev() { + if clause_index_info.opt_arg_index_key.has_key_type(key_type) { + return Some(&clause_index_info.opt_arg_index_key); + } + } + } else { + for clause_index_info in skeleton.iter() { + if clause_index_info.opt_arg_index_key.has_key_type(key_type) { + return Some(&clause_index_info.opt_arg_index_key); + } + } + } + + None +} + +struct IndexingCodeMergingPtr<'a> { + skeleton: &'a mut [ClauseIndexInfo], + // merged_clause_index: usize, + indexing_code: &'a mut Vec, + offset: usize, + append_or_prepend: AppendOrPrepend, +} + +impl<'a> IndexingCodeMergingPtr<'a> { + #[inline] + fn new( + skeleton: &'a mut [ClauseIndexInfo], + indexing_code: &'a mut Vec, + append_or_prepend: AppendOrPrepend, + ) -> Self { + Self { skeleton, indexing_code, offset: 0, append_or_prepend } + } + + fn internalize_constant(&mut self, constant_ptr: IndexingCodePtr) { + let constant_key = + search_skeleton_for_first_key_type( + self.skeleton, + OptArgIndexKeyType::Constant, + self.append_or_prepend, + ); + + let mut constants = IndexMap::new(); + + match constant_key { + Some(OptArgIndexKey::Constant(_, _, ref constant, _)) => { + constants.insert(constant.clone(), constant_ptr); + } + _ => { + unreachable!() + } + } + + if let IndexingCodePtr::Internal(_) = constant_ptr { + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants) + )); + + let last_index = self.indexing_code.len() - 1; + self.indexing_code.swap(self.offset, last_index); + } else { + self.offset = self.indexing_code.len(); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants) + )); + } + } + + fn add_indexed_choice_for_constant(&mut self, external: usize, constant: Constant, index: usize) + { + let third_level_index = + if self.append_or_prepend.is_append() { + sdeq![ + IndexedChoiceInstruction::Try(external), + IndexedChoiceInstruction::Trust(index) + ] + } else { + sdeq![ + IndexedChoiceInstruction::Try(index), + IndexedChoiceInstruction::Trust(external) + ] + }; + + let indexing_code_len = self.indexing_code.len(); + self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(ref mut constants) + ) => { + constants.insert(constant, IndexingCodePtr::Internal(indexing_code_len - self.offset)); + } + _ => { + unreachable!() + } + } + } + + fn extend_indexed_choice(&mut self, index: usize) { + match &mut self.indexing_code[self.offset] { + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) + if self.append_or_prepend.is_append() => { + uncap_choice_seq_with_trust(indexed_choice_instrs); + indexed_choice_instrs.push_back(IndexedChoiceInstruction::Trust(index)); + } + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + uncap_choice_seq_with_try(indexed_choice_instrs); + indexed_choice_instrs.push_front(IndexedChoiceInstruction::Try(index)); + } + _ => { + unreachable!() + } + } + } + + fn index_overlapping_constant( + &mut self, + orig_constant: &Constant, + overlapping_constant: Constant, + index: usize, + ) { + loop { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..) + ) => { + match *c { + IndexingCodePtr::Fail => { + *c = IndexingCodePtr::External(index); + break; + } + IndexingCodePtr::External(_) => { + let mut constants = IndexMap::new(); + constants.insert(orig_constant.clone(), *c); + + *c = IndexingCodePtr::Internal(indexing_code_len); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants) + )); + + self.offset = indexing_code_len; + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + } + } + } + IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants) + ) => { + match constants.get(&overlapping_constant).cloned() { + None | Some(IndexingCodePtr::Fail) => { + constants.insert(overlapping_constant, IndexingCodePtr::External(index)); + } + Some(IndexingCodePtr::External(o)) => { + self.add_indexed_choice_for_constant(o, overlapping_constant, index); + } + Some(IndexingCodePtr::Internal(o)) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + + break; + } + IndexingLine::IndexedChoice(_) => { + self.internalize_constant( + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + } + + fn index_constant(&mut self, constant: Constant, index: usize) { + loop { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..) + ) => { + match *c { + IndexingCodePtr::Fail => { + *c = IndexingCodePtr::External(index); + break; + } + IndexingCodePtr::External(o) => { + *c = IndexingCodePtr::Internal(indexing_code_len - self.offset); + self.internalize_constant(IndexingCodePtr::External(o)); + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + } + } + } + IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(constants) + ) => { + match constants.get(&constant).cloned() { + None | Some(IndexingCodePtr::Fail) => { + constants.insert(constant, IndexingCodePtr::External(index)); + } + Some(IndexingCodePtr::External(o)) => { + self.add_indexed_choice_for_constant(o, constant, index); + } + Some(IndexingCodePtr::Internal(o)) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + + break; + } + IndexingLine::IndexedChoice(_) => { + self.internalize_constant( + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + } + + fn internalize_structure(&mut self, structure_ptr: IndexingCodePtr) { + let structure_key = + search_skeleton_for_first_key_type( + self.skeleton, + OptArgIndexKeyType::Structure, + self.append_or_prepend, + ); + + let mut structures = IndexMap::new(); + + match structure_key { + Some(OptArgIndexKey::Structure(_, _, ref name, ref arity)) => { + structures.insert((name.clone(), *arity), structure_ptr); + } + _ => { + unreachable!() + } + } + + if let IndexingCodePtr::Internal(_) = structure_ptr { + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(structures) + )); + + let last_index = self.indexing_code.len() - 1; + self.indexing_code.swap(self.offset, last_index); + } else { + self.offset = self.indexing_code.len(); + + self.indexing_code.push(IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(structures) + )); + } + } + + fn add_indexed_choice_for_structure(&mut self, external: usize, key: PredicateKey, index: usize) + { + let third_level_index = + if self.append_or_prepend.is_append() { + sdeq![ + IndexedChoiceInstruction::Try(external), + IndexedChoiceInstruction::Trust(index) + ] + } else { + sdeq![ + IndexedChoiceInstruction::Try(index), + IndexedChoiceInstruction::Trust(external) + ] + }; + + let indexing_code_len = self.indexing_code.len(); + self.indexing_code.push(IndexingLine::IndexedChoice(third_level_index)); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(ref mut structures) + ) => { + structures.insert(key, IndexingCodePtr::Internal(indexing_code_len - self.offset)); + } + _ => { + unreachable!() + } + } + } + + fn index_structure(&mut self, key: PredicateKey, index: usize) { + loop { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s) + ) => { + match *s { + IndexingCodePtr::Fail => { + *s = IndexingCodePtr::External(index); + break; + } + IndexingCodePtr::External(o) => { + *s = IndexingCodePtr::Internal(indexing_code_len - self.offset); + self.internalize_structure(IndexingCodePtr::External(o)); + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + } + } + } + IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(structures) + ) => { + match structures.get(&key).cloned() { + None | Some(IndexingCodePtr::Fail) => { + structures.insert(key, IndexingCodePtr::External(index)); + } + Some(IndexingCodePtr::External(o)) => { + self.add_indexed_choice_for_structure(o, key, index); + } + Some(IndexingCodePtr::Internal(o)) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + + break; + } + IndexingLine::IndexedChoice(_) => { + // replace this value, at self.offset, with + // SwitchOnStructures, and swap this IndexedChoice + // vector to the end of self.indexing_code. + self.internalize_structure( + IndexingCodePtr::Internal(indexing_code_len - self.offset), + ); + } + _ => { + unreachable!() + } + } + } + } + + fn index_list(&mut self, index: usize) { + let indexing_code_len = self.indexing_code.len(); + + match &mut self.indexing_code[self.offset] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _) + ) => { + match *l { + IndexingCodePtr::Fail => { + *l = IndexingCodePtr::External(index); + } + IndexingCodePtr::External(o) => { + *l = IndexingCodePtr::Internal(indexing_code_len - self.offset); + + let third_level_index = + if self.append_or_prepend.is_append() { + sdeq![ + IndexedChoiceInstruction::Try(o), + IndexedChoiceInstruction::Trust(index) + ] + } else { + sdeq![ + IndexedChoiceInstruction::Try(index), + IndexedChoiceInstruction::Trust(o) + ] + }; + + self.indexing_code.push( + IndexingLine::IndexedChoice(third_level_index), + ); + } + IndexingCodePtr::Internal(o) => { + self.offset += o; + self.extend_indexed_choice(index); + } + } + } + _ => { + unreachable!() + } + } + } +} + +pub fn merge_clause_index( + target_indexing_code: &mut Vec, + skeleton: &mut [ClauseIndexInfo], // the clause to be merged is the last element in the skeleton. + new_clause_loc: usize, // the absolute location of the new clause in the code vector. + append_or_prepend: AppendOrPrepend, +) { + let opt_arg_index_key = + match append_or_prepend { + AppendOrPrepend::Append => { + skeleton.last_mut().unwrap().opt_arg_index_key.take() + } + AppendOrPrepend::Prepend => { + skeleton.first_mut().unwrap().opt_arg_index_key.take() + } + }; + + let mut merging_ptr = IndexingCodeMergingPtr::new( + skeleton, + target_indexing_code, + append_or_prepend, + ); + + match &opt_arg_index_key { + OptArgIndexKey::Constant(_, index_loc, ref constant, ref overlapping_constants) => { + let offset = new_clause_loc - index_loc + 1; + merging_ptr.index_constant(constant.clone(), offset); + + for overlapping_constant in overlapping_constants { + merging_ptr.index_overlapping_constant( + constant, overlapping_constant.clone(), offset, + ); + } + } + OptArgIndexKey::Structure(_, index_loc, ref name, ref arity) => { + merging_ptr.index_structure((name.clone(), *arity), new_clause_loc - index_loc + 1); + } + OptArgIndexKey::List(_, index_loc) => { + merging_ptr.index_list(new_clause_loc - index_loc + 1); + } + OptArgIndexKey::None => { + unreachable!() + } + } + + match append_or_prepend { + AppendOrPrepend::Append => { + skeleton.last_mut().unwrap().opt_arg_index_key = opt_arg_index_key; + } + AppendOrPrepend::Prepend => { + skeleton.first_mut().unwrap().opt_arg_index_key = opt_arg_index_key; + } + } +} + +#[inline] +fn remove_instruction_with_offset( + code: &mut SliceDeque, + offset: usize, +) { + for (index, line) in code.iter().enumerate() { + if offset == line.offset() { + code.remove(index); + cap_choice_seq(code); + return; + } + } +} + +pub fn remove_constant_indices( + constant: &Constant, + overlapping_constants: &[Constant], + indexing_code: &mut Vec, + offset: usize, +) { + let mut index = 0; + let iter = once(constant).chain(overlapping_constants.iter()); + + match &mut indexing_code[index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..) + ) => { + match *c { + IndexingCodePtr::External(_) => { + *c = IndexingCodePtr::Fail; + return; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + IndexingCodePtr::Fail => { + return; + } + } + } + _ => { + unreachable!() + } + } + + let mut constants_index = 0; + + for constant in iter { // (constant, index_loc) in iter.zip(index_locs.iter()) { + loop { + match &mut indexing_code[index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(ref mut constants) + ) => { + constants_index = index; + + match constants.get(constant).cloned() { + Some(IndexingCodePtr::External(_)) => { + constants.remove(constant); + break; + } + Some(IndexingCodePtr::Internal(o)) => { + index += o; + } + Some(IndexingCodePtr::Fail) | None => { + unreachable!() + } + } + } + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + let ext = IndexingCodePtr::External( + indexed_choice_instrs.pop_back().unwrap().offset() + ); + + match &mut indexing_code[constants_index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..) + ) => { + *c = ext; + } + IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(ref mut constants) + ) => { + constants.insert(constant.clone(), ext); + } + _ => { + unreachable!() + } + } + } + + break; + } + _ => { + unreachable!() + } + } + } + } + + match &indexing_code[constants_index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnConstant(ref constants) + ) if constants.is_empty() => { + match &mut indexing_code[0] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, ref mut c, ..) + ) => { + *c = IndexingCodePtr::Fail; + } + _ => { + unreachable!() + } + } + } + _ => { + } + } +} + +pub fn remove_structure_index( + name: &ClauseName, + arity: usize, + indexing_code: &mut Vec, + offset: usize, +) { + let mut index = 0; + + match &mut indexing_code[index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s) + ) => { + match *s { + IndexingCodePtr::External(_) => { + *s = IndexingCodePtr::Fail; + return; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + IndexingCodePtr::Fail => { + return; + } + } + } + _ => { + unreachable!() + } + } + + let mut structures_index = 0; + + loop { + match &mut indexing_code[index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(ref mut structures) + ) => { + structures_index = index; + + match structures.get(&(name.clone(), arity)).cloned() { + Some(IndexingCodePtr::External(_)) => { + structures.remove(&(name.clone(), arity)); + break; + } + Some(IndexingCodePtr::Internal(o)) => { + index += o; + } + Some(IndexingCodePtr::Fail) | None => { + return; + } + } + } + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + let ext = IndexingCodePtr::External( + indexed_choice_instrs.pop_back().unwrap().offset() + ); + + match &mut indexing_code[structures_index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s) + ) => { + *s = ext; + } + IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(ref mut structures) + ) => { + structures.insert((name.clone(), arity), ext); + } + _ => { + unreachable!() + } + } + } + + break; + } + _ => { + unreachable!() + } + } + } + + match &indexing_code[structures_index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnStructure(ref structures) + ) if structures.is_empty() => { + match &mut indexing_code[0] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, _, ref mut s) + ) => { + *s = IndexingCodePtr::Fail; + } + _ => { + unreachable!() + } + } + } + _ => { + } + } +} + +pub fn remove_list_index( + indexing_code: &mut Vec, + offset: usize, +) { + let mut index = 0; + + match &mut indexing_code[index] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _) + ) => { + match *l { + IndexingCodePtr::External(_) => { + *l = IndexingCodePtr::Fail; + return; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + IndexingCodePtr::Fail => { + return; + } + } + } + _ => { + unreachable!() + } + } + + match &mut indexing_code[index] { + IndexingLine::IndexedChoice(ref mut indexed_choice_instrs) => { + remove_instruction_with_offset(indexed_choice_instrs, offset); + + if indexed_choice_instrs.len() == 1 { + let ext = IndexingCodePtr::External( + indexed_choice_instrs.pop_back().unwrap().offset() + ); + + match &mut indexing_code[0] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, _, _, ref mut l, _) + ) => { + *l = ext; + } + _ => { + unreachable!() + } + } + } + } + _ => { + unreachable!() + } + } +} + +pub fn remove_index( + //skeleton: &[ClauseIndexInfo], + opt_arg_index_key: &OptArgIndexKey, + indexing_code: &mut Vec, + clause_loc: usize, +) { + match opt_arg_index_key { + OptArgIndexKey::Constant(_, _, ref constant, ref overlapping_constants) => { + remove_constant_indices( + constant, + overlapping_constants, + indexing_code, + clause_loc, + //&skeleton[index].index_locs, + ); + } + OptArgIndexKey::Structure(_, _, ref name, ref arity) => { + remove_structure_index( + name, + *arity, + indexing_code, + clause_loc, + //&skeleton[index].index_locs, + ); + } + OptArgIndexKey::List(..) => { + remove_list_index( + indexing_code, + clause_loc, + //&skeleton[index].index_locs, + ); + } + OptArgIndexKey::None => { + unreachable!() + } + } +} + +fn second_level_index( + indices: IndexMap>, + prelude: &mut SliceDeque, +) -> IndexMap +{ + let mut index_locs = IndexMap::new(); + + for (key, mut code) in indices.into_iter() { + if code.len() > 1 { + index_locs.insert(key, IndexingCodePtr::Internal(prelude.len() + 1)); + cap_choice_seq_with_trust(&mut code); + prelude.push_back(IndexingLine::from(code)); + } else { + code.first().map(|i| { + index_locs.insert(key, IndexingCodePtr::External(i.offset())); + }); + } + } + + index_locs +} + +fn switch_on( + instr_fn: impl Fn(IndexMap) -> IndexingInstruction, + index: IndexMap>, + prelude: &mut SliceDeque, +) -> IndexingCodePtr { + let index = second_level_index(index, prelude); + + if index.len() > 1 { + let instr = instr_fn(index); + prelude.push_front(IndexingLine::from(instr)); + + IndexingCodePtr::Internal(1) + } else { + index.into_iter() + .next() + .map(|(_, v)| v) + .unwrap_or(IndexingCodePtr::Fail) + } +} + +fn switch_on_list( + mut lists: SliceDeque, + prelude: &mut SliceDeque, +) -> IndexingCodePtr { + if lists.len() > 1 { + cap_choice_seq_with_trust(&mut lists); + prelude.push_back(IndexingLine::from(lists)); + IndexingCodePtr::Internal(1) + } else { + lists.first() + .map(|i| IndexingCodePtr::External(i.offset())) + .unwrap_or(IndexingCodePtr::Fail) + } +} + +#[inline] +fn cap_choice_seq(prelude: &mut [IndexedChoiceInstruction]) { + prelude.first_mut().map(|instr| { + *instr = IndexedChoiceInstruction::Try(instr.offset()); + }); + + cap_choice_seq_with_trust(prelude); +} + +#[inline] +fn cap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) { + prelude.last_mut().map(|instr| { + if let IndexedChoiceInstruction::Retry(i) = instr { + *instr = IndexedChoiceInstruction::Trust(*i); + } + }); +} + +#[inline] +fn uncap_choice_seq_with_trust(prelude: &mut [IndexedChoiceInstruction]) { + prelude.last_mut().map(|instr| { + if let IndexedChoiceInstruction::Trust(i) = instr { + *instr = IndexedChoiceInstruction::Retry(*i); + } + }); +} + +#[inline] +fn uncap_choice_seq_with_try(prelude: &mut [IndexedChoiceInstruction]) { + prelude.first_mut().map(|instr| { + if let IndexedChoiceInstruction::Try(i) = instr { + *instr = IndexedChoiceInstruction::Retry(*i); + } + }); +} + +fn compute_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction { + // in either case, increment index to skip the IndexingLine vector. + if is_first_index { + IndexedChoiceInstruction::Try(index + 1) + } else { + IndexedChoiceInstruction::Retry(index + 1) + } +} + +pub fn constant_key_alternatives(constant: &Constant, atom_tbl: TabledData) -> Vec { + let mut constants = vec![]; + + match constant { + Constant::Atom(ref name, ref op) => { + if name.is_char() { + let c = name.as_str().chars().next().unwrap(); + constants.push(Constant::Char(c)); + } + + if op.is_some() { + constants.push(Constant::Atom(name.clone(), None)); + } + } + Constant::Char(c) => { + let atom = clause_name!(c.to_string(), atom_tbl); + constants.push(Constant::Atom(atom, None)); + } + Constant::Fixnum(ref n) => { + constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + + if *n >= 0 { + if let Ok(n) = usize::try_from(*n) { + constants.push(Constant::Usize(n)); + } + } + } + Constant::Integer(ref n) => { + if let Some(n) = n.to_isize() { + constants.push(Constant::Fixnum(n)); + } + + if let Some(n) = n.to_usize() { + constants.push(Constant::Usize(n)); + } + } + Constant::Usize(n) => { + constants.push(Constant::Integer(Rc::new(Integer::from(*n)))); + + if let Ok(n) = isize::try_from(*n) { + constants.push(Constant::Fixnum(n)); + } + } + _ => { + } + } + + constants } #[derive(Debug)] pub struct CodeOffsets { atom_tbl: TabledData, - pub constants: IndexMap, - pub lists: ThirdLevelIndex, - pub structures: IndexMap<(ClauseName, usize), ThirdLevelIndex>, + pub constants: IndexMap>, + pub lists: SliceDeque, + pub structures: IndexMap<(ClauseName, usize), SliceDeque>, + optimal_index: usize, } impl CodeOffsets { - pub fn new() -> Self { + pub fn new(atom_tbl: TabledData, optimal_index: usize) -> Self { CodeOffsets { - atom_tbl: TabledData::new(Rc::new("_index".to_string())), + atom_tbl, constants: IndexMap::new(), - lists: Vec::new(), + lists: sdeq![], structures: IndexMap::new(), + optimal_index } } - fn cap_choice_seq_with_trust(prelude: &mut ThirdLevelIndex) { - prelude.last_mut().map(|instr| { - match instr { - &mut IndexedChoiceInstruction::Retry(i) => { - *instr = IndexedChoiceInstruction::Trust(i) - } - _ => {} - }; - }); + fn index_list(&mut self, index: usize) { + let is_initial_index = self.lists.is_empty(); + self.lists.push_back(compute_index(is_initial_index, index)); } - fn add_index(is_first_index: bool, index: usize) -> IndexedChoiceInstruction { - if is_first_index { - IndexedChoiceInstruction::Try(index) - } else { - IndexedChoiceInstruction::Retry(index) + fn index_constant(&mut self, constant: &Constant, index: usize) -> Vec { + let overlapping_constants = + constant_key_alternatives(constant, self.atom_tbl.clone()); + + let code = self.constants + .entry(constant.clone()) + .or_insert(sdeq![]); + + let is_initial_index = code.is_empty(); + code.push_back(compute_index(is_initial_index, index)); + + for constant in &overlapping_constants { + let code = self.constants + .entry(constant.clone()) + .or_insert(sdeq![]); + + let is_initial_index = code.is_empty(); + let index = compute_index(is_initial_index, index); + + code.push_back(index); } + + overlapping_constants } - fn intercept_overlapping_constant(&mut self, constant: &Constant, index: usize) { - match constant { - &Constant::Atom(ref name, ref op) if name.is_char() => { - let c = name.as_str().chars().next().unwrap(); - let code = self.constants - .entry(Constant::Char(c)) - .or_insert(vec![]); + fn index_structure(&mut self, name: &ClauseName, arity: usize, index: usize) -> usize { + let code = self + .structures + .entry((name.clone(), arity)) + .or_insert(sdeq![]); - code.push(Self::add_index(code.is_empty(), index)); + let code_len = code.len(); + let is_initial_index = code.is_empty(); - if op.is_some() { - let code = self.constants - .entry(Constant::Atom(name.clone(), None)) - .or_insert(vec![]); - - code.push(Self::add_index(false, index)); - } - } - &Constant::Atom(ref name, Some(_)) => { - let code = self.constants - .entry(Constant::Atom(name.clone(), None)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - &Constant::Char(c) => { - let atom = clause_name!(c.to_string(), self.atom_tbl.clone()); - - let code = self.constants - .entry(Constant::Atom(atom, None)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - &Constant::Fixnum(n) => { - let code = self.constants - .entry(Constant::Integer(Rc::new(Integer::from(n)))) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - - if n >= 0 { - if let Ok(n) = usize::try_from(n) { - let code = self.constants - .entry(Constant::Usize(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - } - &Constant::Integer(ref n) => { - if let Some(n) = n.to_isize() { - let code = self.constants - .entry(Constant::Fixnum(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - - if let Some(n) = n.to_usize() { - let code = self.constants - .entry(Constant::Usize(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - &Constant::Usize(n) => { - let code = self.constants - .entry(Constant::Integer(Rc::new(Integer::from(n)))) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - - if let Ok(n) = isize::try_from(n) { - let code = self.constants - .entry(Constant::Fixnum(n)) - .or_insert(vec![]); - - code.push(Self::add_index(code.is_empty(), index)); - } - } - _ => { - } - } + code.push_back(compute_index(is_initial_index, index)); + code_len } - pub fn index_term(&mut self, optimal_arg: &Term, index: usize) { + pub fn index_term( + &mut self, + optimal_arg: &Term, + index: usize, + clause_index_info: &mut ClauseIndexInfo, + ) { match optimal_arg { &Term::Clause(_, ref name, ref terms, _) => { - let code = self - .structures - .entry((name.clone(), terms.len())) - .or_insert(Vec::new()); + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Structure(self.optimal_index, 0, name.clone(), terms.len()); - let is_initial_index = code.is_empty(); - code.push(Self::add_index(is_initial_index, index)); + self.index_structure(name, terms.len(), index); } &Term::Cons(..) | &Term::Constant(_, Constant::String(_)) => { - let is_initial_index = self.lists.is_empty(); - self.lists.push(Self::add_index(is_initial_index, index)); + clause_index_info.opt_arg_index_key = + OptArgIndexKey::List(self.optimal_index, 0); + + self.index_list(index); } &Term::Constant(_, ref constant) => { - self.intercept_overlapping_constant(constant, index); + let overlapping_constants = + self.index_constant(constant, index); - let code = self.constants - .entry(constant.clone()) - .or_insert(vec![]); - - let is_initial_index = code.is_empty(); - code.push(Self::add_index(is_initial_index, index)); + clause_index_info.opt_arg_index_key = + OptArgIndexKey::Constant( + self.optimal_index, + 0, + constant.clone(), + overlapping_constants, + ); } _ => { } - }; - } - - fn second_level_index( - indices: IndexMap, - prelude: &mut CodeDeque, - ) -> IndexMap - where - Index: Eq + Hash, - { - let mut index_locs = IndexMap::new(); - - for (key, mut code) in indices.into_iter() { - if code.len() > 1 { - index_locs.insert(key, IntIndex::Internal(prelude.len())); - Self::cap_choice_seq_with_trust(&mut code); - prelude.extend(code.into_iter().map(|code| Line::from(code))); - } else { - code.first().map(|i| { - index_locs.insert(key, IntIndex::External(i.offset())); - }); - } } - - index_locs } - fn no_indices(&self) -> bool { + pub fn no_indices(&self) -> bool { let no_constants = self.constants.is_empty(); let no_structures = self.structures.is_empty(); let no_lists = self.lists.is_empty(); @@ -205,179 +1092,50 @@ impl CodeOffsets { no_constants && no_structures && no_lists } - fn flatten_index(index: IndexMap, len: usize) -> IndexMap - where - Index: Eq + Hash, - { - let mut flattened_index = IndexMap::new(); - - for (key, int_index) in index.into_iter() { - match int_index { - IntIndex::External(offset) => { - flattened_index.insert(key, offset + len + 1); - } - IntIndex::Internal(offset) => { - flattened_index.insert(key, offset + 1); - } - _ => {} - }; - } - - flattened_index - } - - fn adjust_internal_index(index: IntIndex) -> IntIndex { - match index { - IntIndex::Internal(o) => IntIndex::Internal(o + 1), - IntIndex::External(o) => IntIndex::External(o), - _ => IntIndex::Fail, - } - } - - fn switch_on_constant( - con_ind: IndexMap, - prelude: &mut CodeDeque, - optimal_index: usize, - ) -> IntIndex { - let con_ind = Self::second_level_index(con_ind, prelude); - - if con_ind.len() > 1 { - let index = Self::flatten_index(con_ind, prelude.len()); - let instr = IndexingInstruction::SwitchOnConstant( - optimal_index, - index.len(), - index - ); - - prelude.push_front(Line::from(instr)); - - IntIndex::Internal(1) - } else { - con_ind - .values() - .next() - .map(|index| Self::adjust_internal_index(*index)) - .unwrap_or(IntIndex::Fail) - } - } - - fn switch_on_structure( - str_ind: IndexMap<(ClauseName, usize), ThirdLevelIndex>, - prelude: &mut CodeDeque, - optimal_index: usize, - ) -> IntIndex { - let str_ind = Self::second_level_index(str_ind, prelude); - - if str_ind.len() > 1 { - let index = Self::flatten_index(str_ind, prelude.len()); - let instr = IndexingInstruction::SwitchOnStructure( - optimal_index, - index.len(), - index - ); - - prelude.push_front(Line::from(instr)); - - IntIndex::Internal(1) - } else { - str_ind - .values() - .next() - .map(|index| Self::adjust_internal_index(*index)) - .unwrap_or(IntIndex::Fail) - } - } - - fn switch_on_list(mut lists: ThirdLevelIndex, prelude: &mut CodeDeque) -> IntIndex { - if lists.len() > 1 { - Self::cap_choice_seq_with_trust(&mut lists); - prelude.extend(lists.into_iter().map(|i| Line::from(i))); - IntIndex::Internal(0) - } else { - lists - .first() - .map(|i| IntIndex::External(i.offset())) - .unwrap_or(IntIndex::Fail) - } - } - - fn switch_on_str_offset_from( - str_loc: IntIndex, - prelude_len: usize, - con_loc: IntIndex, - ) -> usize { - match str_loc { - IntIndex::External(o) => o + prelude_len + 1, - IntIndex::Fail => 0, - IntIndex::Internal(_) => match con_loc { - IntIndex::Internal(_) => 2, - _ => 1, - }, - } - } - - fn switch_on_con_offset_from(con_loc: IntIndex, prelude_len: usize) -> usize { - match con_loc { - IntIndex::External(offset) => offset + prelude_len + 1, - IntIndex::Fail => 0, - IntIndex::Internal(offset) => offset, - } - } - - fn switch_on_lst_offset_from( - lst_loc: IntIndex, - prelude_len: usize, - ) -> usize { - match lst_loc { - IntIndex::External(o) => o + prelude_len + 1, - IntIndex::Fail => 0, - IntIndex::Internal(_) => 1, // this internal is always 0. - } - } - - pub fn add_indices(self, code: &mut Code, mut code_body: Code, optimal_index: usize) { + pub fn compute_indices(self, skip_stub_try_me_else: bool) -> Vec { if self.no_indices() { - *code = code_body; - return; + return vec![]; } - let mut prelude = VecDeque::new(); + let mut prelude = sdeq![]; - let lst_loc = Self::switch_on_list(self.lists, &mut prelude); - let str_loc = - Self::switch_on_structure(self.structures, &mut prelude, optimal_index); - let con_loc = - Self::switch_on_constant(self.constants, &mut prelude, optimal_index); + let mut lst_loc = switch_on_list(self.lists, &mut prelude); - let prelude_length = prelude.len(); - - for (index, line) in prelude.iter_mut().enumerate() { - match line { - &mut Line::IndexedChoice(IndexedChoiceInstruction::Try(ref mut i)) | - &mut Line::IndexedChoice(IndexedChoiceInstruction::Retry(ref mut i)) | - &mut Line::IndexedChoice(IndexedChoiceInstruction::Trust(ref mut i)) => { - *i += prelude_length - index; - } - _ => { - } - } - } - - let str_loc = Self::switch_on_str_offset_from(str_loc, prelude.len(), con_loc); - let con_loc = Self::switch_on_con_offset_from(con_loc, prelude.len()); - let lst_loc = Self::switch_on_lst_offset_from(lst_loc, prelude.len()); - - let switch_instr = IndexingInstruction::SwitchOnTerm( - optimal_index, - prelude.len() + 1, - con_loc, - lst_loc, - str_loc + let mut str_loc = switch_on( + IndexingInstruction::SwitchOnStructure, + self.structures, + &mut prelude, ); - prelude.push_front(Line::from(switch_instr)); + let con_loc = switch_on( + IndexingInstruction::SwitchOnConstant, + self.constants, + &mut prelude, + ); - *code = Vec::from(prelude); - code.append(&mut code_body); + match &mut str_loc { + IndexingCodePtr::Internal(ref mut i) => { + *i += con_loc.is_internal() as usize; + } + _ => { + } + }; + + match &mut lst_loc { + IndexingCodePtr::Internal(ref mut i) => { + *i += con_loc.is_internal() as usize; + *i += str_loc.is_internal() as usize; + } + _ => { + } + }; + + let var_offset = 1 + skip_stub_try_me_else as usize; + + prelude.push_front(IndexingLine::from( + IndexingInstruction::SwitchOnTerm(self.optimal_index, var_offset, con_loc, lst_loc, str_loc) + )); + + prelude.into_iter().collect() } } diff --git a/src/instructions.rs b/src/instructions.rs index c3de3469..d27d120a 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -1,7 +1,8 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::clause_types::*; use crate::forms::*; +use crate::indexing::IndexingCodePtr; use crate::machine::heap::*; use crate::machine::machine_errors::MachineStub; use crate::machine::machine_indices::*; @@ -9,7 +10,8 @@ use crate::rug::Integer; use crate::indexmap::IndexMap; -use std::collections::VecDeque; +use slice_deque::SliceDeque; + use std::rc::Rc; fn reg_type_into_functor(r: RegType) -> MachineStub { @@ -48,9 +50,9 @@ impl ArithmeticTerm { #[derive(Debug)] pub enum ChoiceInstruction { DefaultRetryMeElse(usize), - DefaultTrustMe, + DefaultTrustMe(usize), RetryMeElse(usize), - TrustMe, + TrustMe(usize), TryMeElse(usize), } @@ -63,14 +65,14 @@ impl ChoiceInstruction { &ChoiceInstruction::RetryMeElse(offset) => { functor!("retry_me_else", [integer(offset)]) } - &ChoiceInstruction::TrustMe => { - functor!("trust_me") + &ChoiceInstruction::TrustMe(offset) => { + functor!("trust_me", [integer(offset)]) } &ChoiceInstruction::DefaultRetryMeElse(offset) => { functor!("default_retry_me_else", [integer(offset)]) } - &ChoiceInstruction::DefaultTrustMe => { - functor!("default_trust_me") + &ChoiceInstruction::DefaultTrustMe(offset) => { + functor!("default_trust_me", [integer(offset)]) } } } @@ -106,19 +108,13 @@ impl CutInstruction { } } -#[derive(Debug)] +#[derive(Clone, Copy, Debug)] pub enum IndexedChoiceInstruction { Retry(usize), Trust(usize), Try(usize), } -impl From for Line { - fn from(i: IndexedChoiceInstruction) -> Self { - Line::IndexedChoice(i) - } -} - impl IndexedChoiceInstruction { pub fn offset(&self) -> usize { match self { @@ -144,6 +140,26 @@ impl IndexedChoiceInstruction { } /// A `Line` is an instruction (cf. page 98 of wambook). +#[derive(Debug)] +pub enum IndexingLine { + Indexing(IndexingInstruction), + IndexedChoice(SliceDeque), +} + +impl From for IndexingLine { + #[inline] + fn from(instr: IndexingInstruction) -> Self { + IndexingLine::Indexing(instr) + } +} + +impl From> for IndexingLine { + #[inline] + fn from(instrs: SliceDeque) -> Self { + IndexingLine::IndexedChoice(instrs) + } +} + #[derive(Debug)] pub enum Line { Arithmetic(ArithmeticInstruction), @@ -151,12 +167,13 @@ pub enum Line { Control(ControlInstruction), Cut(CutInstruction), Fact(FactInstruction), - Indexing(IndexingInstruction), + IndexingCode(Vec), IndexedChoice(IndexedChoiceInstruction), Query(QueryInstruction), } impl Line { + #[inline] pub fn is_head_instr(&self) -> bool { match self { &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) { match self { - &Line::Arithmetic(ref arith_instr) => arith_instr.to_functor(h), - &Line::Choice(ref choice_instr) => choice_instr.to_functor(), - &Line::Control(ref control_instr) => control_instr.to_functor(), - &Line::Cut(ref cut_instr) => cut_instr.to_functor(h), - &Line::Fact(ref fact_instr) => fact_instr.to_functor(h), - &Line::Indexing(ref indexing_instr) => indexing_instr.to_functor(), - &Line::IndexedChoice(ref indexed_choice_instr) => indexed_choice_instr.to_functor(), - &Line::Query(ref query_instr) => query_instr.to_functor(h), + &Line::Arithmetic(ref arith_instr) => + functors.push(arith_instr.to_functor(h)), + &Line::Choice(ref choice_instr) => + functors.push(choice_instr.to_functor()), + &Line::Control(ref control_instr) => + functors.push(control_instr.to_functor()), + &Line::Cut(ref cut_instr) => + 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> { + match line { + Line::IndexingCode(ref mut indexing_code) => { + Some(indexing_code) + } + _ => { + None + } + } +} + +#[inline] +pub fn to_indexing_line(line: &Line) -> Option<&Vec> { + match line { + Line::IndexingCode(ref indexing_code) => { + Some(indexing_code) + } + _ => { + None } } } @@ -386,6 +451,9 @@ pub enum ControlInstruction { CallClause(ClauseType, usize, usize, bool, bool), Deallocate, 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, } @@ -418,6 +486,9 @@ impl ControlInstruction { &ControlInstruction::JmpBy(_, offset, ..) => { functor!("jmp_by", [integer(offset)]) } + &ControlInstruction::RevJmpBy(offset) => { + functor!("rev_jmp_by", [integer(offset)]) + } &ControlInstruction::Proceed => { functor!("proceed") } @@ -429,40 +500,94 @@ impl ControlInstruction { #[derive(Debug)] pub enum IndexingInstruction { // The first index is the optimal argument being indexed. - SwitchOnTerm(usize, usize, usize, usize, usize), - SwitchOnConstant(usize, usize, IndexMap), - SwitchOnStructure(usize, usize, IndexMap<(ClauseName, usize), usize>), -} - -impl From for Line { - fn from(i: IndexingInstruction) -> Self { - Line::Indexing(i) - } + SwitchOnTerm(usize, usize, IndexingCodePtr, IndexingCodePtr, IndexingCodePtr), + SwitchOnConstant(IndexMap), + SwitchOnStructure(IndexMap<(ClauseName, usize), IndexingCodePtr>), } impl IndexingInstruction { - pub fn to_functor(&self) -> MachineStub { + pub fn to_functor(&self, mut h: usize) -> MachineStub { match self { &IndexingInstruction::SwitchOnTerm(arg, vars, constants, lists, structures) => { functor!( "switch_on_term", [integer(arg), integer(vars), - integer(constants), - integer(lists), - integer(structures)] + indexing_code_ptr(h, constants), + indexing_code_ptr(h, lists), + 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!( "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!( "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; -pub type ThirdLevelIndex = Vec; - pub type Code = Vec; - -pub type CodeDeque = VecDeque; diff --git a/src/iterators.rs b/src/iterators.rs index 218ed78e..a3b5956b 100644 --- a/src/iterators.rs +++ b/src/iterators.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::clause_types::*; use crate::forms::*; @@ -481,7 +481,7 @@ impl<'a> ChunkedIterator<'a> { } })) } - +/* pub fn from_term_sequence(terms: &'a [QueryTerm]) -> Self { ChunkedIterator { chunk_num: 0, @@ -490,7 +490,7 @@ impl<'a> ChunkedIterator<'a> { cut_var_in_head: false, } } - +*/ pub fn from_rule_body(p1: &'a QueryTerm, clauses: &'a Vec) -> Self { let inner_iter = Box::new(once(ChunkedTerm::BodyTerm(p1))); let iter = inner_iter.chain(clauses.iter().map(|t| ChunkedTerm::BodyTerm(t))); diff --git a/src/lib/atts.pl b/src/lib/atts.pl index fbf440d0..8fa16e11 100644 --- a/src/lib/atts.pl +++ b/src/lib/atts.pl @@ -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, '$absent_attr'/2, '$copy_attr_list'/2, '$get_attr'/2, '$put_attr'/2, '$absent_from_list'/2, @@ -19,9 +20,7 @@ ). '$default_attr_list'([PG | PGs], Module, AttrVar) --> - ( { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)] - ; { true } - ), + [Module:put_atts(AttrVar, PG)], '$default_attr_list'(PGs, Module, AttrVar). '$default_attr_list'([], _, _) --> []. @@ -66,7 +65,8 @@ '$del_attr_step'(Ls1, V, Attr) :- ( nonvar(Ls1) -> Ls1 = [_ | Ls2], '$del_attr_buried'(Ls1, Ls2, V, Attr) - ; true ). + ; true + ). %% assumptions: Ls0 is a list, Ls1 is its tail; %% the head of Ls0 can be ignored. @@ -75,8 +75,8 @@ ; Ls1 = [Att | Ls2] -> ( Att \= Attr -> '$del_attr_buried'(Ls1, Ls2, V, Attr) ; '$enqueue_attr_var'(V), - '$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_non_head'(Ls0), %% set tail of Ls0 = tail of Ls1. can be undone by backtracking. + '$del_attr_step'(Ls1, V, Attr) ) ). @@ -88,66 +88,66 @@ user:term_expansion(Term0, Terms) :- nonvar(Term0), Term0 = (:- attribute 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(Atts), + put_attrs(Atts, Module), get_attrs_var_check, - get_attrs(Atts). + get_attrs(Atts, Module). 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) :- var(Attr), throw(error(instantiation_error, put_atts/2)))]. 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) :- var(Attr), !, '$get_attr_list'(Var, Ls), nonvar(Ls), '$copy_attr_list'(Ls, Attr))]. -put_attrs(Name/Arity) --> - put_attr(Name, Arity), - { numbervars([Var, Attr], 0, _) }, +put_attrs(Name/Arity, Module) --> + put_attr(Name, Arity, Module), [(put_atts(Var, Attr) :- lists:maplist(put_atts(Var), Attr), !)]. -put_attrs((Name/Arity, Atts)) --> +put_attrs((Name/Arity, Atts), Module) --> { nonvar(Atts) }, - put_attr(Name, Arity), - put_attrs(Atts). + put_attr(Name, Arity, Module), + put_attrs(Atts, Module). -get_attrs(Name/Arity) --> - get_attr(Name, Arity). -get_attrs((Name/Arity, Atts)) --> +get_attrs(Name/Arity, Module) --> + get_attr(Name, Arity, Module). +get_attrs((Name/Arity, Atts), Module) --> { nonvar(Atts) }, - get_attr(Name, Arity), - get_attrs(Atts). + get_attr(Name, Arity, Module), + get_attrs(Atts, Module). -put_attr(Name, Arity) --> - { functor(Attr, Name, Arity), - numbervars(Attr, 0, Arity), - V = '$VAR'(Arity) }, - [(put_atts(V, +Attr) :- !, functor(Attr, Head, Arity), - functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), - '$del_attr'(Ls, V, AttrForm), - '$put_attr'(V, Attr)), - (put_atts(V, Attr) :- !, functor(Attr, Head, Arity), - functor(AttrForm, Head, Arity), - '$get_attr_list'(V, Ls), - '$del_attr'(Ls, V, AttrForm), - '$put_attr'(V, Attr)), - (put_atts(V, -Attr) :- !, functor(Attr, _, _), - '$get_attr_list'(V, Ls), - '$del_attr'(Ls, V, Attr))]. +put_attr(Name, Arity, Module) --> + { functor(Attr, Name, Arity) }, + [(put_atts(V, +Attr) :- + !, + functor(Attr, Head, Arity), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + '$del_attr'(Ls, V, Module:AttrForm), + '$put_attr'(V, Module:Attr)), + (put_atts(V, Attr) :- + !, + functor(Attr, Head, Arity), + functor(AttrForm, Head, Arity), + '$get_attr_list'(V, Ls), + '$del_attr'(Ls, V, Module:AttrForm), + '$put_attr'(V, Module:Attr)), + (put_atts(V, -Attr) :- + !, + functor(Attr, _, _), + '$get_attr_list'(V, Ls), + '$del_attr'(Ls, V, Module:Attr))]. -get_attr(Name, Arity) --> - { functor(Attr, Name, Arity), - numbervars(Attr, 0, Arity), - V = '$VAR'(Arity) }, - [(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)), - (get_atts(V, Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Attr)), - (get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Attr))]. +get_attr(Name, Arity, Module) --> + { functor(Attr, Name, Arity) }, + [(get_atts(V, +Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)), + (get_atts(V, Attr) :- !, functor(Attr, _, _), '$get_attr'(V, Module:Attr)), + (get_atts(V, -Attr) :- !, functor(Attr, _, _), '$absent_attr'(V, Module:Attr))]. user:goal_expansion(Term, M:put_atts(Var, Attr)) :- nonvar(Term), diff --git a/src/lib/builtins.pl b/src/lib/builtins.pl index 3d7aa79f..3aba986b 100644 --- a/src/lib/builtins.pl +++ b/src/lib/builtins.pl @@ -1,45 +1,3 @@ -:- op(400, yfx, /). - -% module resolution operator. -:- op(600, xfy, :). - -user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- - '$expand_op_list'([Op | OtherOps], Pred, Spec, OpResults). - -'$expand_op_list'([], _, _, []). -'$expand_op_list'([Op | OtherOps], Pred, Spec, [(:- op(Pred, Spec, Op)) | OtherResults]) :- - '$expand_op_list'(OtherOps, Pred, Spec, OtherResults). - -/* 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(400, yfx, *). -:- op(200, xfy, [**, ^]). -:- op(500, yfx, [/\, \/, xor]). -:- op(400, yfx, [div, //, rdiv, <<, >>, mod, rem]). -:- op(200, fy, [+, -, \]). - -:- op(1200, xfx, -->). - -% arithmetic comparison operators. -:- op(700, xfx, [>, <, =\=, =:=, >=, =<]). - -% term comparison. -:- op(700, xfx, [==, \==, @=<, @>=, @<, @>]). - -% conditional operators. -:- op(1050, xfy, ->). -:- op(1100, xfy, ;). - -% control. -:- op(700, xfx, [=, =.., \=]). -:- op(900, fy, \+). - :- module(builtins, [(=)/2, (\=)/2, (\+)/1, (',')/2, (->)/2, (;)/2, (=..)/2, (:)/2, (:)/3, (:)/4, (:)/5, (:)/6, (:)/7, (:)/8, (:)/9, (:)/10, (:)/11, (:)/12, @@ -50,21 +8,21 @@ user:term_expansion((:- op(Pred, Spec, [Op | OtherOps])), OpResults) :- clause/2, close/1, close/2, current_input/1, current_output/1, current_op/3, current_predicate/1, current_prolog_flag/2, - expand_goal/2, expand_term/2, fail/0, false/0, - findall/3, findall/4, flush_output/0, - flush_output/1, get_byte/1, get_byte/2, - get_char/1, get_char/2, get_code/1, get_code/2, - halt/0, halt/1, max_arity/1, number_chars/2, - number_codes/2, once/1, op/3, open/3, open/4, - peek_byte/1, peek_byte/2, peek_char/1, - peek_char/2, peek_code/1, peek_code/2, - put_byte/1, put_byte/2, put_code/1, put_code/2, - put_char/1, put_char/2, read_term/2, read_term/3, - repeat/0, retract/1, set_prolog_flag/2, - set_input/1, set_stream_position/2, set_output/1, - setof/3, stream_property/2, sub_atom/5, - subsumes_term/2, term_variables/2, throw/1, - true/0, unify_with_occurs_check/2, write/1, + fail/0, false/0, findall/3, findall/4, + flush_output/0, flush_output/1, get_byte/1, + get_byte/2, get_char/1, get_char/2, get_code/1, + get_code/2, halt/0, halt/1, max_arity/1, + number_chars/2, number_codes/2, once/1, op/3, + open/3, open/4, peek_byte/1, peek_byte/2, + peek_char/1, peek_char/2, peek_code/1, + peek_code/2, put_byte/1, put_byte/2, put_code/1, + put_code/2, put_char/1, put_char/2, read_term/2, + read_term/3, repeat/0, retract/1, + set_prolog_flag/2, set_input/1, + set_stream_position/2, set_output/1, setof/3, + stream_property/2, sub_atom/5, subsumes_term/2, + term_variables/2, throw/1, true/0, + unify_with_occurs_check/2, write/1, write_canonical/1, write_term/2, write_term/3, writeq/1]). @@ -80,13 +38,16 @@ true. false :- '$fail'. -% dynamic module resolution. - Module : Predicate :- - ( atom(Module) -> '$module_call'(Module, Predicate) - ; throw(error(type_error(atom, Module), (:)/2)) + ( atom(Module) -> + '$module_call'(Module, Predicate) + ; + throw(error(type_error(atom, Module), (:)/2)) ). + +% dynamic module resolution. + :(Module, Predicate, A1) :- ( atom(Module) -> '$module_call'(A1, Module, Predicate) ; throw(error(type_error(atom, Module), (:)/2)) @@ -137,7 +98,6 @@ Module : Predicate :- ; throw(error(type_error(atom, Module), (:)/2)) ). - % flags. current_prolog_flag(Flag, false) :- Flag == bounded, !. @@ -171,7 +131,7 @@ set_prolog_flag(min_integer, Value) :- set_prolog_flag(integer_rounding_function, down) :- !. % 7.11.1.4 set_prolog_flag(integer_rounding_function, Value) :- throw(error(domain_error(flag_value, integer_rounding_function + Value), - set_prolog_flag/2)). % 8.17.1.3 e + set_prolog_flag/2)). % 8.17.1.3 e set_prolog_flag(double_quotes, chars) :- !, '$set_double_quotes'(chars). % 7.11.2.5, list of one-char atoms. set_prolog_flag(double_quotes, atom) :- @@ -180,7 +140,7 @@ set_prolog_flag(double_quotes, codes) :- !, '$set_double_quotes'(codes). set_prolog_flag(double_quotes, Value) :- throw(error(domain_error(flag_value, double_quotes + Value), - set_prolog_flag/2)). % 8.17.1.3 e + set_prolog_flag/2)). % 8.17.1.3 e set_prolog_flag(Flag, _) :- atom(Flag), throw(error(domain_error(prolog_flag, Flag), set_prolog_flag/2)). % 8.17.1.3 d @@ -192,6 +152,8 @@ set_prolog_flag(Flag, _) :- fail :- '$fail'. +:- meta_predicate \+(0). + \+ G :- call(G), !, false. \+ _. @@ -200,6 +162,8 @@ X \= X :- !, false. _ \= _. +:- meta_predicate once(0). + once(G) :- call(G), !. @@ -207,6 +171,20 @@ repeat. repeat :- repeat. + +:- meta_predicate ','(0, 0). + +:- meta_predicate ','(0, +, +). + +:- meta_predicate ;(0, 0). + +:- meta_predicate ;(0, 0, +). + +:- meta_predicate ->(0, 0). + +:- meta_predicate ->(0, 0, +). + + ','(G1, G2) :- '$get_b_value'(B), ( '$call_with_default_policy'(var(G1)) -> @@ -321,19 +299,26 @@ call_or_cut(G, _) :- univ_errors(Term, List, N) :- '$skip_max_list'(N, -1, List, R), ( var(R) -> - ( var(Term), throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) - ; true - ) + ( var(Term), + throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 a) + ; true + ) ; R \== [] -> throw(error(type_error(list, List), (=..)/2)) % 8.5.3.3 b) ; List = [H|T] -> - ( var(H), var(Term), % R == [] => List is a proper list. + ( var(H), + var(Term), % R == [] => List is a proper list. throw(error(instantiation_error, (=..)/2)) % 8.5.3.3 c) - ; T \== [], nonvar(H), \+ atom(H), + ; T \== [], + nonvar(H), + \+ atom(H), throw(error(type_error(atom, H), (=..)/2)) % 8.5.3.3 d) - ; compound(H), T == [], + ; compound(H), + T == [], throw(error(type_error(atomic, H), (=..)/2)) % 8.5.3.3 e) - ; var(Term), max_arity(M), N - 1 > M, + ; var(Term), + max_arity(M), + N - 1 > M, throw(error(representation_error(max_arity), (=..)/2)) % 8.5.3.3 g) ; true ) @@ -342,14 +327,17 @@ univ_errors(Term, List, N) :- ; true ). -Term =.. List :- '$call_with_default_policy'(univ_errors(Term, List, N)), - '$call_with_default_policy'(univ_worker(Term, List, N)). +Term =.. List :- + '$call_with_default_policy'(univ_errors(Term, List, N)), + '$call_with_default_policy'(univ_worker(Term, List, N)). :- non_counted_backtracking univ_worker/3. univ_worker(Term, List, _) :- - atomic(Term), !, '$call_with_default_policy'(List = [Term]). + atomic(Term), + !, + '$call_with_default_policy'(List = [Term]). univ_worker(Term, [Name|Args], N) :- var(Term), !, '$call_with_default_policy'(Arity is N-1), @@ -364,46 +352,78 @@ univ_worker(Term, List, _) :- :- non_counted_backtracking get_args/4. get_args(Args, _, _, 0) :- - !, '$call_with_default_policy'(Args = []). + !, + '$call_with_default_policy'(Args = []). get_args([Arg], Func, N, N) :- - !, '$call_with_default_policy'(arg(N, Func, Arg)). + !, + '$call_with_default_policy'(arg(N, Func, Arg)). get_args([Arg|Args], Func, I0, N) :- '$call_with_default_policy'(arg(I0, Func, Arg)), '$call_with_default_policy'(I1 is I0 + 1), '$call_with_default_policy'(get_args(Args, Func, I1, N)). + +:- meta_predicate parse_options_list(?, 0, ?, ?, ?). + +parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- + '$skip_max_list'(_, -1, Options, Tail), + ( Tail == [] -> + true + ; var(Tail) -> + throw(error(instantiation_error, Stub)) % 8.11.5.3c) + ; Tail \== [] -> + throw(error(type_error(list, Options), Stub)) % 8.11.5.3e) + ), + ( lists:maplist(nonvar, Options), + catch(lists:maplist(Selector, Options, OptionPairs0), + error(E, _), + builtins:throw(error(E, Stub))) -> + lists:append(DefaultPairs, OptionPairs0, OptionPairs1), + keysort(OptionPairs1, OptionPairs), + select_rightmost_options(OptionPairs, OptionValues) + ; + throw(error(instantiation_error, Stub)) % 8.11.5.3c) + ). + + parse_write_options(Options, OptionValues, Stub) :- DefaultOptions = [ignore_ops-false, max_depth-0, numbervars-false, quoted-false, variable_names-[]], - parse_options_list(Options, parse_write_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_write_options_, DefaultOptions, OptionValues, Stub). parse_write_options_(ignore_ops(IgnoreOps), ignore_ops-IgnoreOps) :- - ( nonvar(IgnoreOps), lists:member(IgnoreOps, [true, false]) + ( nonvar(IgnoreOps), + lists:member(IgnoreOps, [true, false]) ; throw(error(domain_error(write_option, ignore_ops(IgnoreOps)), _)) ). parse_write_options_(quoted(Quoted), quoted-Quoted) :- - ( nonvar(Quoted), lists:member(Quoted, [true, false]) + ( nonvar(Quoted), + lists:member(Quoted, [true, false]) ; throw(error(domain_error(write_option, quoted(Quoted)), _)) ). parse_write_options_(numbervars(NumberVars), numbervars-NumberVars) :- - ( nonvar(NumberVars), lists:member(NumberVars, [true, false]) + ( nonvar(NumberVars), + lists:member(NumberVars, [true, false]) ; throw(error(domain_error(write_option, numbervars(NumberVars)), _)) ). parse_write_options_(variable_names(VNNames), variable_names-VNNames) :- must_be_var_names_list(VNNames). parse_write_options_(max_depth(MaxDepth), max_depth-MaxDepth) :- - ( integer(MaxDepth), MaxDepth >= 0 + ( integer(MaxDepth), + MaxDepth >= 0 ; throw(error(domain_error(write_option, max_depth(MaxDepth)), _)) ). must_be_var_names_list(VarNames) :- '$skip_max_list'(_, -1, VarNames, Tail), - ( Tail == [] -> must_be_var_names_list_(VarNames, VarNames) - ; var(Tail) -> throw(error(instantiation_error, write_term/2)) + ( Tail == [] -> + must_be_var_names_list_(VarNames, VarNames) + ; var(Tail) -> + throw(error(instantiation_error, write_term/2)) ; throw(error(domain_error(write_option, variable_names(VarNames)), write_term/2)) ). @@ -411,8 +431,10 @@ must_be_var_names_list_([], List). must_be_var_names_list_([VarName | VarNames], List) :- ( nonvar(VarName) -> ( VarName = (Atom = _) -> - ( atom(Atom) -> must_be_var_names_list_(VarNames, List) - ; var(Atom) -> throw(error(instantiation_error, write_term/2)) + ( atom(Atom) -> + must_be_var_names_list_(VarNames, List) + ; var(Atom) -> + throw(error(instantiation_error, write_term/2)) ; throw(error(domain_error(write_option, variable_names(List)), write_term/2)) ) ; throw(error(domain_error(write_option, variable_names(List)), write_term/2)) @@ -455,30 +477,9 @@ select_rightmost_options([Option-Value | OptionPairs], OptionValues) :- select_rightmost_options([], []). -parse_options_list(Options, Selector, DefaultPairs, OptionValues, Stub) :- - '$skip_max_list'(_, -1, Options, Tail), - ( Tail == [] -> - true - ; var(Tail) -> - throw(error(instantiation_error, Stub)) % 8.11.5.3c) - ; Tail \== [] -> - throw(error(type_error(list, Options), Stub)) % 8.11.5.3e) - ), - ( lists:maplist(nonvar, Options), - catch(lists:maplist(Selector, Options, OptionPairs0), - error(E, _), - throw(error(E, Stub))) -> - lists:append(DefaultPairs, OptionPairs0, OptionPairs1), - keysort(OptionPairs1, OptionPairs), - select_rightmost_options(OptionPairs, OptionValues) - ; - throw(error(instantiation_error, Stub)) % 8.11.5.3c) - ). - - parse_read_term_options(Options, OptionValues, Stub) :- DefaultOptions = [singletons-_, variables-_, variable_names-_], - parse_options_list(Options, parse_read_term_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_read_term_options_, DefaultOptions, OptionValues, Stub). parse_read_term_options_(singletons(Vars), singletons-Vars). @@ -498,20 +499,21 @@ read_term(Term, Options) :- read_term(Stream, Term, Options). -% expand_goal. - -expand_goal(Term0, Term) :- '$expand_goal'(Term0, Term). - -% expand_term. - -expand_term(Term0, Term) :- '$expand_term'(Term0, Term). - % term_variables. % ensures List is either a variable or a list. -can_be_list(List, _) :- var(List), !. -can_be_list(List, _) :- '$skip_max_list'(_, -1, List, Tail), ( var(Tail) -> true ; Tail == []), !. -can_be_list(List, PI) :- throw(error(type_error(list, List), PI)). +can_be_list(List, _) :- + var(List), + !. +can_be_list(List, _) :- + '$skip_max_list'(_, -1, List, Tail), + ( var(Tail) -> + true + ; Tail == [] + ), + !. +can_be_list(List, PI) :- + throw(error(type_error(list, List), PI)). term_variables(Term, Vars) :- can_be_list(Vars, term_variables/2), @@ -519,7 +521,14 @@ term_variables(Term, Vars) :- % exceptions. -catch(G,C,R) :- '$get_current_block'(Bb), '$call_with_default_policy'(catch(G,C,R,Bb)). +:- meta_predicate catch(0, ?, 0). + +catch(G,C,R) :- + '$get_current_block'(Bb), + '$call_with_default_policy'(catch(G,C,R,Bb)). + + +:- meta_predicate catch(0, ?, 0, +). :- non_counted_backtracking catch/4. catch(G,C,R,Bb) :- @@ -531,16 +540,30 @@ catch(G,C,R,Bb) :- '$get_ball'(Ball), '$call_with_default_policy'(handle_ball(Ball, C, R)). + :- non_counted_backtracking end_block/2. -end_block(Bb, NBb) :- '$clean_up_block'(NBb), '$reset_block'(Bb). -end_block(Bb, NBb) :- '$reset_block'(NBb), '$fail'. +end_block(Bb, NBb) :- + '$clean_up_block'(NBb), + '$reset_block'(Bb). +end_block(Bb, NBb) :- + '$reset_block'(NBb), + '$fail'. + +:- meta_predicate handle_ball(?, ?, 0). :- non_counted_backtracking handle_ball/3. -handle_ball(C, C, R) :- !, '$erase_ball', call(R). -handle_ball(_, _, _) :- '$unwind_stack'. +handle_ball(C, C, R) :- + !, + '$erase_ball', + call(R). +handle_ball(_, _, _) :- + '$unwind_stack'. throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'. + +% :- meta_predicate '$iterate_find_all'(?, 0, ?, ?). + :- non_counted_backtracking '$iterate_find_all'/4. '$iterate_find_all'(Template, Goal, _, LhOffset) :- call(Goal), @@ -550,14 +573,23 @@ throw(Ball) :- '$set_ball'(Ball), '$unwind_stack'. '$truncate_if_no_lh_growth'(LhOffset), '$get_lh_from_offset'(LhOffset, Solutions). + truncate_lh_to(LhLength) :- '$truncate_lh_to'(LhLength). + +:- meta_predicate findall(?, 0, ?). + findall(Template, Goal, Solutions) :- error:can_be(list, Solutions), '$lh_length'(LhLength), - '$call_with_default_policy'(catch('$iterate_find_all'(Template, Goal, Solutions, LhLength), - Error, - ( truncate_lh_to(LhLength), throw(Error) ))). + '$call_with_default_policy'( + catch(builtins:'$iterate_find_all'(Template, Goal, Solutions, LhLength), + Error, + ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) )) + ). + + +% :- meta_predicate '$iterate_find_all_diff'(?, 0, ?, ?, ?). :- non_counted_backtracking '$iterate_find_all_diff'/5. '$iterate_find_all_diff'(Template, Goal, _, _, LhOffset) :- @@ -569,14 +601,16 @@ findall(Template, Goal, Solutions) :- '$get_lh_from_offset_diff'(LhOffset, Solutions0, Solutions1). +% :- meta_predicate findall(?, 0, ?, ?). + findall(Template, Goal, Solutions0, Solutions1) :- error:can_be(list, Solutions0), error:can_be(list, Solutions1), '$lh_length'(LhLength), - '$call_with_default_policy'(catch('$iterate_find_all_diff'(Template, Goal, Solutions0, - Solutions1, LhLength), - Error, - ( truncate_lh_to(LhLength), throw(Error) ))). + '$call_with_default_policy'(catch(builtins:'$iterate_find_all_diff'(Template, Goal, Solutions0, + Solutions1, LhLength), + Error, + ( builtins:truncate_lh_to(LhLength), builtins:throw(Error) ))). set_difference([X|Xs], [Y|Ys], Zs) :- X == Y, !, set_difference(Xs, [Y|Ys], Zs). @@ -588,7 +622,10 @@ set_difference([], _, []) :- !. set_difference(Xs, [], Xs). group_by_variant([V2-S2 | Pairs], V1-S1, [S2 | Solutions], Pairs0) :- - iso_ext:variant(V1, V2), !, V1 = V2, group_by_variant(Pairs, V2-S2, Solutions, Pairs0). + iso_ext:variant(V1, V2), + !, + V1 = V2, + group_by_variant(Pairs, V2-S2, Solutions, Pairs0). group_by_variant(Pairs, _, [], Pairs). group_by_variants([V-S|Pairs], [V-Solution|Solutions]) :- @@ -611,8 +648,12 @@ rightmost_power(Term, FinalTerm, Xs) :- ; Xs = [], FinalTerm = Term ). + +% :- meta_predicate findall_with_existential(?, 0, ?, ?, ?). + findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) :- - ( nonvar(Goal), Goal = _ ^ _ -> + ( nonvar(Goal), + Goal = _ ^ _ -> rightmost_power(Goal, Goal1, ExistentialVars0), term_variables(ExistentialVars0, ExistentialVars), sort(Witnesses0, Witnesses1), @@ -623,6 +664,9 @@ findall_with_existential(Template, Goal, PairedSolutions, Witnesses0, Witnesses) findall(Witnesses-Template, Goal, PairedSolutions) ). + +:- meta_predicate bagof(?, 0, ?). + bagof(Template, Goal, Solution) :- error:can_be(list, Solution), term_variables(Template, TemplateVars0), @@ -643,6 +687,9 @@ iterate_variants_and_sort([V-Solution0|GroupSolutions], V, Solution) :- iterate_variants_and_sort([_|GroupSolutions], Ws, Solution) :- iterate_variants_and_sort(GroupSolutions, Ws, Solution). + +:- meta_predicate setof(?, 0, ?). + setof(Template, Goal, Solution) :- error:can_be(list, Solution), term_variables(Template, TemplateVars0), @@ -659,36 +706,47 @@ setof(Template, Goal, Solution) :- '$clause_body_is_valid'(B) :- ( var(B) -> true - ; functor(B, Name, _) -> ( atom(Name), Name \== '.' -> true - ; throw(error(type_error(callable, B), clause/2)) - ) + ; functor(B, Name, _) -> + ( atom(Name), Name \== '.' -> true + ; throw(error(type_error(callable, B), clause/2)) + ) ; throw(error(type_error(callable, B), clause/2)) ). '$module_clause'(H, B, Module) :- ( var(H) -> throw(error(instantiation_error, clause/2)) - ; functor(H, Name, Arity) -> ( Name == '.' -> throw(error(type_error(callable, H), clause/2)) - ; '$module_head_is_dynamic'(H, Module) -> - '$clause_body_is_valid'(B), - '$get_module_clause'(H, B, Module) - ; throw(error(permission_error(access, private_procedure, Name/Arity), - clause/2)) - ) + ; functor(H, Name, Arity) -> + ( Name == '.' -> + throw(error(type_error(callable, H), clause/2)) + ; '$head_is_dynamic'(Module, H) -> + '$clause_body_is_valid'(B), + Module:'$clause'(H, B) %%TODO: how do we show this exists? + ; throw(error(permission_error(access, private_procedure, Name/Arity), + clause/2)) + ) ; throw(error(type_error(callable, H), clause/2)) ). + +:- dynamic('$clause'/2). + clause(H, B) :- - ( var(H) -> throw(error(instantiation_error, clause/2)) + ( var(H) -> + throw(error(instantiation_error, clause/2)) ; functor(H, Name, Arity) -> - ( Name == '.' -> throw(error(type_error(callable, H), clause/2)) - ; Name == (:), Arity =:= 2 -> + ( Name == '.' -> + throw(error(type_error(callable, H), clause/2)) + ; Name == (:), + Arity =:= 2 -> arg(1, H, Module), arg(2, H, F), '$module_clause'(F, B, Module) - %% '$no_such_predicate' fails if H is not callable. - ; '$no_such_predicate'(H) -> '$fail' - ; '$head_is_dynamic'(H) -> '$clause_body_is_valid'(B), - '$get_clause'(H, B) + ; '$no_such_predicate'(user, H) -> %% '$no_such_predicate' fails if + %% H is not callable. + '$fail' + ; '$head_is_dynamic'(user, H) -> + '$clause_body_is_valid'(B), + '$clause'(H, B) ; throw(error(permission_error(access, private_procedure, Name/Arity), clause/2)) ) @@ -698,19 +756,21 @@ clause(H, B) :- call_module_asserta(Head, Body, Name, Arity, Module) :- '$clause_body_is_valid'(Body), functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses), + findall((VarHead :- VarBody), builtins:clause(Module:VarHead, VarBody), Clauses), '$module_asserta'((Head :- Body), Clauses, Name, Arity, Module). call_asserta(Head, Body, Name, Arity) :- '$clause_body_is_valid'(Body), functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses), - '$asserta'((Head :- Body), Clauses, Name, Arity). + '$asserta'(Head, Body, Name, Arity). module_asserta_clause(Head, Body, Module) :- ( var(Head) -> throw(error(instantiation_error, asserta/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( '$module_head_is_dynamic'(Head, Module) -> call_module_asserta(Head, Body, Name, Arity, Module) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( '$module_head_is_dynamic'(Head, Module) -> + call_module_asserta(Head, Body, Name, Arity, Module) ; throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1)) ) ; throw(error(type_error(callable, Head), asserta/1)) @@ -718,166 +778,218 @@ module_asserta_clause(Head, Body, Module) :- asserta_clause(Head, Body) :- ( var(Head) -> throw(error(instantiation_error, asserta/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( Name == (:), Arity =:= 2 -> - arg(1, Head, Module), - arg(2, Head, F), - module_asserta_clause(F, Body, Module) - ; '$no_such_predicate'(Head) -> call_asserta(Head, Body, Name, Arity) - ; '$head_is_dynamic'(Head) -> call_asserta(Head, Body, Name, Arity) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( Name == (:), + Arity =:= 2 -> + arg(1, Head, Module), + arg(2, Head, F), + module_asserta_clause(F, Body, Module) + ; '$no_such_predicate'(user, Head) -> + call_asserta(Head, Body, Name, Arity) + ; '$head_is_dynamic'(user, Head) -> + call_asserta(Head, Body, Name, Arity) ; throw(error(permission_error(modify, static_procedure, Name/Arity), asserta/1)) ) ; throw(error(type_error(callable, Head), asserta/1)) ). asserta(Clause) :- - ( Clause \= (_ :- _) -> Head = Clause, Body = true, asserta_clause(Head, Body) - ; Clause = (Head :- Body) -> asserta_clause(Head, Body) + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, asserta_clause(Head, Body) + ; Clause = (Head :- Body) -> + asserta_clause(Head, Body) ). +% NOT MODIFIED. call_module_assertz(Head, Body, Name, Arity, Module) :- '$clause_body_is_valid'(Body), functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses), + findall((VarHead :- VarBody), builtins:clause(Module:VarHead, VarBody), Clauses), '$module_assertz'((Head :- Body), Clauses, Name, Arity, Module). -call_assertz(Head, Body, Name, Arity) :- - '$clause_body_is_valid'(Body), - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses), - '$assertz'((Head :- Body), Clauses, Name, Arity). - module_assertz_clause(Head, Body, Module) :- - ( var(Head) -> throw(error(instantiation_error, assertz/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( '$module_head_is_dynamic'(Head, Module) -> call_module_assertz(Head, Body, Name, Arity, Module) + ( var(Head) -> + throw(error(instantiation_error, assertz/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( '$head_is_dynamic'(Module, Head) -> + call_module_assertz(Head, Body, Name, Arity, Module) ; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1)) ) ; throw(error(type_error(callable, Head), assertz/1)) ). +% MODIFIED. +call_assertz(Head, Body, Name, Arity) :- + '$clause_body_is_valid'(Body), + functor(VarHead, Name, Arity), + '$assertz'(Head, Body, Name, Arity). + assertz_clause(Head, Body) :- - ( var(Head) -> throw(error(instantiation_error, assertz/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( Name == (:), Arity =:= 2 -> - arg(1, Head, Module), - arg(2, Head, F), - module_assertz_clause(F, Body, Module) - ; '$no_such_predicate'(Head) -> - call_assertz(Head, Body, Name, Arity) - ; '$head_is_dynamic'(Head) -> - call_assertz(Head, Body, Name, Arity) + ( var(Head) -> + throw(error(instantiation_error, assertz/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( Name == (:), + Arity =:= 2 -> + arg(1, Head, Module), + arg(2, Head, F), + module_assertz_clause(F, Body, Module) + ; '$no_such_predicate'(user, Head) -> + call_assertz(Head, Body, Name, Arity) + ; '$head_is_dynamic'(user, Head) -> + call_assertz(Head, Body, Name, Arity) ; throw(error(permission_error(modify, static_procedure, Name/Arity), assertz/1)) ) ; throw(error(type_error(callable, Head), assertz/1)) ). assertz(Clause) :- - ( Clause \= (_ :- _) -> Head = Clause, Body = true, assertz_clause(Head, Body) - ; Clause = (Head :- Body) -> assertz_clause(Head, Body) + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, + assertz_clause(Head, Body) + ; Clause = (Head :- Body) -> + assertz_clause(Head, Body) ). -first_match_index([Clause0 | Clauses], Clause1, N0, N) :- - ( Clause0 \= Clause1 -> - N1 is N0 + 1, - first_match_index(Clauses, Clause1, N1, N) - ; N0 = N, Clause0 = Clause1 - ). - -retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :- - functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses1), - first_match_index(Clauses1, (Head :- Body), 0, N), - ( Clauses0 == [] -> ! - ; true - ), - '$retract_clause'(Name, Arity, N, Clauses1). -retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :- - retract_clauses(Clauses0, Head, Body, Name, Arity). - -call_retract(Head, Body, Name, Arity) :- - findall((Head :- Body), clause(Head, Body), Clauses), - retract_clauses(Clauses, Head, Body, Name, Arity). module_retract_clauses([Clause|Clauses0], Head, Body, Name, Arity, Module) :- functor(VarHead, Name, Arity), - findall((VarHead :- VarBody), clause(Module:VarHead, VarBody), Clauses1), + findall((VarHead :- VarBody), builtins:clause(Module:VarHead, VarBody), Clauses1), first_match_index(Clauses1, (Head :- Body), 0, N), ( Clauses0 == [] -> ! ; true ), '$module_retract_clause'(Name, Arity, N, Clauses1, Module). + module_retract_clauses([_|Clauses0], Head, Body, Name, Arity, Module) :- module_retract_clauses(Clauses0, Head, Body, Name, Arity, Module). call_module_retract(Head, Body, Name, Arity, Module) :- - findall((Head :- Body), clause(Module:Head, Body), Clauses), + findall((Head :- Body), builtins:clause(Module:Head, Body), Clauses), module_retract_clauses(Clauses, Head, Body, Name, Arity, Module). retract_module_clause(Head, Body, Module) :- - ( var(Head) -> throw(error(instantiation_error, retract/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> + ( var(Head) -> + throw(error(instantiation_error, retract/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> ( '$module_head_is_dynamic'(Head, Module) -> - call_module_retract(Head, Body, Name, Arity, Module) + call_module_retract(Head, Body, Name, Arity, Module) ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1)) ) ; throw(error(type_error(callable, Head), retract/1)) ). + +first_match_index([Clause0 | Clauses], Clause1, N0, N) :- + ( Clause0 \= Clause1 -> + N1 is N0 + 1, + first_match_index(Clauses, Clause1, N1, N) + ; N0 = N, + Clause0 = Clause1 + ). + +retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :- + functor(VarHead, Name, Arity), + findall((VarHead :- VarBody), builtins:'$clause'(VarHead, VarBody), Clauses1), + first_match_index(Clauses1, (Head :- Body), 0, N), + ( Clauses0 == [] -> ! + ; true + ), + '$retract_clause'(Name, Arity, N). + +retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :- + retract_clauses(Clauses0, Head, Body, Name, Arity). + +call_retract(Head, Body, Name, Arity) :- + findall((Head :- Body), builtins:'$clause'(Head, Body), Clauses), + retract_clauses(Clauses, Head, Body, Name, Arity). + retract_clause(Head, Body) :- - ( var(Head) -> throw(error(instantiation_error, retract/1)) - ; functor(Head, Name, Arity), atom(Name), Name \== '.' -> - ( Name == (:), Arity =:= 2 -> - arg(1, Head, Module), - arg(2, Head, F), - retract_module_clause(F, Body, Module) - ; '$head_is_dynamic'(Head) -> call_retract(Head, Body, Name, Arity) - ; '$no_such_predicate'(Head) -> '$fail' + ( var(Head) -> + throw(error(instantiation_error, retract/1)) + ; functor(Head, Name, Arity), + atom(Name), + Name \== '.' -> + ( Name == (:), + Arity =:= 2 -> + arg(1, Head, Module), + arg(2, Head, F), + retract_module_clause(F, Body, Module) + ; '$head_is_dynamic'(user, Head) -> + call_retract(Head, Body, Name, Arity) + ; '$no_such_predicate'(user, Head) -> + '$fail' ; throw(error(permission_error(modify, static_procedure, Name/Arity), retract/1)) ) ; throw(error(type_error(callable, Head), retract/1)) ). retract(Clause) :- - ( Clause \= (_ :- _) -> Head = Clause, Body = true, retract_clause(Head, Body) - ; Clause = (Head :- Body) -> retract_clause(Head, Body) + ( Clause \= (_ :- _) -> + Head = Clause, + Body = true, + retract_clause(Head, Body) + ; Clause = (Head :- Body) -> + retract_clause(Head, Body) ). + module_abolish(Pred, Module) :- - ( var(Pred) -> throw(error(instantiation_error), abolish/1) + ( var(Pred) -> + throw(error(instantiation_error), abolish/1) ; Pred = Name/Arity -> - ( var(Name) -> throw(error(instantiation_error, abolish/1)) + ( var(Name) -> + throw(error(instantiation_error, abolish/1)) ; integer(Arity) -> - ( \+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1)) - ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) - ; max_arity(N), Arity > N -> throw(error(representation_error(max_arity), abolish/1)) - ; functor(Head, Name, Arity) -> - ( '$module_head_is_dynamic'(Head, Module) -> - '$abolish_module_clause'(Name, Arity, Module) - ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) - ) - ) + ( \+ atom(Name) -> + throw(error(type_error(atom, Name), abolish/1)) + ; Arity < 0 -> + throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) + ; max_arity(N), Arity > N -> + throw(error(representation_error(max_arity), abolish/1)) + ; functor(Head, Name, Arity) -> + ( '$module_head_is_dynamic'(Head, Module) -> + '$abolish_module_clause'(Name, Arity, Module) + ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) + ) + ) ; throw(error(type_error(integer, Arity), abolish/1)) ) ; throw(error(type_error(predicate_indicator, Module:Pred), abolish/1)) ). abolish(Pred) :- - ( var(Pred) -> throw(error(instantiation_error), abolish/1) - ; Pred = Module:InnerPred -> module_abolish(InnerPred, Module) + ( var(Pred) -> + throw(error(instantiation_error), abolish/1) + ; Pred = Module:InnerPred -> + module_abolish(InnerPred, Module) ; Pred = Name/Arity -> - ( var(Name) -> throw(error(instantiation_error, abolish/1)) - ; var(Arity) -> throw(error(instantiation_error, abolish/1)) + ( var(Name) -> + throw(error(instantiation_error, abolish/1)) + ; var(Arity) -> + throw(error(instantiation_error, abolish/1)) ; integer(Arity) -> - ( \+ atom(Name) -> throw(error(type_error(atom, Name), abolish/1)) - ; Arity < 0 -> throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) - ; max_arity(N), Arity > N -> throw(error(representation_error(max_arity), abolish/1)) - ; functor(Head, Name, Arity) -> - ( '$no_such_predicate'(Head) -> true - ; '$head_is_dynamic'(Head) -> '$abolish_clause'(Name, Arity) - ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) - ) - ) + ( \+ atom(Name) -> + throw(error(type_error(atom, Name), abolish/1)) + ; Arity < 0 -> + throw(error(domain_error(not_less_than_zero, Arity), abolish/1)) + ; max_arity(N), Arity > N -> + throw(error(representation_error(max_arity), abolish/1)) + ; functor(Head, Name, Arity) -> + ( '$no_such_predicate'(Head) -> true + ; '$head_is_dynamic'(Head) -> '$abolish_clause'(Name, Arity) + ; throw(error(permission_error(modify, static_procedure, Pred), abolish/1)) + ) + ) ; throw(error(type_error(integer, Arity), abolish/1)) ) ; throw(error(type_error(predicate_indicator, Pred), abolish/1)) @@ -889,6 +1001,7 @@ abolish(Pred) :- '$get_next_db_ref'(Ref, NextRef), '$iterate_db_refs'(NextRef, Name/Arity). + current_predicate(Pred) :- ( nonvar(Pred), Pred \= _ / _ -> throw(error(type_error(predicate_indicator, Pred), current_predicate/1)) @@ -909,8 +1022,10 @@ can_be_op_specifier(Spec) :- var(Spec). can_be_op_specifier(Spec) :- op_specifier(Spec). current_op(Priority, Spec, Op) :- - ( can_be_op_priority(Priority), can_be_op_specifier(Spec), error:can_be(atom, Op) - -> '$get_next_op_db_ref'(Ref, _), + ( can_be_op_priority(Priority), + can_be_op_specifier(Spec), + error:can_be(atom, Op) -> + '$get_next_op_db_ref'(Ref, _), '$iterate_op_db_refs'(Ref, Priority, Spec, Op) ). @@ -929,36 +1044,52 @@ op_priority(Priority) :- throw(error(domain_error(operator_priority, Priority))) % 8.14.3.3 h) ; true ). + op_priority(Priority) :- throw(error(type_error(integer, Priority), op/3)). % 8.14.3.3 d) -op_specifier(OpSpec) :- atom(OpSpec), +op_specifier(OpSpec) :- + atom(OpSpec), ( lists:member(OpSpec, [yfx, xfy, xfx, yf, fy, xf, fx]), ! ; throw(error(domain_error(operator_specifier, OpSpec), op/3)) % 8.14.3.3 i) ). -op_specifier(OpSpec) :- throw(error(type_error(atom, OpSpec), op/3)). -valid_op(Op) :- atom(Op), - ( Op == (',') -> throw(error(permission_error(modify, operator, (',')), op/3)) % 8.14.3.3 j), k). - ; Op == {} -> throw(error(permission_error(create, operator, {}), op/3)) - ; Op == [] -> throw(error(permission_error(create, operator, []), op/3)) +op_specifier(OpSpec) :- + throw(error(type_error(atom, OpSpec), op/3)). + +valid_op(Op) :- + atom(Op), + ( Op == (',') -> + throw(error(permission_error(modify, operator, (',')), op/3)) % 8.14.3.3 j), k). + ; Op == {} -> + throw(error(permission_error(create, operator, {}), op/3)) + ; Op == [] -> + throw(error(permission_error(create, operator, []), op/3)) ; true ). -op_(Priority, OpSpec, Op) :- '$op'(Priority, OpSpec, Op). +op_(Priority, OpSpec, Op) :- + '$op'(Priority, OpSpec, Op). op(Priority, OpSpec, Op) :- - ( var(Priority) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 a) - ; var(OpSpec) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 b) - ; var(Op) -> throw(error(instantiation_error, op/3)) % 8.14.3.3 c) - ; Op == '|' -> ( op_priority(Priority), op_specifier(OpSpec), - lists:member(OpSpec, [xfx, xfy, yfx]), ( Priority >= 1001 ; Priority == 0 ) - -> '$op'(Priority, OpSpec, Op) - ; throw(error(permission_error(create, operator, (|)), op/3))) % www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing#72 + ( var(Priority) -> + throw(error(instantiation_error, op/3)) % 8.14.3.3 a) + ; var(OpSpec) -> + throw(error(instantiation_error, op/3)) % 8.14.3.3 b) + ; var(Op) -> + throw(error(instantiation_error, op/3)) % 8.14.3.3 c) + ; Op == '|' -> + ( op_priority(Priority), + op_specifier(OpSpec), + lists:member(OpSpec, [xfx, xfy, yfx]), + ( Priority >= 1001 ; Priority == 0 ) + -> '$op'(Priority, OpSpec, Op) + ; throw(error(permission_error(create, operator, (|)), op/3))) % www.complang.tuwien.ac.at/ulrich/iso-prolog/conformity_testing#72 ; valid_op(Op), op_priority(Priority), op_specifier(OpSpec) -> '$op'(Priority, OpSpec, Op) ; list_of_op_atoms(Op), op_priority(Priority), op_specifier(OpSpec) -> - lists:maplist(op_(Priority, OpSpec), Op), ! + lists:maplist(op_(Priority, OpSpec), Op), + ! ; throw(error(type_error(list, Op), op/3)) % 8.14.3.3 f) ). @@ -973,41 +1104,54 @@ halt(N) :- ). atom_length(Atom, Length) :- - ( var(Atom) -> throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a) - ; atom(Atom) -> ( var(Length) -> '$atom_length'(Atom, Length) - ; integer(Length), Length >= 0 -> '$atom_length'(Atom, Length) - ; integer(Length) -> throw(error(domain_error(not_less_than_zero, Length), atom_length/2)) - % 8.16.1.3 d) - ; throw(error(type_error(integer, Length), atom_length/2)) % 8.16.1.3 c) - ) + ( var(Atom) -> + throw(error(instantiation_error, atom_length/2)) % 8.16.1.3 a) + ; atom(Atom) -> + ( var(Length) -> + '$atom_length'(Atom, Length) + ; integer(Length), Length >= 0 -> + '$atom_length'(Atom, Length) + ; integer(Length) -> + throw(error(domain_error(not_less_than_zero, Length), atom_length/2)) + % 8.16.1.3 d) + ; throw(error(type_error(integer, Length), atom_length/2)) % 8.16.1.3 c) + ) ; throw(error(type_error(atom, Atom), atom_length/2)) % 8.16.1.3 b) ). atom_chars(Atom, List) :- '$skip_max_list'(_, -1, List, Tail), - ( ( Tail == [] ; var(Tail) ) -> true + ( ( Tail == [] ; var(Tail) ) -> + true ; throw(error(type_error(list, List), atom_chars/2)) ), ( var(Atom) -> - ( var(Tail) -> throw(error(instantiation_error, atom_chars/2)) - ; ground(List) -> '$atom_chars'(Atom, List) + ( var(Tail) -> + throw(error(instantiation_error, atom_chars/2)) + ; ground(List) -> + '$atom_chars'(Atom, List) ; throw(error(instantiation_error, atom_chars/2)) ) - ; atom(Atom) -> '$atom_chars'(Atom, List) + ; atom(Atom) -> + '$atom_chars'(Atom, List) ; throw(error(type_error(atom, Atom), atom_chars/2)) ). atom_codes(Atom, List) :- '$skip_max_list'(_, -1, List, Tail), - ( ( Tail == [] ; var(Tail) ) -> true + ( ( Tail == [] ; var(Tail) ) -> + true ; throw(error(type_error(list, List), atom_codes/2)) ), ( var(Atom) -> - ( var(Tail) -> throw(error(instantiation_error, atom_codes/2)) - ; ground(List), Tail == [] -> '$atom_codes'(Atom, List) + ( var(Tail) -> + throw(error(instantiation_error, atom_codes/2)) + ; ground(List), Tail == [] -> + '$atom_codes'(Atom, List) ; throw(error(instantiation_error, atom_codes/2)) ) - ; atom(Atom) -> '$atom_codes'(Atom, List) + ; atom(Atom) -> + '$atom_codes'(Atom, List) ; throw(error(type_error(atom, Atom), atom_codes/2)) ). @@ -1016,18 +1160,19 @@ atom_concat(Atom_1, Atom_2, Atom_12) :- error:can_be(atom, Atom_2), error:can_be(atom, Atom_12), ( var(Atom_1) -> - ( var(Atom_12) -> throw(error(instantiation_error, atom_concat/3)) + ( var(Atom_12) -> + throw(error(instantiation_error, atom_concat/3)) ; atom_chars(Atom_12, Atom_12_Chars), - lists:append(BeforeChars, AfterChars, Atom_12_Chars), - atom_chars(Atom_1, BeforeChars), - atom_chars(Atom_2, AfterChars) + lists:append(BeforeChars, AfterChars, Atom_12_Chars), + atom_chars(Atom_1, BeforeChars), + atom_chars(Atom_2, AfterChars) ) ; var(Atom_2) -> ( var(Atom_12) -> throw(error(instantiation_error, atom_concat/3)) ; atom_chars(Atom_1, Atom_1_Chars), - atom_chars(Atom_12, Atom_12_Chars), - lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars), - atom_chars(Atom_2, Atom_2_Chars) + atom_chars(Atom_12, Atom_12_Chars), + lists:append(Atom_1_Chars, Atom_2_Chars, Atom_12_Chars), + atom_chars(Atom_2, Atom_2_Chars) ) ; atom_chars(Atom_1, Atom_1_Chars), atom_chars(Atom_2, Atom_2_Chars), @@ -1041,9 +1186,12 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :- error:can_be(integer, Before), error:can_be(integer, Length), error:can_be(integer, After), - ( integer(Before), Before < 0 -> throw(error(domain_error(not_less_than_zero, Before), sub_atom/5)) - ; integer(Length), Length < 0 -> throw(error(domain_error(not_less_than_zero, Length), sub_atom/5)) - ; integer(After), After < 0 -> throw(error(domain_error(not_less_than_zero, After), sub_atom/5)) + ( integer(Before), Before < 0 -> + throw(error(domain_error(not_less_than_zero, Before), sub_atom/5)) + ; integer(Length), Length < 0 -> + throw(error(domain_error(not_less_than_zero, Length), sub_atom/5)) + ; integer(After), After < 0 -> + throw(error(domain_error(not_less_than_zero, After), sub_atom/5)) ; atom_chars(Atom, AtomChars), lists:append(BeforeChars, LengthAndAfterChars, AtomChars), lists:append(LengthChars, AfterChars, LengthAndAfterChars), @@ -1055,11 +1203,14 @@ sub_atom(Atom, Before, Length, After, Sub_atom) :- char_code(Char, Code) :- ( var(Char) -> - ( var(Code) -> throw(error(instantiation_error, char_code/2)) - ; integer(Code) -> '$char_code'(Char, Code) + ( var(Code) -> + throw(error(instantiation_error, char_code/2)) + ; integer(Code) -> + '$char_code'(Char, Code) ; throw(error(type_error(integer, Code), char_code/2)) ) - ; atom_length(Char, 1) -> '$char_code'(Char, Code) + ; atom_length(Char, 1) -> + '$char_code'(Char, Code) ; throw(error(type_error(character, Char), char_code/2)) ). @@ -1081,7 +1232,8 @@ must_be_number(N, _) :- ), !. must_be_number(N, PI) :- - ( nonvar(N) -> throw(error(type_error(number, N), PI)) + ( nonvar(N) -> + throw(error(type_error(number, N), PI)) ; throw(error(instantiation_error, PI)) ). @@ -1144,7 +1296,7 @@ set_output(S) :- parse_stream_options(Options, OptionValues, Stub) :- DefaultOptions = [alias-[], eof_action-eof_code, reposition-false, type-text], - parse_options_list(Options, parse_stream_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_stream_options_, DefaultOptions, OptionValues, Stub). parse_stream_options_(type(Type), type-Type) :- @@ -1191,7 +1343,7 @@ open(SourceSink, Mode, Stream, StreamOptions) :- parse_close_options(Options, OptionValues, Stub) :- DefaultOptions = [force-false], - parse_options_list(Options, parse_close_options_, DefaultOptions, OptionValues, Stub). + parse_options_list(Options, builtins:parse_close_options_, DefaultOptions, OptionValues, Stub). parse_close_options_(force(Force), force-Force) :- ( nonvar(Force), lists:member(Force, [true, false]), ! diff --git a/src/lib/clpb.pl b/src/lib/clpb.pl index 0b802a46..0310e775 100644 --- a/src/lib/clpb.pl +++ b/src/lib/clpb.pl @@ -17,8 +17,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ :- module(clpb, [op(300, fy, ~), - op(500, yfx, #), - sat/1, + op(500, yfx, #), + sat/1, taut/2, labeling/1, sat_count/2, diff --git a/src/lib/dcgs.pl b/src/lib/dcgs.pl index 942f6b8e..f9410d99 100644 --- a/src/lib/dcgs.pl +++ b/src/lib/dcgs.pl @@ -5,14 +5,27 @@ :- use_module(library(error)). :- 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, S) :- - ( var(GRBody) -> throw(error(instantiation_error, phrase/3)) - ; dcg_constr(GRBody) -> phrase_(GRBody, S0, S) - ; functor(GRBody, _, _) -> call(GRBody, S0, S) + ( var(GRBody) -> + throw(error(instantiation_error, phrase/3)) + ; strip_module(GRBody, Module, GRBody0), + dcg_constr(GRBody0), + ( var(Module) -> + phrase_(GRBody0, S0, S) + ; phrase_(Module:GRBody0, S0, S) + ) + ; functor(GRBody, _, _) -> + call(GRBody, S0, S) ; throw(error(type_error(callable, GRBody), phrase/3)) ). @@ -20,27 +33,42 @@ phrase_([], S, S). phrase_(!, S, S). phrase_((A, B), S0, S) :- phrase(A, S0, S1), phrase(B, S1, S). +phrase_(M:(A, B), S0, S) :- + phrase(M:A, S0, S1), phrase(M:B, S1, S). phrase_((A -> B ; C), S0, S) :- !, ( phrase(A, S0, S1) -> phrase(B, S1, S) ; phrase(C, S0, S) ). +phrase_(M:(A -> B ; C), S0, S) :- + !, + ( phrase(M:A, S0, S1) -> + phrase(M:B, S1, S) + ; phrase(M:C, S0, S) + ). phrase_((A ; B), S0, S) :- ( phrase(A, S0, S) ; phrase(B, S0, S) ). +phrase_(M:(A ; B), S0, S) :- + ( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ). phrase_((A | B), S0, S) :- ( phrase(A, S0, S) ; phrase(B, S0, S) ). +phrase_(M:(A | B), S0, S) :- + ( phrase(M:A, S0, S) ; phrase(M:B, S0, S) ). phrase_({G}, S0, S) :- ( call(G), S0 = S ). phrase_(call(G), S0, S) :- call(G, S0, S). phrase_((A -> B), S0, S) :- phrase((A -> B ; fail), S0, S). +phrase_(M:(A -> B), S0, S) :- + phrase((M:A -> M:B ; fail), S0, S). phrase_(phrase(NonTerminal), S0, S) :- phrase(NonTerminal, S0, S). phrase_([T|Ts], S0, S) :- 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), diff --git a/src/lib/diag.pl b/src/lib/diag.pl index d135238b..0fa3896f 100644 --- a/src/lib/diag.pl +++ b/src/lib/diag.pl @@ -2,13 +2,23 @@ :- use_module(library(error)). + wam_instructions(Clause, Listing) :- ( nonvar(Clause) -> - Clause = Name / Arity, - must_be(atom, Name), - must_be(integer, Arity), - ( Arity >= 0 -> '$wam_instructions'(Name, Arity, Listing) - ; throw(error(domain_error(not_less_than_zero, Arity), wam_instructions/2)) + ( Clause = Name / Arity -> + fetch_instructions(user, Name, Arity, Listing) + ; Clause = Module : (Name / Arity) -> + fetch_instructions(Module, Name, Arity, Listing) ) ; 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)) + ). diff --git a/src/lib/dif.pl b/src/lib/dif.pl index bb92979a..9c3b8ed8 100644 --- a/src/lib/dif.pl +++ b/src/lib/dif.pl @@ -8,8 +8,8 @@ put_dif_att(Var, X, Y) :- ( get_atts(Var, +dif(Z)) -> - sort([X \== Y | Z], NewZ), - put_atts(Var, +dif(NewZ)) + sort([X \== Y | Z], NewZ), + put_atts(Var, +dif(NewZ)) ; put_atts(Var, +dif([X \== Y])) ). @@ -21,8 +21,8 @@ dif_set_variables([Var|Vars], X, Y) :- append_goals([], _). append_goals([Var|Vars], Goals) :- ( get_atts(Var, +dif(VarGoals)) -> - append(Goals, VarGoals, NewGoals0), - sort(NewGoals0, NewGoals) + append(Goals, VarGoals, NewGoals0), + sort(NewGoals0, NewGoals) ; NewGoals = Goals ), put_atts(Var, +dif(NewGoals)), @@ -30,8 +30,8 @@ append_goals([Var|Vars], Goals) :- verify_attributes(Var, Value, Goals) :- ( get_atts(Var, +dif(Goals)) -> - term_variables(Value, ValueVars), - append_goals(ValueVars, Goals) + term_variables(Value, ValueVars), + append_goals(ValueVars, Goals) ; Goals = [] ). @@ -50,7 +50,7 @@ dif(X, Y) :- gather_dif_goals([]) --> []. gather_dif_goals([(X \== Y) | Goals]) --> ( { X \= Y } -> [] - ; [dif(X, Y)] + ; [dif:dif(X, Y)] ), gather_dif_goals(Goals). diff --git a/src/lib/error.pl b/src/lib/error.pl index 7e2189c4..99592790 100644 --- a/src/lib/error.pl +++ b/src/lib/error.pl @@ -44,10 +44,10 @@ must_be_(var, Term) :- ). must_be_(integer, Term) :- check_(integer, integer, Term). must_be_(atom, Term) :- check_(atom, atom, Term). -must_be_(character, T) :- check_(character, character, T). -must_be_(list, Term) :- check_(ilist, list, Term). -must_be_(type, Term) :- check_(type, type, Term). -must_be_(boolean, Term) :- check_(boolean, boolean, Term). +must_be_(character, T) :- check_(error:character, character, T). +must_be_(list, Term) :- check_(error:ilist, list, Term). +must_be_(type, Term) :- check_(error:type, type, Term). +must_be_(boolean, Term) :- check_(error:boolean, boolean, Term). check_(Pred, Type, Term) :- ( var(Term) -> instantiation_error(must_be/2) diff --git a/src/lib/iso_ext.pl b/src/lib/iso_ext.pl index e5ba94c1..c7c3d6c3 100644 --- a/src/lib/iso_ext.pl +++ b/src/lib/iso_ext.pl @@ -11,6 +11,12 @@ :- use_module(library(error), [can_be/2,domain_error/3]). + +:- meta_predicate call_cleanup(0, 0). + +:- meta_predicate setup_call_cleanup(0, 0, 0). + + forall(Generate, Test) :- \+ (Generate, \+ Test). @@ -45,6 +51,7 @@ 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, _) :- throw(error(type_error(atom, Key), bb_get/2)). + call_cleanup(G, C) :- setup_call_cleanup(true, G, C). @@ -117,6 +124,8 @@ handle_ile(B, E, _) :- '$remove_call_policy_check'(B), '$call_with_default_policy'(throw(E)). +:- meta_predicate call_with_inference_limit(0, ?, ?). + call_with_inference_limit(G, L, R) :- '$get_current_block'(Bb), '$get_b_value'(B), diff --git a/src/lib/lists.pl b/src/lib/lists.pl index a1acdb6d..c6160e55 100644 --- a/src/lib/lists.pl +++ b/src/lib/lists.pl @@ -1,15 +1,29 @@ :- module(lists, [member/2, select/3, append/2, append/3, foldl/4, foldl/5, - memberchk/2, reverse/2, length/2, maplist/2, - maplist/3, maplist/4, maplist/5, maplist/6, - 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]). + memberchk/2, reverse/2, length/2, maplist/2, + maplist/3, maplist/4, maplist/5, maplist/6, + 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]). :- 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) :- - var(N), !, + var(N), + !, '$skip_max_list'(M, -1, Xs, Xs0), ( 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, Ys, [Y1|YsPreludeRev], Xss). - maplist(_, []). maplist(Cont1, [E1|E1s]) :- call(Cont1, E1), @@ -87,21 +100,25 @@ maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s]) :- call(Cont, E1, E2, E3, E4), maplist(Cont, E1s, E2s, E3s, E4s). + maplist(_, [], [], [], [], []). maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s]) :- call(Cont, E1, E2, E3, E4, E5), maplist(Cont, E1s, E2s, E3s, E4s, E5s). + maplist(_, [], [], [], [], [], []). maplist(Cont, [E1|E1s], [E2|E2s], [E3|E3s], [E4|E4s], [E5|E5s], [E6|E6s]) :- call(Cont, E1, E2, E3, E4, E5, E6), maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s). + maplist(_, [], [], [], [], [], [], []). 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), maplist(Cont, E1s, E2s, E3s, E4s, E5s, E6s, E7s). + maplist(_, [], [], [], [], [], [], [], []). 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), @@ -132,6 +149,7 @@ foldl_([L|Ls], G_3, A0, A) :- foldl(Goal_4, Xs, Ys, A0, A) :- foldl_(Xs, Ys, Goal_4, A0, A). + foldl_([], [], _, A, A). foldl_([X|Xs], [Y|Ys], G_4, A0, A) :- call(G_4, X, Y, A0, A1), diff --git a/src/lib/ops_and_meta_predicates.pl b/src/lib/ops_and_meta_predicates.pl new file mode 100644 index 00000000..2d78c615 --- /dev/null +++ b/src/lib/ops_and_meta_predicates.pl @@ -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(0). +:- meta_predicate call(1, ?). +:- meta_predicate call(2, ?, ?). +:- meta_predicate call(3, ?, ?, ?). +:- meta_predicate call(4, ?, ?, ?, ?). +:- meta_predicate call(5, ?, ?, ?, ?, ?). +:- meta_predicate call(6, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(7, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(8, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(9, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(10, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(11, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(12, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(13, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(14, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(15, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(16, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(17, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(18, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(19, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(20, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(21, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(22, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(23, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(24, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(25, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(26, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(27, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(28, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(29, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(30, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(31, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(32, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(33, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(34, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(35, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(36, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(37, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(38, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(39, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(40, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(41, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(42, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(43, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(44, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(45, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(46, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(47, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(48, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(49, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(50, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(51, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(52, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(53, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(54, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(55, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(56, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(57, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(58, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(59, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(60, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(60, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(61, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(62, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). +:- meta_predicate call(63, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?). diff --git a/src/lib/pairs.pl b/src/lib/pairs.pl index adcfb138..d8023856 100644 --- a/src/lib/pairs.pl +++ b/src/lib/pairs.pl @@ -5,6 +5,8 @@ map_list_to_pairs/3]). +:- meta_predicate map_list_to_pairs(0, ?, ?). + pairs_keys_values([], [], []). pairs_keys_values([A-B|ABs], [A|As], [B|Bs]) :- pairs_keys_values(ABs, As, Bs). diff --git a/src/lib/tabling/wrapper.pl b/src/lib/tabling/wrapper.pl index c66be996..4c902e84 100644 --- a/src/lib/tabling/wrapper.pl +++ b/src/lib/tabling/wrapper.pl @@ -75,7 +75,7 @@ wrappers(Name/Arity) --> atom_concat(Name, ' tabled', WrapName), Head =.. [Name|Args], WrappedHead =.. [WrapName|Args], - '$module_of'(Module, Name) %prolog_load_context(module, Module) + prolog_load_context(module, Module) }, [ ( Head :- start_tabling(Module:Head, WrappedHead) @@ -109,10 +109,10 @@ rename_term(Name, WrapName) :- user:term_expansion(Term0, Clauses) :- - nonvar(Term0), + nonvar(Term0), Term0 = (:- table Preds), phrase(wrappers(Preds), Clauses). user:term_expansion(Clause, NewClause) :- - nonvar(Clause), - '$module_of'(Module, Clause), + nonvar(Clause), + prolog_load_context(module, Module), rename(Clause, NewClause, Module). diff --git a/src/lib/time.pl b/src/lib/time.pl index 30ec0f45..13df2e42 100644 --- a/src/lib/time.pl +++ b/src/lib/time.pl @@ -82,6 +82,8 @@ sleep(T) :- % '$cpu_now' can be replaced by statistics/2 once that is implemented. +:- meta_predicate time(0). + time(Goal) :- '$cpu_now'(T0), setup_call_cleanup(true, diff --git a/src/loader.pl b/src/loader.pl new file mode 100644 index 00000000..b16150c6 --- /dev/null +++ b/src/loader.pl @@ -0,0 +1,494 @@ + +:- 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)). + + +'$print_message_and_fail'(Error, Culprit) :- +% writeq(error(Error, Culprit)), +% nl, + '$fail'. + +expand_term(Term, ExpandedTerm) :- + ( catch(user:term_expansion(Term, ExpandedTerm0), + E, + loader:'$print_message_and_fail'(E, user:term_expansion)) -> + ( var(ExpandedTerm0) -> + error:instantiation_error(term_expansion/2) + ; ExpandedTerm0 = [_|_] -> + term_expansion_list(ExpandedTerm0, ExpandedTerm, []) + ; expand_term(ExpandedTerm0, ExpandedTerm) + ) + ; Term = ExpandedTerm + ). + + +term_expansion_list([], ExpandedTerms, ExpandedTerms). +term_expansion_list([Term|Terms], ExpandedTermsHead, ExpandedTermsTail) :- + expand_term(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, + loader:'$print_message_and_fail'(E, Module:goal_expansion)) -> + ( var(ExpandedGoal0) -> + error:instantiation_error(goal_expansion/2) + ; goal_expansion(ExpandedGoal0, Module, ExpandedGoal) + ) + ; Goal = ExpandedGoal + ). + + + +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(0, 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, HeadVars) :- + ( var(Head) -> + instantiation_error(load/1) + ; predicate_property(Head, meta_predicate(MetaSpecs)), + Head =.. [_ | HeadArgs] -> + module_expanded_head_variables_(HeadArgs, MetaSpecs, HeadVars, []) + ; HeadVars = [] + ). + + +expand_term_goals(Terms0, Terms) :- + ( Terms0 = (Head1 :- Body0) -> + ( var(Head1) -> + instantiation_error(load/1) + ; prolog_load_context(module, Target), + module_expanded_head_variables(Head1, HeadVars), + expand_goal(Body0, Target, Body1, HeadVars) + ), + Terms = (Head1 :- Body1) + ; Terms = Terms0 + ). + + +expand_terms_and_goals(Term, Terms) :- + expand_term(Term, Terms0), + ( var(Terms0) -> + instantiation_error(load/1) + ; Terms0 = [_|_] -> + maplist(loader:expand_term_goals, Terms0, Terms) + ; expand_term_goals(Terms0, Terms) + ). + + +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, Module, Name, Arity, MetaPredicateTerm) :- + '$cpp_meta_predicate_property'(Module, Name, Arity, MetaPredicateTerm). +check_predicate_property(built_in, _, Name, Arity, built_in) :- + '$cpp_built_in_property'(Name, Arity). + + +extract_predicate_property(Property, PropertyType) :- + ( var(Property) -> + true + ; functor(Property, PropertyType, _) + ). + +predicate_property(Callable, Property) :- + ( var(Callable) -> + instantiation_error(load/1) + ; Callable =.. [(:), Module, Callable0], + atom(Module) -> + functor(Callable0, Name, Arity), + extract_predicate_property(Property, PropertyType), + check_predicate_property(PropertyType, Module, Name, Arity, Property) + ; functor(Callable, Name, Arity), + extract_predicate_property(Property, PropertyType), + ( prolog_load_context(module, Module) -> + true + ; Module = user + ), + check_predicate_property(PropertyType, Module, 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 + ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), + ( Module \== 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 = _:_ -> + ESG = ESG0 + ; ESG = M:ESG0 + ). + + +expand_meta_predicate_subgoals([SG | SGs], [MS | MSs], M, [ESG | ESGs], HeadVars) :- + ( ( 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 == (:), + SubGoals = [M, SubGoal] -> + expand_module_names(SubGoal, MetaSpecs, Module, ExpandedSubGoal, HeadVars), + ExpandedGoals = M:ExpandedSubGoal + ; 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 + ; goal_expansion(UnexpandedGoals, Module, UnexpandedGoals1), + ( Module \== 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(Module: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) -> + Goals1 =.. [Functor, Goals0, Hole] + ; ( Goals0 = [G | Gs] -> + ( Gs == [] -> + Goals1 =.. [Functor, G, Hole] + ; Goals1 =.. [Functor, G, Goals2], + thread_goals(Gs, Goals2, Hole, Functor) + ) + ; Goals1 =.. [Functor, Goals0, Hole] + ) + ). diff --git a/src/machine/arithmetic_ops.rs b/src/machine/arithmetic_ops.rs index 110353ac..0c8fb8ff 100644 --- a/src/machine/arithmetic_ops.rs +++ b/src/machine/arithmetic_ops.rs @@ -1,6 +1,6 @@ use crate::divrem::*; -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::arithmetic::*; use crate::clause_types::*; diff --git a/src/machine/attributed_variables.pl b/src/machine/attributed_variables.pl index 8756eb3c..3cd4c0f1 100644 --- a/src/machine/attributed_variables.pl +++ b/src/machine/attributed_variables.pl @@ -1,5 +1,6 @@ :- module('$atts', []). + driver(Vars, Values) :- iterate(Vars, Values, ListOfListsOfGoalLists), !, @@ -13,9 +14,9 @@ iterate([Var|VarBindings], [Value|ValueBindings], [ListOfGoalLists | ListsCubed] iterate(VarBindings, ValueBindings, ListsCubed). iterate([], [], []). + gather_modules(Attrs, []) :- var(Attrs), !. -gather_modules([Attr|Attrs], [Module|Modules]) :- - '$module_of'(Module, Attr), % write the owning module of Attr to Module. +gather_modules([Module:_|Attrs], [Module|Modules]) :- gather_modules(Attrs, Modules). call_verify_attributes(Attrs, _, _, []) :- @@ -26,27 +27,31 @@ call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :- sort(Modules0, Modules), verify_attrs(Modules, Var, Value, ListOfGoalLists). -verify_attrs([Module|Modules], Var, Value, [Goals|ListOfGoalLists]) :- + +verify_attrs([Module|Modules], Var, Value, [Module-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_0(ListOfGoalLists), call_goals(ListsCubed). call_goals([]). -call_goals_0([GoalList | GoalLists]) :- - ( var(GoalList), throw(error(instantiation_error, call_goals_0/1)) +call_goals_0([Module-GoalList | GoalLists]) :- + ( var(GoalList), + throw(error(instantiation_error, call_goals_0/1)) ; true ), - call_goals_1(GoalList), + call_goals_1(GoalList, Module), call_goals_0(GoalLists). call_goals_0([]). -call_goals_1([Goal | Goals]) :- - call(Goal), - call_goals_1(Goals). -call_goals_1([]). +call_goals_1([Goal | Goals], Module) :- + expand_goal(Goal, Module, Goal1), % TODO: remove this when goal expansions are added to call/N. + call(Module:Goal1), + call_goals_1(Goals, Module). +call_goals_1([], _). diff --git a/src/machine/attributed_variables.rs b/src/machine/attributed_variables.rs index c7b198d5..790114fc 100644 --- a/src/machine/attributed_variables.rs +++ b/src/machine/attributed_variables.rs @@ -6,9 +6,6 @@ use crate::indexmap::IndexSet; use std::cmp::Ordering; 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)>; #[derive(Debug)] @@ -126,7 +123,7 @@ impl MachineState { self.stack.index_and_frame_mut(e).prelude.interrupt_cp = self.attr_var_init.cp; 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] = diff --git a/src/machine/code_repo.rs b/src/machine/code_repo.rs index b9045c72..092f6407 100644 --- a/src/machine/code_repo.rs +++ b/src/machine/code_repo.rs @@ -1,127 +1,52 @@ use crate::clause_types::*; -use crate::codegen::*; -use crate::debray_allocator::*; -use crate::forms::*; use crate::instructions::*; -use crate::machine::compile::*; -use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::indexmap::IndexSet; - -use std::collections::VecDeque; -use std::mem; - #[derive(Debug)] pub struct CodeRepo { - pub(super) cached_query: Code, - pub(super) goal_expanders: Code, - pub(super) term_expanders: Code, pub(super) code: Code, - pub(super) in_situ_code: Code, - pub(super) term_dir: TermDir, } impl CodeRepo { #[inline] - pub(super) fn new() -> Self { + pub(super) + fn new() -> Self { CodeRepo { - cached_query: vec![], - goal_expanders: Code::new(), - term_expanders: Code::new(), code: Code::new(), - in_situ_code: Code::new(), - term_dir: TermDir::new(), } } #[inline] - pub fn term_dir_entry_len(&self, key: PredicateKey) -> (usize, usize) { - self.term_dir - .get(&key) - .map(|entry| ((entry.0).0.len(), entry.1.len())) - .unwrap_or((0, 0)) - } - - #[inline] - pub fn truncate_terms( - &mut self, - key: PredicateKey, - len: usize, - queue_len: usize, - ) -> (Predicate, VecDeque) { - 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, - ) -> 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); + pub(super) + fn lookup_local_instr<'a>( + &'a self, + p: LocalCodePtr, + ) -> RefOrOwned<'a, Line> { + match p { + LocalCodePtr::Halt => { + unreachable!() } - _ => { - in_situ_code_dir.insert((name, arity), p); + LocalCodePtr::DirEntry(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::::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) @@ -131,32 +56,12 @@ impl CodeRepo { p: &CodePtr, ) -> Option> { match p { - &CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) => { - if p < self.goal_expanders.len() { - Some(RefOrOwned::Borrowed(&self.goal_expanders[p])) - } else { - None - } + &CodePtr::Local(local) => { + return Some(self.lookup_local_instr(local)); } - &CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) => { - if p < self.term_expanders.len() { - Some(RefOrOwned::Borrowed(&self.term_expanders[p])) - } else { - None - } + &CodePtr::REPL(..) => { + 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, _) => { let call_clause = call_clause!( ClauseType::BuiltIn(built_in.clone()), @@ -164,14 +69,27 @@ impl CodeRepo { 0, last_call ); + Some(RefOrOwned::Owned(call_clause)) } &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)) } - &CodePtr::VerifyAttrInterrupt(p) => Some(RefOrOwned::Borrowed(&self.code[p])), - &CodePtr::DynamicTransaction(..) => None, + &CodePtr::VerifyAttrInterrupt(p) => { + Some(RefOrOwned::Borrowed(&self.code[p])) + } +/* + &CodePtr::DynamicTransaction(..) => { + None + } +*/ } } } diff --git a/src/machine/code_walker.rs b/src/machine/code_walker.rs index 152395c5..94944889 100644 --- a/src/machine/code_walker.rs +++ b/src/machine/code_walker.rs @@ -1,73 +1,39 @@ use crate::instructions::*; -use std::collections::VecDeque; +use indexmap::IndexSet; -fn scan_for_trust_me( - code: &Code, - jmp_offsets: &mut VecDeque, - before_idx: usize, - after_idx: &mut usize, -) { - // record the location of the line after the TrustMe capping the - // choice instruction sequence to after_idx. - loop { - match &code[*after_idx] { - &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) | - &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) | - &Line::IndexedChoice(IndexedChoiceInstruction::Retry(offset)) => { - *after_idx += offset; - } - &Line::Choice(ChoiceInstruction::DefaultTrustMe) | - &Line::Choice(ChoiceInstruction::TrustMe) | - &Line::IndexedChoice(IndexedChoiceInstruction::Trust(..)) => { - break; - } - _ => { - *after_idx += 1; +fn capture_offset(line: &Line, index: usize, stack: &mut Vec) -> bool { + match line { + &Line::Choice(ChoiceInstruction::TryMeElse(offset)) if offset > 0 => { + stack.push(index + offset); + } + &Line::Choice(ChoiceInstruction::DefaultRetryMeElse(offset)) | + &Line::Choice(ChoiceInstruction::RetryMeElse(offset)) if offset > 0 => { + stack.push(index + offset); + } + &Line::Control(ControlInstruction::JmpBy(_, offset, _, false)) => { + stack.push(index + offset); + } + &Line::Control(ControlInstruction::JmpBy(_, offset, _, true)) => { + stack.push(index + offset); + return true; + } + &Line::Control(ControlInstruction::Proceed) | + &Line::Control(ControlInstruction::CallClause(_, _, _, true, _)) => { + return true; + } + &Line::Control(ControlInstruction::RevJmpBy(offset)) => { + 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; -} - -fn capture_next_range(code: &Code, queue: &mut VecDeque, 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, - }; - } + false } /* This function walks the code of a single predicate, supposed to @@ -76,15 +42,22 @@ fn capture_next_range(code: &Code, queue: &mut VecDeque, last_idx: &mut u */ 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() { - let mut last_idx = first_idx; + while let Some(first_index) = stack.pop() { + if visited_indices.contains(&first_index) { + continue; + } else { + visited_indices.insert(first_index); + } - capture_next_range(code, &mut queue, &mut last_idx); - - for instr in &code[first_idx .. last_idx + 1] { + for (index, instr) in code[first_index ..].iter().enumerate() { 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 * 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]); @@ -106,3 +80,4 @@ pub fn walk_code_mut(code: &mut Code, p: usize, mut walker: impl FnMut(&mut Line } } } +*/ diff --git a/src/machine/compile.rs b/src/machine/compile.rs index 36544eba..13ac32c5 100644 --- a/src/machine/compile.rs +++ b/src/machine/compile.rs @@ -1,1454 +1,1712 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::parser::get_desc; -use crate::prolog_parser::tabled_rc::TabledData; - use crate::codegen::*; use crate::debray_allocator::*; -use crate::forms::*; -use crate::instructions::*; -use crate::iterators::*; -use crate::machine::code_walker::*; -use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; -use crate::machine::term_expansion::ExpansionAdditionResult; -use crate::machine::toplevel::*; +use crate::indexing::{merge_clause_index, remove_index}; +use crate::machine::load_state::set_code_index; +use crate::machine::loader::*; +use crate::machine::load_state::LoadState; use crate::machine::*; +use crate::machine::term_stream::*; -use crate::indexmap::{IndexMap, IndexSet}; - -use crate::ref_thread_local::RefThreadLocal; +use slice_deque::sdeq; use std::cell::Cell; use std::collections::VecDeque; -use std::fs::File; -use std::mem; -use std::path::PathBuf; +use std::ops::Range; -#[allow(dead_code)] -pub fn print_code(code: &Code) { - for clause in code { - match clause { - &Line::Arithmetic(ref arith) => println!("{}", arith), - &Line::Fact(ref fact_instr) => println!("{}", fact_instr), - &Line::Cut(ref cut) => println!("{}", cut), - &Line::Choice(ref choice) => println!("{}", choice), - &Line::Control(ref control) => println!("{}", control), - &Line::IndexedChoice(ref choice) => println!("{}", choice), - &Line::Indexing(ref indexing) => println!("{}", indexing), - &Line::Query(ref query_instr) => println!("{}", query_instr), - } - } -} - -fn fix_filename( - atom_tbl: TabledData, - mut path: PathBuf, -) -> Result -{ - if !path.is_file() { - if path.extension().is_none() { - path.set_extension("pl"); - } - - if !path.is_file() { - let filename = clause_name!(path.to_string_lossy().to_string(), atom_tbl); - return Err(SessionError::InvalidFileName(filename)); - } - } - - Ok(path) -} - -fn load_module( - wam: &mut Machine, - stream: Stream, - suppress_warnings: bool, - listing_src: &ListingSource, -) -> Result { - // follow the operation of compile_user_module, but before - // compiling, check that a module is declared in the file. if not, - // throw an exception. - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - setup_indices(wam, clause_name!("builtins"), &mut indices)?; - - let mut compiler = ListingCompiler::new( - &wam.code_repo, - suppress_warnings, - listing_src.clone(), - ); - - let mut stream = parsing_stream(stream)?; - - let results = compiler.gather_items( - wam, - &mut stream, - &mut indices, - ); - - let module_name = if let Some(ref module) = &compiler.module { - module.module_decl.name.clone() - } else { - // this impromptu definition (namely, its exports) will be filled out later. - let module_decl = ModuleDecl { name: listing_src.name(), exports: vec![] }; - - let mut module = Module::new(module_decl, wam.indices.atom_tbl.clone(), listing_src.clone()); - let module_name = module.module_decl.name.clone(); - - module.is_impromptu_module = true; - - compiler.module = Some(module); - module_name - }; - - results.and_then(|results| compile_work_impl(&mut compiler, wam, indices, results)) - .or_else(|e| { - wam.indices.take_module(module_name.clone()); - compiler.print_error(&e); - Err(e) - })?; - - Ok(module_name) +struct StandaloneCompileResult { + clause_code: Code, + standalone_skeleton: PredicateSkeleton, } pub(super) -fn load_module_from_file( +fn bootstrapping_compile( + stream: Stream, wam: &mut Machine, - path_buf: PathBuf, - suppress_warnings: bool, -) -> Result { - let mut path_buf = fix_filename(wam.indices.atom_tbl.clone(), path_buf)?; - let filename = clause_name!(path_buf.to_string_lossy().to_string(), wam.indices.atom_tbl); + listing_src: ListingSource, +) -> Result<(), SessionError> { + let stream = &mut parsing_stream(stream)?; + let term_stream = + BootstrappingTermStream::from_prolog_stream( + stream, + wam.machine_st.atom_tbl.clone(), + wam.machine_st.flags, + listing_src, + ); - let file_handle = Stream::from_file_as_input(filename.clone(), File::open(&path_buf).or_else(|_| { - Err(SessionError::InvalidFileName(filename.clone())) - })?); + let loader = Loader::new(term_stream, wam); + loader.load()?; - path_buf.pop(); - - let listing_src = ListingSource::from_file_and_path(filename, path_buf); - load_module(wam, file_handle, suppress_warnings, &listing_src) + Ok(()) } -pub type PredicateCompileQueue = (Predicate, VecDeque); - // throw errors if declaration or query found. +pub(super) fn compile_relation( cg: &mut CodeGenerator, tl: &TopLevel -) -> Result { +) -> Result { match tl { - &TopLevel::Declaration(_) | &TopLevel::Query(_) => Err(ParserError::ExpectedRel), - &TopLevel::Predicate(ref clauses) => cg.compile_predicate(&clauses.0), - &TopLevel::Fact(ref fact, ..) => Ok(cg.compile_fact(fact)), - &TopLevel::Rule(ref rule, ..) => cg.compile_rule(rule), + &TopLevel::Declaration(_) | &TopLevel::Query(_) => + Err(CompilationError::ExpectedRel), + &TopLevel::Predicate(ref clauses) => + cg.compile_predicate(&clauses), + &TopLevel::Fact(ref fact, ..) => + Ok(cg.compile_fact(fact)), + &TopLevel::Rule(ref rule, ..) => + cg.compile_rule(rule), } } -fn issue_singleton_warnings( - src_name: ClauseName, - terms_and_locs: Vec<(Term, usize, usize)>, -) { - for (term, line_num, _col_num) in terms_and_locs { - let mut singletons = vec![]; - let mut var_count = IndexMap::new(); - - for subterm in breadth_first_iter(&term, true) { - if let TermRef::Var(_, _, var) = subterm { - let entry = var_count.entry(var).or_insert(0); - *entry += 1; - } - } - - for (var, count) in var_count { - if count == 1 && !var.starts_with("_") && var.as_str() != "!" { - singletons.push(var); - } - } - - if let Some(last_var) = singletons.pop() { - print!("Warning: {}:{}: Singleton variables: [", - src_name, line_num); - - for var in singletons { - print!("{}, ", var); - } - - println!("{}]", last_var); - } - } -} - -// set first jmp_by_call or jmp_by_index instruction to code.len() - -// idx, where idx is the place it occurs. It only does this to the -// *first* uninitialized jmp index it encounters, then returns. -fn set_first_index(code: &mut Code) { - let code_len = code.len(); - - for (idx, line) in code.iter_mut().enumerate() { - match line { - &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) - if *offset == 0 => - { - *offset = code_len - idx; - debug_assert!(*offset > 0); - - break; - } - _ => {} - }; - } -} - -pub fn compile_appendix( +pub(super) +fn compile_appendix( code: &mut Code, queue: &VecDeque, + jmp_by_locs: Vec, non_counted_bt: bool, -) -> Result<(), ParserError> { + atom_tbl: TabledData, +) -> Result<(), CompilationError> { + let mut jmp_by_locs = VecDeque::from(jmp_by_locs); + for tl in queue.iter() { - set_first_index(code); - let mut cg = CodeGenerator::::new(non_counted_bt); + let code_len = code.len(); + let jmp_by_offset = jmp_by_locs.pop_front().unwrap(); + + match &mut code[jmp_by_offset] { + &mut Line::Control(ControlInstruction::JmpBy(_, ref mut offset, ..)) => { + *offset = code_len - jmp_by_offset; + } + _ => { + unreachable!() + } + } + + // false because the inner predicate is a one-off, hence not extensible. + let settings = CodeGenSettings::new(false, non_counted_bt); + + let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); let decl_code = compile_relation(&mut cg, tl)?; + + jmp_by_locs.extend(cg.jmp_by_locs.into_iter().map(|offset| offset + code.len())); code.extend(decl_code.into_iter()); } Ok(()) } -fn append_trivial_goal(name: &ClauseName, pred: &mut Predicate) -{ - let var = Box::new(Term::Var(Cell::default(), Rc::new(String::from("X")))); - let body = QueryTerm::Clause( - Cell::default(), - ClauseType::from(clause_name!("$at_end_of_expansion"), 0, None), - vec![], - false - ); +fn lower_bound_of_target_clause(skeleton: &PredicateSkeleton, target_pos: usize) -> usize { + if target_pos == 0 { + return 0; + } - let rule = Rule { - head: (name.clone(), vec![var.clone(), var], body), - clauses: vec![] - }; + let arg_num = skeleton.clauses[target_pos - 1].opt_arg_index_key.arg_num(); - pred.0.push(PredicateClause::Rule(rule, 0, 0)); -} + if arg_num == 0 { + return target_pos - 1; + } -impl CodeRepo { - pub fn compile_hook( - &mut self, - hook: CompileTimeHook, - ) -> Result<(), ParserError> { - let key = (hook.name(), hook.arity()); + for index in (0 .. target_pos - 1).rev() { + let current_arg_num = skeleton.clauses[index].opt_arg_index_key.arg_num(); - match self.term_dir.get_mut(&key) { - Some(ref mut preds) => { - append_trivial_goal(&key.0, &mut preds.0); - - let mut cg = CodeGenerator::::new(false); - let mut code = cg.compile_predicate(&(preds.0).0)?; - - compile_appendix(&mut code, &preds.1, false)?; - - (preds.0).0.pop(); - - Ok(match hook { - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - self.term_expanders = code - } - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - self.goal_expanders = code - } - }) - } - None => Ok(match hook { - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - if self.term_expanders.is_empty() { - let mut preds = Predicate::new(); - append_trivial_goal(&key.0, &mut preds); - - let mut cg = CodeGenerator::::new(false); - self.term_expanders = cg.compile_predicate(&preds.0)?; - } - } - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - if self.goal_expanders.is_empty() { - let mut preds = Predicate::new(); - append_trivial_goal(&key.0, &mut preds); - - let mut cg = CodeGenerator::::new(false); - self.goal_expanders = cg.compile_predicate(&preds.0)?; - } - } - }) + if current_arg_num == 0 || current_arg_num != arg_num { + return index + 1; } } + + 0 } -fn compile_query( - terms: Vec, +fn compile_standalone_clause( + clause: PredicateClause, queue: VecDeque, -) -> Result<(Code, AllocVarDict), ParserError> { - // count backtracking inferences. - let mut cg = CodeGenerator::::new(false); - let mut code = cg.compile_query(&terms)?; + settings: CodeGenSettings, + atom_tbl: TabledData, +) -> Result { + let mut cg = CodeGenerator::::new(atom_tbl.clone(), settings); + let mut clause_code = cg.compile_predicate(&vec![clause])?; - compile_appendix(&mut code, &queue, false)?; - Ok((code, cg.take_vars())) -} - -fn add_hooks_to_mockup( - code_repo: &mut CodeRepo, - hook: CompileTimeHook, - expansions: (Predicate, VecDeque), -) { - let key = (hook.name(), hook.arity()); - let preds = code_repo - .term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); - - (preds.0).0.extend((expansions.0).0.into_iter()); - preds.1.extend(expansions.1.into_iter()); -} - -fn setup_module_expansions(wam: &mut Machine, module: &Module) { - let term_expansions = module.term_expansions.clone(); - let goal_expansions = module.goal_expansions.clone(); - - add_hooks_to_mockup( - &mut wam.code_repo, - CompileTimeHook::TermExpansion, - term_expansions, - ); - - add_hooks_to_mockup( - &mut wam.code_repo, - CompileTimeHook::GoalExpansion, - goal_expansions, - ); -} - -pub(super) -fn compile_into_module( - wam: &mut Machine, - module_name: ClauseName, - src: Stream, - name: ClauseName, -) -> EvalSession { - let mut indices = default_index_store!(wam.atom_tbl_of(&name)); - let module = wam.indices.take_module(module_name.clone()).unwrap(); - - indices.code_dir = module.code_dir.clone(); - indices.op_dir = module.op_dir.clone(); - indices.atom_tbl = module.atom_tbl.clone(); - - let mut compiler = ListingCompiler::new( - &wam.code_repo, - true, - module.listing_src.clone(), - ); - - match compile_into_module_impl(wam, &mut compiler, module, src, indices) { - Ok(()) => { - EvalSession::EntrySuccess - } - Err(e) => { - compiler.drop_expansions(&mut wam.code_repo); - EvalSession::from(e) - } - } -} - -fn compile_into_module_impl( - wam: &mut Machine, - compiler: &mut ListingCompiler, - module: Module, - src: Stream, - mut indices: IndexStore, -) -> Result<(), SessionError> { - setup_module_expansions(wam, &module); - - let module_name = module.module_decl.name.clone(); - // compiler.module = Some(module); This trips the goal expansion up. Should be possible to 'merge' modules. - // A much better strategy! - wam.indices.insert_module(module); - - wam.code_repo.compile_hook(CompileTimeHook::TermExpansion)?; - wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion)?; - - let mut results = compiler.gather_items( - wam, - &mut parsing_stream(src)?, - &mut indices, + compile_appendix( + &mut clause_code, + &queue, + cg.jmp_by_locs, + settings.non_counted_bt, + atom_tbl, )?; - 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)?; - - let top_level_term_dir = results.top_level_term_dirs.consolidate(); - let module = wam.indices.take_module(module_name).unwrap(); - - add_module( - wam, - module, - indices, - 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); - - Ok(compiler.drop_expansions(&mut wam.code_repo)) + Ok(StandaloneCompileResult { + clause_code, + standalone_skeleton: cg.skeleton, + }) } -#[derive(Debug)] -pub struct GatherResult { - dynamic_clause_map: DynamicClauseMap, - pub(crate) worker_results: Vec, - toplevel_results: Vec, - toplevel_indices: IndexStore, - addition_results: ExpansionAdditionResult, - top_level_terms: Vec<(Term, usize, usize)>, - top_level_term_dirs: TermDirQuantum, - module_term_dirs: TermDirQuantum, - in_situ_code_dir: InSituCodeDir, - in_situ_code: Code, - in_situ_module_dir: ModuleStubDir, -} - -#[derive(Debug)] -pub struct ClauseCodeGenerator { - len_offset: usize, - code: Code, - module_name: ClauseName, - pi_to_loc: IndexMap, -} - -impl ClauseCodeGenerator { - #[inline] - fn new(len_offset: usize, module_name: ClauseName) -> Self { - ClauseCodeGenerator { - len_offset, - code: vec![], - module_name, - pi_to_loc: IndexMap::new(), +fn derelictize_try_me_else( + code: &mut Code, + index: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + match &mut code[index] { + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + None } - } - - // compiles the latest version of clause/2. - fn generate_clause_code( - &mut self, - dynamic_clause_map: &DynamicClauseMap, - wam: &Machine, - ) -> Result<(), SessionError> { - for ((name, arity), heads_and_tails) in dynamic_clause_map { - if heads_and_tails.is_empty() { - continue; - } - - let predicate = Predicate( - heads_and_tails - .iter() - .map(|(head, tail)| { - let clause = Term::Clause( - Cell::default(), - clause_name!("clause"), - vec![Box::new(head.clone()), Box::new(tail.clone())], - None, - ); - - PredicateClause::Fact(clause, 0, 0) - }) - .collect(), + Line::Choice(ChoiceInstruction::TryMeElse(ref mut offset)) => { + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse(index, *offset), ); - let p = self.code.len() + wam.code_repo.code.len() + self.len_offset; - let mut cg = CodeGenerator::::new(false); - - let mut decl_code = compile_relation( - &mut cg, - &TopLevel::Predicate(predicate), - )?; - - compile_appendix(&mut decl_code, &VecDeque::new(), false)?; - - self.pi_to_loc.insert((name.clone(), *arity), p); - self.code.extend(decl_code.into_iter()); + Some(mem::replace(offset, 0)) + } + _ => { + unreachable!() } - - Ok(()) } +} - fn add_clause_code(self, wam: &mut Machine, dynamic_code_dir: DynamicClauseMap) - { - wam.code_repo.code.extend(self.code.into_iter()); +fn merge_indices( + code: &mut Code, + target_index_loc: usize, + index_range: Range, + skeleton: &mut [ClauseIndexInfo], + retraction_info: &mut RetractionInfo, +) { + for clause_index in index_range { + if let Some(index_loc) = skeleton[clause_index].opt_arg_index_key.switch_on_term_loc() { + let clause_loc = + find_inner_choice_instr(code, skeleton[clause_index].clause_start, index_loc); - if self.module_name.as_str() == "user" { - for ((name, arity), _) in &dynamic_code_dir { - wam.indices.code_dir.entry((name.clone(), *arity)) - .or_insert(CodeIndex::dynamic_undefined(clause_name!("user"))); + let target_indexing_line = + to_indexing_line_mut(&mut code[target_index_loc]).unwrap(); + + skeleton[clause_index].opt_arg_index_key.set_switch_on_term_loc(target_index_loc); + + merge_clause_index( + target_indexing_line, + &mut skeleton[0 .. clause_index + 1], + clause_loc, + AppendOrPrepend::Append, + ); + + retraction_info.push_record( + RetractionRecord::AddedIndex( + skeleton[clause_index].opt_arg_index_key.clone(), + clause_loc, + ), + ); + } else { + break; + } + } +} + +fn find_inner_choice_instr( + code: &Code, + mut index: usize, + index_loc: usize, +) -> usize { + loop { + match &code[index] { + Line::Choice(ChoiceInstruction::TryMeElse(o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + if *o > 0 { + return index; + } else { + index = index_loc; + } + } + Line::Choice(ChoiceInstruction::TrustMe(_)) => { + return index; + } + Line::IndexingCode(indexing_code) => { + match &indexing_code[0] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, v, ..) + ) => { + index += v; + } + _ => { + unreachable!(); + } + } + } + Line::Control(ControlInstruction::RevJmpBy(offset)) => { + index -= offset; + } + _ => { + /* Here we land at the line after a TryMeElse(0), + * which happens iff a single clause belongs to the + * indexed subsequence. So, end the search by pointing + * to the original derelict TryMeElse. + */ + return index - 1; } } - - for ((name, arity), _) in dynamic_code_dir { - wam.indices.dynamic_code_dir.insert((name.owning_module(), name, arity), - DynamicPredicateInfo::default()); - } - - for ((name, arity), p) in self.pi_to_loc { - let entry = wam - .indices - .dynamic_code_dir - .entry((name.owning_module(), name, arity)) - .or_insert(DynamicPredicateInfo::default()); - - entry.clauses_subsection_p = p; - } } } -fn insert_or_refresh_term_dir_quantum( - term_dir: &TermDir, - key: PredicateKey, - term_dirs: &mut TermDirQuantum +fn remove_index_from_subsequence( + code: &mut Code, + opt_arg_index_key: &OptArgIndexKey, + clause_start: usize, + retraction_info: &mut RetractionInfo, ) { - match term_dir.get(&key) { - Some((ref preds, ref queue)) => { - let entry = TermDirQuantumEntry::from(preds, queue); - term_dirs.insert_or_refresh(key, entry); + if let Some(index_loc) = opt_arg_index_key.switch_on_term_loc() { + let clause_start = find_inner_choice_instr(code, clause_start, index_loc); + + let target_indexing_line = + to_indexing_line_mut(&mut code[index_loc]).unwrap(); + + let offset = clause_start - index_loc + 1; + + remove_index(opt_arg_index_key, target_indexing_line, offset); + + // TODO: this isn't sufficiently precise. The removed offset could + // appear anywhere inside an Internal record. + retraction_info.push_record( + RetractionRecord::RemovedIndex( + index_loc, + opt_arg_index_key.clone(), + offset, + ), + ); + } +} + +fn merge_indexed_subsequences( + code: &mut Code, + skeleton: &mut PredicateSkeleton, + lower_upper_bound: usize, + upper_lower_bound: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + // patch the inner-threaded choice instructions to link the + // two sequences, patch lower_bound's outer-threaded choice + // instruction to TrustMe (or RetryMeElse), and derelict-ize + // target_pos + 1's inner TryMeElse. + + let inner_trust_me_loc = + skeleton.clauses[upper_lower_bound - 2].clause_start; + + let inner_try_me_else_loc = find_inner_choice_instr( + code, + skeleton.clauses[upper_lower_bound].clause_start, + skeleton.clauses[upper_lower_bound].opt_arg_index_key + .switch_on_term_loc().unwrap(), + ); + + match &mut code[inner_try_me_else_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse( + skeleton.clauses[upper_lower_bound].clause_start, + *o, + ), + ); + + match *o { + 0 => { + code[inner_try_me_else_loc] = + Line::Choice(ChoiceInstruction::TrustMe(0)); + } + o => { + match &code[inner_try_me_else_loc + o] { + Line::Control(ControlInstruction::RevJmpBy(0)) => { + code[inner_try_me_else_loc] = + Line::Choice(ChoiceInstruction::TrustMe(o)); + } + _ => { + code[inner_try_me_else_loc] = + Line::Choice(ChoiceInstruction::RetryMeElse(o)); + } + } + } + } + } + _ => { + } + } + + thread_choice_instr_at_to( + code, + inner_trust_me_loc, + inner_try_me_else_loc, + retraction_info, + ); + + let mut end_of_upper_lower_bound = None; + + for index in upper_lower_bound .. skeleton.clauses.len() { + if !skeleton.clauses[index].opt_arg_index_key.is_some() { + end_of_upper_lower_bound = Some(index); + break; + } + } + + let outer_threaded_choice_instr_loc = + skeleton.clauses[lower_upper_bound].clause_start - 2; + + match end_of_upper_lower_bound { + Some(outer_threaded_clause_index) => { + thread_choice_instr_at_to( + code, + outer_threaded_choice_instr_loc, + skeleton.clauses[outer_threaded_clause_index].clause_start, + retraction_info, + ); } None => { - let entry = TermDirQuantumEntry::from(&Predicate::new(), &VecDeque::new()); - term_dirs.insert_or_refresh(key, entry); + match &mut code[outer_threaded_choice_instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse(inner_trust_me_loc, *o), + ); + + *o = 0; + + return Some(IndexPtr::Index(outer_threaded_choice_instr_loc + 1)); + } + _ => { + } + } + } + } + + None +} + +fn delete_from_dynamic_skeleton( + compilation_target: CompilationTarget, + key: PredicateKey, + skeleton: &mut PredicateSkeleton, + target_pos: usize, + retraction_info: &mut RetractionInfo, +) -> usize { + let clause_clause_loc = skeleton.clause_clause_locs.remove(target_pos); + let clause_index_info = skeleton.clauses.remove(target_pos); + + retraction_info.push_record( + RetractionRecord::RemovedDynamicSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + ), + ); + + clause_clause_loc +} + +fn blunt_leading_choice_instr( + code: &mut Code, + mut instr_loc: usize, + retraction_info: &mut RetractionInfo, +) -> usize { + loop { + match &mut code[instr_loc] { + Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + retraction_info.push_record( + RetractionRecord::ModifiedRetryMeElse(instr_loc, *o), + ); + + code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(*o)); + + return instr_loc; + } + Line::Choice(ChoiceInstruction::TrustMe(offset)) => { + retraction_info.push_record( + RetractionRecord::AppendedTrustMe(instr_loc, *offset, false), + ); + + code[instr_loc] = Line::Choice(ChoiceInstruction::TryMeElse(0)); + return instr_loc + 1; + } + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + return instr_loc + 1; + } + Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + instr_loc += *o; + } + Line::Control(ControlInstruction::RevJmpBy(o)) => { + instr_loc -= *o; + } + _ => { + unreachable!() + } } } } -#[derive(Debug)] -pub struct ListingCompiler { - module: Option, - user_term_dir: TermDir, - orig_term_expansion_lens: (usize, usize), - orig_goal_expansion_lens: (usize, usize), - initialization_goals: (Vec, VecDeque), - suppress_warnings: bool, - listing_src: ListingSource, // a file? a module? -} - -fn add_toplevel( - wam: &mut Machine, - indices: IndexStore, - term_dir: TermDir, +fn set_switch_var_offset_to_choice_instr( + code: &mut Code, + index_loc: usize, + offset: usize, + retraction_info: &mut RetractionInfo, ) { - wam.add_batched_code_dir(indices.code_dir); - wam.add_batched_ops(indices.op_dir); - wam.add_in_situ_module_dir(indices.module_dir); + let target_indexing_line = + to_indexing_line_mut(&mut code[index_loc]).unwrap(); - wam.code_repo.term_dir.extend(term_dir.into_iter()); + let v = + match &mut target_indexing_line[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, ..)) => { + *v + } + _ => { + unreachable!(); + } + }; + + match &code[index_loc + v] { + Line::Choice(ChoiceInstruction::TryMeElse(_)) => { + } + _ => { + set_switch_var_offset( + code, + index_loc, + offset, + retraction_info, + ); + } + } } #[inline] -fn add_module( - wam: &mut Machine, - mut module: Module, - indices: IndexStore, - term_dir: TermDir, +fn set_switch_var_offset( + code: &mut Code, + index_loc: usize, + offset: usize, + retraction_info: &mut RetractionInfo, ) { - module.code_dir.extend(indices.code_dir); - module.op_dir.extend(indices.op_dir); - module.term_dir.extend(term_dir); + let target_indexing_line = + to_indexing_line_mut(&mut code[index_loc]).unwrap(); - wam.add_in_situ_module_dir(indices.module_dir); - wam.add_module(module); + let old_v = + match &mut target_indexing_line[0] { + IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, ref mut v, ..)) => { + mem::replace(v, offset) + } + _ => { + unreachable!() + } + }; + + retraction_info.push_record( + RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v), + ); } -fn add_non_module_code( - wam: &mut Machine, - dynamic_clause_map: DynamicClauseMap, - code: Code, - indices: IndexStore, - term_dir: TermDir, -) -> Result<(), SessionError> { - wam.check_toplevel_code(&indices)?; +fn internalize_choice_instr_at( + code: &mut Code, + instr_loc: usize, + retraction_info: &mut RetractionInfo, +) { + match &mut code[instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse(instr_loc, 0), + ); - let mut clause_code_generator = ClauseCodeGenerator::new(code.len(), clause_name!("user")); - clause_code_generator.generate_clause_code(&dynamic_clause_map, wam)?; - - add_toplevel(wam, indices, term_dir); - wam.code_repo.code.extend(code); - clause_code_generator.add_clause_code(wam, dynamic_clause_map); - - Ok(()) -} - -pub(super) -fn load_library( - wam: &mut Machine, - name: ClauseName, - suppress_warnings: bool, -) -> Result { - match LIBRARIES.borrow().get(name.as_str()) { - Some(code) => { - let listing_src = ListingSource::User; - - load_module( - wam, - Stream::from(*code), - suppress_warnings, - &listing_src, - ) + code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(0)); } - None => { - let err = ExistenceError::ModuleSource(ModuleSource::Library( - name.clone() - )); + Line::Choice(ChoiceInstruction::TryMeElse(o)) => { + let o = *o; - Err(SessionError::ExistenceError(err)) - } - } -} + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse(instr_loc, o), + ); -impl ListingCompiler { - #[inline] - pub fn new( - code_repo: &CodeRepo, - suppress_warnings: bool, - listing_src: ListingSource, - ) -> Self { - ListingCompiler { - module: None, - user_term_dir: TermDir::new(), - orig_term_expansion_lens: code_repo - .term_dir_entry_len((clause_name!("term_expansion"), 2)), - orig_goal_expansion_lens: code_repo - .term_dir_entry_len((clause_name!("goal_expansion"), 2)), - initialization_goals: (vec![], VecDeque::from(vec![])), - suppress_warnings, - listing_src - } - } - - /* Replace calls to self with a localized index cell, not - * available to the global CodeIndex. This is done to implement - * logical update semantics for dynamic database updates. - */ - fn localize_self_calls(&mut self, key: PredicateKey, code: &mut Code, p: usize, target_p: usize) - { - let (name, arity) = key; - - let self_idx = CodeIndex::default(); - set_code_index!(self_idx, IndexPtr::Index(target_p), self.get_module_name()); - - walk_code_mut(code, p, |instr| - match instr { - Line::Control(ControlInstruction::CallClause(ref mut ct, ..)) => { - 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(); - } - _ => {} + match &mut code[instr_loc + o] { + Line::Control(ControlInstruction::RevJmpBy(p)) + if *p == 0 => { + code[instr_loc] = Line::Choice(ChoiceInstruction::TrustMe(o)); } + _ => { + code[instr_loc] = Line::Choice(ChoiceInstruction::RetryMeElse(o)); } - _ => {} - }, + } + } + _ => { + unreachable!(); + } + } +} + +fn thread_choice_instr_at_to( + code: &mut Code, + mut instr_loc: usize, + target_loc: usize, + retraction_info: &mut RetractionInfo, +) { + loop { + match &mut code[instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) + if target_loc >= instr_loc => { + retraction_info.push_record( + RetractionRecord::ReplacedChoiceOffset(instr_loc, *o), + ); + + *o = target_loc - instr_loc; + return; + } + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => { + instr_loc += *o; + } + Line::Control(ControlInstruction::RevJmpBy(ref mut o)) + if instr_loc >= target_loc => { + retraction_info.push_record( + RetractionRecord::ModifiedRevJmpBy(instr_loc, *o), + ); + + *o = instr_loc - target_loc; + return; + } + Line::Choice(ChoiceInstruction::TrustMe(ref mut o)) + if target_loc >= instr_loc => { + retraction_info.push_record( + RetractionRecord::AppendedTrustMe(instr_loc, *o, false), + //choice_instr.is_default()), + ); + + code[instr_loc] = + Line::Choice(ChoiceInstruction::RetryMeElse(target_loc - instr_loc)); + + return; + } + Line::Choice(ChoiceInstruction::TrustMe(o)) + if *o > 0 => { + instr_loc += *o; + } + _ => { + unreachable!() + } + } + } +} + +fn remove_non_leading_clause( + code: &mut Code, + preceding_choice_instr_loc: usize, + non_indexed_choice_instr_loc: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + match &mut code[non_indexed_choice_instr_loc] { + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) => { + let o = *o; + + thread_choice_instr_at_to( + code, + preceding_choice_instr_loc, + non_indexed_choice_instr_loc + o, + retraction_info, + ); + + None + } + Line::Choice(ChoiceInstruction::TrustMe(_)) => { + match &mut code[preceding_choice_instr_loc] { + Line::Choice(ChoiceInstruction::RetryMeElse(o)) => { + retraction_info.push_record( + RetractionRecord::ModifiedRetryMeElse( + preceding_choice_instr_loc, + *o, + ), + ); + + code[preceding_choice_instr_loc] = + Line::Choice(ChoiceInstruction::TrustMe(0)); + + None + } + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse( + preceding_choice_instr_loc, + *o, + ) + ); + + *o = 0; + + Some(IndexPtr::Index(preceding_choice_instr_loc + 1)) + } + _ => { + unreachable!(); + } + } + } + _ => { + unreachable!(); + } + } +} + +fn finalize_retract( + key: PredicateKey, + compilation_target: CompilationTarget, + skeleton: &mut PredicateSkeleton, + code_index: CodeIndex, + target_pos: usize, + index_ptr_opt: Option, + retraction_info: &mut RetractionInfo, +) -> usize { + let clause_clause_loc = + delete_from_dynamic_skeleton( + compilation_target.clone(), + key.clone(), + skeleton, + target_pos, + retraction_info, + ); + + if let Some(index_ptr) = index_ptr_opt { + set_code_index( + retraction_info, + &compilation_target, + key, + &code_index, + index_ptr, ); } - fn use_module( - &mut self, - submodule: ClauseName, - code_repo: &mut CodeRepo, - flags: MachineFlags, - wam_indices: &mut IndexStore, - indices: &mut IndexStore, - ) -> Result<(), SessionError> { - let module_name = self.get_module_name(); + clause_clause_loc +} - if let Some(mut submodule) = wam_indices.take_module(submodule) { - unwind_protect!( - indices.use_module(code_repo, flags, &submodule), - wam_indices.insert_module(submodule) - ); - - if let Some(ref mut module) = &mut self.module { - module.remove_module(module_name, &submodule); - unwind_protect!( - module.use_module(code_repo, flags, &submodule), - wam_indices.insert_module(submodule) +fn remove_leading_unindexed_clause( + code: &mut Code, + non_indexed_choice_instr_loc: usize, + retraction_info: &mut RetractionInfo, +) -> Option { + match &mut code[non_indexed_choice_instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) => { + if *o > 0 { + retraction_info.push_record( + RetractionRecord::ModifiedTryMeElse( + non_indexed_choice_instr_loc, + *o, + ) ); + + let o = mem::replace(o, 0); + + let index_ptr = blunt_leading_choice_instr( + code, + non_indexed_choice_instr_loc + o, + retraction_info, + ); + + Some(IndexPtr::Index(index_ptr)) } else { - submodule.inserted_expansions = true; - wam_indices.remove_module(clause_name!("user"), &submodule); + Some(IndexPtr::DynamicUndefined) } - - Ok(wam_indices.insert_module(submodule)) - } else { - let err = ExistenceError::ModuleSource(ModuleSource::File( - module_name, - )); - - Err(SessionError::ExistenceError(err)) + } + _ => { + unreachable!(); } } +} - fn use_qualified_module( - &mut self, - submodule: ClauseName, - code_repo: &mut CodeRepo, - flags: MachineFlags, - exports: &Vec, - wam_indices: &mut IndexStore, - indices: &mut IndexStore, - ) -> Result<(), SessionError> { - let module_name = self.get_module_name(); +fn prepend_compiled_clause( + code: &mut Code, + compilation_target: CompilationTarget, + key: PredicateKey, + mut clause_code: Code, + skeleton: &mut PredicateSkeleton, + retraction_info: &mut RetractionInfo, +) -> usize { + let clause_loc = code.len(); + let mut prepend_queue = sdeq![]; - if let Some(mut submodule) = wam_indices.take_module(submodule) { - unwind_protect!( - indices.use_qualified_module(code_repo, flags, &submodule, exports), - wam_indices.insert_module(submodule) - ); + let target_arg_num = skeleton.clauses[0].opt_arg_index_key.arg_num(); + let head_arg_num = skeleton.clauses[1].opt_arg_index_key.arg_num(); - if let &mut Some(ref mut module) = &mut self.module { - module.remove_module(module_name, &submodule); - unwind_protect!( - module.use_qualified_module(code_repo, flags, &submodule, exports), - wam_indices.insert_module(submodule) + if skeleton.clauses[0].opt_arg_index_key.switch_on_term_loc().is_some() { + match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) if target_arg_num == head_arg_num => { + prepend_queue.extend(clause_code.drain(3 ..)); + + skeleton.clauses[0].opt_arg_index_key += index_loc - 1; + skeleton.clauses[0].clause_start = clause_loc + 2; + + retraction_info.push_record( + RetractionRecord::AddedIndex( + skeleton.clauses[0].opt_arg_index_key.clone(), + skeleton.clauses[0].clause_start, + ), ); - } else { - submodule.inserted_expansions = true; - wam_indices.remove_module(clause_name!("user"), &submodule); + + let outer_thread_choice_loc = skeleton.clauses[1].clause_start - 2; + + retraction_info.push_record( + RetractionRecord::SkeletonClauseStartReplaced( + compilation_target, + key.clone(), + 1, + skeleton.clauses[1].clause_start, + ), + ); + + skeleton.clauses[1].clause_start = + find_inner_choice_instr( + code, + skeleton.clauses[1].clause_start, + index_loc, + ); + + let inner_thread_rev_offset = + 3 + prepend_queue.len() + clause_loc - skeleton.clauses[1].clause_start; + + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)), + ); + + prepend_queue.push_front( + Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())), + ); + + // prepend_queue is now: + // | TryMeElse N_2 + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1) + + prepend_queue.push_front( + Line::Control(ControlInstruction::RevJmpBy( + 1 + clause_loc - index_loc + )), + ); + + let outer_thread_choice_offset = // outer_thread_choice_loc WAS index_loc - 1.. + match derelictize_try_me_else(code, outer_thread_choice_loc, retraction_info) { + Some(next_subseq_offset) => { + // skeleton.clauses[1] has a non-stub TryMeElse. + + let outer_thread_rev_offset = + prepend_queue.len() + 1 + clause_loc - outer_thread_choice_loc - + next_subseq_offset; + + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(outer_thread_rev_offset)) + ); + + prepend_queue.len() + } + None => { + // This case occurs when the clauses of + // the host predicate, up to and including + // the prepending of this clause, are + // indexed. + + // The outer TryMeElse / RevJmpBy pushed + // in this case are stub instructions + // awaiting the addition of unindexed + // clauses. + + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(0)), + ); + + 0 + } + }; + + prepend_queue.push_front( + Line::Choice(ChoiceInstruction::TryMeElse(outer_thread_choice_offset)), + ); + + // prepend_queue is now: + // | TryMeElse N_3 + // | RevJmpBy (SwitchOnTerm at index_loc) + // | TryMeElse N_2 + // | (clause_code) + // N_2 | RevJmpBy (RetryMeElse(M_1) or TryMeElse(0) at index_loc + 1) + // N_3 | RevJmpBy (TryMeElse(N_1) at index_loc - 1 or TrustMe if N_1 == 0) + + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + + merge_clause_index( + target_indexing_line, + &mut skeleton.clauses, + clause_loc + 2, // == skeleton.clauses[0].clause_start + AppendOrPrepend::Prepend, + ); + + set_switch_var_offset( + code, + index_loc, + clause_loc - index_loc + 2, + retraction_info, + ); + + internalize_choice_instr_at(code, skeleton.clauses[1].clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + clause_loc + (outer_thread_choice_offset == 0) as usize } + _ => { + prepend_queue.extend(clause_code.drain(1 ..)); - Ok(wam_indices.insert_module(submodule)) - } else { - let err = ExistenceError::ModuleSource(ModuleSource::File( - module_name - )); + skeleton.clauses[0].opt_arg_index_key += clause_loc; + skeleton.clauses[0].clause_start = clause_loc + 2; - Err(SessionError::ExistenceError(err)) + let old_clause_start = skeleton.clauses[1].clause_start; + + let inner_thread_rev_offset = + 2 + prepend_queue.len() + clause_loc - old_clause_start; + + // this is a stub for chaining inner-threaded choice + // instructions. + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(0)) + ); + + let prepend_queue_len = prepend_queue.len(); + + match &mut prepend_queue[1] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) + if *o == 0 => { + *o = prepend_queue_len - 2; + } + _ => { + unreachable!(); + } + } + + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)), + ); + + prepend_queue.push_front( + Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())), + ); + + // prepend_queue is now: + // | TryMeElse(N_2) + // | SwitchOnTerm 2, ... + // | TryMeElse(0) + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1)) + + internalize_choice_instr_at(code, old_clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + clause_loc // + (outer_thread_choice_offset == 0 as usize) + } } - } + } else { + match skeleton.clauses[1].opt_arg_index_key.switch_on_term_loc() { + Some(_) => { + prepend_queue.extend(clause_code.drain(1 ..)); - #[inline] - fn get_module_name(&self) -> ClauseName { - self.module - .as_ref() - .map(|module| module.module_decl.name.clone()) - .unwrap_or(ClauseName::BuiltIn("user")) - } + let old_clause_start = skeleton.clauses[1].clause_start - 2; - fn generate_init_goal_code( - &mut self, - ) -> Result { - let query_terms = mem::replace(&mut self.initialization_goals.0, vec![]); - let queue = mem::replace(&mut self.initialization_goals.1, VecDeque::new()); + let inner_thread_rev_offset = + 1 + prepend_queue.len() + clause_loc - old_clause_start; - compile_query(query_terms, queue) - .map(|(code, _)| code) - .map_err(SessionError::from) - } + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)), + ); - 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(); + prepend_queue.push_front( + Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())), + ); - let idx = code_dir - .entry(key.clone()) - .or_insert(CodeIndex::default()); + // prepend_queue is now: + // | TryMeElse(N_2) + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1)) - 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); + internalize_choice_instr_at(code, old_clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + // skeleton.clauses[0].opt_arg_index_key += clause_loc; + skeleton.clauses[0].clause_start = clause_loc; + + clause_loc // + (outer_thread_choice_offset == 0 as usize) } None => { - let (decl, queue) = decl; + prepend_queue.extend(clause_code.drain(1 ..)); - let mut cg = CodeGenerator::::new(false); - let mut decl_code = cg.compile_predicate(&decl.0)?; + let old_clause_start = skeleton.clauses[1].clause_start; - compile_appendix(&mut decl_code, &queue, false)?; + let inner_thread_rev_offset = + 1 + prepend_queue.len() + clause_loc - old_clause_start; - let in_situ_p = in_situ_code.len(); + prepend_queue.push_back( + Line::Control(ControlInstruction::RevJmpBy(inner_thread_rev_offset)), + ); - in_situ_code.extend(decl_code.into_iter()); + prepend_queue.push_front( + Line::Choice(ChoiceInstruction::TryMeElse(prepend_queue.len())), + ); - 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); + // prepend_queue is now: + // | TryMeElse(N_2) + // | (clause_code) + // +N_2 | RevJmpBy (RetryMeElse(M_1)) + + internalize_choice_instr_at(code, old_clause_start, retraction_info); + + code.extend(prepend_queue.into_iter()); + + // skeleton.clauses[0].opt_arg_index_key += clause_loc; + skeleton.clauses[0].clause_start = clause_loc; + + clause_loc // + (outer_thread_choice_offset == 0 as usize) } - }) + } + } +} + +fn append_compiled_clause( + code: &mut Code, + mut clause_code: Code, + skeleton: &mut PredicateSkeleton, + retraction_info: &mut RetractionInfo, +) -> Option { + let clause_loc = code.len(); + let target_pos = skeleton.clauses.len() - 1; + let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); + + code.push(Line::Choice(ChoiceInstruction::TrustMe(0))); + skeleton.clauses[target_pos].clause_start = clause_loc; + + let mut code_ptr_opt = None; + + let lower_bound_arg_num = skeleton.clauses[lower_bound].opt_arg_index_key.arg_num(); + let target_arg_num = skeleton.clauses[target_pos].opt_arg_index_key.arg_num(); + + let threaded_choice_instr_loc = + match skeleton.clauses[lower_bound].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) if lower_bound_arg_num == target_arg_num => { + code.extend(clause_code.drain(3 ..)); // skip the indexing code + + // set skeleton[target_pos].opt_arg_index_key to + // index_loc. its original value is always 1. + skeleton.clauses[target_pos].opt_arg_index_key += index_loc - 1; + + retraction_info.push_record( + RetractionRecord::AddedIndex( + skeleton.clauses[target_pos].opt_arg_index_key.clone(), + skeleton.clauses[target_pos].clause_start, + ), + ); + + let target_indexing_line = to_indexing_line_mut(&mut code[index_loc]).unwrap(); + + merge_clause_index( + target_indexing_line, + &mut skeleton.clauses[lower_bound ..], + clause_loc, + AppendOrPrepend::Append, + ); + + if lower_bound + 1 == target_pos { + let lower_bound_clause_start = find_inner_choice_instr( + code, + skeleton.clauses[lower_bound].clause_start, + index_loc, + ); + + set_switch_var_offset( + code, + index_loc, + lower_bound_clause_start - index_loc, + retraction_info, + ); + } + + skeleton.clauses[target_pos - 1].clause_start + } + _ => { + skeleton.clauses[target_pos].opt_arg_index_key += clause_loc; + code.extend(clause_code.drain(1 ..)); + + match skeleton.clauses[lower_bound].opt_arg_index_key.switch_on_term_loc() { + Some(_) => { + if lower_bound == 0 { + code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start - 2); + } + + skeleton.clauses[lower_bound].clause_start - 2 + } + None => { + if lower_bound == 0 { + code_ptr_opt = Some(skeleton.clauses[lower_bound].clause_start); + } + + match skeleton.clauses[target_pos].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) => { + // point to the inner-threaded TryMeElse(0) if target_pos is + // indexed, and make switch_on_term point one line after it in + // its variable offset. + skeleton.clauses[target_pos].clause_start += 2; + + set_switch_var_offset( + code, + index_loc, + 2, + retraction_info, + ); + } + None => { + } + } + + skeleton.clauses[lower_bound].clause_start + } + } + } + }; + + thread_choice_instr_at_to(code, threaded_choice_instr_loc, clause_loc, retraction_info); + + code_ptr_opt +} + +#[inline] +fn mergeable_indexed_subsequences( + lower_bound: usize, + target_pos: usize, + skeleton: &PredicateSkeleton, +) -> bool { + let lower_bound_arg_num = skeleton.clauses[lower_bound].opt_arg_index_key.arg_num(); + + if target_pos + 1 < skeleton.clauses.len() { + let succ_arg_num = skeleton.clauses[target_pos + 1].opt_arg_index_key.arg_num(); + let target_arg_num = skeleton.clauses[target_pos].opt_arg_index_key.arg_num(); + + return target_arg_num != succ_arg_num && lower_bound_arg_num == succ_arg_num; } - fn adapt_in_situ_code( + false +} + +impl<'a> LoadState<'a> { + fn compile( &mut self, - decls: Vec, - wam: &Machine, - code_dir: &mut CodeDir, - module_dir: &mut ModuleDir, - in_situ_code: &mut Code, - in_situ_code_dir: &InSituCodeDir, - in_situ_module_dir: &ModuleStubDir, - ) -> Result<(), SessionError> { - for decl in decls { - let key = decl.0 - .predicate_indicator() - .ok_or(SessionError::NamelessEntry)?; + key: PredicateKey, + predicates: &Vec, + queue: &VecDeque, + settings: CodeGenSettings, + ) -> Result { + let code_index = self.get_or_insert_code_index(key.clone()); + let code_len = self.wam.code_repo.code.len(); + let mut code_ptr = code_len; - let (name, _arity) = key.clone(); - let module_name = name.owning_module(); + let mut cg = CodeGenerator::::new( + self.wam.machine_st.atom_tbl.clone(), + settings, + ); - match in_situ_module_dir.get(&module_name) { - 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![] - }; + let mut code = cg.compile_predicate(predicates)?; - Module::new( - module_decl, - module_stub.atom_tbl.clone(), - self.listing_src.clone(), - ) - }); + compile_appendix( + &mut code, + queue, + cg.jmp_by_locs, + settings.non_counted_bt, + self.wam.machine_st.atom_tbl.clone(), + )?; - self.set_code_index( - wam, - key, - in_situ_code, - &mut module.code_dir, - &module_stub.in_situ_code_dir, - decl, - )?; + if settings.is_extensible { + for clause_index_info in cg.skeleton.clauses.iter_mut() { + clause_index_info.clause_start += code_len; + clause_index_info.opt_arg_index_key += code_len; + } + + match &mut code[0] { + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + code_ptr += 1; } _ => { - self.set_code_index( - wam, - key, - in_situ_code, - code_dir, - in_situ_code_dir, - decl, - )?; + } + } + + match self.wam.indices.get_predicate_skeleton( + &self.compilation_target, + &key, + ) { + Some(skeleton) => { + self.retraction_info.push_record( + RetractionRecord::SkeletonClauseTruncateBack( + self.compilation_target.clone(), + key.clone(), + skeleton.clauses.len(), + ), + ); + + skeleton.clauses.extend(cg.skeleton.clauses.into_iter()); + } + None => { + self.add_extensible_predicate(key.clone(), cg.skeleton); } } } - Ok(()) + set_code_index( + &mut self.retraction_info, + &self.compilation_target, + key, + &code_index, + IndexPtr::Index(code_ptr), + ); + + self.wam.code_repo.code.extend(code.into_iter()); + Ok(code_index.get()) } - fn add_term_dir_terms( + fn record_incremental_compile(&mut self, key: PredicateKey, append_or_prepend: AppendOrPrepend) + { + self.retraction_info.push_record( + match &self.compilation_target { + CompilationTarget::User => { + match append_or_prepend { + AppendOrPrepend::Append => { + RetractionRecord::AppendedUserExtensiblePredicate( + key, + ) + } + AppendOrPrepend::Prepend => { + RetractionRecord::PrependedUserExtensiblePredicate( + key, + ) + } + } + } + CompilationTarget::Module(ref module_name) => { + match append_or_prepend { + AppendOrPrepend::Append => { + RetractionRecord::AppendedModuleExtensiblePredicate( + module_name.clone(), key, + ) + } + AppendOrPrepend::Prepend => { + RetractionRecord::PrependedModuleExtensiblePredicate( + module_name.clone(), key, + ) + } + } + } + } + ); + } + + pub(super) + fn incremental_compile_clause( &mut self, - hook: CompileTimeHook, - code_repo: &mut CodeRepo, key: PredicateKey, clause: PredicateClause, queue: VecDeque, - ) -> (usize, usize) { - let preds = code_repo - .term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); + non_counted_bt: bool, + append_or_prepend: AppendOrPrepend, + ) -> Result { + self.record_incremental_compile(key.clone(), append_or_prepend); - let (mut len, mut queue_len) = ((preds.0).0.len(), preds.1.len()); + let skeleton = + match self.wam.indices.get_predicate_skeleton( + &self.compilation_target, + &key, + ) { + Some(skeleton) if !skeleton.clauses.is_empty() => { + skeleton + } + _ => { + // true because this predicate is extensible. + let settings = CodeGenSettings::new(true, non_counted_bt); + return self.compile(key, &vec![clause], &queue, settings); + } + }; - if self.module.is_some() && hook.has_module_scope() { - let module_preds = self - .user_term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); + let settings = CodeGenSettings::new(true, non_counted_bt); + let atom_tbl = self.wam.machine_st.atom_tbl.clone(); - if let Some(ref mut module) = &mut self.module { - module.add_expansion_record(hook, clause.clone(), queue.clone()); - module.add_local_expansion(hook, clause.clone(), queue.clone()); + let StandaloneCompileResult { clause_code, mut standalone_skeleton } = + compile_standalone_clause(clause, queue, settings, atom_tbl)?; + + match append_or_prepend { + AppendOrPrepend::Append => { + skeleton.clauses.push_back(standalone_skeleton.clauses.pop_back().unwrap()); + + self.retraction_info.push_record( + RetractionRecord::SkeletonClausePopBack( + self.compilation_target.clone(), + key.clone(), + ), + ); + + let result = + append_compiled_clause( + &mut self.wam.code_repo.code, + clause_code, + skeleton, + &mut self.retraction_info, + ); + + let code_index = self.get_or_insert_code_index(key.clone()); + + if let Some(new_code_index) = result { + set_code_index( + &mut self.retraction_info, + &self.compilation_target, + key, + &code_index, + IndexPtr::Index(new_code_index), + ); + } + + Ok(code_index.get()) } + AppendOrPrepend::Prepend => { + skeleton.clauses.push_front(standalone_skeleton.clauses.pop_back().unwrap()); - (module_preds.0).0.push(clause); - module_preds.1.extend(queue.into_iter()); + self.retraction_info.push_record( + RetractionRecord::SkeletonClausePopFront( + self.compilation_target.clone(), + key.clone(), + ), + ); - (preds.0).0.extend((module_preds.0).0.iter().cloned()); - preds.1.extend(module_preds.1.iter().cloned()); - } else { - let module_preds = self - .user_term_dir - .entry(key.clone()) - .or_insert((Predicate::new(), VecDeque::from(vec![]))); + let threaded_choice_instr_loc = + prepend_compiled_clause( + &mut self.wam.code_repo.code, + self.compilation_target.clone(), + key.clone(), + clause_code, + skeleton, + &mut self.retraction_info, + ); - len += 1; - queue_len += queue.len(); + let code_index = self.get_or_insert_code_index(key.clone()); - (preds.0).0.push(clause); - preds.1.extend(queue.into_iter()); + set_code_index( + &mut self.retraction_info, + &self.compilation_target, + key, + &code_index, + IndexPtr::Index(threaded_choice_instr_loc), + ); - (preds.0).0.extend((module_preds.0).0.iter().cloned()); - preds.1.extend(module_preds.1.iter().cloned()); + Ok(IndexPtr::Index(threaded_choice_instr_loc)) + } } - - (len, queue_len) } - fn submit_op( - &mut self, - wam: &Machine, - indices: &mut IndexStore, - op_decl: &OpDecl, - ) -> Result<(), SessionError> { - let spec = get_desc( - op_decl.name(), - composite_op!( - self.module.is_some(), - &wam.indices.op_dir, - &mut indices.op_dir - ), - ); + pub(super) + fn retract_clause(&mut self, key: PredicateKey, target_pos: usize) -> usize { + let code_index = self.get_or_insert_code_index(key.clone()); - op_decl.submit(self.get_module_name(), spec, &mut indices.op_dir) - } + let skeleton = + match self.wam.indices.get_predicate_skeleton( + &self.compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton + } + None => { + unreachable!(); + } + }; - fn process_decl( - &mut self, - decl: Declaration, - wam: &mut Machine, - indices: &mut IndexStore, - flags: MachineFlags, - non_counted_bt_preds: &mut IndexSet, - ) -> Result<(), SessionError> { - match decl { - Declaration::Dynamic(..) => { - Ok(()) - } - Declaration::EndOfFile => { - Ok(()) - } - Declaration::Hook(hook, clause, queue) => { - let key = (hook.name(), hook.arity()); - let (len, queue_len) = - self.add_term_dir_terms(hook, &mut wam.code_repo, key.clone(), clause, queue); + let code = &mut self.wam.code_repo.code; + let lower_bound = lower_bound_of_target_clause(skeleton, target_pos); + let lower_bound_is_unindexed = !skeleton.clauses[lower_bound].opt_arg_index_key.is_some(); - let result = wam - .code_repo - .compile_hook(hook) - .map_err(SessionError::from); + if target_pos == 0 || (lower_bound + 1 == target_pos && lower_bound_is_unindexed) { + // the clause preceding target_pos, if there is one, is of key type + // OptArgIndexKey::None. + match skeleton.clauses[target_pos].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) => { + let inner_clause_start = find_inner_choice_instr( + code, + skeleton.clauses[target_pos].clause_start, + index_loc, + ); - wam.code_repo.truncate_terms(key, len, queue_len); + remove_index_from_subsequence( + code, + &skeleton.clauses[target_pos].opt_arg_index_key, + inner_clause_start, + &mut self.retraction_info, + ); - result - } - Declaration::Module(module_decl) => { - if self.module.is_none() { - let module_name = module_decl.name.clone(); - let atom_tbl = TabledData::new(module_name.to_rc()); + match derelictize_try_me_else( + code, + inner_clause_start, + &mut self.retraction_info, + ) { + Some(offset) => { + let instr_loc = find_inner_choice_instr( + code, + inner_clause_start + offset, + index_loc, + ); - for export in module_decl.exports.iter() { - if let ModuleExport::OpDecl(ref op_decl) = export { - self.submit_op(wam, indices, op_decl)?; + let clause_loc = blunt_leading_choice_instr( + code, + instr_loc, + &mut self.retraction_info, + ); + + set_switch_var_offset( + code, + index_loc, + clause_loc - index_loc, + &mut self.retraction_info, + ); + + self.retraction_info.push_record( + RetractionRecord::SkeletonClauseStartReplaced( + self.compilation_target.clone(), + key.clone(), + target_pos + 1, + skeleton.clauses[target_pos + 1].clause_start, + ), + ); + + skeleton.clauses[target_pos + 1].clause_start = + skeleton.clauses[target_pos].clause_start; + + return delete_from_dynamic_skeleton( + self.compilation_target.clone(), + key, + skeleton, + target_pos, + &mut self.retraction_info, + ); + } + None => { + let index_ptr_opt = + if target_pos > 0 { + let preceding_choice_instr_loc = + skeleton.clauses[target_pos - 1].clause_start; + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start - 2, + &mut self.retraction_info, + ) + } else { + remove_leading_unindexed_clause( + code, + skeleton.clauses[target_pos].clause_start - 2, + &mut self.retraction_info, + ) + }; + + return finalize_retract( + key, + self.compilation_target.clone(), + skeleton, + code_index, + target_pos, + index_ptr_opt, + &mut self.retraction_info, + ); } } - - let listing_src = self.listing_src.clone(); - - Ok(self.module = Some(Module::new(module_decl, atom_tbl, listing_src))) - } else { - Err(SessionError::from(ParserError::InvalidModuleDecl)) } - } - Declaration::ModuleInitialization(query_terms, queue) => { - self.initialization_goals.0.extend(query_terms.into_iter()); - self.initialization_goals.1.extend(queue.into_iter()); - - Ok(()) - } - Declaration::MultiFile(..) => { - Ok(()) - } - Declaration::NonCountedBacktracking(name, arity) => { - non_counted_bt_preds.insert((name, arity)); - Ok(()) - } - Declaration::Op(op_decl) => { - self.submit_op(wam, indices, &op_decl) - } - Declaration::SetPrologFlag(dbl_quotes) => { - wam.machine_st.flags.double_quotes = dbl_quotes; - Ok(()) - } - Declaration::UseModule(ModuleSource::Library(name)) => { - let name = if !wam.indices.modules.contains_key(&name) { - load_library(wam, name, true)? - } else { - name - }; - - self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices) - } - Declaration::UseModule(ModuleSource::File(filename)) => { - let mut path_buf = self.listing_src.path(); - path_buf.push(filename.as_str()); - - let name = load_module_from_file(wam, path_buf, true)?; - self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices) - } - Declaration::UseQualifiedModule(ModuleSource::Library(name), exports) => { - let name = if !wam.indices.modules.contains_key(&name) { - load_library(wam, name, true)? - } else { - name - }; - - self.use_qualified_module( - name, - &mut wam.code_repo, - flags, - &exports, - &mut wam.indices, - indices - ) - } - Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => { - let mut path_buf = self.listing_src.path(); - path_buf.push(filename.as_str()); - - let name = load_module_from_file(wam, path_buf, true)?; - - self.use_qualified_module( - name, - &mut wam.code_repo, - flags, - &exports, - &mut wam.indices, - indices, - ) + None => { + } } } - } - fn setup_multifile_decl( - &self, - indicator: MultiFileIndicator, - worker: &mut TopLevelBatchWorker, - ) -> Result<(), SessionError> { - 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 index_ptr_opt = + match skeleton.clauses[lower_bound].opt_arg_index_key.switch_on_term_loc() { + Some(target_indexing_loc) + if mergeable_indexed_subsequences(lower_bound, target_pos, skeleton) => + { + let lower_bound_clause_start = find_inner_choice_instr( + code, + skeleton.clauses[lower_bound].clause_start, + target_indexing_loc, + ); - insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs); - } - MultiFileIndicator::ModuleScoped((module_name, key)) => { - match worker.term_stream.wam.indices.modules.get(&module_name) { - Some(ref module) => { - let term_dir = &module.term_dir; - let term_dirs = worker.intra_module_term_dirs - .entry(module_name) - .or_insert(TermDirQuantum::new()); + let result; - insert_or_refresh_term_dir_quantum(term_dir, key, term_dirs); - } - None => { - let err = ExistenceError::ModuleSource(ModuleSource::File( - module_name, - )); + match skeleton.clauses[target_pos + 1].opt_arg_index_key.switch_on_term_loc() { + Some(later_indexing_loc) if later_indexing_loc < target_indexing_loc => { + let target_indexing_line = mem::replace( + &mut code[target_indexing_loc], + Line::Control(ControlInstruction::RevJmpBy( + target_indexing_loc - later_indexing_loc + )), + ); - return Err(SessionError::ExistenceError(err)); + match target_indexing_line { + Line::IndexingCode(indexing_code) => { + self.retraction_info.push_record( + RetractionRecord::ReplacedIndexingLine( + target_indexing_loc, + indexing_code, + ), + ); + } + _ => { + } + } + + set_switch_var_offset( + code, + later_indexing_loc, + lower_bound_clause_start - later_indexing_loc, + &mut self.retraction_info, + ); + + result = merge_indexed_subsequences( + code, + skeleton, + lower_bound, + target_pos + 1, + &mut self.retraction_info, + ); + + merge_indices( + code, + later_indexing_loc, + 0 .. target_pos - lower_bound, + &mut skeleton.clauses[lower_bound ..], + &mut self.retraction_info, + ); + } + _ => { + set_switch_var_offset_to_choice_instr( + code, + target_indexing_loc, + lower_bound_clause_start - target_indexing_loc, + &mut self.retraction_info, + ); + + result = merge_indexed_subsequences( + code, + skeleton, + lower_bound, + target_pos + 1, + &mut self.retraction_info, + ); + + merge_indices( + code, + target_indexing_loc, + target_pos + 1 - lower_bound .. skeleton.clauses.len() - lower_bound, + &mut skeleton.clauses[lower_bound ..], + &mut self.retraction_info, + ); + } + }; + + result + } + _ => { + if target_pos > 0 { + remove_index_from_subsequence( + code, + &skeleton.clauses[target_pos].opt_arg_index_key, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ); + + match skeleton.clauses[target_pos].opt_arg_index_key.switch_on_term_loc() { + Some(index_loc) => { + let preceding_choice_instr_loc = find_inner_choice_instr( + code, + skeleton.clauses[target_pos - 1].clause_start, + index_loc, + ); + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ); + + match &mut code[preceding_choice_instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(0)) => { + set_switch_var_offset( + code, + index_loc, + preceding_choice_instr_loc + 1 - index_loc, + &mut self.retraction_info, + ); + } + _ => { + } + } + + None + } + None => { + let preceding_choice_instr_loc = + if skeleton.clauses[lower_bound].opt_arg_index_key.is_some() { + skeleton.clauses[lower_bound].clause_start - 2 + } else { + skeleton.clauses[lower_bound].clause_start + }; + + remove_non_leading_clause( + code, + preceding_choice_instr_loc, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ) + } + } + } else { + remove_leading_unindexed_clause( + code, + skeleton.clauses[target_pos].clause_start, + &mut self.retraction_info, + ) } } - } - }; + }; + finalize_retract( + key, + self.compilation_target.clone(), + skeleton, + code_index, + target_pos, + index_ptr_opt, + &mut self.retraction_info, + ) + } +} + +impl<'a, TS: TermStream> Loader<'a, TS> { + pub(super) + fn compile_clause_clauses>( + &mut self, + key: PredicateKey, + clause_clauses: ClauseIter, + append_or_prepend: AppendOrPrepend, + ) -> Result<(), SessionError> { + let clause_predicates = + clause_clauses.map(|(head, body)| { + PredicateClause::Fact( + Term::Clause( + Cell::default(), + clause_name!("$clause"), + vec![Box::new(head), Box::new(body)], + None, + ) + ) + }); + + let compilation_target = mem::replace( + &mut self.load_state.compilation_target, + CompilationTarget::Module(clause_name!("builtins")), + ); + + let mut clause_clause_locs = sdeq![]; + + for clause_predicate in clause_predicates { + clause_clause_locs.push_back(self.load_state.wam.code_repo.code.len()); + + let result = self.load_state.incremental_compile_clause( + (clause_name!("$clause"), 2), + clause_predicate, + VecDeque::new(), + false, // non_counted_bt is false. + append_or_prepend, + ); + + if let Err(e) = result { + self.load_state.compilation_target = compilation_target; + return Err(e); + } + } + + match self.load_state.wam.indices.get_predicate_skeleton( + &self.load_state.compilation_target, + &(clause_name!("$clause"), 2), + ) { + Some(skeleton) if append_or_prepend.is_append() => { + skeleton.clause_clause_locs.extend_from_slice(&clause_clause_locs[0 ..]); + } + Some(skeleton) => { + for loc in clause_clause_locs.iter() { + skeleton.clause_clause_locs.push_front(*loc); + } + } + None => { + unreachable!(); + } + } + + match self.load_state.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) if append_or_prepend.is_append() => { + self.load_state.retraction_info.push_record( + RetractionRecord::SkeletonClauseClausesTruncateBack( + compilation_target.clone(), + key.clone(), + skeleton.clause_clause_locs.len(), + ), + ); + + skeleton.clause_clause_locs.append( + &mut clause_clause_locs + ); + } + Some(skeleton) => { + self.load_state.retraction_info.push_record( + RetractionRecord::SkeletonClauseClausesTruncateFront( + compilation_target.clone(), + key.clone(), + skeleton.clause_clause_locs.len(), + ), + ); + + for loc in clause_clause_locs.iter() { + skeleton.clause_clause_locs.push_front(*loc); + } + + self.load_state.increment_clause_assert_margin( + clause_clause_locs.len() + ); + } + None => { + unreachable!(); + } + } + + self.load_state.compilation_target = compilation_target; Ok(()) } - fn process_and_commit_decl( - &mut self, - decl: Declaration, - worker: &mut TopLevelBatchWorker, - indices: &mut IndexStore, - flags: MachineFlags, - ) -> Result<(), SessionError> { - let mut update_expansion_lengths = false; + pub(super) + fn compile_and_submit(&mut self) -> Result<(), SessionError> { + let queue = self.preprocessor.parse_queue(&mut self.load_state)?; - match &decl { - &Declaration::Dynamic(ref name, arity) => { - worker - .dynamic_clause_map - .entry((name.clone(), arity)) - .or_insert(vec![]); + let key = self.predicates + .first() + .and_then(|cl| { + let arity = cl.arity(); + cl.name().map(|name| (name, arity)) + }) + .ok_or(SessionError::NamelessEntry)?; - indices.code_dir - .entry((name.clone(), arity)) - .or_insert(CodeIndex::dynamic_undefined(self.get_module_name())); - } - &Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker - .term_stream - .incr_expansion_lens(hook.user_scope(), 1, queue.len()), - &Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() => { - worker.term_stream.incr_expansion_lens(hook, 1, queue.len()) - } - &Declaration::MultiFile(ref indicator) => { - self.setup_multifile_decl(indicator.clone(), worker)?; - } - &Declaration::UseModule(_) | &Declaration::UseQualifiedModule(..) => { - update_expansion_lengths = true - } - _ => {} - }; + let (is_dynamic, is_extensible) = self.load_state.wam.indices + .get_predicate_skeleton(&self.load_state.compilation_target, &key) + .map(|skeleton| (skeleton.is_dynamic, true)) + .unwrap_or((false, false)); - let result = self.process_decl( - decl, - &mut worker.term_stream.wam, - indices, - flags, - &mut worker.non_counted_bt_preds, - ); + let non_counted_bt = self.non_counted_bt_preds.contains(&key); + let settings = CodeGenSettings::new(is_extensible, non_counted_bt); - if update_expansion_lengths { - worker.term_stream.update_expansion_lens(); + self.load_state.compile(key.clone(), &self.predicates, &queue, settings)?; + + if is_dynamic { + let iter = mem::replace(&mut self.clause_clauses, vec![]).into_iter(); + self.compile_clause_clauses(key, iter, AppendOrPrepend::Append)?; } - result - } - - pub(crate) - fn gather_items( - &mut self, - wam: &mut Machine, - src: &mut ParsingStream, - indices: &mut IndexStore, - ) -> Result { - let flags = wam.machine_flags(); - let atom_tbl = indices.atom_tbl.clone(); - let mut worker = TopLevelBatchWorker::new(src, atom_tbl.clone(), flags, wam); - - let mut toplevel_results = vec![]; - let mut toplevel_indices = default_index_store!(atom_tbl.clone()); - - let mut top_level_term_dirs = TermDirQuantum::new(); - - while let Some(decl) = worker.consume(indices)? { - if decl.is_module_decl() { - toplevel_indices.copy_and_swap(indices); - mem::swap(&mut worker.results, &mut toplevel_results); - worker.in_module = true; - - self.process_and_commit_decl(decl, &mut worker, indices, flags)?; - - if let Some(ref module) = &self.module { - worker.term_stream.set_atom_tbl(module.atom_tbl.clone()); - - top_level_term_dirs = mem::replace( - &mut worker.term_dirs, - TermDirQuantum::new(), - ); - } - } else if decl.is_end_of_file() { - break; - } else { - self.process_and_commit_decl(decl, &mut worker, indices, flags)?; - } - } - - let addition_results = worker.term_stream.rollback_expansion_code()?; - - let module_term_dirs = if self.module.is_some() { - worker.term_dirs - } else { - top_level_term_dirs = worker.term_dirs; - TermDirQuantum::new() - }; - - Ok(GatherResult { - worker_results: worker.results, - dynamic_clause_map: worker.dynamic_clause_map, - toplevel_results, - toplevel_indices, - addition_results, - top_level_terms: worker.term_stream.top_level_terms(), - top_level_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(), - }) - } - - fn drop_expansions(&self, code_repo: &mut CodeRepo) { - let (te_len, te_queue_len) = self.orig_term_expansion_lens; - let (ge_len, ge_queue_len) = self.orig_goal_expansion_lens; - - code_repo.truncate_terms((clause_name!("term_expansion"), 2), te_len, te_queue_len); - code_repo.truncate_terms((clause_name!("goal_expansion"), 2), ge_len, ge_queue_len); - - discard_result!(code_repo.compile_hook(CompileTimeHook::UserGoalExpansion)); - discard_result!(code_repo.compile_hook(CompileTimeHook::UserTermExpansion)); - } - - fn print_error(&self, e: &SessionError) { - if let &SessionError::ParserError(ref e) = e { - if let Some((line_num, _col_num)) = e.line_and_col_num() { - println!("{}:{}: {}", self.listing_src.name(), line_num, e.as_str()); - } - } + Ok(self.predicates.clear()) } } - -fn compile_work_impl( - compiler: &mut ListingCompiler, - wam: &mut Machine, - mut indices: IndexStore, - mut results: GatherResult, -) -> Result<(), SessionError> { - if let Some(ref mut module) = &mut compiler.module { - // compile the module-level goal and term expansions and store - // their locations to the module's code_dir. - let mut decls = module.take_local_expansions(); - - if !decls.is_empty() { - append_trivial_goal(&clause_name!("term_expansion"), &mut decls[0].0); - append_trivial_goal(&clause_name!("goal_expansion"), &mut decls[1].0); - - results.worker_results.extend(decls.into_iter()); - } - } - - let top_level_term_dir = results.top_level_term_dirs.consolidate(); - let module_term_dir = results.module_term_dirs.consolidate(); - - 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, - wam, - &mut indices.code_dir, - &mut indices.module_dir, - &mut code, - &in_situ_code_dir, - &in_situ_module_dir, - )?; - - compiler.adapt_in_situ_code( - results.toplevel_results, - wam, - &mut results.toplevel_indices.code_dir, - &mut indices.module_dir, - &mut code, - &in_situ_code_dir, - &in_situ_module_dir, - )?; - - if let Some(ref mut module) = &mut compiler.module { - if !module.is_impromptu_module { - module.user_term_expansions = results.addition_results.take_term_expansions(); - module.user_goal_expansions = results.addition_results.take_goal_expansions(); - } - } - - wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion)?; - wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion)?; - - if let Some(mut module) = compiler.module.take() { - if module.is_impromptu_module { - module.module_decl.exports = indices.code_dir.keys().cloned() - .filter(|(name, _)| name.owning_module().as_str() != "builtins") - .map(ModuleExport::PredicateKey) - .collect(); - - module.module_decl.exports.extend( - indices.op_dir.iter() - .map(|((name, _), OpDirValue (shared_op_desc, _))| - ModuleExport::OpDecl(OpDecl( - shared_op_desc.prec(), - shared_op_desc.assoc(), - name.clone(), - )) - ) - ); - } - - let mut clause_code_generator = - ClauseCodeGenerator::new(code.len(), module.module_decl.name.clone()); - - wam.check_toplevel_code(&results.toplevel_indices)?; - clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?; - - if let Some(ref module) = wam.indices.modules.swap_remove(&module.module_decl.name) { - wam.indices.remove_module(clause_name!("user"), module); - } - - if module.is_impromptu_module { - add_module(wam, module, indices, module_term_dir); - - 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.insert_module(module); - } else { - add_module(wam, module, indices, module_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); - } else { - add_non_module_code( - wam, - results.dynamic_clause_map, - code, - indices, - top_level_term_dir, - )?; - } - - let init_goal_code = compiler.generate_init_goal_code()?; - - if init_goal_code.len() > 0 { - if !wam.run_init_code(init_goal_code) { - println!("Warning: initialization goal for {} failed", - compiler.listing_src.name()); - } - } - - if !compiler.suppress_warnings { - issue_singleton_warnings( - compiler.listing_src.name(), - results.top_level_terms, - ); - } - - Ok(()) -} - -fn compile_work( - compiler: &mut ListingCompiler, - wam: &mut Machine, - src: Stream, - mut indices: IndexStore, -) -> EvalSession { - let mut stream = try_eval_session!(parsing_stream(src)); - let src = &mut stream; - let results = try_eval_session!(compiler.gather_items(wam, src, &mut indices)); - - try_eval_session!(compile_work_impl(compiler, wam, indices, results)); - - EvalSession::EntrySuccess -} - -/* This is a truncated version of compile_user_module, used for -compiling code composing special forms, ie. the code that calls -M:verify_attributes on attributed variables. */ -pub fn compile_special_form( - wam: &mut Machine, - src: Stream, - listing_src: ListingSource, -) -> Result { - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - setup_indices(wam, clause_name!("builtins"), &mut indices)?; - - let mut src = parsing_stream(src)?; - let mut compiler = ListingCompiler::new(&wam.code_repo, true, listing_src); - let mut results = compiler.gather_items(wam, &mut 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 p = wam.code_repo.code.len(); - let top_level_term_dir = results.top_level_term_dirs.consolidate(); - - add_toplevel(wam, indices, top_level_term_dir); - - wam.code_repo.code.extend(results.in_situ_code.into_iter()); - - Ok(p) -} - -#[inline] -pub fn compile_listing( - wam: &mut Machine, - src: Stream, - indices: IndexStore, - suppress_warnings: bool, - listing_src: ListingSource, -) -> EvalSession { - let mut compiler = ListingCompiler::new(&wam.code_repo, suppress_warnings, listing_src); - - match compile_work(&mut compiler, wam, src, indices) { - EvalSession::Error(e) => { - compiler.drop_expansions(&mut wam.code_repo); - compiler.print_error(&e); - - EvalSession::Error(e) - } - result => result, - } -} - -pub(super) fn setup_indices( - wam: &mut Machine, - module: ClauseName, - indices: &mut IndexStore, -) -> Result<(), SessionError> { - if let Some(module) = wam.indices.take_module(module.clone()) { - let flags = wam.machine_flags(); - let result = indices.use_module(&mut wam.code_repo, flags, &module); - - wam.indices.insert_module(module); - result - } else { - let err = ExistenceError::ModuleSource(ModuleSource::Library( - module - )); - - Err(SessionError::ExistenceError(err)) - } -} - -pub fn compile_user_module( - wam: &mut Machine, - src: Stream, - suppress_warnings: bool, - listing_src: ListingSource, -) -> EvalSession { - let mut indices = default_index_store!(wam.indices.atom_tbl.clone()); - try_eval_session!(setup_indices(wam, clause_name!("builtins"), &mut indices)); - compile_listing(wam, src, indices, suppress_warnings, listing_src) -} diff --git a/src/machine/dynamic_database.rs b/src/machine/dynamic_database.rs deleted file mode 100644 index 6fc01b4c..00000000 --- a/src/machine/dynamic_database.rs +++ /dev/null @@ -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 { - 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, - 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); - } -} diff --git a/src/machine/heap.rs b/src/machine/heap.rs index 8f741f66..0d3a5cf6 100644 --- a/src/machine/heap.rs +++ b/src/machine/heap.rs @@ -1,6 +1,6 @@ use core::marker::PhantomData; -use crate::prolog_parser::ast::Constant; +use crate::prolog_parser_rebis::ast::Constant; use crate::machine::machine_indices::*; use crate::machine::partial_string::*; @@ -168,6 +168,9 @@ impl HeapTemplate { &HeapCellValue::Integer(ref n) => { HeapCellValue::Integer(n.clone()) } + &HeapCellValue::LoadStatePayload(_) => { + HeapCellValue::Addr(Addr::LoadStatePayload(h)) + } &HeapCellValue::NamedStr(arity, ref name, ref op) => { HeapCellValue::NamedStr(arity, name.clone(), op.clone()) } @@ -295,6 +298,9 @@ impl HeapTemplate { val @ HeapCellValue::Rational(_) => { Addr::Con(self.push(val)) } + val @ HeapCellValue::LoadStatePayload(_) => { + Addr::LoadStatePayload(self.push(val)) + } val @ HeapCellValue::NamedStr(..) => { Addr::Str(self.push(val)) } @@ -371,15 +377,6 @@ impl HeapTemplate { } } - #[inline] - pub(crate) - fn take(&mut self) -> Self { - HeapTemplate { - buf: self.buf.take(), - _marker: PhantomData, - } - } - #[inline] pub(crate) fn truncate(&mut self, h: usize) { @@ -479,9 +476,7 @@ impl HeapTemplate { ("dir_entry", 1) => { extract_integer(s+1).map(LocalCodePtr::DirEntry) } - ("in_situ_dir_entry", 1) => { - extract_integer(s+1).map(LocalCodePtr::InSituDirEntry) - } + /* ("top_level", 2) => { if let Some(chunk_num) = extract_integer(s+1) { if let Some(p) = extract_integer(s+2) { @@ -491,13 +486,10 @@ impl HeapTemplate { 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!() @@ -508,8 +500,7 @@ impl HeapTemplate { } #[inline] - pub - fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { + pub fn index_addr<'a>(&'a self, addr: &Addr) -> RefOrOwned<'a, HeapCellValue> { match addr { &Addr::Con(h) | &Addr::Str(h) | &Addr::Stream(h) | &Addr::TcpListener(h) => { RefOrOwned::Borrowed(&self[h]) diff --git a/src/machine/load_state.rs b/src/machine/load_state.rs new file mode 100644 index 00000000..1d5526a5 --- /dev/null +++ b/src/machine/load_state.rs @@ -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, + 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, + 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, + ) -> 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, + ) -> 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, + ) { + 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, + ) -> 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, + ) -> 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!() + } + } + } + } + } +} diff --git a/src/machine/loader.rs b/src/machine/loader.rs new file mode 100644 index 00000000..d29fe3dc --- /dev/null +++ b/src/machine/loader.rs @@ -0,0 +1,1747 @@ +use prolog_parser_rebis::ast::*; + +use crate::forms::*; +use crate::indexing::*; +use crate::machine::*; +use crate::machine::load_state::*; +use crate::machine::machine_indices::*; +use crate::machine::preprocessor::*; + +use indexmap::IndexSet; + +use std::cell::Cell; +use std::convert::TryFrom; +use std::rc::Rc; + +/* + * The loader compiles Prolog terms read from a TermStream instance, + * which may be incremental or monolithic. The monolithic term stream + * reads from a file. It's used only to bootstrap Scryer at + * start-up. Once Scryer is bootstrapped, all compilation and loading + * work is divided between loader.pl and loader.rs. + * + * loader.pl does a few high-level things more easily handled from + * Prolog that are not supported (or needed) during bootstrapping: + * term and goal expansion, loading modules from different streams, + * verifying certain kinds of declarations, perhaps (in the future?) + * compiling inline disjunctions. + * + * Since the loader can operate incrementally, it uses an intermittent + * structure to rebuild the loader between + * invocations. TopLevelBatchWorker needs access to a &'a mut Machine + * for as long as it lives, and we can't have copies of &'a mut + * Machine distributed among multiple owners. + * + * When loading a module, we modify the records of the WAM with the + * location of new predicates, with new meta-predicate information, + * new term and goal expansions, new dynamic clauses, etc. Should the + * loader fail later, all changes must be rolled back, restoring the + * WAM to its prior state. Retraction records describe individual changes + * made by the loader, and they may be used later. + */ + +#[derive(Debug)] +pub(crate) enum RetractionRecord { + AddedMetaPredicate(ClauseName, PredicateKey), + ReplacedMetaPredicate(ClauseName, ClauseName, Vec), + AddedModule(ClauseName), + ReplacedModule(ModuleDecl, ListingSource), + AddedModuleDynamicPredicate(ClauseName, PredicateKey), + AddedModuleExtensiblePredicate(ClauseName, PredicateKey), + AppendedModuleExtensiblePredicate(ClauseName, PredicateKey), + PrependedModuleExtensiblePredicate(ClauseName, PredicateKey), + AddedModuleOp(ClauseName, OpDecl), + ReplacedModuleOp(ClauseName, OpDecl, usize, Specifier), + AddedModulePredicate(ClauseName, PredicateKey), + ReplacedModulePredicate(ClauseName, PredicateKey, IndexPtr), + AddedUserDynamicPredicate(PredicateKey), + AddedUserOp(OpDecl), + ReplacedUserOp(OpDecl, usize, Specifier), + AddedUserExtensiblePredicate(PredicateKey), + AppendedUserExtensiblePredicate(PredicateKey), + PrependedUserExtensiblePredicate(PredicateKey), + AddedUserPredicate(PredicateKey), + ReplacedUserPredicate(PredicateKey, IndexPtr), + AddedIndex(OptArgIndexKey, usize), //, Vec), + RemovedIndex(usize, OptArgIndexKey, usize), + ReplacedChoiceOffset(usize, usize), + AppendedTrustMe(usize, usize, bool), + ReplacedSwitchOnTermVarIndex(usize, usize), + ModifiedTryMeElse(usize, usize), + ModifiedRetryMeElse(usize, usize), + ModifiedRevJmpBy(usize, usize), + IncreasedClauseAssertMargin(ClauseName, usize), + SkeletonClauseClausesTruncateBack(CompilationTarget, PredicateKey, usize), + SkeletonClauseClausesTruncateFront(CompilationTarget, PredicateKey, usize), + SkeletonClausePopBack(CompilationTarget, PredicateKey), + SkeletonClausePopFront(CompilationTarget, PredicateKey), + SkeletonClauseTruncateBack(CompilationTarget, PredicateKey, usize), + SkeletonClauseStartReplaced(CompilationTarget, PredicateKey, usize, usize), + RemovedDynamicSkeletonClause(CompilationTarget, PredicateKey, usize, ClauseIndexInfo, usize), + ReplacedIndexingLine(usize, Vec), +} + +/* + * Retractions to be performed on rollback are represented by + * individual records, and the original extent of the code vector of + * the IndexStore, of which there are several (one per module). The + * "extent" of a code vector is its length prior to an attempted + * module load. The only code vector of the WAM's IndexStore, "code", + * is shared by all modules, including the default "user" module. + */ + +pub(super) struct RetractionInfo { + orig_code_extent: usize, + records: Vec, +} + +impl RetractionInfo { + #[inline] + pub(super) + fn new(orig_code_extent: usize) -> Self { + Self { + orig_code_extent, + records: vec![], //BTreeMap::new(), + } + } + + #[inline] + pub(crate) + fn push_record(&mut self, record: RetractionRecord) { + self.records.push(record); + } + + #[inline] + pub(crate) + fn reset(&mut self, code_len: usize) -> Self { + let orig_code_extent = self.orig_code_extent; + self.orig_code_extent = code_len; + + Self { + orig_code_extent, + records: mem::replace(&mut self.records, vec![]), //BTreeMap::new()), + } + } +} + +impl<'a> Drop for LoadState<'a> { + fn drop(&mut self) { + while let Some(record) = self.retraction_info.records.pop() { + match record { + RetractionRecord::AddedMetaPredicate(target_module_name, key) => { + match target_module_name.as_str() { + "user" => { + self.wam.indices.meta_predicates.remove(&key); + } + _ => { + match self.wam.indices.modules.get_mut(&target_module_name) { + Some(ref mut module) => { + module.meta_predicates.remove(&key); + } + _ => { + unreachable!() + } + } + } + } + } + RetractionRecord::ReplacedMetaPredicate(target_module_name, name, meta_specs) => { + match target_module_name.as_str() { + "user" => { + self.wam.indices.meta_predicates.insert( + (name, meta_specs.len()), + meta_specs, + ); + } + _ => { + match self.wam.indices.modules.get_mut(&target_module_name) { + Some(ref mut module) => { + module.meta_predicates.insert( + (name, meta_specs.len()), + meta_specs, + ); + } + _ => { + unreachable!() + } + } + } + } + } + RetractionRecord::AddedModule(module_name) => { + self.wam.indices.modules.remove(&module_name); + } + RetractionRecord::ReplacedModule(module_decl, listing_src) => { + match self.wam.indices.modules.get_mut(&module_decl.name) { + Some(ref mut module) => { + module.module_decl = module_decl; + module.listing_src = listing_src; + } + _ => { + unreachable!() + } + } + } + RetractionRecord::AddedModuleDynamicPredicate(module_name, key) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.extensible_predicates.get_mut(&key) + .map(|skeleton| { + skeleton.is_dynamic = false; + }); + } + None => { + } + } + } + RetractionRecord::AddedModuleExtensiblePredicate(module_name, key) => { + self.wam.indices.remove_predicate_skeleton( + &CompilationTarget::Module(module_name), + &key, + ); + } + RetractionRecord::AppendedModuleExtensiblePredicate(module_name, key) => { + self.wam.indices.get_predicate_skeleton( + &CompilationTarget::Module(module_name), + &key, + ).map(|skeleton| { + skeleton.clauses.pop_back(); + }); + } + RetractionRecord::PrependedModuleExtensiblePredicate(module_name, key) => { + self.wam.indices.get_predicate_skeleton( + &CompilationTarget::Module(module_name), + &key, + ).map(|skeleton| { + skeleton.clauses.pop_front(); + }); + } + RetractionRecord::AddedModuleOp(module_name, mut op_decl) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + op_decl.remove(&mut module.op_dir); + } + None => { + } + } + } + RetractionRecord::ReplacedModuleOp(module_name, mut op_decl, prec, spec) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + op_decl.prec = prec; + op_decl.spec = spec; + op_decl.insert_into_op_dir(&mut module.op_dir); + } + None => { + } + } + } + RetractionRecord::AddedModulePredicate(module_name, key) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.code_dir.remove(&key); + } + None => { + } + } + } + RetractionRecord::ReplacedModulePredicate(module_name, key, old_code_idx) => { + match self.wam.indices.modules.get_mut(&module_name) { + Some(ref mut module) => { + module.code_dir + .get_mut(&key) + .map(|code_idx| code_idx.replace(old_code_idx)); + } + None => { + } + } + } + RetractionRecord::AddedUserDynamicPredicate(key) => { + self.wam.indices.extensible_predicates.get_mut(&key) + .map(|skeleton| { + skeleton.is_dynamic = false; + }); + } + RetractionRecord::AddedUserExtensiblePredicate(key) => { + self.wam.indices.remove_predicate_skeleton( + &CompilationTarget::User, + &key, + ); + } + RetractionRecord::AppendedUserExtensiblePredicate(key) => { + self.wam.indices.get_predicate_skeleton( + &CompilationTarget::User, + &key, + ).map(|skeleton| { + skeleton.clauses.pop_back(); + }); + } + RetractionRecord::PrependedUserExtensiblePredicate(key) => { + self.wam.indices.get_predicate_skeleton( + &CompilationTarget::User, + &key, + ).map(|skeleton| { + skeleton.clauses.pop_front(); + }); + } + RetractionRecord::AddedUserOp(mut op_decl) => { + op_decl.remove(&mut self.wam.indices.op_dir); + } + RetractionRecord::ReplacedUserOp(mut op_decl, prec, spec) => { + op_decl.prec = prec; + op_decl.spec = spec; + op_decl.insert_into_op_dir(&mut self.wam.indices.op_dir); + } + RetractionRecord::AddedUserPredicate(key) => { + self.wam.indices.code_dir.remove(&key); + } + RetractionRecord::ReplacedUserPredicate(key, old_code_idx) => { + self.wam.indices.code_dir + .get_mut(&key) + .map(|code_idx| code_idx.replace(old_code_idx)); + } + RetractionRecord::AddedIndex(index_key, clause_loc) => { // WAS: inner_index_locs) => { + if let Some(index_loc) = index_key.switch_on_term_loc() { + let indexing_code = + match &mut self.wam.code_repo.code[index_loc] { + Line::IndexingCode(indexing_code) => { + indexing_code + } + _ => { + unreachable!() + } + }; + + match index_key { + OptArgIndexKey::Constant(_, index_loc, constant, overlapping_constants) => { + remove_constant_indices( + &constant, + &overlapping_constants, + indexing_code, + clause_loc - index_loc, // WAS: &inner_index_locs, + ); + } + OptArgIndexKey::Structure(_, index_loc, name, arity) => { + remove_structure_index( + &name, + arity, + indexing_code, + clause_loc - index_loc, // WAS: &inner_index_locs, + ); + } + OptArgIndexKey::List(_, index_loc) => { + remove_list_index( + indexing_code, + clause_loc - index_loc, // WAS: &inner_index_locs, + ); + } + OptArgIndexKey::None => { + unreachable!(); + } + } + } + } + RetractionRecord::RemovedIndex(_index_loc, _index_key, _clause_loc) => { + // TODO: this needs to be fixed! RemovedIndex doesn't provide + // enough information to restore the index. Correct that, then + // write the retraction logic of this arm. + } + RetractionRecord::ReplacedChoiceOffset(instr_loc, offset) => { + match &mut self.wam.code_repo.code[instr_loc] { + Line::Choice(ChoiceInstruction::TryMeElse(ref mut o)) | + Line::Choice(ChoiceInstruction::RetryMeElse(ref mut o)) | + Line::Choice(ChoiceInstruction::DefaultRetryMeElse(ref mut o)) => { + *o = offset; + } + _ => { + unreachable!(); + } + } + } + RetractionRecord::AppendedTrustMe(instr_loc, offset, is_default) => { + match &mut self.wam.code_repo.code[instr_loc] { + Line::Choice(ref mut choice_instr) => { + *choice_instr = if is_default { + ChoiceInstruction::DefaultTrustMe(offset) + } else { + ChoiceInstruction::TrustMe(offset) + }; + } + _ => { + unreachable!(); + } + } + } + RetractionRecord::ReplacedSwitchOnTermVarIndex(index_loc, old_v) => { + match &mut self.wam.code_repo.code[index_loc] { + Line::IndexingCode(ref mut indexing_code) => { + match &mut indexing_code[0] { + IndexingLine::Indexing( + IndexingInstruction::SwitchOnTerm(_, ref mut v, ..) + ) => { + *v = old_v; + } + _ => { + } + } + } + _ => { + } + } + } + RetractionRecord::ModifiedTryMeElse(instr_loc, o) => { + self.wam.code_repo.code[instr_loc] = + Line::Choice(ChoiceInstruction::TryMeElse(o)); + } + RetractionRecord::ModifiedRetryMeElse(instr_loc, o) => { + self.wam.code_repo.code[instr_loc] = + Line::Choice(ChoiceInstruction::RetryMeElse(o)); + } + RetractionRecord::ModifiedRevJmpBy(instr_loc, o) => { + self.wam.code_repo.code[instr_loc] = + Line::Control(ControlInstruction::RevJmpBy(o)); + } + RetractionRecord::IncreasedClauseAssertMargin(module_name, incr) => { + if let Some(module) = self.wam.indices.modules.get_mut(&module_name) { + module.clause_assert_margin -= incr; + } + } + RetractionRecord::SkeletonClauseClausesTruncateFront(compilation_target, key, len) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_front(len); + } + None => { + } + } + + let compilation_target = + match compilation_target { + CompilationTarget::User => { + CompilationTarget::Module(clause_name!("builtins")) + } + _ => { + compilation_target + } + }; + + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &(clause_name!("$clause"), 2), + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_front(len); + } + None => { + } + } + } + RetractionRecord::SkeletonClauseClausesTruncateBack(compilation_target, key, len) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_back(len); + } + None => { + } + } + + let compilation_target = + match compilation_target { + CompilationTarget::User => { + CompilationTarget::Module(clause_name!("builtins")) + } + _ => { + compilation_target + } + }; + + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &(clause_name!("$clause"), 2), + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.truncate_back(len); + } + None => { + } + } + } + RetractionRecord::SkeletonClausePopBack(compilation_target, key) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clauses.pop_back(); + } + None => { + } + } + } + RetractionRecord::SkeletonClausePopFront(compilation_target, key) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clauses.pop_front(); + } + None => { + } + } + } + RetractionRecord::SkeletonClauseTruncateBack(compilation_target, key, len) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clauses.truncate_back(len); + } + None => { + } + } + } + RetractionRecord::SkeletonClauseStartReplaced( + compilation_target, + key, + target_pos, + clause_start, + ) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clauses[target_pos].clause_start = clause_start; + } + None => { + } + } + } + RetractionRecord::RemovedDynamicSkeletonClause( + compilation_target, + key, + target_pos, + clause_index_info, + clause_clause_loc, + ) => { + match self.wam.indices.get_predicate_skeleton( + &compilation_target, + &key, + ) { + Some(skeleton) => { + skeleton.clause_clause_locs.insert(target_pos, clause_clause_loc); + skeleton.clauses.insert(target_pos, clause_index_info); + } + None => { + } + } + } + RetractionRecord::ReplacedIndexingLine(index_loc, indexing_code) => { + self.wam.code_repo.code[index_loc] = Line::IndexingCode(indexing_code); + } + } + } + // TODO: necessary? unnecessary? + // self.wam.code_repo.code.truncate(self.retraction_info.orig_code_extent); + } +} + +#[derive(Debug, Clone)] +pub enum CompilationTarget { + Module(ClauseName), + User, +} + +impl Default for CompilationTarget { + #[inline] + fn default() -> Self { + CompilationTarget::User + } +} + +impl CompilationTarget { + #[inline] + pub(super) + fn take(&mut self) -> CompilationTarget { + mem::replace(self, CompilationTarget::User) + } +} + +pub(crate) struct Loader<'a, TermStream> { + pub(super) load_state: LoadState<'a>, + pub(super) predicates: Vec, + pub(super) clause_clauses: Vec<(Term, Term)>, + term_stream: TermStream, + pub(super) non_counted_bt_preds: IndexSet, + pub(super) preprocessor: Preprocessor, +} + +impl<'a, TS: TermStream> Loader<'a, TS> { + #[inline] + pub(super) + fn new(term_stream: TS, wam: &'a mut Machine) -> Self { + let flags = wam.machine_st.flags; + let load_state = LoadState { + compilation_target: CompilationTarget::User, + module_op_exports: vec![], + retraction_info: RetractionInfo::new(wam.code_repo.code.len()), + wam, + }; + + Self { + load_state, + term_stream, + non_counted_bt_preds: IndexSet::new(), + preprocessor: Preprocessor::new(flags), + predicates: vec![], + clause_clauses: vec![], + } + } + + pub(crate) + fn load(mut self) -> Result { + while let Some(decl) = self.dequeue_terms()? { + self.load_decl(decl)?; + } + + TS::evacuate(self) + } + + fn dequeue_terms(&mut self) -> Result, SessionError> { + while !self.term_stream.eof()? { + let term = self.term_stream.next(&self.load_state.composite_op_dir())?; + + // if is_consistent is false, self.predicates is not empty. + if !term.is_consistent(&self.predicates) { + self.compile_and_submit()?; + } + + let tl = self.preprocessor.try_term_to_tl( + &mut self.load_state, + term, + CutContext::BlocksCuts, + )?; + + match tl { + TopLevel::Fact(fact) => + self.predicates.push(PredicateClause::Fact(fact)), + TopLevel::Rule(rule) => + self.predicates.push(PredicateClause::Rule(rule)), + TopLevel::Predicate(pred) => + self.predicates.extend(pred), + TopLevel::Declaration(decl) => + return Ok(Some(decl)), + TopLevel::Query(_) => + return Err(SessionError::QueryCannotBeDefinedAsFact), + } + } + + Ok(None) + } + + pub(super) + fn load_decl(&mut self, decl: Declaration) -> Result<(), SessionError> { + match decl { + Declaration::Dynamic(name, arity) => { + self.add_dynamic_predicate(name, arity); + } + Declaration::MetaPredicate(module_name, name, meta_specs) => { + self.load_state.add_meta_predicate_record( + module_name, + name, + meta_specs, + ); + } + Declaration::Module(module_decl) => { + self.load_state.compilation_target = + CompilationTarget::Module(module_decl.name.clone()); + + self.load_state.add_module( + module_decl, + self.term_stream.listing_src().clone(), + ); + } + Declaration::NonCountedBacktracking(name, arity) => { + self.non_counted_bt_preds.insert((name, arity)); + } + Declaration::Op(op_decl) => { + self.load_state.add_op_decl(&op_decl); + } + Declaration::UseModule(module_src) => { + self.load_state.use_module(module_src)?; + } + Declaration::UseQualifiedModule(module_src, exports) => { + self.load_state.use_qualified_module(module_src, exports)?; + } + } + + Ok(()) + } + + pub(super) + fn read_term_from_heap(&self, heap_term_loc: RegType) -> Result { + let machine_st = &self.load_state.wam.machine_st; + let term_addr = machine_st[heap_term_loc]; + + if machine_st.is_cyclic_term(term_addr) { + return Err(SessionError::from(CompilationError::CannotParseCyclicTerm)); + } + + let mut term_stack = vec![]; + + for addr in machine_st.post_order_iter(term_addr) { + match machine_st.heap.index_addr(&addr).as_ref() { + HeapCellValue::Addr(Addr::Lis(_)) | + HeapCellValue::Addr(Addr::PStrLocation(..)) => { + let tail = term_stack.pop().unwrap(); + let head = term_stack.pop().unwrap(); + + term_stack.push(Term::Cons( + Cell::default(), + Box::new(head), + Box::new(tail), + )); + } + HeapCellValue::Addr(addr) => { + if let Some(r) = addr.as_var() { + let offset_string = + match r { + Ref::HeapCell(h) | Ref::AttrVar(h) => + format!("_{}", h), + Ref::StackCell(fr, sc) => + format!("_s_{}_{}", fr, sc), + }; + + term_stack.push(Term::Var( + Cell::default(), + Rc::new(offset_string), + )); + } else { + match addr.as_constant_index(machine_st) { + Some(constant) => { + term_stack.push(Term::Constant(Cell::default(), constant)); + } + None => { + return Err(SessionError::from(CompilationError::UnreadableTerm)); + } + } + } + } + HeapCellValue::Atom(ref name, ref shared_op_desc) => { + term_stack.push(Term::Constant( + Cell::default(), + Constant::Atom(name.clone(), shared_op_desc.clone()), + )); + } + HeapCellValue::Integer(ref integer) => { + term_stack.push(Term::Constant( + Cell::default(), + Constant::Integer(integer.clone()), + )); + } + HeapCellValue::NamedStr(arity, ref name, ref shared_op_desc) => { + let subterms = term_stack.drain(term_stack.len() - arity ..) + .map(Box::new) + .collect(); + + term_stack.push(Term::Clause( + Cell::default(), + name.clone(), + subterms, + shared_op_desc.clone(), + )); + } + HeapCellValue::PartialString(..) => { + let string = machine_st.heap_pstr_iter(addr).to_string(); + term_stack.push(Term::Constant( + Cell::default(), + Constant::String(Rc::new(string)), + )); + } + HeapCellValue::Rational(ref rational) => { + term_stack.push(Term::Constant( + Cell::default(), + Constant::Rational(rational.clone()), + )); + } + _ => { + return Err(SessionError::from(CompilationError::UnreadableTerm)); + } + } + } + + debug_assert!(term_stack.len() == 1); + Ok(term_stack.pop().unwrap()) + } + + fn extract_module_export_list_from_heap( + &self, + r: RegType, + ) -> Result, SessionError> { + let export_list = self.read_term_from_heap(r)?; + let atom_tbl = self.load_state.wam.machine_st.atom_tbl.clone(); + let export_list = setup_module_export_list(export_list, atom_tbl)?; + + Ok(export_list.into_iter().collect()) + } + + fn add_clause_clause(&mut self, term: Term) -> Result<(), CompilationError> { + match term { + Term::Clause(_, turnstile, mut terms, _) + if turnstile.as_str() == ":-" && terms.len() == 2 => { + let body = *terms.pop().unwrap(); + let head = *terms.pop().unwrap(); + + self.clause_clauses.push((head, body)); + } + head @ Term::Constant(_, Constant::Atom(..)) | + head @ Term::Clause(..) => { + let body = Term::Constant( + Cell::default(), + Constant::Atom(clause_name!("true"), None), + ); + + self.clause_clauses.push((head, body)); + } + _ => { + return Err(CompilationError::InadmissibleFact); + } + } + + Ok(()) + } + + fn add_dynamic_predicate(&mut self, name: ClauseName, arity: usize) { + let key = (name, arity); + + match &self.load_state.compilation_target { + CompilationTarget::User => { + match self.load_state.wam.indices.extensible_predicates.get_mut(&key) { + Some(ref mut skeleton) => { + if !skeleton.is_dynamic { + skeleton.is_dynamic = true; + + self.load_state.retraction_info.push_record( + RetractionRecord::AddedUserDynamicPredicate(key.clone()) + ); + } + } + None => { + self.load_state.wam.indices.extensible_predicates.insert( + key.clone(), + PredicateSkeleton::new().set_dynamic(true), + ); + + self.load_state.retraction_info.push_record( + RetractionRecord::AddedUserExtensiblePredicate(key.clone()) + ); + } + } + } + CompilationTarget::Module(ref module_name) => { + match self.load_state.wam.indices.modules.get_mut(module_name) { + Some(ref mut module) => { + match module.extensible_predicates.get_mut(&key) { + Some(ref mut skeleton) => { + if !skeleton.is_dynamic { + skeleton.is_dynamic = true; + + self.load_state.retraction_info.push_record( + RetractionRecord::AddedModuleDynamicPredicate( + module_name.clone(), + key.clone(), + ), + ); + } + } + None => { + module.extensible_predicates.insert( + key.clone(), + PredicateSkeleton::new().set_dynamic(true), + ); + + self.load_state.retraction_info.push_record( + RetractionRecord::AddedModuleExtensiblePredicate( + module_name.clone(), + key.clone(), + ), + ); + } + } + } + None => { + unreachable!(); + } + } + } + } + + let code_index = self.load_state.get_or_insert_code_index(key.clone()); + + set_code_index( + &mut self.load_state.retraction_info, + &self.load_state.compilation_target, + key, + &code_index, + IndexPtr::DynamicUndefined, + ); + } +} + +impl Machine { + pub(crate) + fn use_module(&mut self) { + let subevacuable_addr = + self.machine_st.store(self.machine_st.deref(self.machine_st[temp_v!(2)])); + + let module_src = + ModuleSource::Library( + match subevacuable_addr { + Addr::LoadStatePayload(payload) => { + match &self.machine_st.heap[payload] { + HeapCellValue::LoadStatePayload(payload) => { + match &payload.compilation_target { + CompilationTarget::Module(ref module_name) => { + module_name.clone() + } + CompilationTarget::User => { + return; + } + } + } + _ => { + unreachable!() + } + } + } + _ => { + unreachable!() + } + } + ); + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + + let use_module = || { + let export_list = loader.extract_module_export_list_from_heap(temp_v!(3))?; + + if export_list.is_empty() { + loader.load_state.use_module(module_src)?; + } else { + loader.load_state.use_qualified_module(module_src, export_list)?; + } + + LiveTermStream::evacuate(loader) + }; + + let result = use_module(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn load_compiled_library(&mut self) { + let library = atom_from!( + self.machine_st, + self.machine_st.store(self.machine_st.deref( + self.machine_st[temp_v!(1)] + )) + ); + + if let Some(module) = self.indices.modules.get(&library) { + if let ListingSource::DynamicallyGenerated = module.listing_src { + self.machine_st.fail = true; + return; + } + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + + let import_module = || { + loader.load_state.import_module(library)?; + LiveTermStream::evacuate(loader) + }; + + let result = import_module(); + self.restore_load_state_payload(result, evacuable_h); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) + fn declare_module(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st.store(self.machine_st.deref( + self.machine_st[temp_v!(1)] + )) + ); + + // let export_list = self.machine_st.extract_module_export_list(temp_v!(2)); + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let declare_module = || { + // let export_list = export_list?; + let exports = loader.extract_module_export_list_from_heap(temp_v!(2))?; + + let module_decl = ModuleDecl { + name: module_name, + exports: exports.into_iter().collect(), + }; + + loader.load_decl(Declaration::Module(module_decl))?; + LiveTermStream::evacuate(loader) + }; + + let result = declare_module(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn add_dynamic_predicate(&mut self) { + let predicate_name = atom_from!( + self.machine_st, + self.machine_st.store(self.machine_st.deref( + self.machine_st[temp_v!(1)] + )) + ); + + let arity = + self.machine_st.store(self.machine_st.deref(self.machine_st[temp_v!(2)])); + + let arity = + match Number::try_from((arity, &self.machine_st.heap)) { + Ok(Number::Integer(n)) if &*n >= &0 && &*n <= &MAX_ARITY => + Ok(n.to_usize().unwrap()), + Ok(Number::Fixnum(n)) if n >= 0 && n <= MAX_ARITY as isize => + Ok(usize::try_from(n).unwrap()), + _ => + Err(SessionError::from(CompilationError::InvalidRuleHead)) + }; + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let add_dynamic_predicate = || { + loader.add_dynamic_predicate(predicate_name, arity?); + LiveTermStream::evacuate(loader) + }; + + let result = add_dynamic_predicate(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn add_term_expansion_clause(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + + let add_clause = || { + let term = loader.read_term_from_heap(temp_v!(1))?; + + loader.incremental_compile_clause( + (clause_name!("term_expansion"), 2), + term, + CompilationTarget::User, + false, + AppendOrPrepend::Append, + )?; + + LiveTermStream::evacuate(loader) + }; + + let result = add_clause(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn add_goal_expansion_clause(&mut self) { + let target_module_name = atom_from!( + self.machine_st, + self.machine_st.store(self.machine_st.deref( + self.machine_st[temp_v!(1)] + )) + ); + + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(3)); + + let compilation_target = + match target_module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(target_module_name), + }; + + let add_clause = || { + let term = loader.read_term_from_heap(temp_v!(2))?; + + loader.incremental_compile_clause( + (clause_name!("goal_expansion"), 2), + term, + compilation_target, + false, // backtracking inferences are counted by call_with_inference_limit. + AppendOrPrepend::Append, + )?; + + LiveTermStream::evacuate(loader) + }; + + let result = add_clause(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn loader_from_heap_evacuable(&mut self, r: RegType) -> (Loader, usize) { + let (load_state_payload, evacuable_h) = + match self.machine_st.store(self.machine_st.deref(self.machine_st[r])) { + Addr::LoadStatePayload(h) => { + ( mem::replace( + &mut self.machine_st.heap[h], + HeapCellValue::Addr(Addr::EmptyList), + ), + h, + ) + } + _ => { + unreachable!() + } + }; + + match load_state_payload { + HeapCellValue::LoadStatePayload(payload) => { + (Loader::from_load_state_payload(self, payload), evacuable_h) + } + _ => { + unreachable!() + } + } + } + + #[inline] + pub(crate) + fn push_load_state_payload(&mut self) { + let payload = LoadStatePayload::new(self); + let addr = Addr::LoadStatePayload( + self.machine_st.heap.push(HeapCellValue::LoadStatePayload(payload)) + ); + + self.machine_st.bind(self.machine_st[temp_v!(1)].as_var().unwrap(), addr); + } + + #[inline] + pub(crate) + fn pop_load_state_payload(&mut self) { + let load_state_payload = + match self.machine_st.store(self.machine_st.deref(self.machine_st[temp_v!(1)])) { + Addr::LoadStatePayload(h) => { + mem::replace( + &mut self.machine_st.heap[h], + HeapCellValue::Addr(Addr::EmptyList), + ) + } + _ => { + unreachable!() + } + }; + + match load_state_payload { + HeapCellValue::LoadStatePayload(payload) => { + Loader::from_load_state_payload(self, payload); + } + _ => { + // unlike in loader_from_heap_evacuable, + // pop_load_state_payload is allowed to fail to find a + // LoadStatePayload in the heap, as a Rust-side + // top-level command may have failed to write the + // load state payload back to the heap. + } + } + } + + #[inline] + pub(crate) + fn pop_load_context(&mut self) { + self.load_contexts.pop(); + } + + pub(crate) + fn push_load_context(&mut self) { + let stream = + try_or_fail!( + self.machine_st, + self.machine_st.get_stream_or_alias( + self.machine_st[temp_v!(1)], + &self.indices, + "$push_load_context", + 2, + ) + ); + + let path = + atom_from!( + self.machine_st, + self.machine_st.store(self.machine_st.deref( + self.machine_st[temp_v!(2)] + )) + ); + + self.load_contexts.push(LoadContext::new(path.as_str(), stream)); + } + + pub(crate) + fn restore_load_state_payload( + &mut self, + result: Result, + evacuable_h: usize, + ) { + match result { + Ok(payload) => { + self.machine_st.heap[evacuable_h] = HeapCellValue::LoadStatePayload( + payload + ); + } + Err(e) => { + self.throw_session_error(e, (clause_name!("load"), 1)); + } + } + } + + pub(crate) + fn clause_to_evacuable(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(2)); + + let enqueue_term = || { + let term = loader.read_term_from_heap(temp_v!(1))?; + + if let Some(predicate_name) = ClauseInfo::name(&term) { + let arity = ClauseInfo::arity(&term); + + let is_dynamic = + loader.load_state.wam.indices.get_predicate_skeleton( + &loader.load_state.compilation_target, + &(predicate_name, arity), + ).map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false); + + if is_dynamic { + loader.add_clause_clause(term.clone())?; + } + } + + loader.enqueue_term(term); + loader.load() + }; + + let result = enqueue_term(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn conclude_load(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + + let compile_final_terms = || { + if !loader.predicates.is_empty() { + loader.compile_and_submit()?; + } + + loader.load_state.remove_module_op_exports(); + LiveTermStream::evacuate(loader) + }; + + let result = compile_final_terms(); + self.restore_load_state_payload(result, evacuable_h); + } + + pub(crate) + fn load_context_source(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + let path_str = load_context.path.to_str().unwrap(); + let path_atom = + clause_name!(path_str.to_string(), self.machine_st.atom_tbl); + + let path_addr = Addr::Con( + self.machine_st.heap.push(HeapCellValue::Atom(path_atom, None)) + ); + + self.machine_st.unify(path_addr, self.machine_st[temp_v!(1)]); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) + fn load_context_file(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + if let Some(file_name) = load_context.path.file_name() { + let file_name_str = file_name.to_str().unwrap(); + let file_name_atom = + clause_name!(file_name_str.to_string(), self.machine_st.atom_tbl); + + let file_name_addr = Addr::Con( + self.machine_st.heap.push(HeapCellValue::Atom(file_name_atom, None)) + ); + + self.machine_st.unify(file_name_addr, self.machine_st[temp_v!(1)]); + return; + } + } + + self.machine_st.fail = true; + } + + pub(crate) + fn load_context_directory(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + if let Some(directory) = load_context.path.ancestors().next() { + let directory_str = directory.to_str().unwrap(); + let directory_atom = + clause_name!(directory_str.to_string(), self.machine_st.atom_tbl); + + let directory_addr = Addr::Con( + self.machine_st.heap.push(HeapCellValue::Atom(directory_atom, None)) + ); + + self.machine_st.unify(directory_addr, self.machine_st[temp_v!(1)]); + return; + } + } + + self.machine_st.fail = true; + } + + pub(crate) + fn load_context_module(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + let module_name_addr = Addr::Con( + self.machine_st.heap.push(HeapCellValue::Atom( + load_context.module.clone(), + None, + )) + ); + + self.machine_st.unify(module_name_addr, self.machine_st[temp_v!(1)]); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) + fn load_context_stream(&mut self) { + if let Some(load_context) = self.load_contexts.last() { + let stream_addr = Addr::Stream( + self.machine_st.heap.push(HeapCellValue::Stream( + load_context.stream.clone() + )) + ); + + self.machine_st.unify(stream_addr, self.machine_st[temp_v!(1)]); + } else { + self.machine_st.fail = true; + } + } + + pub(crate) + fn compile_user_assert(&mut self, append_or_prepend: AppendOrPrepend) { + let key = + self.machine_st.read_predicate_key( + self.machine_st[temp_v!(3)], + self.machine_st[temp_v!(4)], + ); + + let compile_user_assert = || { + let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + + let head = loader.read_term_from_heap(temp_v!(1))?; + let body = loader.read_term_from_heap(temp_v!(2))?; + + let asserted_clause = + Term::Clause( + Cell::default(), + clause_name!(":-"), + vec![Box::new(head.clone()), Box::new(body.clone())], + fetch_op_spec(clause_name!(":-"), 2, &loader.load_state.wam.indices.op_dir), + ); + + loader.incremental_compile_clause( + key.clone(), + asserted_clause, + CompilationTarget::User, + false, + append_or_prepend, + )?; + + // if a new predicate was just created, make it dynamic. + loader.load_state.wam.indices.get_predicate_skeleton( + &loader.load_state.compilation_target, + &key, + ).map(|skeleton| skeleton.is_dynamic = true); + + loader.compile_clause_clauses(key, std::iter::once((head, body)), append_or_prepend)?; + + LiveTermStream::evacuate(loader) + }; + + match compile_user_assert() { + Ok(_) => { + } + Err(e) => { + let error_pi = + match append_or_prepend { + AppendOrPrepend::Append => (clause_name!("assertz"), 1), + AppendOrPrepend::Prepend => (clause_name!("asserta"), 1), + }; + + self.throw_session_error(e, error_pi); + } + } + } + + pub(crate) + fn retract_user_clause(&mut self) { + let key = + self.machine_st.read_predicate_key( + self.machine_st[temp_v!(1)], + self.machine_st[temp_v!(2)], + ); + + let target_pos = + self.machine_st.store(self.machine_st.deref(self.machine_st[temp_v!(3)])); + + let target_pos = + match Number::try_from((target_pos, &self.machine_st.heap)) { + Ok(Number::Integer(n)) => + n.to_usize().unwrap(), + Ok(Number::Fixnum(n)) => + usize::try_from(n).unwrap(), + _ => + unreachable!() + }; + + let retract_user_clause = || { + let mut loader = Loader::new(LiveTermStream::new(ListingSource::User), self); + let clause_clause_loc = loader.load_state.retract_clause(key, target_pos); + + let clause_assert_margin = + loader.load_state.wam.indices.modules.get(&clause_name!("builtins")) + .map(|builtins| builtins.clause_assert_margin) + .unwrap(); + + let target_pos = + match loader.load_state.wam.indices.get_predicate_skeleton( + &CompilationTarget::Module(clause_name!("builtins")), + &(clause_name!("$clause"), 2), + ) { + Some(skeleton) => { + let search_result = + skeleton.clause_clause_locs[0 .. clause_assert_margin] + .binary_search_by(|loc| clause_clause_loc.cmp(&loc)); + + let result = + search_result.unwrap_or_else(|_| { + skeleton.clause_clause_locs[clause_assert_margin ..] + .binary_search_by(|loc| loc.cmp(&clause_clause_loc)) + .unwrap() + clause_assert_margin + }); + + if result < clause_assert_margin { + loader.load_state.wam.indices.modules.get_mut(&clause_name!("builtins")) + .map(|builtins| builtins.clause_assert_margin -= 1); + } + + result + } + None => { + unreachable!(); + } + }; + + + let compilation_target = mem::replace( + &mut loader.load_state.compilation_target, + CompilationTarget::Module(clause_name!("builtins")), + ); + + loader.load_state.retract_clause((clause_name!("$clause"), 2), target_pos); + loader.load_state.compilation_target = compilation_target; + + LiveTermStream::evacuate(loader) + }; + + match retract_user_clause() { + Ok(_) => { + } + Err(e) => { + self.throw_session_error(e, (clause_name!("retract"), 1)); + } + } + } + + pub(crate) + fn meta_predicate_property(&mut self) { + let module_name = atom_from!( + self.machine_st, + self.machine_st.store(self.machine_st.deref( + self.machine_st[temp_v!(1)] + )) + ); + + let (predicate_name, arity) = + self.machine_st.read_predicate_key( + self.machine_st[temp_v!(2)], + self.machine_st[temp_v!(3)], + ); + + let compilation_target = + match module_name.as_str() { + "user" => CompilationTarget::User, + _ => CompilationTarget::Module(module_name), + }; + + match self.indices.get_meta_predicate_spec(predicate_name, arity, &compilation_target) { + Some(meta_specs) => { + let list_loc = self.machine_st.heap.to_list( + meta_specs.iter().map(|meta_spec| { + match meta_spec { + MetaSpec::Minus => HeapCellValue::Atom(clause_name!("+"), None), + MetaSpec::Plus => HeapCellValue::Atom(clause_name!("-"), None), + MetaSpec::Either => HeapCellValue::Atom(clause_name!("?"), None), + MetaSpec::RequiresExpansionWithArgument(ref arg_num) => { + HeapCellValue::Addr(Addr::Usize(*arg_num)) + } + } + }), + ); + + let heap_loc = self.machine_st.heap.push( + HeapCellValue::NamedStr(1, clause_name!("meta_predicate"), None), + ); + + self.machine_st.heap.push(HeapCellValue::Addr(Addr::HeapCell(list_loc))); + self.machine_st.unify(Addr::HeapCell(heap_loc), self.machine_st[temp_v!(4)]); + } + None => { + self.machine_st.fail = true; + } + } + } + + pub(crate) + fn builtin_property(&mut self) { + let key = + self.machine_st.read_predicate_key( + self.machine_st[temp_v!(1)], + self.machine_st[temp_v!(2)], + ); + + match ClauseType::from(key.0, key.1, None) { + ClauseType::BuiltIn(_) | ClauseType::Inlined(..) | ClauseType::CallN => { + return; + } + ClauseType::Named(ref name, arity, _) => { + if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { + self.machine_st.fail = !module.code_dir.contains_key( + &(name.clone(), arity), + ); + + return; + } + } + ClauseType::Op(ref name, ref op_desc, _) => { + if let Some(module) = self.indices.modules.get(&(clause_name!("builtins"))) { + self.machine_st.fail = !module.code_dir.contains_key( + &(name.clone(), op_desc.arity()), + ); + + return; + } + } + _ => { + } + } + + self.machine_st.fail = true; + } + + pub(crate) + fn compile_pending_predicates(&mut self) { + let (mut loader, evacuable_h) = self.loader_from_heap_evacuable(temp_v!(1)); + + let compile_pending_predicates = || { + if !loader.predicates.is_empty() { + loader.compile_and_submit()?; + } + + LiveTermStream::evacuate(loader) + }; + + let result = compile_pending_predicates(); + self.restore_load_state_payload(result, evacuable_h); + } +} + +impl<'a> Loader<'a, LiveTermStream> { + pub(super) + fn to_load_state_payload(mut self) -> LoadStatePayload { + LoadStatePayload { + term_stream: + mem::replace( + &mut self.term_stream, + LiveTermStream::new(ListingSource::User), + ), + preprocessor: + mem::replace( + &mut self.preprocessor, + Preprocessor::new(self.load_state.wam.machine_st.flags), + ), + non_counted_bt_preds: + mem::replace( + &mut self.non_counted_bt_preds, + IndexSet::new(), + ), + compilation_target: + self.load_state.compilation_target.take(), + retraction_info: + mem::replace( + &mut self.load_state.retraction_info, + RetractionInfo::new(self.load_state.wam.code_repo.code.len()), + ), + predicates: + mem::replace( + &mut self.predicates, + vec![], + ), + clause_clauses: + mem::replace( + &mut self.clause_clauses, + vec![], + ), + module_op_exports: + mem::replace( + &mut self.load_state.module_op_exports, + vec![], + ), + } + } + + pub(super) + fn from_load_state_payload(wam: &'a mut Machine, mut payload: LoadStatePayload) -> Self { + Loader { + term_stream: + mem::replace( + &mut payload.term_stream, + LiveTermStream::new(ListingSource::User), + ), + preprocessor: + mem::replace( + &mut payload.preprocessor, + Preprocessor::new(MachineFlags::default()), + ), + non_counted_bt_preds: + mem::replace( + &mut payload.non_counted_bt_preds, + IndexSet::new(), + ), + clause_clauses: + mem::replace( + &mut payload.clause_clauses, + vec![], + ), + predicates: + mem::replace( + &mut payload.predicates, + vec![], + ), + load_state: LoadState { + compilation_target: payload.compilation_target.take(), + module_op_exports: + mem::replace( + &mut payload.module_op_exports, + vec![], + ), + retraction_info: + mem::replace( + &mut payload.retraction_info, + RetractionInfo::new(0), + ), + wam, + }, + } + } + + fn incremental_compile_clause( + &mut self, + key: PredicateKey, + term: Term, + compilation_target: CompilationTarget, + non_counted_bt: bool, + append_or_prepend: AppendOrPrepend, + ) -> Result<(), SessionError> { + let mut preprocessor = Preprocessor::new(self.load_state.wam.machine_st.flags); + + let tl = preprocessor.try_term_to_tl( + &mut self.load_state, + term, + CutContext::BlocksCuts, + )?; + + let queue = preprocessor.parse_queue(&mut self.load_state)?; + + let clause = + match tl { + TopLevel::Fact(fact) => { + PredicateClause::Fact(fact) + } + TopLevel::Rule(rule) => { + PredicateClause::Rule(rule) + } + _ => { + unreachable!() + } + }; + + let compilation_target = + mem::replace(&mut self.load_state.compilation_target, compilation_target); + + let result = self.load_state.incremental_compile_clause( + key, + clause, + queue, + non_counted_bt, + append_or_prepend, + ); + + self.load_state.compilation_target = compilation_target; + result?; + + Ok(()) + } + + #[inline] + fn enqueue_term(&mut self, term: Term) { + self.term_stream.term_queue.push_back(term); + } +} + +#[inline] +pub(super) +fn load_module( + code_dir: &mut CodeDir, + op_dir: &mut OpDir, + meta_predicate_dir: &mut MetaPredicateDir, + compilation_target: &CompilationTarget, + module: &Module, +) { + import_module_exports( + &mut RetractionInfo::new(0), + &compilation_target, + module, + code_dir, + op_dir, + meta_predicate_dir, + ); +} diff --git a/src/machine/machine_errors.rs b/src/machine/machine_errors.rs index 1dcc1db8..ffb95aef 100644 --- a/src/machine/machine_errors.rs +++ b/src/machine/machine_errors.rs @@ -1,6 +1,6 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; -use crate::forms::{ModuleSource, Number, PredicateKey}; +use crate::forms::{ModuleSource, Number}; //, PredicateKey}; use crate::machine::heap::*; use crate::machine::machine_indices::*; 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) fn session_error(h: usize, err: SessionError) -> Self { match err { - SessionError::CannotOverwriteBuiltIn(pred_str) | + // SessionError::CannotOverwriteBuiltIn(pred_str) | + /* SessionError::CannotOverwriteImport(pred_str) => { Self::permission_error( h, @@ -381,12 +368,14 @@ impl MachineError { functor!(clause_name(pred_str)), ) } + */ SessionError::ExistenceError(err) => { Self::existence_error(h, err) } - SessionError::InvalidFileName(filename) => { - Self::existence_error(h, ExistenceError::Module(filename)) - } + // SessionError::InvalidFileName(filename) => { + // Self::existence_error(h, ExistenceError::Module(filename)) + // } + /* SessionError::ModuleDoesNotContainExport(..) => { Self::permission_error( h, @@ -395,6 +384,15 @@ impl MachineError { 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 => { Self::permission_error( h, @@ -411,7 +409,7 @@ impl MachineError { functor!(clause_name(op)), ) } - SessionError::ParserError(err) => { + SessionError::CompilationError(err) => { Self::syntax_error(h, err) } SessionError::QueryCannotBeDefinedAsFact => { @@ -426,13 +424,15 @@ impl MachineError { } pub(super) - fn syntax_error(h: usize, err: ParserError) -> Self { - if let ParserError::Arithmetic(err) = err { + fn syntax_error>(h: usize, err: E) -> Self { + let err = err.into(); + + if let CompilationError::Arithmetic(err) = err { return Self::arithmetic_error(h, err); } let location = err.line_and_col_num(); - let stub = functor!(err.as_str()); + let stub = err.as_functor(h); let stub = functor!( "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 for CompilationError { + #[inline] + fn from(err: ArithmeticError) -> CompilationError { + CompilationError::Arithmetic(err) + } +} + +impl From 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)] pub enum Permission { - Access, + // Access, Create, InputStream, Modify, @@ -490,7 +584,7 @@ impl Permission { #[inline] pub fn as_str(self) -> &'static str { match self { - Permission::Access => "access", + // Permission::Access => "access", Permission::Create => "create", Permission::InputStream => "input", Permission::Modify => "modify", @@ -807,37 +901,55 @@ pub enum ExistenceError { #[derive(Debug)] pub enum SessionError { - CannotOverwriteBuiltIn(ClauseName), - CannotOverwriteImport(ClauseName), + CompilationError(CompilationError), + // CannotOverwriteBuiltIn(ClauseName), + // CannotOverwriteImport(ClauseName), ExistenceError(ExistenceError), - InvalidFileName(ClauseName), - ModuleDoesNotContainExport(ClauseName, PredicateKey), + // InvalidFileName(ClauseName), + // ModuleDoesNotContainExport(ClauseName, PredicateKey), + ModuleCannotImportSelf(ClauseName), NamelessEntry, OpIsInfixAndPostFix(ClauseName), QueryCannotBeDefinedAsFact, - ParserError(ParserError), } #[derive(Debug)] pub enum EvalSession { - EntrySuccess, + // EntrySuccess, Error(SessionError), } impl From for EvalSession { + #[inline] fn from(err: SessionError) -> Self { EvalSession::Error(err) } } +impl From for SessionError { + #[inline] + fn from(err: std::io::Error) -> SessionError { + SessionError::from(ParserError::from(err)) + } +} + impl From for SessionError { + #[inline] fn from(err: ParserError) -> Self { - SessionError::ParserError(err) + SessionError::CompilationError(CompilationError::from(err)) + } +} + +impl From for SessionError { + #[inline] + fn from(err: CompilationError) -> Self { + SessionError::CompilationError(err) } } impl From for EvalSession { + #[inline] fn from(err: ParserError) -> Self { - EvalSession::from(SessionError::ParserError(err)) + EvalSession::from(SessionError::from(err)) } } diff --git a/src/machine/machine_indices.rs b/src/machine/machine_indices.rs index 13fb6ae7..869d4c92 100644 --- a/src/machine/machine_indices.rs +++ b/src/machine/machine_indices.rs @@ -1,9 +1,9 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; use crate::clause_types::*; use crate::fixtures::*; use crate::forms::*; +use crate::machine::CompilationTarget; use crate::machine::code_repo::CodeRepo; use crate::machine::Ball; use crate::machine::heap::*; @@ -11,20 +11,21 @@ use crate::machine::machine_state::*; use crate::machine::partial_string::*; use crate::machine::raw_block::RawBlockTraits; use crate::machine::streams::Stream; +use crate::machine::term_stream::LoadStatePayload; use crate::instructions::*; use crate::ordered_float::OrderedFloat; use crate::rug::{Integer, Rational}; use crate::indexmap::IndexMap; -use std::cell::RefCell; +use std::cell::Cell; use std::cmp::Ordering; -use std::collections::{BTreeMap, BTreeSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet}; use std::convert::TryFrom; use std::fmt; -use std::mem; +// use std::mem; use std::net::TcpListener; -use std::ops::{Add, AddAssign, Sub, SubAssign}; +use std::ops::{Add, AddAssign, Deref, Sub, SubAssign}; use std::rc::Rc; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -64,6 +65,7 @@ pub enum Addr { Fixnum(isize), Float(OrderedFloat), Lis(usize), + LoadStatePayload(usize), HeapCell(usize), PStrLocation(usize, usize), // location of pstr in heap, offset into string in bytes. StackCell(usize, usize), @@ -231,7 +233,7 @@ impl Addr { Addr::Lis(_) | Addr::PStrLocation(..) | Addr::Str(_) => { Some(TermOrderCategory::Compound) } - Addr::CutPoint(_) | Addr::Stream(_) | Addr::TcpListener(_) => { + Addr::CutPoint(_) | Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => { None } } @@ -369,6 +371,7 @@ pub enum HeapCellValue { Atom(ClauseName, Option), DBRef(DBRef), Integer(Rc), + LoadStatePayload(LoadStatePayload), NamedStr(usize, ClauseName, Option), // arity, name, precedence/Specifier if it has one. Rational(Rc), PartialString(PartialString, bool), // the partial string, a bool indicating whether it came from a Constant. @@ -387,6 +390,9 @@ impl HeapCellValue { HeapCellValue::Rational(..) => { Addr::Con(focus) } + HeapCellValue::LoadStatePayload(_) => { + Addr::LoadStatePayload(focus) + } HeapCellValue::NamedStr(_, _, _) => { Addr::Str(focus) } @@ -417,6 +423,9 @@ impl HeapCellValue { &HeapCellValue::Integer(ref n) => { HeapCellValue::Integer(n.clone()) } + &HeapCellValue::LoadStatePayload(_) => { + HeapCellValue::Atom(clause_name!("$live_term_stream"), None) + } &HeapCellValue::NamedStr(arity, ref name, ref op) => { HeapCellValue::NamedStr(arity, name.clone(), op.clone()) } @@ -443,50 +452,42 @@ impl From for HeapCellValue { } } -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Debug, Clone, Copy, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum IndexPtr { DynamicUndefined, // a predicate, declared as dynamic, whose location in code is as yet undefined. - Undefined, - InSituDirEntry(usize), Index(usize), - UserGoalExpansion, - UserTermExpansion + Undefined, } #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] -pub struct CodeIndex(pub Rc>); +pub struct CodeIndex(pub Rc>); + +impl Deref for CodeIndex { + type Target = Cell; + + #[inline] + fn deref(&self) -> &Self::Target { + self.0.deref() + } +} impl CodeIndex { #[inline] - pub fn new(ptr: IndexPtr, module_name: ClauseName) -> Self { - CodeIndex(Rc::new(RefCell::new(( ptr, module_name )))) + pub(super) + fn new(ptr: IndexPtr) -> Self { + CodeIndex(Rc::new(Cell::new(ptr))) } #[inline] pub fn is_undefined(&self) -> bool { - let index_ptr = &self.0.borrow().0; - - match index_ptr { - &IndexPtr::Undefined | &IndexPtr::DynamicUndefined => true, + match self.0.get() { + IndexPtr::Undefined => true, // | &IndexPtr::DynamicUndefined => true, _ => 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 { - match self.0.borrow().0 { + match self.0.get() { IndexPtr::Index(i) => Some(i), _ => None, } @@ -495,60 +496,35 @@ impl CodeIndex { impl Default for CodeIndex { fn default() -> Self { - CodeIndex(Rc::new(RefCell::new(( - IndexPtr::Undefined, - clause_name!(""), - )))) + CodeIndex(Rc::new(Cell::new(IndexPtr::Undefined))) } } -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, 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)] pub enum REPLCodePtr { - CompileBatch, + AddDynamicPredicate, + AddGoalExpansionClause, + AddTermExpansionClause, + BuiltInProperty, + ClauseToEvacuable, + ConcludeLoad, + DeclareModule, + LoadCompiledLibrary, + LoadContextSource, + LoadContextFile, + LoadContextDirectory, + LoadContextModule, + LoadContextStream, + PopLoadContext, + PopLoadStatePayload, + PushLoadContext, + PushLoadStatePayload, UseModule, - UseQualifiedModule, - UseModuleFromFile, - UseQualifiedModuleFromFile + MetaPredicateProperty, + CompilePendingPredicates, + UserAsserta, + UserAssertz, + UserRetract, } #[derive(Debug, Clone, PartialEq)] @@ -556,7 +532,7 @@ pub enum CodePtr { BuiltInClause(BuiltInClauseType, LocalCodePtr), // local is the successor call. CallN(usize, LocalCodePtr, bool), // arity, local, last call. 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. VerifyAttrInterrupt(usize), // location of the verify attribute interrupt code in the CodeDir. } @@ -568,18 +544,26 @@ impl CodePtr { | &CodePtr::CallN(_, ref local, _) | &CodePtr::Local(ref local) => local.clone(), &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)] pub enum LocalCodePtr { - DirEntry(usize), // offset. - InSituDirEntry(usize), - TopLevel(usize, usize), // chunk_num, offset. - UserGoalExpansion(usize), - UserTermExpansion(usize), + DirEntry(usize), // offset + Halt, + IndexingBuf(usize, usize, usize), // DirEntry offset, first internal offset, second internal offset + // TopLevel(usize, usize), // chunk_num, offset } impl LocalCodePtr { @@ -591,6 +575,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) fn is_reset_cont_marker(&self, code_repo: &CodeRepo, last_call: bool) -> bool { match code_repo.lookup_instr(last_call, &CodePtr::Local(*self)) { @@ -621,28 +615,21 @@ impl LocalCodePtr { [integer(*p)] )); } - LocalCodePtr::InSituDirEntry(p) => { - heap.append(functor!( - "in_situ_dir_entry", - [integer(*p)] - )); + LocalCodePtr::Halt => { + heap.append(functor!("halt")); } + /* LocalCodePtr::TopLevel(chunk_num, offset) => { heap.append(functor!( "top_level", [integer(*chunk_num), integer(*offset)] )); } - LocalCodePtr::UserGoalExpansion(p) => { + */ + LocalCodePtr::IndexingBuf(p, o, i) => { heap.append(functor!( - "user_goal_expansion", - [integer(*p)] - )); - } - LocalCodePtr::UserTermExpansion(p) => { - heap.append(functor!( - "user_term_expansion", - [integer(*p)] + "indexed_buf", + [integer(*p), integer(*o), integer(*i)] )); } } @@ -651,6 +638,7 @@ impl LocalCodePtr { } } +/* impl PartialOrd for CodePtr { fn partial_cmp(&self, other: &CodePtr) -> Option { match (self, other) { @@ -667,11 +655,8 @@ impl PartialOrd for CodePtr { impl PartialOrd for LocalCodePtr { fn partial_cmp(&self, other: &LocalCodePtr) -> Option { match (self, other) { - (&LocalCodePtr::InSituDirEntry(p1), &LocalCodePtr::InSituDirEntry(ref p2)) - | (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) - | (&LocalCodePtr::UserTermExpansion(p1), &LocalCodePtr::UserTermExpansion(ref p2)) - | (&LocalCodePtr::UserGoalExpansion(p1), &LocalCodePtr::UserGoalExpansion(ref p2)) - | (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => { + (&LocalCodePtr::DirEntry(p1), &LocalCodePtr::DirEntry(ref p2)) | + (&LocalCodePtr::TopLevel(_, p1), &LocalCodePtr::TopLevel(_, ref p2)) => { p1.partial_cmp(p2) } (_, &LocalCodePtr::TopLevel(_, _)) => { @@ -683,29 +668,34 @@ impl PartialOrd for LocalCodePtr { } } } +*/ impl Default for CodePtr { + #[inline] fn default() -> Self { CodePtr::Local(LocalCodePtr::default()) } } impl Default for LocalCodePtr { + #[inline] fn default() -> Self { - LocalCodePtr::TopLevel(0, 0) + LocalCodePtr::DirEntry(0) } } impl Add for LocalCodePtr { type Output = LocalCodePtr; + #[inline] fn add(self, rhs: usize) -> Self::Output { match self { - LocalCodePtr::InSituDirEntry(p) => LocalCodePtr::InSituDirEntry(p + rhs), - LocalCodePtr::DirEntry(p) => LocalCodePtr::DirEntry(p + rhs), - LocalCodePtr::TopLevel(cn, p) => LocalCodePtr::TopLevel(cn, p + rhs), - LocalCodePtr::UserTermExpansion(p) => LocalCodePtr::UserTermExpansion(p + rhs), - LocalCodePtr::UserGoalExpansion(p) => LocalCodePtr::UserGoalExpansion(p + rhs), + LocalCodePtr::DirEntry(p) => + LocalCodePtr::DirEntry(p + rhs), + LocalCodePtr::Halt => + unreachable!(), + LocalCodePtr::IndexingBuf(p, o, i) => + LocalCodePtr::IndexingBuf(p, o, i + rhs), } } } @@ -713,30 +703,40 @@ impl Add for LocalCodePtr { impl Sub for LocalCodePtr { type Output = Option; + #[inline] fn sub(self, rhs: usize) -> Self::Output { match self { - LocalCodePtr::InSituDirEntry(p) => - p.checked_sub(rhs).map(LocalCodePtr::InSituDirEntry), LocalCodePtr::DirEntry(p) => p.checked_sub(rhs).map(LocalCodePtr::DirEntry), - LocalCodePtr::TopLevel(cn, p) => - p.checked_sub(rhs).map(|r| LocalCodePtr::TopLevel(cn, r)), - LocalCodePtr::UserTermExpansion(p) => - p.checked_sub(rhs).map(LocalCodePtr::UserTermExpansion), - LocalCodePtr::UserGoalExpansion(p) => - p.checked_sub(rhs).map(LocalCodePtr::UserGoalExpansion), + LocalCodePtr::Halt => + unreachable!(), + LocalCodePtr::IndexingBuf(p, o, i) => + i.checked_sub(rhs).map(|r| LocalCodePtr::IndexingBuf(p, o, r)), } } } +impl SubAssign 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 for LocalCodePtr { + #[inline] fn add_assign(&mut self, rhs: usize) { match self { - &mut LocalCodePtr::InSituDirEntry(ref mut p) - | &mut LocalCodePtr::UserGoalExpansion(ref mut p) - | &mut LocalCodePtr::UserTermExpansion(ref mut p) - | &mut LocalCodePtr::DirEntry(ref mut p) - | &mut LocalCodePtr::TopLevel(_, ref mut p) => *p += rhs, + &mut LocalCodePtr::DirEntry(ref mut p) /* | + &mut LocalCodePtr::TopLevel(_, ref mut p) */ => *p += rhs, + &mut LocalCodePtr::IndexingBuf(_, _, ref mut i) => *i += rhs, + &mut LocalCodePtr::Halt => unreachable!(), } } } @@ -746,10 +746,14 @@ impl Add for CodePtr { fn add(self, rhs: usize) -> Self::Output { match self { - p @ CodePtr::REPL(..) - | p @ CodePtr::VerifyAttrInterrupt(_) - | p @ CodePtr::DynamicTransaction(..) => p, - CodePtr::Local(local) => CodePtr::Local(local + rhs), + p @ CodePtr::REPL(..) | + p @ CodePtr::VerifyAttrInterrupt(_) => { // | + // p @ CodePtr::DynamicTransaction(..) => { + p + } + CodePtr::Local(local) => { + CodePtr::Local(local + rhs) + } CodePtr::BuiltInClause(_, local) | CodePtr::CallN(_, local, _) => { CodePtr::Local(local + rhs) } @@ -767,186 +771,206 @@ impl AddAssign for CodePtr { } } -pub type HeapVarDict = IndexMap, Addr>; -pub type AllocVarDict = IndexMap, VarData>; - -#[derive(Debug, Clone)] -pub struct DynamicPredicateInfo { - pub(super) clauses_subsection_p: usize, // a LocalCodePtr::DirEntry value. -} - -impl Default for DynamicPredicateInfo { - fn default() -> Self { - DynamicPredicateInfo { - clauses_subsection_p: 0, +impl SubAssign for CodePtr { + #[inline] + fn sub_assign(&mut self, rhs: usize) { + match self { + CodePtr::Local(ref mut local) => *local -= rhs, + _ => unreachable!(), } } } + +pub type HeapVarDict = IndexMap, Addr>; +pub type AllocVarDict = IndexMap, VarData>; + pub type InSituCodeDir = IndexMap; - -// key type: module name, predicate indicator. -pub type DynamicCodeDir = IndexMap<(ClauseName, ClauseName, usize), DynamicPredicateInfo>; - pub type GlobalVarDir = IndexMap)>; #[derive(Debug)] pub(crate) struct ModuleStub { - pub(crate) atom_tbl: TabledData, pub(crate) in_situ_code_dir: InSituCodeDir, } -impl ModuleStub { - pub(crate) fn new(atom_tbl: TabledData) -> Self { - ModuleStub { - atom_tbl, - in_situ_code_dir: InSituCodeDir::new(), - } - } -} - -pub(crate) type ModuleStubDir = IndexMap; +// pub(crate) type ModuleStubDir = IndexMap; pub(crate) type StreamAliasDir = IndexMap; pub(crate) type StreamDir = BTreeSet; +pub type MetaPredicateDir = IndexMap>; + +pub type ExtensiblePredicates = IndexMap; + #[derive(Debug)] pub struct IndexStore { - pub(super) atom_tbl: TabledData, pub(super) code_dir: CodeDir, - pub(super) dynamic_code_dir: DynamicCodeDir, + pub(super) extensible_predicates: ExtensiblePredicates, pub(super) global_variables: GlobalVarDir, - pub(super) in_situ_code_dir: InSituCodeDir, - pub(super) in_situ_module_dir: ModuleStubDir, - pub(super) module_dir: ModuleDir, + pub(super) meta_predicates: MetaPredicateDir, pub(super) modules: ModuleDir, pub(super) op_dir: OpDir, pub(super) streams: StreamDir, pub(super) stream_aliases: StreamAliasDir, } +impl Default for IndexStore { + #[inline] + fn default() -> Self { + index_store!(CodeDir::new(), default_op_dir(), ModuleDir::new()) + } +} + impl IndexStore { - pub fn predicate_exists( - &self, - name: ClauseName, - module: ClauseName, - arity: usize, - op_spec: Option, - ) -> bool { - match self.modules.get(&module) { - Some(module) => match ClauseType::from(name, arity, op_spec) { - ClauseType::Named(name, arity, _) => module.code_dir.contains_key(&(name, arity)), - ClauseType::Op(name, spec, ..) => { - module.code_dir.contains_key(&(name, spec.arity())) + pub fn get_predicate_skeleton( + &mut self, + compilation_target: &CompilationTarget, + key: &PredicateKey, + ) -> Option<&mut PredicateSkeleton> { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => { + self.extensible_predicates.get_mut(key) + } + _ => { + match compilation_target { + 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) { - self.code_dir.insert((clause_name!("term_expansion"), 2), - CodeIndex(Rc::new(RefCell::new( - (IndexPtr::UserTermExpansion, - clause_name!("user")) - )))); - self.code_dir.insert((clause_name!("goal_expansion"), 2), - CodeIndex(Rc::new(RefCell::new( - (IndexPtr::UserGoalExpansion, - clause_name!("user")) - )))); + pub fn remove_predicate_skeleton( + &mut self, + compilation_target: &CompilationTarget, + key: &PredicateKey, + ) { + match (key.0.as_str(), key.1) { + ("term_expansion", 2) => { + self.extensible_predicates.remove(key); + }, + _ => { + 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 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( + pub fn get_predicate_code_index( &self, - module: ClauseName, name: ClauseName, arity: usize, - ) -> Option { - self.dynamic_code_dir.get(&(module, name, arity)).cloned() + module: ClauseName, + op_spec: Option, + ) -> Option { + 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(crate) fn take_in_situ_module_dir(&mut self) -> ModuleStubDir { - mem::replace(&mut self.in_situ_module_dir, ModuleStubDir::new()) + pub fn get_meta_predicate_spec( + &self, + name: ClauseName, + arity: usize, + compilation_target: &CompilationTarget, + ) -> Option<&Vec> { + 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 take_in_situ_code_dir(&mut self) -> InSituCodeDir { - mem::replace(&mut self.in_situ_code_dir, InSituCodeDir::new()) - } - - #[inline] - pub fn take_module(&mut self, name: ClauseName) -> Option { - self.modules.swap_remove(&name) - } - - #[inline] - pub fn insert_module(&mut self, module: Module) { - self.modules.insert(module.module_decl.name.clone(), module); + pub fn is_dynamic_predicate(&self, module_name: ClauseName, key: PredicateKey) -> bool { + match module_name.as_str() { + "user" => { + self.extensible_predicates.get(&key) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false) + } + _ => { + match self.modules.get(&module_name) { + Some(ref module) => { + module.extensible_predicates.get(&key) + .map(|skeleton| skeleton.is_dynamic) + .unwrap_or(false) + } + None => { + false + } + } + } + } } #[inline] pub(super) fn new() -> Self { - IndexStore { - 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(), - } + IndexStore::default() } - #[inline] - pub(super) fn copy_and_swap(&mut self, other: &mut IndexStore) { - 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 { - 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) { + pub(super) + fn get_cleaner_sites(&self) -> (usize, usize) { let r_w_h = clause_name!("run_cleaners_with_handling"); let r_wo_h = clause_name!("run_cleaners_without_handling"); - let iso_ext = clause_name!("iso_ext"); 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()); 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()); if let Some(r_w_h) = r_w_h { @@ -960,129 +984,6 @@ impl IndexStore { } pub type CodeDir = BTreeMap; -pub type TermDir = IndexMap)>; - -#[derive(Debug)] -pub struct TermDirQuantumEntry { - pub old_terms: (Predicate, VecDeque), - pub new_terms: (Predicate, VecDeque), - 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) -> 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); - -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> { Borrowed(&'a T), @@ -1094,7 +995,8 @@ impl<'a, T: 'a + fmt::Debug> fmt::Debug for RefOrOwned<'a, T> { match self { &RefOrOwned::Borrowed(ref borrowed) => write!(f, "Borrowed({:?})", borrowed), - &RefOrOwned::Owned(ref owned) => write!(f, "Owned({:?})", owned), + &RefOrOwned::Owned(ref owned) => + write!(f, "Owned({:?})", owned), } } } @@ -1107,9 +1009,7 @@ impl<'a, T> RefOrOwned<'a, T> { } } - pub fn to_owned(self) -> T - where - T: Clone, + pub fn to_owned(self) -> T where T: Clone { match self { RefOrOwned::Borrowed(item) => item.clone(), diff --git a/src/machine/machine_state.rs b/src/machine/machine_state.rs index e8799566..a49465ec 100644 --- a/src/machine/machine_state.rs +++ b/src/machine/machine_state.rs @@ -1,5 +1,5 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::tabled_rc::*; use crate::clause_types::*; use crate::forms::*; @@ -9,14 +9,14 @@ use crate::machine::copier::*; use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; -use crate::machine::modules::*; +use crate::machine::partial_string::HeapPStrIter; use crate::machine::stack::*; use crate::machine::streams::*; use crate::rug::Integer; use crate::downcast::Any; -use crate::indexmap::{IndexMap, IndexSet}; +use crate::indexmap::IndexMap; use std::cmp::Ordering; use std::convert::TryFrom; @@ -25,292 +25,6 @@ use std::io::Write; use std::mem; use std::ops::{Index, IndexMut}; -#[derive(Debug)] -pub(crate) struct HeapPStrIter<'a> { - focus: Addr, - machine_st: &'a MachineState, - seen: IndexSet, -} - -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 { - 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 { - 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 { - 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)] pub struct Ball { pub(super) boundary: usize, @@ -332,17 +46,6 @@ impl Ball { 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) fn copy_and_align(&self, h: usize) -> Heap { let diff = self.boundary as i64 - h as i64; @@ -586,6 +289,7 @@ impl Default for HeapPtr { #[derive(Debug)] pub struct MachineState { + pub(crate) atom_tbl: TabledData, pub(super) s: HeapPtr, pub(super) p: CodePtr, pub(super) b: usize, @@ -640,7 +344,7 @@ impl MachineState { loop { match self.read( stream.clone(), - indices.atom_tbl.clone(), + self.atom_tbl.clone(), &indices.op_dir, ) { Ok(term_write_result) => { @@ -654,7 +358,7 @@ impl MachineState { let mut list_of_var_eqs = vec![]; 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 spec = fetch_atom_op_spec(clause_name!("="), None, &indices.op_dir); @@ -854,6 +558,15 @@ impl MachineState { 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] pub(crate) fn heap_pstr_iter<'a>(&'a self, focus: Addr) -> HeapPStrIter<'a> { @@ -895,6 +608,24 @@ impl MachineState { 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) fn call_at_index(&mut self, arity: usize, p: LocalCodePtr) { self.cp.assign_if_local(self.p.clone() + 1); @@ -914,58 +645,35 @@ impl MachineState { fn module_lookup( &mut self, indices: &IndexStore, + call_policy: &mut Box, key: PredicateKey, module_name: ClauseName, - last_call: bool, + _last_call: bool, + current_input_stream: &mut Stream, + current_output_stream: &mut Stream, ) -> CallResult { - let (name, arity) = key; - - if let Some(ref idx) = indices.get_code_index((name.clone(), arity), module_name.clone()) { - match idx.0.borrow().0 { - IndexPtr::Index(compiled_tl_index) => { - if last_call { - self.execute_at_index(arity, dir_entry!(compiled_tl_index)); - } else { - self.call_at_index(arity, dir_entry!(compiled_tl_index)); - } - - return Ok(()); - } - IndexPtr::DynamicUndefined => { - self.fail = true; - return Ok(()); - } - 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(()); - } - _ => {} - } + if module_name.as_str() == "user" { + return call_policy.call_clause_type( + self, + key, + &indices.code_dir, + &indices.op_dir, + current_input_stream, + current_output_stream, + ); + } else if let Some(module) = indices.modules.get(&module_name) { + return call_policy.call_clause_type( + self, + key, + &module.code_dir, + &module.op_dir, + current_input_stream, + current_output_stream, + ); } + let (name, arity) = key; + let h = self.heap.h(); let stub = MachineError::functor_stub(name.clone(), 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 -{ - 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>; 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.hb = machine_st.heap.h(); - machine_st.p += offset; + machine_st.p = CodePtr::Local(dir_entry!(machine_st.p.local().abs_loc() + offset)); Ok(()) } @@ -1130,7 +795,7 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { machine_st.stack.truncate(b); 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(()) } @@ -1180,13 +845,12 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &mut IndexStore, + idx: &CodeIndex, ) -> CallResult { if machine_st.last_call { - self.try_execute(machine_st, name, arity, idx, indices) + self.try_execute(machine_st, name, arity, idx) } 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, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &IndexStore, + idx: &CodeIndex, ) -> CallResult { - match idx.0.borrow().0 { + match idx.get() { IndexPtr::DynamicUndefined => { machine_st.fail = true; + return Ok(()); } 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) => { - 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)); + machine_st.call_at_index(arity, LocalCodePtr::DirEntry(compiled_tl_index)); } } @@ -1227,26 +882,19 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &IndexStore, + idx: &CodeIndex, ) -> CallResult { - match idx.0.borrow().0 { - IndexPtr::DynamicUndefined => - machine_st.fail = true, - IndexPtr::Undefined => - return try_in_situ(machine_st, name, arity, indices, true), + match idx.get() { + IndexPtr::DynamicUndefined => { + machine_st.fail = true; + return Ok(()); + } + IndexPtr::Undefined => { + return Err(machine_st.throw_undefined_error(name, arity)); + } IndexPtr::Index(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(()) @@ -1256,7 +904,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { &mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, - indices: &mut IndexStore, + _code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { @@ -1305,15 +954,15 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { let atom = match machine_st.compare_term_test(&a2, &a3) { 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) } 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) } 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) } }; @@ -1338,8 +987,8 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { &BuiltInClauseType::Read => { match machine_st.read( current_input_stream.clone(), - indices.atom_tbl.clone(), - &indices.op_dir, + machine_st.atom_tbl.clone(), + op_dir, ) { Ok(offset) => { let addr = machine_st[temp_v!(1)]; @@ -1347,16 +996,18 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { } Err(ParserError::UnexpectedEOF) => { let addr = machine_st[temp_v!(1)]; - let eof = clause_name!("end_of_file".to_string(), - indices.atom_tbl); + let eof = clause_name!("end_of_file".to_string(), machine_st.atom_tbl); + let atom = machine_st.heap.to_unifiable( HeapCellValue::Atom(eof, None) ); + machine_st.unify(addr, atom); } Err(e) => { let h = machine_st.heap.h(); let stub = MachineError::functor_stub(clause_name!("read"), 1); + let err = MachineError::syntax_error(h, e); 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) } &BuiltInClauseType::Functor => { - machine_st.try_functor(&indices)?; + machine_st.try_functor(op_dir)?; return_from_clause!(machine_st.last_call, machine_st) } &BuiltInClauseType::NotEq => { @@ -1453,24 +1104,66 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { } } - fn compile_hook( + fn call_clause_type( &mut self, 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 { - machine_st.cp = LocalCodePtr::TopLevel(0, 0); + let (name, arity) = key; - machine_st.num_of_args = hook.arity(); - machine_st.b0 = machine_st.b; + match ClauseType::from(name.clone(), arity, None) { + 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 { - CompileTimeHook::UserTermExpansion | CompileTimeHook::TermExpansion => { - CodePtr::Local(LocalCodePtr::UserTermExpansion(0)) + if machine_st.fail { + return Ok(()); + } + + machine_st.p = CodePtr::CallN(arity, machine_st.p.local(), machine_st.last_call); } - CompileTimeHook::UserGoalExpansion | CompileTimeHook::GoalExpansion => { - CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)) + 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(..) => { + 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(()) } @@ -1479,57 +1172,20 @@ pub(crate) trait CallPolicy: Any + fmt::Debug { &mut self, machine_st: &mut MachineState, arity: usize, - indices: &mut IndexStore, + code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { - if let Some((name, arity)) = machine_st.setup_call_n(arity) { - match ClauseType::from(name.clone(), arity, None) { - ClauseType::BuiltIn(built_in) => { - machine_st.setup_built_in_call(built_in.clone()); - self.call_builtin( - machine_st, - &built_in, - indices, - 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, - )); - } - }; + if let Some(key) = machine_st.setup_call_n(arity) { + self.call_clause_type( + machine_st, + key, + code_dir, + op_dir, + current_input_stream, + current_output_stream, + )?; } Ok(()) @@ -1542,11 +1198,9 @@ impl CallPolicy for CWILCallPolicy { machine_st: &mut MachineState, name: ClauseName, arity: usize, - idx: CodeIndex, - indices: &mut IndexStore, + idx: &CodeIndex, ) -> CallResult { - self.prev_policy - .context_call(machine_st, name, arity, idx, indices)?; + self.prev_policy.context_call(machine_st, name, arity, idx)?;//, indices)?; self.increment(machine_st) } @@ -1574,14 +1228,16 @@ impl CallPolicy for CWILCallPolicy { &mut self, machine_st: &mut MachineState, ct: &BuiltInClauseType, - indices: &mut IndexStore, + code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { self.prev_policy.call_builtin( machine_st, ct, - indices, + code_dir, + op_dir, current_input_stream, current_output_stream )?; @@ -1593,14 +1249,16 @@ impl CallPolicy for CWILCallPolicy { &mut self, machine_st: &mut MachineState, arity: usize, - indices: &mut IndexStore, + code_dir: &CodeDir, + op_dir: &OpDir, current_input_stream: &mut Stream, current_output_stream: &mut Stream, ) -> CallResult { self.prev_policy.call_n( machine_st, arity, - indices, + code_dir, + op_dir, current_input_stream, current_output_stream, )?; diff --git a/src/machine/machine_state_impl.rs b/src/machine/machine_state_impl.rs index 5de07140..277caa08 100644 --- a/src/machine/machine_state_impl.rs +++ b/src/machine/machine_state_impl.rs @@ -1,9 +1,10 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::tabled_rc::*; use crate::clause_types::*; use crate::forms::*; use crate::heap_iter::*; +use crate::indexing::*; use crate::instructions::*; use crate::machine::INTERRUPT; use crate::machine::attributed_variables::*; @@ -13,6 +14,7 @@ use crate::machine::heap::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::partial_string::*; use crate::machine::stack::*; use crate::machine::streams::*; use crate::ordered_float::*; @@ -24,22 +26,11 @@ use std::cmp::Ordering; use std::convert::TryFrom; 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 { pub(crate) fn new() -> Self { MachineState { + atom_tbl: TabledData::new(Rc::new("".to_owned())), s: HeapPtr::default(), p: CodePtr::default(), 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] pub fn machine_flags(&self) -> MachineFlags { self.flags @@ -1390,85 +1351,130 @@ impl MachineState { } pub(super) - fn execute_indexing_instr(&mut self, instr: &IndexingInstruction) { - match instr { - &IndexingInstruction::SwitchOnTerm(arg, v, c, l, s) => { - let addr = self[temp_v!(arg)]; - let addr = self.store(self.deref(addr)); + fn execute_indexing_instr( + &mut self, + indexing_lines: &Vec, + call_policy: &mut Box, + ) { + 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 { - Addr::Stream(_) | Addr::TcpListener(_) => { - 0 - } - Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => { - 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 { - 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, - } + loop { + match &indexing_lines[index] { + &IndexingLine::Indexing(IndexingInstruction::SwitchOnTerm(_, v, c, l, s)) => { + let offset = match addr { + Addr::LoadStatePayload(_) | Addr::Stream(_) | Addr::TcpListener(_) => { + IndexingCodePtr::Fail } - None => { - 0 + Addr::HeapCell(_) | Addr::StackCell(..) | Addr::AttrVar(..) => { + 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 { - 0 => self.fail = true, - o => self.p += o, - }; - } - &IndexingInstruction::SwitchOnStructure(arg, _, ref hm) => { - let a1 = self.registers[arg]; - let addr = self.store(self.deref(a1)); - - 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, - _ => 0, + match offset { + IndexingCodePtr::Fail => { + self.fail = true; + break; + } + IndexingCodePtr::External(o) => { + self.p += o; + break; + } + IndexingCodePtr::Internal(o) => { + index += o; + } + }; + } + &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 { - 0 + None => { + 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 { - 0 => self.fail = true, - o => self.p += o, - }; + self.execute_indexed_choice_instr(instrs.first().unwrap(), call_policy); + break; + } } }; } @@ -1679,23 +1685,38 @@ impl MachineState { Some((name, arity + narity - 1)) } - pub(super) fn unwind_stack(&mut self) { + pub(super) + fn unwind_stack(&mut self) { self.b = self.block; 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 fail = false; let mut iter = self.pre_order_iter(addr); + let is_composite = |addr: &Addr| { + match *addr { + Addr::Str(_) | Addr::Lis(_) | Addr::PStrLocation(..) => { + true + } + _ => { + false + } + } + }; + loop { if let Some(addr) = iter.stack().last() { - if !seen.contains(addr) { - seen.insert(*addr); - } else { - fail = true; - break; + if is_composite(addr) { + if !seen.contains(addr) { + seen.insert(*addr); + } else { + fail = true; + break; + } } } @@ -2513,7 +2534,7 @@ impl MachineState { } 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 a1 = self.store(self.deref(self[temp_v!(1)])); @@ -2531,7 +2552,7 @@ impl MachineState { name.clone(), arity, spec, - &indices.op_dir, + &op_dir, ); self.try_functor_compound_case(name, arity, spec) @@ -2545,7 +2566,7 @@ impl MachineState { clause_name!("."), 2, None, - &indices.op_dir, + &op_dir, ); self.try_functor_compound_case(clause_name!("."), 2, spec) @@ -2620,7 +2641,7 @@ impl MachineState { name, arity as usize, spec, - &indices.op_dir, + &op_dir, a1.as_var().unwrap(), ); } else { @@ -2637,10 +2658,10 @@ impl MachineState { } Addr::Char(c) => { self.try_functor_fabricate_struct( - clause_name!(c.to_string(), indices.atom_tbl), + clause_name!(c.to_string(), self.atom_tbl), arity as usize, None, - &indices.op_dir, + &op_dir, a1.as_var().unwrap(), ); } @@ -3156,16 +3177,23 @@ impl MachineState { call_policy.call_builtin( self, ct, - indices, + &indices.code_dir, + &indices.op_dir, current_input_stream, current_output_stream, ) ), &ClauseType::CallN => try_or_fail!( 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) => { self.execute_inlined(ct); @@ -3176,7 +3204,7 @@ impl MachineState { &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { try_or_fail!( 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!( @@ -3234,6 +3262,9 @@ impl MachineState { self.b0 = self.b; self.p += offset; } + &ControlInstruction::RevJmpBy(offset) => { + self.p -= offset; + } &ControlInstruction::Proceed => { self.p = CodePtr::Local(self.cp); } @@ -3272,7 +3303,7 @@ impl MachineState { } self.hb = self.heap.h(); - self.p += offset; + self.p = CodePtr::Local(dir_entry!(self.p.local().abs_loc() + offset)); } &IndexedChoiceInstruction::Retry(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, instr: &ChoiceInstruction, call_policy: &mut Box, @@ -3320,14 +3352,14 @@ impl MachineState { let mut call_policy = DefaultCallPolicy {}; try_or_fail!(self, call_policy.retry_me_else(self, offset)) } - &ChoiceInstruction::DefaultTrustMe => { + &ChoiceInstruction::DefaultTrustMe(_) => { let mut call_policy = DefaultCallPolicy {}; try_or_fail!(self, call_policy.trust_me(self)) } &ChoiceInstruction::RetryMeElse(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)) } } @@ -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(); - } } diff --git a/src/machine/mod.rs b/src/machine/mod.rs index daaf4e81..9a75837c 100644 --- a/src/machine/mod.rs +++ b/src/machine/mod.rs @@ -1,30 +1,31 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::tabled_rc::*; use crate::clause_types::*; use crate::forms::*; -use crate::heap_print::*; use crate::instructions::*; use crate::machine::heap::*; +use crate::machine::loader::*; +use crate::machine::term_stream::{LiveTermStream, LoadStatePayload, TermStream}; use crate::read::*; mod attributed_variables; pub(super) mod code_repo; pub mod code_walker; -pub mod compile; +mod compile; mod copier; -mod dynamic_database; pub mod heap; +mod load_state; +mod loader; pub mod machine_errors; pub mod machine_indices; pub(super) mod machine_state; -pub mod modules; pub mod partial_string; +mod preprocessor; mod raw_block; mod stack; pub(crate) mod streams; -pub(super) mod term_expansion; -pub mod toplevel; +mod term_stream; #[macro_use] mod arithmetic_ops; @@ -32,25 +33,21 @@ mod arithmetic_ops; mod machine_state_impl; mod system_calls; -use crate::machine::attributed_variables::*; -use crate::machine::code_repo::*; +//use crate::machine::attributed_variables::*; use crate::machine::compile::*; +use crate::machine::code_repo::*; +// use crate::machine::loader::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; -use crate::machine::modules::*; use crate::machine::streams::*; -use crate::machine::toplevel::*; use crate::indexmap::IndexMap; -use std::collections::VecDeque; -use std::convert::TryFrom; +//use std::convert::TryFrom; use std::fs::File; use std::mem; -use std::ops::Index; use std::path::PathBuf; -use std::rc::Rc; use std::sync::atomic::AtomicBool; #[derive(Debug)] @@ -80,6 +77,24 @@ impl Default for MachinePolicies { } } +#[derive(Debug)] +pub(super) struct LoadContext { + pub(super) path: PathBuf, + pub(super) stream: Stream, + pub(super) module: ClauseName, +} + +impl LoadContext { + #[inline] + fn new(path: &str, stream: Stream) -> Self { + LoadContext { + path: PathBuf::from(path), + stream, + module: clause_name!("user"), + } + } +} + #[derive(Debug)] pub struct Machine { pub(super) machine_st: MachineState, @@ -87,136 +102,23 @@ pub struct Machine { pub(super) policies: MachinePolicies, pub(super) indices: IndexStore, pub(super) code_repo: CodeRepo, - pub(super) toplevel_idx: usize, - pub(super) current_input_stream: Stream, - pub(super) current_output_stream: Stream, + pub(super) user_input: Stream, + pub(super) user_output: Stream, + pub(super) load_contexts: Vec, } -impl Index for CodeRepo { - type Output = Line; +#[inline] +fn current_dir() -> std::path::PathBuf { + let mut path_buf = std::path::PathBuf::from(file!()); - fn index(&self, ptr: LocalCodePtr) -> &Self::Output { - match ptr { - LocalCodePtr::InSituDirEntry(p) => &self.in_situ_code[p], - LocalCodePtr::TopLevel(_, p) => &self.cached_query[p], - LocalCodePtr::DirEntry(p) => &self.code[p], - LocalCodePtr::UserGoalExpansion(p) => &self.goal_expanders[p], - LocalCodePtr::UserTermExpansion(p) => &self.term_expanders[p], - } - } -} - -impl Index for Machine { - type Output = Line; - - fn index(&self, ptr: LocalCodePtr) -> &Self::Output { - &self.code_repo[ptr] - } -} - -impl SubModuleUser for IndexStore { - fn atom_tbl(&self) -> TabledData { - self.atom_tbl.clone() - } - - fn op_dir(&mut self) -> &mut OpDir { - &mut self.op_dir - } - - fn get_code_index(&self, key: PredicateKey, module_name: ClauseName) -> Option { - match module_name.as_str() { - "user" => { - self.code_dir.get(&key).cloned() - } - _ => { - 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() - }) - } - } - } - - 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) { - if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) { - if !code_idx.is_undefined() { - match (name.as_str(), arity) { - ("term_expansion", 2) => { - } - ("goal_expansion", 2) => { - } - _ => { - println!("Warning: overwriting {}/{}", &name, arity); - } - } - } - - let (p, module_name) = idx.0.borrow().clone(); - set_code_index!(code_idx, p, module_name); - return; - } - - self.code_dir.insert((name.clone(), arity), idx.clone()); - } - - fn use_qualified_module( - &mut self, - code_repo: &mut CodeRepo, - _: MachineFlags, - submodule: &Module, - exports: &Vec, - ) -> Result<(), SessionError> { - use_qualified_module(self, submodule, exports)?; - submodule - .dump_expansions(code_repo) - .map_err(SessionError::from) - } - - fn use_module( - &mut self, - code_repo: &mut CodeRepo, - _: MachineFlags, - submodule: &Module, - ) -> Result<(), SessionError> { - use_module(self, submodule)?; - - if !submodule.inserted_expansions { - submodule - .dump_expansions(code_repo) - .map_err(SessionError::from) - } else { - Ok(()) - } - } + path_buf.pop(); + path_buf } include!(concat!(env!("OUT_DIR"), "/libraries.rs")); -static TOPLEVEL: &str = include_str!("../toplevel.pl"); - impl Machine { + /* fn compile_special_forms(&mut self) { let verify_attrs_src = ListingSource::User; @@ -250,36 +152,6 @@ impl Machine { } } - fn compile_top_level(&mut self) -> Result<(), SessionError> - { - self.toplevel_idx = self.code_repo.code.len(); - - let top_lvl_src = ListingSource::User; - - compile_user_module( - self, - Stream::from(TOPLEVEL), - true, - top_lvl_src, - ); - - if let Some(module) = self.indices.take_module(clause_name!("$toplevel")) { - self.indices.use_module( - &mut self.code_repo, - self.machine_st.flags, - &module, - )?; - - Ok(self.indices.insert_module(module)) - } else { - let err = ExistenceError::ModuleSource(ModuleSource::File( - clause_name!("$toplevel"), - )); - - Err(SessionError::ExistenceError(err)) - } - } - fn compile_scryerrc(&mut self) { let mut path = match dirs_next::home_dir() { Some(path) => path, @@ -302,10 +174,10 @@ impl Machine { path.to_path_buf(), ); - compile_user_module(self, file_src, true, rc_src); + compile_user_module(self, file_src, rc_src); } } - +*/ #[cfg(test)] pub fn reset(&mut self) { self.current_input_stream = readline::input_stream(); @@ -313,17 +185,95 @@ impl Machine { self.machine_st.reset(); } - pub fn run_init_code(&mut self, code: Code) -> bool { - let old_machine_st = self.sink_to_snapshot(); - self.machine_st.reset(); + fn run_module_predicate(&mut self, module_name: ClauseName, key: PredicateKey) { + if let Some(module) = self.indices.modules.get(&module_name) { + if let Some(ref code_index) = module.code_dir.get(&key) { + let p = code_index.local().unwrap(); - self.code_repo.cached_query = code; - self.run_query(); + self.machine_st.cp = LocalCodePtr::Halt; + self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p)); - let result = self.machine_st.fail; - self.absorb_snapshot(old_machine_st); + return self.run_query(); + } + } - !result + unreachable!(); + } + + fn load_file(&mut self, path: String, stream: Stream) { + self.machine_st[temp_v!(1)] = Addr::Stream( + self.machine_st.heap.push(HeapCellValue::Stream( + stream, + )) + ); + + self.machine_st[temp_v!(2)] = Addr::Con( + self.machine_st.heap.push(HeapCellValue::Atom( + clause_name!(path, self.machine_st.atom_tbl), + None, + )) + ); + + self.run_module_predicate(clause_name!("loader"), (clause_name!("file_load"), 2)); + } + + fn load_top_level(&mut self) { + let mut path_buf = current_dir(); + path_buf.push("toplevel.pl"); + + let path = path_buf.to_str().unwrap().to_string(); + + self.load_file(path, Stream::from(include_str!("../toplevel.pl"))); + + if let Some(toplevel) = self.indices.modules.get(&clause_name!("$toplevel")) { + load_module( + &mut self.indices.code_dir, + &mut self.indices.op_dir, + &mut self.indices.meta_predicates, + &CompilationTarget::User, + toplevel, + ); + } else { + unreachable!() + } + } + + fn load_special_forms(&mut self) { + let mut path_buf = current_dir(); + path_buf.push("machine/attributed_variables.pl"); + + bootstrapping_compile( + Stream::from(include_str!("attributed_variables.pl")), + self, + ListingSource::from_file_and_path( + clause_name!("attributed_variables"), + path_buf, + ), + ).unwrap(); + + let mut path_buf = current_dir(); + path_buf.push("machine/project_attributes.pl"); + + bootstrapping_compile( + Stream::from(include_str!("project_attributes.pl")), + self, + ListingSource::from_file_and_path( + clause_name!("project_attributes"), + path_buf, + ), + ).unwrap(); + + if let Some(module) = self.indices.modules.get(&clause_name!("$atts")) { + if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) { + self.machine_st.attr_var_init.verify_attrs_loc = code_index.local().unwrap(); + } + } + + if let Some(module) = self.indices.modules.get(&clause_name!("$project_atts")) { + if let Some(code_index) = module.code_dir.get(&(clause_name!("driver"), 2)) { + self.machine_st.attr_var_init.project_attrs_loc = code_index.local().unwrap(); + } + } } pub fn run_top_level(&mut self) { @@ -336,15 +286,16 @@ impl Machine { } let list_addr = Addr::HeapCell(self.machine_st.heap.to_list(arg_pstrs.into_iter())); + self.machine_st[temp_v!(1)] = list_addr; - loop { - self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx)); - self.run_query(); - } + // WAS: + // self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("$repl"), 1)); + + self.run_module_predicate(clause_name!("$toplevel"), (clause_name!("repl"), 0)); } - pub fn new(current_input_stream: Stream, current_output_stream: Stream) -> Self + pub fn new(user_input: Stream, user_output: Stream) -> Self { use crate::ref_thread_local::RefThreadLocal; @@ -354,193 +305,118 @@ impl Machine { policies: MachinePolicies::new(), indices: IndexStore::new(), code_repo: CodeRepo::new(), - toplevel_idx: 0, - current_input_stream, - current_output_stream, + user_input, + user_output, + load_contexts: vec![], }; - let atom_tbl = wam.indices.atom_tbl.clone(); + let mut lib_path = current_dir(); - wam.indices.add_term_and_goal_expansion_indices(); + lib_path.pop(); + lib_path.push("lib"); - compile_listing( + bootstrapping_compile( + Stream::from(LIBRARIES.borrow()["ops_and_meta_predicates"]), &mut wam, + ListingSource::from_file_and_path( + clause_name!("ops_and_meta_predicates.pl"), + lib_path.clone(), + ), + ).unwrap(); + + bootstrapping_compile( Stream::from(LIBRARIES.borrow()["builtins"]), - default_index_store!(atom_tbl.clone()), - true, - ListingSource::User, - ); - - wam.compile_special_forms(); - - compile_user_module( &mut wam, - Stream::from(LIBRARIES.borrow()["error"]), - true, - ListingSource::User, - ); + ListingSource::from_file_and_path( + clause_name!("builtins.pl"), + lib_path.clone(), + ), + ).unwrap(); - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["pairs"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["lists"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["iso_ext"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["si"]), - true, - ListingSource::User, - ); - - compile_user_module( - &mut wam, - Stream::from(LIBRARIES.borrow()["charsio"]), - true, - ListingSource::User, - ); - - if wam.compile_top_level().is_err() { - panic!("Loading '$toplevel' module failed"); + if let Some(builtins) = wam.indices.modules.get(&clause_name!("builtins")) { + load_module( + &mut wam.indices.code_dir, + &mut wam.indices.op_dir, + &mut wam.indices.meta_predicates, + &CompilationTarget::User, + builtins, + ); + } else { + unreachable!() } - wam.compile_scryerrc(); + lib_path.pop(); // remove the "lib" at the end + + bootstrapping_compile( + Stream::from(include_str!("../loader.pl")), + &mut wam, + ListingSource::from_file_and_path( + clause_name!("loader.pl"), + lib_path.clone(), + ), + ).unwrap(); + + if let Some(loader) = wam.indices.modules.swap_remove(&clause_name!("loader")) { + if let Some(builtins) = wam.indices.modules.get_mut(&clause_name!("builtins")) { + // Import loader's exports into the builtins module so they will be + // implicitly included every further module. + load_module( + &mut builtins.code_dir, + &mut builtins.op_dir, + &mut builtins.meta_predicates, + &CompilationTarget::Module(clause_name!("builtins")), + &loader, + ); + + for export in &loader.module_decl.exports { + builtins.module_decl.exports.push(export.clone()); + } + } + + load_module( + &mut wam.indices.code_dir, + &mut wam.indices.op_dir, + &mut wam.indices.meta_predicates, + &CompilationTarget::User, + &loader, + ); + + wam.indices.modules.insert(clause_name!("loader"), loader); + } else { + unreachable!() + } + + wam.load_special_forms(); + wam.load_top_level(); wam.configure_streams(); wam } pub fn configure_streams(&mut self) { - self.current_input_stream.options.alias = Some(clause_name!("user_input")); + self.user_input.options.alias = Some(clause_name!("user_input")); self.indices.stream_aliases.insert( clause_name!("user_input"), - self.current_input_stream.clone(), + self.user_input.clone(), ); self.indices.streams.insert( - self.current_input_stream.clone() + self.user_input.clone() ); - self.current_output_stream.options.alias = Some(clause_name!("user_output")); + self.user_output.options.alias = Some(clause_name!("user_output")); self.indices.stream_aliases.insert( clause_name!("user_output"), - self.current_output_stream.clone(), + self.user_output.clone(), ); self.indices.streams.insert( - self.current_output_stream.clone() + self.user_output.clone() ); } - #[inline] - pub fn machine_flags(&self) -> MachineFlags { - self.machine_st.flags - } - - pub fn check_toplevel_code(&self, indices: &IndexStore) -> Result<(), SessionError> { - for (key, idx) in &indices.code_dir { - match ClauseType::from(key.0.clone(), key.1, None) { - ClauseType::Named(..) | ClauseType::Op(..) => {} - _ => { - // ensure we don't try to overwrite the name/arity of a builtin. - let err_str = format!("{}/{}", key.0, key.1); - let err_str = clause_name!(err_str, self.indices.atom_tbl()); - - return Err(SessionError::CannotOverwriteBuiltIn(err_str)); - } - }; - - if let Some(ref existing_idx) = self.indices.code_dir.get(&key) { - // ensure we don't try to overwrite an existing predicate from a different module. - if !existing_idx.is_undefined() && !idx.is_undefined() { - // allow the overwriting of user-level predicates by all other predicates. - if existing_idx.module_name().as_str() == "user" { - continue; - } - - if existing_idx.module_name() != idx.module_name() { - let err_str = format!( - "{}/{} from module {}", - key.0, - key.1, - existing_idx.module_name().as_str() - ); - let err_str = clause_name!(err_str, self.indices.atom_tbl()); - - return Err(SessionError::CannotOverwriteImport(err_str)); - } - } - } - } - - Ok(()) - } - - pub(crate) fn add_batched_code_dir(&mut self, code_dir: CodeDir) { - // error detection has finished, so update the master index of keys. - for (key, idx) in code_dir { - if let Some(ref master_idx) = self.indices.code_dir.get(&key) { - // ensure we don't double borrow if master_idx == idx. - // we don't need to modify anything in that case. - if !Rc::ptr_eq(&master_idx.0, &idx.0) { - set_code_index!(master_idx, idx.0.borrow().0, idx.module_name()); - } - - continue; - } - - self.indices.code_dir.insert(key, idx); - } - } - - #[inline] - pub(crate) fn add_batched_ops(&mut self, op_dir: OpDir) { - 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] - pub fn add_module(&mut self, module: Module) { - self.indices - .modules - .insert(module.module_decl.name.clone(), module); - } - fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) { let h = self.machine_st.heap.h(); @@ -552,307 +428,121 @@ impl Machine { return; } - fn extract_module_export_list(&mut self) -> Result, ParserError> - { - let mut export_list = self.machine_st[temp_v!(2)].clone(); - let mut exports = vec![]; - - while let Addr::Lis(l) = self.machine_st.store(self.machine_st.deref(export_list)) { - match &self.machine_st.heap[l] { - &HeapCellValue::Addr(Addr::Str(s)) => { - match &self.machine_st.heap[s] { - HeapCellValue::NamedStr(arity, ref name, _) - if *arity == 2 && name.as_str() == "/" => { - let name = match &self.machine_st.heap[s+1] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let arity = match &self.machine_st.heap[s+2] { - &HeapCellValue::Integer(ref arity) => - arity.to_usize().unwrap(), - &HeapCellValue::Addr(Addr::Fixnum(n)) => - usize::try_from(n).unwrap(), - _ => - unreachable!() - }; - - exports.push(ModuleExport::PredicateKey((name, arity))); - } - HeapCellValue::NamedStr(arity, ref name, _) - if *arity == 3 && name.as_str() == "op" => { - let name = match &self.machine_st.heap[s+3] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let spec = match &self.machine_st.heap[s+2] { - &HeapCellValue::Atom(ref name, _) => - name.clone(), - _ => - unreachable!() - }; - - let prec = match &self.machine_st.heap[s+1] { - &HeapCellValue::Integer(ref arity) => - arity.to_usize().unwrap(), - &HeapCellValue::Addr(Addr::Fixnum(n)) => - usize::try_from(n).unwrap(), - _ => - unreachable!() - }; - - exports.push(ModuleExport::OpDecl(to_op_decl( - prec, - spec.as_str(), - name, - )?)); - } - _ => unreachable!() - } - } - _ => unreachable!() - } - - export_list = self.machine_st.heap[l+1].as_addr(l+1); - } - - Ok(exports) - } - - fn use_module(&mut self, to_src: ToSource) - where ToSource: Fn(ClauseName) -> ModuleSource - { - // the term expander will overwrite the cached query, so save it here. - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - - let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = { - let addr = self.machine_st.store(self.machine_st.deref(module_spec)); - - match self.machine_st.heap.index_addr(&addr).as_ref() { - HeapCellValue::Atom(name, _) => - name.clone(), - HeapCellValue::Addr(Addr::Char(c)) => - clause_name!(c.to_string(), self.indices.atom_tbl), - HeapCellValue::Addr(addr @ Addr::PStrLocation(..)) => { - let mut heap_pstr_iter = - self.machine_st.heap_pstr_iter(*addr); - clause_name!( - heap_pstr_iter.to_string(), - self.indices.atom_tbl - ) - } - _ => unreachable!(), - } - }; - - let load_result = match to_src(name) { - ModuleSource::Library(name) => - if let Some(module) = self.indices.take_module(name.clone()) { - self.indices.remove_module(clause_name!("user"), &module); - self.indices.modules.insert(name.clone(), module); - - Ok(name) - } else { - load_library(self, name, false) - }, - ModuleSource::File(name) => - load_module_from_file(self, PathBuf::from(name.as_str()), false) - }; - - let result = load_result.and_then(|name| { - let module = self.indices.take_module(name.clone()).unwrap(); - - if !module.is_impromptu_module { - self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?; - } - - Ok(self.indices.insert_module(module)) - }); - - self.code_repo.cached_query = cached_query; - - if let Err(e) = result { - self.throw_session_error(e, (clause_name!("use_module"), 1)); - } - } - - fn use_qualified_module(&mut self, to_src: ToSource) - where ToSource: Fn(ClauseName) -> ModuleSource - { - // the term expander will overwrite the cached query, so save it here. - let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - - let module_spec = self.machine_st[temp_v!(1)].clone(); - let name = { - let addr = self.machine_st.store(self.machine_st.deref(module_spec)); - - match self.machine_st.heap.index_addr(&addr).as_ref() { - HeapCellValue::Atom(name, _) => - name.clone(), - HeapCellValue::Addr(Addr::Char(c)) => - clause_name!(c.to_string(), self.indices.atom_tbl), - _ => - unreachable!(), - } - }; - - let exports = match self.extract_module_export_list() { - Ok(exports) => exports, - Err(e) => { - self.throw_session_error(SessionError::from(e), (clause_name!("use_module"), 2)); - return; - } - }; - - let load_result = match to_src(name) { - ModuleSource::Library(name) => - if let Some(module) = self.indices.take_module(name.clone()) { - self.indices.remove_module(clause_name!("user"), &module); - self.indices.modules.insert(name.clone(), module); - - Ok(name) - } else { - load_library(self, name, false) - }, - ModuleSource::File(name) => - load_module_from_file(self, PathBuf::from(name.as_str()), false) - }; - - let result = load_result.and_then(|name| { - let module = self.indices.take_module(name.clone()).unwrap(); - - if !module.is_impromptu_module { - self.indices.use_qualified_module(&mut self.code_repo, - self.machine_st.flags, - &module, - &exports)?; - } - - Ok(self.indices.insert_module(module)) - }); - - self.code_repo.cached_query = cached_query; - - if let Err(e) = result { - self.throw_session_error(e, (clause_name!("use_module"), 2)); - } - } - fn handle_toplevel_command(&mut self, code_ptr: REPLCodePtr, p: LocalCodePtr) { match code_ptr { - REPLCodePtr::CompileBatch => { - let user_src = ListingSource::User; - - let src = readline::input_stream(); - readline::set_prompt(false); - - if let EvalSession::Error(e) = compile_user_module(self, src, false, user_src) { - self.throw_session_error(e, (clause_name!("repl"), 0)); - } + REPLCodePtr::AddDynamicPredicate => { + self.add_dynamic_predicate(); + } + REPLCodePtr::AddGoalExpansionClause => { + self.add_goal_expansion_clause(); + } + REPLCodePtr::AddTermExpansionClause => { + self.add_term_expansion_clause(); + } + REPLCodePtr::ClauseToEvacuable => { + self.clause_to_evacuable(); + } + REPLCodePtr::ConcludeLoad => { + self.conclude_load(); + } + REPLCodePtr::PopLoadContext => { + self.pop_load_context(); + } + REPLCodePtr::PushLoadContext => { + self.push_load_context(); + } + REPLCodePtr::PopLoadStatePayload => { + self.pop_load_state_payload(); + } + REPLCodePtr::UseModule => { + self.use_module(); + } + REPLCodePtr::LoadCompiledLibrary => { + self.load_compiled_library(); + } + REPLCodePtr::DeclareModule => { + self.declare_module(); + } + REPLCodePtr::PushLoadStatePayload => { + self.push_load_state_payload(); + } + REPLCodePtr::LoadContextSource => { + self.load_context_source(); + } + REPLCodePtr::LoadContextFile => { + self.load_context_file(); + } + REPLCodePtr::LoadContextDirectory => { + self.load_context_directory(); + } + REPLCodePtr::LoadContextModule => { + self.load_context_module(); + } + REPLCodePtr::LoadContextStream => { + self.load_context_stream(); + } + REPLCodePtr::MetaPredicateProperty => { + self.meta_predicate_property(); + } + REPLCodePtr::BuiltInProperty => { + self.builtin_property(); + } + REPLCodePtr::CompilePendingPredicates => { + self.compile_pending_predicates(); + } + REPLCodePtr::UserAssertz => { + self.compile_user_assert(AppendOrPrepend::Append); + } + REPLCodePtr::UserAsserta => { + self.compile_user_assert(AppendOrPrepend::Prepend); + } + REPLCodePtr::UserRetract => { + self.retract_user_clause(); } - REPLCodePtr::UseModule => - self.use_module(ModuleSource::Library), - REPLCodePtr::UseModuleFromFile => - self.use_module(ModuleSource::File), - REPLCodePtr::UseQualifiedModule => - self.use_qualified_module(ModuleSource::Library), - REPLCodePtr::UseQualifiedModuleFromFile => - self.use_qualified_module(ModuleSource::File) } self.machine_st.p = CodePtr::Local(p); } - fn sink_to_snapshot(&mut self) -> MachineState { - let mut snapshot = MachineState::with_small_heap(); - - snapshot.hb = self.machine_st.hb; - snapshot.e = self.machine_st.e; - snapshot.b = self.machine_st.b; - snapshot.b0 = self.machine_st.b0; - snapshot.s = self.machine_st.s.clone(); - snapshot.tr = self.machine_st.tr; - snapshot.num_of_args = self.machine_st.num_of_args; - - snapshot.fail = self.machine_st.fail; - snapshot.trail = mem::replace(&mut self.machine_st.trail, vec![]); - snapshot.heap = self.machine_st.heap.take(); - snapshot.mode = self.machine_st.mode; - snapshot.stack = self.machine_st.stack.take(); - snapshot.registers = mem::replace(&mut self.machine_st.registers, vec![]); - snapshot.block = self.machine_st.block; - - snapshot.ball = self.machine_st.ball.take(); - snapshot.lifted_heap = self.machine_st.lifted_heap.take(); - - snapshot - } - - fn absorb_snapshot(&mut self, mut snapshot: MachineState) { - self.machine_st.hb = snapshot.hb; - self.machine_st.e = snapshot.e; - self.machine_st.b = snapshot.b; - self.machine_st.b0 = snapshot.b0; - self.machine_st.s = snapshot.s; - self.machine_st.tr = snapshot.tr; - self.machine_st.num_of_args = snapshot.num_of_args; - - self.machine_st.fail = snapshot.fail; - self.machine_st.trail = mem::replace(&mut snapshot.trail, vec![]); - - self.inner_heap = self.machine_st.heap.take(); - self.inner_heap.truncate(0); - - self.machine_st.heap = snapshot.heap.take(); - self.machine_st.mode = snapshot.mode; - self.machine_st.stack = snapshot.stack; - self.machine_st.registers = mem::replace(&mut snapshot.registers, vec![]); - self.machine_st.block = snapshot.block; - - self.machine_st.ball = snapshot.ball.take(); - self.machine_st.lifted_heap = snapshot.lifted_heap.take(); - } - - pub(super) fn run_query(&mut self) { - self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query()); - let end_ptr = CodePtr::Local(self.machine_st.cp); - - while self.machine_st.p < end_ptr { + pub(super) + fn run_query(&mut self) { + while !self.machine_st.p.is_halt() { self.machine_st.query_stepper( &mut self.indices, &mut self.policies, &mut self.code_repo, - &mut self.current_input_stream, - &mut self.current_output_stream, + &mut self.user_input, + &mut self.user_output, ); match self.machine_st.p { - CodePtr::Local(LocalCodePtr::TopLevel(_, p)) if p > 0 => { - } CodePtr::REPL(code_ptr, p) => { - self.handle_toplevel_command(code_ptr, p) + self.handle_toplevel_command(code_ptr, p); + + if self.machine_st.fail { + self.machine_st.backtrack(); + } } - CodePtr::DynamicTransaction(trans_type, p) => { + /* + CodePtr::DynamicTransaction(_trans_type, _p) => { // self.code_repo.cached_query is about to be overwritten by the term expander, // so hold onto it locally and restore it after the compiler has finished. self.machine_st.fail = false; + /* let cached_query = mem::replace(&mut self.code_repo.cached_query, vec![]); - self.dynamic_transaction(trans_type, p); + // self.dynamic_transaction(trans_type, p); self.code_repo.cached_query = cached_query; if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p { break; } + */ + } + */ + _ => { + break; } - _ => - break }; } } @@ -865,8 +555,8 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) { match instr { &Line::Arithmetic(ref arith_instr) => { @@ -884,8 +574,8 @@ impl MachineState { code_repo, &mut policies.call_policy, &mut policies.cut_policy, - current_input_stream, - current_output_stream, + user_input, + user_output, control_instr, ) } @@ -893,8 +583,8 @@ impl MachineState { self.execute_fact_instr(&fact_instr); self.p += 1; } - &Line::Indexing(ref indexing_instr) => { - self.execute_indexing_instr(&indexing_instr) + &Line::IndexingCode(ref indexing_lines) => { + self.execute_indexing_instr(indexing_lines, &mut policies.call_policy) } &Line::IndexedChoice(ref choice_instr) => { self.execute_indexed_choice_instr(choice_instr, &mut policies.call_policy) @@ -911,8 +601,8 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) { let instr = match code_repo.lookup_instr(self.last_call, &self.p) { Some(instr) => instr, @@ -924,40 +614,40 @@ impl MachineState { indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ); } fn backtrack(&mut self) { - if self.b > 0 { - let b = self.b; + // if self.b > 0 { + let b = self.b; - self.b0 = self.stack.index_or_frame(b).prelude.b0; - self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); + self.b0 = self.stack.index_or_frame(b).prelude.b0; + self.p = CodePtr::Local(self.stack.index_or_frame(b).prelude.bp); - if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p { - self.fail = p == 0; - } else { - self.fail = false; - } + /* + if let CodePtr::Local(LocalCodePtr::TopLevel(_, p)) = self.p { + self.fail = p == 0; } else { + */ + self.fail = false; + // } + /*} else { self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0)); - } + }*/ } fn check_machine_index(&mut self, code_repo: &CodeRepo) -> bool { match self.p { - CodePtr::Local(LocalCodePtr::DirEntry(p)) if p < code_repo.code.len() => {} - CodePtr::Local(LocalCodePtr::UserTermExpansion(p)) - if p < code_repo.term_expanders.len() => {} - CodePtr::Local(LocalCodePtr::UserTermExpansion(_)) => self.fail = true, - CodePtr::Local(LocalCodePtr::UserGoalExpansion(p)) - if p < code_repo.goal_expanders.len() => {} - CodePtr::Local(LocalCodePtr::UserGoalExpansion(_)) => self.fail = true, - CodePtr::Local(LocalCodePtr::InSituDirEntry(p)) if p < code_repo.in_situ_code.len() => { + CodePtr::Local(LocalCodePtr::DirEntry(p)) | + CodePtr::Local(LocalCodePtr::IndexingBuf(p, ..)) + if p < code_repo.code.len() => { + } + CodePtr::Local(LocalCodePtr::Halt) | CodePtr::REPL(..) => { + return false; } - CodePtr::Local(_) | CodePtr::REPL(..) => return false, + /* CodePtr::DynamicTransaction(..) => { // prevent use of dynamic transactions from // succeeding in expansions. self.fail will be toggled @@ -965,7 +655,9 @@ impl MachineState { self.fail = true; return false; } - _ => {} + */ + _ => { + } } true @@ -977,8 +669,8 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &mut CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) -> bool { loop { let instr = match code_repo.lookup_instr(self.last_call, &self.p) { @@ -999,8 +691,8 @@ impl MachineState { indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ); if self.fail { @@ -1025,16 +717,16 @@ impl MachineState { indices: &mut IndexStore, policies: &mut MachinePolicies, code_repo: &mut CodeRepo, - current_input_stream: &mut Stream, - current_output_stream: &mut Stream, + user_input: &mut Stream, + user_output: &mut Stream, ) { loop { self.execute_instr( indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ); if self.fail { @@ -1055,8 +747,8 @@ impl MachineState { indices, policies, code_repo, - current_input_stream, - current_output_stream, + user_input, + user_output, ) { if self.fail { break; diff --git a/src/machine/modules.rs b/src/machine/modules.rs deleted file mode 100644 index 42576032..00000000 --- a/src/machine/modules.rs +++ /dev/null @@ -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, - 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, - ) { - 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, - ) { - 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)> - { - 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; - fn op_dir(&mut self) -> &mut OpDir; - fn remove_code_index(&mut self, _: PredicateKey); - fn get_code_index(&self, _: PredicateKey, _: ClauseName) -> Option; - - fn insert_dir_entry(&mut self, _: ClauseName, _: usize, _: CodeIndex); - - fn get_op_module_name(&mut self, name: ClauseName, fixity: Fixity) -> Option { - 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, - ) -> Result<(), SessionError>; - - fn use_module( - &mut self, - _: &mut CodeRepo, - _: MachineFlags, - _: &Module - ) -> Result<(), SessionError>; -} - -pub fn use_qualified_module( - user: &mut User, - submodule: &Module, - exports: &Vec, -) -> 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: &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 { - self.atom_tbl.clone() - } - - fn op_dir(&mut self) -> &mut OpDir { - &mut self.op_dir - } - - fn get_code_index(&self, key: PredicateKey, _: ClauseName) -> Option { - 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, - ) -> 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(()) - } -} diff --git a/src/machine/partial_string.rs b/src/machine/partial_string.rs index 1413b37c..7d865d49 100644 --- a/src/machine/partial_string.rs +++ b/src/machine/partial_string.rs @@ -1,12 +1,18 @@ +use crate::machine::*; +use crate::machine::machine_indices::*; + use core::marker::PhantomData; use std::alloc; +use std::cmp::Ordering; use std::mem; use std::ptr; use std::ops::RangeFrom; use std::slice; use std::str; +use indexmap::IndexSet; + #[derive(Debug)] pub struct PartialString { buf: *const u8, @@ -200,3 +206,290 @@ impl PartialString { } } } + +#[derive(Debug)] +pub(crate) struct HeapPStrIter<'a> { + focus: Addr, + machine_st: &'a MachineState, + seen: IndexSet, +} + +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 { + 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 { + 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 { + 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) +} diff --git a/src/machine/preprocessor.rs b/src/machine/preprocessor.rs new file mode 100644 index 00000000..a6e3f1e3 --- /dev/null +++ b/src/machine/preprocessor.rs @@ -0,0 +1,989 @@ +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::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(terms: I, mut term: Term, sym: ClauseName) -> Term +where + I: DoubleEndedIterator, +{ + 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 { + 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>, + atom_tbl: TabledData, +) -> Result { + 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 +{ + 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 +{ + 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, +) -> Result { + 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, +) -> Result, 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>, + atom_tbl: TabledData, +) -> Result { + 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>) -> Result { + 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>) -> Result { + 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); + +fn setup_qualified_import( + mut terms: Vec>, + atom_tbl: TabledData, +) -> Result { + 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>, + load_state: &LoadState<'a>, +) -> Result<(ClauseName, ClauseName, Vec), CompilationError> +{ + fn get_name_and_meta_specs( + name: ClauseName, + terms: &mut [Box], + ) -> Result<(ClauseName, Vec), 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::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) -> Result +{ + 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, 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) -> 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) { + 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>, +) -> Result { + 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>, + fixity: Option, +) -> 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>, + fixity: Option, +) -> 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>, +} + +impl Preprocessor { + pub(super) + fn new(flags: MachineFlags) -> Self { + Preprocessor { + flags, + queue: VecDeque::new(), + } + } + + fn setup_fact(&mut self, term: Term) -> Result { + match term { + Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => { + Ok(term) + } + _ => { + Err(CompilationError::InadmissibleFact) + } + } + } + + fn compute_head(&self, term: &Term) -> Vec { + 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, 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) { + // 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) { + 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) { + 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 { + 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::Constant(_, Constant::Char('!')) => { + Ok(QueryTerm::BlockedCut) + } + 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 { + 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>, + cut_context: CutContext, + ) -> Result, 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>, + cut_context: CutContext, + ) -> Result { + 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>, + cut_context: CutContext, + ) -> Result { + 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 { + 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>( + &mut self, + load_state: &mut LoadState<'a>, + terms: I, + cut_context: CutContext, + ) -> Result, 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, 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) + } +} diff --git a/src/machine/project_attributes.pl b/src/machine/project_attributes.pl index 0d7a82d0..cee4f1ce 100644 --- a/src/machine/project_attributes.pl +++ b/src/machine/project_attributes.pl @@ -1,11 +1,11 @@ :- module('$project_atts', [copy_term/3]). -'$attribute_goals_driver'(QueryVars, AttrVars) :- - gather_modules(AttrVars, Modules0, _), +driver(QueryVars, AttrVars) :- + gather_attr_modules(AttrVars, Modules0), sort(Modules0, Modules), call_project_attributes(Modules, QueryVars, AttrVars), - call_attribute_goals(Modules, call_query_var_goals, QueryVars), - call_attribute_goals(Modules, call_attr_var_goals, AttrVars). + call_attribute_goals(Modules, '$project_atts':call_query_var_goals, QueryVars), + call_attribute_goals(Modules, '$project_atts':call_attr_var_goals, AttrVars). enqueue_goals(Goals0) :- nonvar(Goals0), @@ -36,7 +36,7 @@ call_project_attributes([Module|Modules], QueryVars, AttrVars) :- call_project_attributes(Modules, QueryVars, AttrVars). call_attribute_goals([], _, _). -call_attribute_goals([Module | Modules], GoalCaller, AttrVars) :- +call_attribute_goals([Module|Modules], GoalCaller, AttrVars) :- call(GoalCaller, AttrVars, Module, Goals), enqueue_goals(Goals), 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([AttrVar|AttrVars], Module, Goals) :- - ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0) - , atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) - ), - E, - ( '$print_attribute_goals_exception'(Module, E), - atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals) - )) + ( catch(( Module:attribute_goals(AttrVar, Goals, RGoals0), + atts:'$default_attr_list'(Module, AttrVar, RGoals0, RGoals) + ), + E, + ( '$project_atts':'$print_attribute_goals_exception'(Module, E), + atts:'$default_attr_list'(Module, AttrVar, Goals, RGoals) + )) -> true ; 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([AttrVar|AttrVars], Module, Goals) :- ( catch(Module:attribute_goals(AttrVar, Goals, RGoals), - E, - '$print_attribute_goals_exception'(Module, E) - ) + E, + '$project_atts':'$print_attribute_goals_exception'(Module, E) + ) -> true ; true ), 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([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), 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) :- - '$term_attributed_variables'(Source, Vars), - gather_modules(Vars, Modules0, _), + '$term_attributed_variables'(Source, AttrVars), + gather_attr_modules(AttrVars, Modules0), 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), !, '$copy_term_without_attr_vars'([Source | Goals1], [Dest | Goals]). diff --git a/src/machine/stack.rs b/src/machine/stack.rs index 4bd3802b..ab7d48e2 100644 --- a/src/machine/stack.rs +++ b/src/machine/stack.rs @@ -246,10 +246,6 @@ impl Stack { } } - pub fn take(&mut self) -> Self { - Stack { buf: self.buf.take(), _marker: PhantomData } - } - #[inline] pub fn truncate(&mut self, b: usize) { if b == 0 { diff --git a/src/machine/streams.rs b/src/machine/streams.rs index 1375cb65..21040c60 100644 --- a/src/machine/streams.rs +++ b/src/machine/streams.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::read::PrologStream; use crate::read::readline::*; @@ -179,10 +179,10 @@ impl Drop for StreamInstance { fn drop(&mut self) { match self { 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) => { - discard_result!(tls_stream.shutdown()); + tls_stream.shutdown().unwrap(); } _ => { } diff --git a/src/machine/system_calls.rs b/src/machine/system_calls.rs index da31e966..2ed49409 100644 --- a/src/machine/system_calls.rs +++ b/src/machine/system_calls.rs @@ -1,19 +1,21 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::parser::*; -use crate::prolog_parser::tabled_rc::*; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::parser::*; +use crate::prolog_parser_rebis::tabled_rc::*; use crate::clause_types::*; use crate::forms::*; use crate::heap_print::*; use crate::instructions::*; +use crate::machine; use crate::machine::code_repo::CodeRepo; use crate::machine::copier::*; use crate::machine::code_walker::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; use crate::machine::machine_state::*; +use crate::machine::preprocessor::to_op_decl; use crate::machine::streams::*; -use crate::machine::toplevel::to_op_decl; + use crate::ordered_float::OrderedFloat; use crate::read::readline; use crate::rug::Integer; @@ -402,9 +404,7 @@ impl MachineState { } } - let mode = - atom_from!(self, indices, self.store(self.deref(self[temp_v!(2)]))); - + let mode = atom_from!(self, self.store(self.deref(self[temp_v!(2)]))); let mut open_options = fs::OpenOptions::new(); let (is_input_file, in_append_mode) = @@ -560,7 +560,7 @@ impl MachineState { let spec = get_clause_spec( name.clone(), *arity, - composite_op!(&indices.op_dir), + &CompositeOpDir::new(&indices.op_dir, None), ); let addr = self.heap.to_unifiable(HeapCellValue::DBRef( @@ -681,11 +681,11 @@ impl MachineState { let mut parser = Parser::new( &mut stream, - indices.atom_tbl.clone(), + self.atom_tbl.clone(), self.machine_flags(), ); - match parser.read_term(composite_op!(&indices.op_dir)) { + match parser.read_term(&CompositeOpDir::new(&indices.op_dir, None)) { Err(err) => { let h = self.heap.h(); let err = MachineError::syntax_error(h, err); @@ -792,6 +792,7 @@ impl MachineState { current_output_stream: &mut Stream, ) -> CallResult { match ct { + /* &SystemClauseType::AbolishClause => { let p = self.cp; let trans_type = DynamicTransactionType::Abolish; @@ -806,6 +807,7 @@ impl MachineState { self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } + */ &SystemClauseType::BindFromRegister => { let reg = self.store(self.deref(self[temp_v!(2)])); let n = @@ -833,6 +835,7 @@ impl MachineState { self.fail = true; } + /* &SystemClauseType::AssertDynamicPredicateToFront => { let p = self.cp; let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Front); @@ -841,19 +844,21 @@ impl MachineState { return Ok(()); } &SystemClauseType::AssertDynamicPredicateToBack => { - let p = self.cp; - let trans_type = DynamicTransactionType::Assert(DynamicAssertPlace::Back); + // let p = self.cp; + // 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(()); } + */ &SystemClauseType::CurrentHostname => { match hostname::get().ok() { Some(host) => { match host.into_string().ok() { Some(host) => { 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); @@ -1016,6 +1021,7 @@ impl MachineState { return Err(err); } }; + let chars = self.heap.put_complete_string(current); self.unify(self[temp_v!(1)], chars); @@ -1092,11 +1098,13 @@ impl MachineState { return Ok(()); } } + /* &SystemClauseType::AtEndOfExpansion => { if self.cp == LocalCodePtr::TopLevel(0, 0) { self.at_end_of_expansion = true; } } + */ &SystemClauseType::AtomChars => { let a1 = self[temp_v!(1)]; @@ -1139,7 +1147,7 @@ impl MachineState { if &string == "[]" { self.unify(addr, Addr::EmptyList); } else { - let chars = clause_name!(string, indices.atom_tbl); + let chars = clause_name!(string, self.atom_tbl); let atom = self.heap.to_unifiable( HeapCellValue::Atom(chars, None) ); @@ -1254,7 +1262,7 @@ impl MachineState { } 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); @@ -1281,7 +1289,7 @@ impl MachineState { clause_name!("[]") } Addr::Char(c) => { - clause_name!(c.to_string(), indices.atom_tbl) + clause_name!(c.to_string(), self.atom_tbl) } _ => { unreachable!() @@ -1858,6 +1866,7 @@ impl MachineState { } } } + /* &SystemClauseType::ModuleAssertDynamicPredicateToFront => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleAssert(DynamicAssertPlace::Front); @@ -1872,6 +1881,7 @@ impl MachineState { self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } + */ &SystemClauseType::LiftedHeapLength => { let a1 = self[temp_v!(1)]; let lh_len = Addr::Usize(self.lifted_heap.h()); @@ -2854,6 +2864,7 @@ impl MachineState { self.unify(Addr::Char(c), a1); } +/* &SystemClauseType::GetModuleClause => { let module = self[temp_v!(3)]; let head = self[temp_v!(1)]; @@ -2944,20 +2955,24 @@ impl MachineState { _ => unreachable!(), }; } +*/ &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] { - &HeapCellValue::NamedStr(arity, ref name, ..) => indices - .get_clause_subsection(name.owning_module(), name.clone(), arity) - .is_some(), + &HeapCellValue::NamedStr(arity, ref name, ..) => + indices.is_dynamic_predicate(module_name, (name.clone(), arity)), _ => unreachable!(), }, Addr::Con(h) if self.heap.atom_at(h) => { - if let HeapCellValue::Atom(name, _) = &self.heap[h] { - indices.get_clause_subsection(name.owning_module(), name.clone(), 0) - .is_some() + if let HeapCellValue::Atom(name, _) = &self.heap[h] { + indices.is_dynamic_predicate(module_name, (name.clone(), 0)) } else { unreachable!() } @@ -3111,21 +3126,27 @@ impl MachineState { return self.module_lookup( indices, + call_policy, (name, arity + narity), module_name, true, + current_input_stream, + current_output_stream, ); } else { unreachable!() } } 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( indices, + call_policy, (name.clone(), narity), module_name, true, + current_input_stream, + current_output_stream, ); } else { unreachable!() @@ -3160,6 +3181,7 @@ impl MachineState { } } } + /* &SystemClauseType::ExpandGoal => { self.p = CodePtr::Local(LocalCodePtr::UserGoalExpansion(0)); return Ok(()); @@ -3168,6 +3190,7 @@ impl MachineState { self.p = CodePtr::Local(LocalCodePtr::UserTermExpansion(0)); return Ok(()); } + */ &SystemClauseType::GetNextDBRef => { let a1 = self[temp_v!(1)]; @@ -3185,7 +3208,7 @@ impl MachineState { let spec = get_clause_spec( name.clone(), *arity, - composite_op!(&indices.op_dir), + &CompositeOpDir::new(&indices.op_dir, None), ); let db_ref = DBRef::NamedPred(name.clone(), *arity, spec); @@ -3429,7 +3452,7 @@ impl MachineState { let op = match self.store(self.deref(op)) { 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) => if let HeapCellValue::Atom(ref name, _) = &self.heap[h] { name.clone() @@ -3440,16 +3463,18 @@ impl MachineState { unreachable!(), }; - let module = op.owning_module(); - let result = to_op_decl(priority, specifier.as_str(), op) .map_err(SessionError::from) - .and_then(|op_decl| { - if op_decl.0 == 0 { + .and_then(|mut op_decl| { + if op_decl.prec == 0 { Ok(op_decl.remove(&mut indices.op_dir)) } else { - let spec = get_desc(op_decl.name(), composite_op!(&indices.op_dir)); - op_decl.submit(module, spec, &mut indices.op_dir) + let spec = get_op_desc( + 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 = self.heap_pstr_iter(Addr::PStrLocation(h, n)); - let file_spec = + let file_spec = clause_name!( heap_pstr_iter.to_string(), - indices.atom_tbl.clone() + self.atom_tbl ); 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 => { - 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] { &HeapCellValue::NamedStr(arity, ref name, ref spec) => { - let module = name.owning_module(); - indices.predicate_exists(name.clone(), module, arity, spec.clone()) + indices.get_predicate_code_index( + name.clone(), + arity, + module_name, + spec.clone(), + ).is_some() } _ => { unreachable!() @@ -3967,14 +3945,14 @@ impl MachineState { }, Addr::Con(h) if self.heap.atom_at(h) => { if let &HeapCellValue::Atom(ref name, ref spec) = &self.heap[h] { - let module = name.owning_module(); let spec = fetch_atom_op_spec( name.clone(), spec.clone(), &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 { unreachable!() } @@ -4116,6 +4094,7 @@ impl MachineState { &SystemClauseType::REPL(repl_code_ptr) => { return self.repl_redirect(repl_code_ptr); } + /* &SystemClauseType::ModuleRetractClause => { let p = self.cp; let trans_type = DynamicTransactionType::ModuleRetract; @@ -4130,6 +4109,7 @@ impl MachineState { self.p = CodePtr::DynamicTransaction(trans_type, p); return Ok(()); } + */ &SystemClauseType::ReturnFromVerifyAttr => { let e = self.e; let frame_len = self.stack.index_and_frame(e).prelude.univ_prelude.num_cells; @@ -4326,6 +4306,7 @@ impl MachineState { self.unify(a1, a2); } +/* &SystemClauseType::GetClause => { let head = self[temp_v!(1)]; @@ -4343,14 +4324,14 @@ impl MachineState { } }, 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( name.owning_module(), name.clone(), 0, ) } else { - unreachable!() + unreachable!() } } _ => { @@ -4372,6 +4353,7 @@ impl MachineState { } } } +*/ &SystemClauseType::GetCutPoint => { let a1 = self[temp_v!(1)]; let a2 = Addr::CutPoint(self.b0); @@ -4524,7 +4506,7 @@ impl MachineState { let term_write_result = match self.read( Stream::from(chars), - indices.atom_tbl.clone(), + self.atom_tbl.clone(), &indices.op_dir, ) { Ok(term_write_result) => { @@ -4595,10 +4577,11 @@ impl MachineState { let mut rand = RANDOM_STATE.borrow_mut(); rand.seed(&seed); } - &SystemClauseType::SkipMaxList => + &SystemClauseType::SkipMaxList => { if let Err(err) = self.skip_max_list() { return Err(err); - }, + } + } &SystemClauseType::Sleep => { let time = self.store(self.deref(self[temp_v!(1)])); @@ -4695,11 +4678,10 @@ impl MachineState { let stream = match TcpStream::connect(&socket_addr).map_err(|e| e.kind()) { 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 tls = match self.store(self.deref(self[temp_v!(8)])) { + let mut stream = { + let tls = match self.store(self.deref(self[temp_v!(8)])) { Addr::Con(h) if self.heap.atom_at(h) => { if let HeapCellValue::Atom(ref atom, _) = &self.heap[h] { atom.as_str() @@ -4711,6 +4693,7 @@ impl MachineState { unreachable!() } }; + match tls { "false" => { Stream::from_tcp_stream(socket_addr, tcp_stream) } "true" => { let connector = TlsConnector::new().unwrap(); @@ -4724,6 +4707,7 @@ impl MachineState { _ => { unreachable!() } } }; + stream.options = options; if let Some(ref alias) = &stream.options.alias { @@ -4877,7 +4861,7 @@ impl MachineState { match tcp_listener.accept().ok() { Some((tcp_stream, socket_addr)) => { let client = - clause_name!(format!("{}", socket_addr), indices.atom_tbl); + clause_name!(format!("{}", socket_addr), self.atom_tbl); let mut tcp_stream = Stream::from_tcp_stream(client.clone(), tcp_stream); @@ -5226,8 +5210,13 @@ impl MachineState { self.fail = self.structural_eq_test(); } &SystemClauseType::WAMInstructions => { - let name = self[temp_v!(1)]; - let arity = self[temp_v!(2)]; + let module_name = atom_from!( + 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)) { Addr::Con(h) if self.heap.atom_at(h) => { @@ -5257,51 +5246,84 @@ impl MachineState { } }; - let first_idx = match indices - .code_dir - .get(&(name.clone(), arity.to_usize().unwrap())) - { - Some(ref idx) if idx.local().is_some() => { - if let Some(idx) = idx.local() { - idx - } else { - unreachable!() + let key = (name.clone(), arity.to_usize().unwrap()); + + let first_idx = match module_name.as_str() { + "user" => indices.code_dir.get(&key), + _ => match indices.modules.get(&module_name) { + Some(module) => module.code_dir.get(&key), + None => { + let stub = MachineError::functor_stub(key.0, key.1); + 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 functors = vec![]; + let mut functor_list = vec![]; walk_code( &code_repo.code, first_idx, |instr| { - let section = instr.to_functor(h); - functors.push(Addr::HeapCell(h)); + let old_len = functors.len(); + instr.enqueue_functors(h, &mut functors); + let new_len = functors.len(); - h += section.len(); - self.heap.extend(section.into_iter()); + for index in old_len .. new_len { + functor_list.push(Addr::HeapCell(h)); + h += functors[index].len(); + } }, ); - let listing = Addr::HeapCell(self.heap.to_list(functors.into_iter())); - let listing_var = self[temp_v!(3)]; + for functor in functors { + 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); } @@ -5831,6 +5853,53 @@ impl MachineState { 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) @@ -5905,7 +5974,7 @@ impl MachineState { } else { let mut avec = Vec::new(); 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( HeapCellValue::Atom(chars, None) ); @@ -5926,7 +5995,7 @@ impl MachineState { } 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( HeapCellValue::Atom(chars, None) ); @@ -5955,7 +6024,7 @@ impl MachineState { Some(name) => { let mut avec = Vec::new(); 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( HeapCellValue::Atom(chars, None) ); @@ -5976,7 +6045,7 @@ impl MachineState { } 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( HeapCellValue::Atom(chars, None) ); diff --git a/src/machine/term_expansion.rs b/src/machine/term_expansion.rs deleted file mode 100644 index 6ee8f8d3..00000000 --- a/src/machine/term_expansion.rs +++ /dev/null @@ -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(terms: I, mut term: Term, sym: ClauseName) -> Term -where - I: DoubleEndedIterator, -{ - 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, - tail: Box, -) -> Result>, 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, - 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), - goal_expansion_additions: (Predicate, VecDeque), -} - -impl ExpansionAdditionResult { - pub fn take_term_expansions(&mut self) -> (Predicate, VecDeque) { - 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) { - 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, - atom_tbl: TabledData, - 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) { - self.parser.set_atom_tbl(atom_tbl); - } - - #[inline] - pub fn eof(&mut self) -> Result { - 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 { - 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 { - 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 { - 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 { - 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, - ) -> Result, 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 { - 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()) - } - } -} diff --git a/src/machine/term_stream.rs b/src/machine/term_stream.rs new file mode 100644 index 00000000..e408a6f1 --- /dev/null +++ b/src/machine/term_stream.rs @@ -0,0 +1,149 @@ +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::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; + fn eof(&mut self) -> Result; + fn listing_src(&self) -> &ListingSource; + fn evacuate<'a>(loader: Loader<'a, Self>) -> Result; +} + +#[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, + 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 { + self.parser.reset(); + self.parser.read_term(op_dir) + .map_err(CompilationError::from) + } + + #[inline] + fn eof(&mut self) -> Result { + 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) -> Result { + 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, + 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, + pub(super) preprocessor: Preprocessor, + pub(super) predicates: Vec, + 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 { + Ok(self.term_queue.pop_front().unwrap()) + } + + #[inline] + fn eof(&mut self) -> Result { + return Ok(self.term_queue.is_empty()); + } + + #[inline] + fn listing_src(&self) -> &ListingSource { + &self.listing_src + } + + #[inline] + fn evacuate(loader: Loader) -> Result { + Ok(loader.to_load_state_payload()) + } +} diff --git a/src/machine/toplevel.rs b/src/machine/toplevel.rs deleted file mode 100644 index eaa17691..00000000 --- a/src/machine/toplevel.rs +++ /dev/null @@ -1,1352 +0,0 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::tabled_rc::*; - -use crate::forms::*; -use crate::iterators::*; -use crate::machine::machine_errors::*; -use crate::machine::machine_indices::*; -use crate::machine::term_expansion::*; -use crate::machine::*; - -use crate::indexmap::{IndexMap, IndexSet}; - -use std::borrow::BorrowMut; -use std::cell::Cell; -use std::collections::VecDeque; -use std::convert::TryFrom; -use std::fmt; -use std::mem; -use std::ops::DerefMut; -use std::rc::Rc; - -enum IndexSource<'a, T> { - TermStream, - Local(&'a mut T) -} - -impl<'a, T: fmt::Debug> fmt::Debug for IndexSource<'a, T> { - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - match self { - IndexSource::TermStream => write!(fmt, "TermStream"), - IndexSource::Local(ref local) => write!(fmt, "Local({:?})", local), - } - } -} - -fn op_dir<'a, 'b: 'a>(from: &'b IndexSource<'a, IndexStore>) -> RefOrOwned<'a, OpDir> { - match from { - IndexSource::TermStream => RefOrOwned::Owned(OpDir::new()), - IndexSource::Local(ref indices) => RefOrOwned::Borrowed(&indices.op_dir) - } -} - -#[derive(Debug)] -struct CompositeIndices<'a, 'b, 'c> { - term_stream: &'b mut TermStream<'a>, - index_src: IndexSource<'c, IndexStore>, - static_code_dir: Option> -} - -impl<'a, 'b, 'c> CompositeIndices<'a, 'b, 'c> { - fn new( - term_stream: &'b mut TermStream<'a>, - index_src: IndexSource<'c, IndexStore>, - static_code_dir: Option>, - ) -> Self { - CompositeIndices { - term_stream, - index_src, - static_code_dir, - } - } - - fn atom_tbl(&self) -> TabledData { - match self.index_src { - IndexSource::TermStream => self.term_stream.wam.indices.atom_tbl.clone(), - IndexSource::Local(ref indices) => indices.atom_tbl.clone(), - } - } - - fn local_code_dir(&mut self) -> &mut CodeDir { - match self.index_src { - IndexSource::TermStream => &mut self.term_stream.wam.indices.code_dir, - IndexSource::Local(ref mut indices) => &mut indices.code_dir, - } - } - - fn static_code_dir(&self) -> Option<&CodeDir> { - match self.static_code_dir { - Some(IndexSource::TermStream) => Some(&self.term_stream.wam.indices.code_dir), - Some(IndexSource::Local(ref code_dir)) => Some(code_dir), - None => None - } - } - - fn get_code_index(&mut self, name: ClauseName, arity: usize) -> CodeIndex { - let idx_opt = self.local_code_dir().get(&(name.clone(), arity)); - let idx_opt = match idx_opt { - Some(idx) => Some(idx.clone()), - None => match self.static_code_dir() { - Some(ref code_dir) => code_dir.get(&(name.clone(), arity)).cloned(), - _ => None, - } - }; - - if let Some(idx) = idx_opt { - self.local_code_dir().insert((name.clone(), arity), idx.clone()); - idx - } else { - let idx = CodeIndex::default(); - self.local_code_dir().insert((name.clone(), arity), idx.clone()); - idx - } - } - - fn get_clause_type( - &mut self, - name: ClauseName, - arity: usize, - spec: Option, - ) -> ClauseType { - match ClauseType::from(name, arity, spec) { - ClauseType::Named(name, arity, _) => { - let idx = self.get_code_index(name.clone(), arity); - ClauseType::Named(name, arity, idx.clone()) - } - ClauseType::Op(name, spec, _) => { - let idx = self.get_code_index(name.clone(), arity); - ClauseType::Op(name, spec, idx.clone()) - } - 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( - name: &str, - arity: usize, - terms: &Vec>, -) -> Option { - match (name, arity) { - ("term_expansion", 2) => Some(CompileTimeHook::TermExpansion), - ("goal_expansion", 2) => Some(CompileTimeHook::GoalExpansion), - (":", 2) => { - if let &Term::Constant(_, Constant::Atom(ref name, _)) = &terms[0].as_ref() { - if name.as_str() == "user" { - if let &Term::Clause(_, ref name, ref terms, _) = &terms[1].as_ref() { - return match name.as_str() { - "term_expansion" if terms.len() == 2 => { - Some(CompileTimeHook::UserTermExpansion) - } - "goal_expansion" if terms.len() == 2 => { - Some(CompileTimeHook::UserGoalExpansion) - } - _ => None, - }; - } - } - } - - None - } - _ => None, - } -} - -#[inline] -fn is_compile_time_hook(name: &ClauseName, terms: &Vec>) -> Option { - if name.as_str() == ":-" { - if let Some(ref term) = terms.first() { - if let &Term::Clause(_, ref name, ref terms, _) = term.as_ref() { - return as_compile_time_hook(name.as_str(), terms.len(), terms); - } - } - } - - as_compile_time_hook(name.as_str(), terms.len(), terms) -} - -type CompileTimeHookCompileInfo = (CompileTimeHook, PredicateClause, VecDeque); - -pub fn to_op_decl(prec: usize, spec: &str, name: ClauseName) -> Result { - match spec { - "xfx" => Ok(OpDecl(prec, XFX, name)), - "xfy" => Ok(OpDecl(prec, XFY, name)), - "yfx" => Ok(OpDecl(prec, YFX, name)), - "fx" => Ok(OpDecl(prec, FX, name)), - "fy" => Ok(OpDecl(prec, FY, name)), - "xf" => Ok(OpDecl(prec, XF, name)), - "yf" => Ok(OpDecl(prec, YF, name)), - _ => Err(ParserError::InconsistentEntry), - } -} - -fn setup_op_decl( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - let name = match *terms.pop().unwrap() { - Term::Constant(_, Constant::Atom(name, _)) => name, - Term::Constant(_, Constant::Char(c)) => clause_name!(c.to_string(), atom_tbl.clone()), - _ => return Err(ParserError::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.clone()), - _ => return Err(ParserError::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(ParserError::InconsistentEntry), - }, - _ => return Err(ParserError::InconsistentEntry), - }; - - to_op_decl(prec, spec.as_str(), name) -} - -fn setup_predicate_indicator(term: &mut Term) -> Result -{ - 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(ParserError::InvalidModuleExport)?; - - let name = name - .to_constant() - .and_then(|c| c.to_atom()) - .ok_or(ParserError::InvalidModuleExport)?; - - if slash.as_str() == "/" { - Ok((name, arity)) - } else { - Ok((name, arity + 2)) - } - } - _ => Err(ParserError::InvalidModuleExport), - } -} - -fn setup_scoped_predicate_indicator(term: &mut Term) -> Result -{ - 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( - mut term: Term, - atom_tbl: TabledData, -) -> Result { - 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(ParserError::InvalidModuleDecl) - } - } else { - Err(ParserError::InvalidModuleDecl) - } - }) -} - -fn setup_module_decl( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - let mut export_list = *terms.pop().unwrap(); - let name = terms - .pop() - .unwrap() - .to_constant() - .and_then(|c| c.to_atom()) - .ok_or(ParserError::InvalidModuleDecl)?; - - 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(ParserError::InvalidModuleDecl) - } else { - Ok(ModuleDecl { name, exports }) - } -} - -fn read_library_path( - term: Term, - atom_tbl: TabledData, -) -> Option { - match term { - Term::Constant(_, Constant::Atom(atom, _)) => { - Some(atom.defrock_brackets()) - } - _ => { - let mut atoms = vec![]; - - for term in unfold_by_str(term, "/") { - match term { - Term::Constant(_, Constant::Atom(atom, _)) => { - atoms.push(atom.as_str().to_owned()); - } - _ => return None, - } - } - - Some(clause_name!(atoms.join("/"), atom_tbl)) - } - } -} - -fn setup_use_module_decl(mut terms: Vec>, atom_tbl: TabledData) -> Result { - match *terms.pop().unwrap() { - Term::Clause(_, ref name, ref mut terms, None) - if name.as_str() == "library" && terms.len() == 1 => - { - read_library_path(*terms.pop().unwrap(), atom_tbl) - .map(|c| ModuleSource::Library(c)) - .ok_or(ParserError::InvalidUseModuleDecl) - } - Term::Constant(_, Constant::Atom(ref name, _)) => - Ok(ModuleSource::File(name.clone())), - _ => Err(ParserError::InvalidUseModuleDecl), - } -} - -fn setup_double_quotes(mut terms: Vec>) -> Result { - 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(ParserError::InvalidDoubleQuotesDecl), - } - } - _ => { - Err(ParserError::InvalidDoubleQuotesDecl) - } - } - }, - _ => { - Err(ParserError::InvalidDoubleQuotesDecl) - } - } -} - -type UseModuleExport = (ModuleSource, Vec); - -fn setup_qualified_import( - mut terms: Vec>, - atom_tbl: TabledData, -) -> Result { - 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 => - { - read_library_path(*terms.pop().unwrap(), atom_tbl.clone()) - .map(|c| ModuleSource::Library(c)) - .ok_or(ParserError::InvalidUseModuleDecl) - } - Term::Constant(_, Constant::Atom(ref name, _)) => Ok(ModuleSource::File(name.clone())), - _ => Err(ParserError::InvalidUseModuleDecl), - }?; - - let mut exports = vec![]; - - while let Term::Cons(_, t1, t2) = export_list { - exports.push(setup_module_export(*t1, atom_tbl.clone())?); - export_list = *t2; - } - - if export_list.to_constant() != Some(Constant::EmptyList) { - Err(ParserError::InvalidModuleDecl) - } else { - Ok((module_src, exports)) - } -} - -fn merge_clauses(tls: &mut VecDeque) -> Result -{ - let mut clauses: Vec = 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(ParserError::InconsistentEntry), - TopLevel::Fact(..) => { - if let TopLevel::Fact(fact, line_num, col_num) = tl { - let clause = PredicateClause::Fact(fact, line_num, col_num); - clauses.push(clause); - } - } - TopLevel::Rule(..) => { - if let TopLevel::Rule(rule, line_num, col_num) = tl { - let clause = PredicateClause::Rule(rule, line_num, col_num); - clauses.push(clause); - } - } - TopLevel::Predicate(..) => { - if let TopLevel::Predicate(predicate) = tl { - clauses.extend(predicate.clauses().into_iter()) - } - } - _ => { - tls.push_front(tl); - break; - } - } - } - - if clauses.is_empty() { - Err(ParserError::InconsistentEntry) - } else { - Ok(TopLevel::Predicate(Predicate(clauses))) - } -} - -fn mark_cut_variables_as(terms: &mut Vec, 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) -> 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) { - 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 flatten_hook(mut term: Term) -> Term { - if let Term::Clause(_, ref mut name, ref mut terms, _) = &mut term { - match (name.as_str(), terms.len()) { - (":-", 2) => { - let inner_term = match terms.first_mut().map(|term| term.borrow_mut()) { - Some(&mut Term::Clause(_, ref name, ref mut inner_terms, _)) => { - if name.as_str() == ":" && inner_terms.len() == 2 { - Some(*inner_terms.pop().unwrap()) - } else { - None - } - } - _ => None, - }; - - if let Some(inner_term) = inner_term { - mem::swap(&mut terms[0], &mut Box::new(inner_term)); - } - } - (":", 2) => return *terms.pop().unwrap(), - _ => {} - } - } - - term -} - -fn draw_from_term_dir_impl( - term_dir: &TermDir, - term_dirs: &mut TermDirQuantum, - key: &PredicateKey, - preds: &mut Vec, - queue: &mut VecDeque -) { - 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( - indices: &CompositeIndices, - intra_module_term_dirs: &mut IndexMap, - top_level_term_dirs: &mut TermDirQuantum, - key: &PredicateKey, - preds: &mut Vec, - queue: &mut VecDeque, -) { - 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>( - indices: &mut CompositeIndices<'a, 'b, 'c>, - flags: MachineFlags, - mut terms: Vec>, - line_num: usize, - col_num: usize, -) -> Result { - let term = *terms.pop().unwrap(); - - 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)) - } - ("initialization", 1) => { - let mut rel_worker = RelationWorker::new(flags, line_num, col_num); - let (query_terms, _) = rel_worker.setup_query(indices, terms, false, false)?; - let queue = rel_worker.parse_queue(indices)?; - - Ok(Declaration::ModuleInitialization(query_terms, queue)) - } - ("module", 2) => - Ok(Declaration::Module(setup_module_decl(terms, indices.atom_tbl())?)), - ("op", 3) => - Ok(Declaration::Op(setup_op_decl(terms, indices.atom_tbl())?)), - ("non_counted_backtracking", 1) => { - let (name, arity) = setup_predicate_indicator(&mut *terms.pop().unwrap())?; - Ok(Declaration::NonCountedBacktracking(name, arity)) - } - ("set_prolog_flag", 2) => { - Ok(Declaration::SetPrologFlag(setup_double_quotes(terms)?)) - } - ("multifile", 1) => { - let mut term = *terms.pop().unwrap(); - - 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) => { - Ok(Declaration::UseModule(setup_use_module_decl(terms, indices.atom_tbl())?)) - } - ("use_module", 2) => { - let (name, exports) = setup_qualified_import(terms, indices.atom_tbl())?; - Ok(Declaration::UseQualifiedModule(name, exports)) - } - _ => { - Err(ParserError::InconsistentEntry) - } - }, - _ => { - Err(ParserError::InconsistentEntry) - } - } -} - -#[derive(Debug)] -struct RelationWorker { - flags: MachineFlags, - dynamic_clauses: Vec<(Term, Term)>, // Head, Body. - queue: VecDeque>, - line_num: usize, - col_num: usize -} - -impl RelationWorker { - fn new(flags: MachineFlags, line_num: usize, col_num: usize) -> Self { - RelationWorker { - dynamic_clauses: vec![], - flags, - queue: VecDeque::new(), - line_num, - col_num - } - } - - fn setup_fact(&mut self, term: Term, assume_dyn: bool) -> Result { - match term { - Term::Clause(..) | Term::Constant(_, Constant::Atom(..)) => { - let tail = - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)); - - if assume_dyn { - self.dynamic_clauses.push((term.clone(), tail)); - } - - Ok(term) - } - _ => Err(ParserError::InadmissibleFact), - } - } - - fn compute_head(&self, term: &Term) -> Vec { - 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, 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) { - // 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) { - 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) { - 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, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - ) -> Result { - match term { - Term::Constant(_, Constant::Atom(name, fixity)) => { - if name.as_str() == "!" || name.as_str() == "blocked_!" { - Ok(QueryTerm::BlockedCut) - } else { - let ct = indices.get_clause_type(name, 0, fixity); - Ok(QueryTerm::Clause(Cell::default(), ct, vec![], false)) - } - } - 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(ParserError::InadmissibleQueryTerm) - } - } - _ => { - let ct = indices.get_clause_type(name, terms.len(), fixity); - Ok(QueryTerm::Clause(Cell::default(), ct, terms, false)) - } - } - Term::Var(..) => Ok(QueryTerm::Clause( - Cell::default(), - ClauseType::CallN, - vec![Box::new(term)], - false, - )), - _ => Err(ParserError::InadmissibleQueryTerm), - } - } - - fn pre_query_term<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - ) -> Result { - match term { - Term::Clause(r, name, mut subterms, fixity) => { - if subterms.len() == 1 && name.as_str() == "$call_with_default_policy" { - self.to_query_term(indices, *subterms.pop().unwrap()) - .map(|mut query_term| { - query_term.set_default_caller(); - query_term - }) - } else { - self.to_query_term(indices, Term::Clause(r, name, subterms, fixity)) - } - } - _ => self.to_query_term(indices, term), - } - } - - fn setup_query<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - terms: Vec>, - blocks_cuts: bool, - assume_dyn: bool, - ) -> Result<(Vec, Term), ParserError> { - let mut query_terms = vec![]; - let mut work_queue = VecDeque::from(terms); - let mut machine_st = MachineState::new(); - - let mut dynamic_clause_terms = vec![]; - - while let Some(term) = work_queue.pop_front() { - let term = *term; - let op_dir = op_dir(&indices.index_src); - - let mut expanded_terms = indices.term_stream.expand_goals( - &mut machine_st, - op_dir.as_ref(), - VecDeque::from(vec![term]) - )?; - - while let Some(term) = expanded_terms.pop() { - work_queue.push_front(Box::new(term)); - } - - if 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 !blocks_cuts { - mark_cut_variable(&mut term); - } - - if assume_dyn { - dynamic_clause_terms.push(term.clone()); - } - - query_terms.push(self.pre_query_term(indices, term)?); - } - } - - let dynamic_clause_body = - if let Some(term) = dynamic_clause_terms.pop() { - fold_by_str(dynamic_clause_terms.into_iter(), term, clause_name!(",")) - } else { - Term::Constant(Cell::default(), Constant::Atom(clause_name!("true"), None)) - }; - - Ok((query_terms, dynamic_clause_body)) - } - - fn setup_hook<'a, 'b, 'c>( - &mut self, - hook: CompileTimeHook, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - ) -> Result { - match flatten_hook(term) { - Term::Clause(r, name, terms, _) => { - if name == hook.name() && terms.len() == hook.arity() { - let term = self.setup_fact(Term::Clause(r, name, terms, None), false)?; - Ok((hook, PredicateClause::Fact(term, 0, 0), VecDeque::from(vec![]))) - } else if name.as_str() == ":-" && terms.len() == 2 { - let rule = self.setup_rule(indices, terms, true, false)?; - let results_queue = self.parse_queue(indices)?; - - Ok((hook, PredicateClause::Rule(rule, 0, 0), results_queue)) - } else { - Err(ParserError::InvalidHook) - } - } - _ => Err(ParserError::InvalidHook), - } - } - - fn setup_rule<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - mut terms: Vec>, - blocks_cuts: bool, - assume_dyn: bool, - ) -> Result { - let dynamic_term_head = *terms.first().cloned().unwrap(); - let post_head_terms: Vec<_> = terms.drain(1 ..).collect(); - - let (mut query_terms, dynamic_term_body) = - self.setup_query(indices, post_head_terms, blocks_cuts, assume_dyn)?; - - if assume_dyn { - self.dynamic_clauses.push((dynamic_term_head, dynamic_term_body)); - } - - 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(ParserError::InvalidRuleHead), - } - } - - fn try_term_to_query<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - terms: Vec>, - blocks_cuts: bool, - ) -> Result { - let (result, _) = self.setup_query( - indices, - terms, - blocks_cuts, - false, - )?; - - Ok(TopLevel::Query(result)) - } - - fn compact_module_scoped_head<'a, 'b, 'c>( - &self, - term: &mut Term, - indices: &mut CompositeIndices<'a, 'b, 'c>, - ) { - 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>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - term: Term, - blocks_cuts: bool, - ) -> Result { - match term { - Term::Clause(r, name, mut terms, fixity) => { - if let Some(hook) = is_compile_time_hook(&name, &terms) { - let term = Term::Clause(r, name, terms, fixity); - let (hook, clause, queue) = self.setup_hook(hook, indices, term)?; - - Ok(TopLevel::Declaration(Declaration::Hook( - hook, clause, queue, - ))) - } else if name.as_str() == "?-" { - self.try_term_to_query(indices, terms, blocks_cuts) - } else if name.as_str() == ":-" && terms.len() == 2 { - self.compact_module_scoped_head(&mut terms[0], indices); - - Ok(TopLevel::Rule(self.setup_rule( - indices, - terms, - blocks_cuts, - true, - )?, self.line_num, self.col_num)) - } else if name.as_str() == ":-" && terms.len() == 1 { - Ok(TopLevel::Declaration(setup_declaration(indices, self.flags, terms, - self.line_num, self.col_num)?)) - } else { - 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)) - } - } - term => { - Ok(TopLevel::Fact(self.setup_fact(term, true)?, self.line_num, self.col_num)) - } - } - } - - fn try_terms_to_tls<'a, 'b, 'c, I>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - terms: I, - blocks_cuts: bool, - ) -> Result, ParserError> - where - I: IntoIterator - { - let mut results = VecDeque::new(); - - for term in terms.into_iter() { - results.push_back(self.try_term_to_tl(indices, term, blocks_cuts)?); - } - - Ok(results) - } - - fn parse_queue<'a, 'b, 'c>( - &mut self, - indices: &mut CompositeIndices<'a, 'b, 'c>, - ) -> Result, ParserError> { - let mut queue = VecDeque::new(); - - while let Some(terms) = self.queue.pop_front() { - let clauses = merge_clauses(&mut self.try_terms_to_tls(indices, terms, false)?)?; - queue.push_back(clauses); - } - - Ok(queue) - } - - fn absorb(&mut self, other: RelationWorker) { - self.queue.extend(other.queue.into_iter()); - self.dynamic_clauses.extend(other.dynamic_clauses.into_iter()); - } -} - -pub type DynamicClause = Vec<(Term, Term)>; - -pub type DynamicClauseMap = IndexMap<(ClauseName, usize), DynamicClause>; - -#[derive(Debug)] -pub struct TopLevelBatchWorker<'a> { - pub(crate) term_stream: TermStream<'a>, - rel_worker: RelationWorker, - pub(crate) results: Vec<(Predicate, VecDeque)>, - pub(crate) dynamic_clause_map: DynamicClauseMap, - pub(crate) in_module: bool, - pub(crate) term_dirs: TermDirQuantum, - pub(crate) intra_module_term_dirs: IndexMap, - pub(crate) non_counted_bt_preds: IndexSet, -} - -impl<'a> TopLevelBatchWorker<'a> { - pub fn new( - stream: &'a mut ParsingStream, - atom_tbl: TabledData, - flags: MachineFlags, - wam: &'a mut Machine, - ) -> Self { - let term_stream = TermStream::new(stream, atom_tbl, flags, wam); - - let line_num = term_stream.line_num(); - let col_num = term_stream.col_num(); - - TopLevelBatchWorker { - term_stream, - rel_worker: RelationWorker::new(flags, line_num, col_num), - results: vec![], - dynamic_clause_map: IndexMap::new(), - in_module: false, - term_dirs: TermDirQuantum::new(), - intra_module_term_dirs: IndexMap::new(), - non_counted_bt_preds: IndexSet::new(), - } - } - - fn try_term_to_tl( - &mut self, - indices: &mut IndexStore, - term: Term, - ) -> Result<(TopLevel, RelationWorker), SessionError> { - let line_num = self.term_stream.line_num(); - let col_num = self.term_stream.col_num(); - - let mut new_rel_worker = RelationWorker::new(self.rel_worker.flags, line_num, col_num); - let mut indices = CompositeIndices::new( - &mut self.term_stream, - IndexSource::Local(indices), - if self.in_module { None } else { Some(IndexSource::TermStream) } - ); - - Ok(( - new_rel_worker.try_term_to_tl(&mut indices, term, true)?, - new_rel_worker, - )) - } - - fn process_result( - &mut self, - indices: &mut IndexStore, - preds: &mut Vec, - ) -> Result<(), SessionError> { - let mut indices = CompositeIndices::new( - &mut self.term_stream, - IndexSource::Local(indices), - if self.in_module { None } else { Some(IndexSource::TermStream) }, - ); - - let key = (preds[0].name().unwrap(), preds[0].arity()); - - let mut preds = mem::replace(preds, vec![]); - let mut 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, - ); - - let result = (Predicate(preds), queue); - - indices.term_stream.wam.code_repo.add_in_situ_result( - &result, - &mut indices.term_stream.wam.indices.in_situ_code_dir, - &mut indices.term_stream.wam.indices.in_situ_module_dir, - &self.non_counted_bt_preds, - )?; - - Ok(self.results.push(result)) - } - - fn take_dynamic_clauses(&mut self) { - let (name, arity) = match self.rel_worker.dynamic_clauses.first() { - Some((head, _)) => (head.name().unwrap(), head.arity()), - None => return, - }; - - match self.dynamic_clause_map.get_mut(&(name.clone(), arity)) { - Some(ref mut entry) => { - entry.clear(); // don't treat dynamic predicates as if they're discontiguous. - entry.extend(self.rel_worker.dynamic_clauses.drain(0 ..)); - } - _ => { - self.rel_worker.dynamic_clauses.clear(); - } - } - } - - pub fn consume( - &mut self, - indices: &mut IndexStore, - ) -> Result, SessionError> { - let mut preds = vec![]; - - while !self.term_stream.eof()? { - let term = self.term_stream.read_term(&indices.op_dir)?; - - // if is_consistent is false, preds is non-empty. - let term = if !term.is_consistent(&preds) { - self.process_result(indices, &mut preds)?; - 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)?; - - if tl.is_end_of_file_atom() { - tl = TopLevel::Declaration(Declaration::EndOfFile); - } - - self.rel_worker.absorb(new_rel_worker); - - match tl { - TopLevel::Fact(fact, line_num, col_num) => - preds.push(PredicateClause::Fact(fact, line_num, col_num)), - TopLevel::Rule(rule, line_num, col_num) => - preds.push(PredicateClause::Rule(rule, line_num, col_num)), - TopLevel::Predicate(pred) => - preds.extend(pred.0), - TopLevel::Declaration(decl) => - return Ok(Some(decl)), - TopLevel::Query(_) => - return Err(SessionError::QueryCannotBeDefinedAsFact), - } - } - - if !preds.is_empty() { - self.process_result(indices, &mut preds)?; - self.take_dynamic_clauses(); - } - - Ok(None) - } -} diff --git a/src/macros.rs b/src/macros.rs index 7de7da2f..aa043327 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -68,10 +68,18 @@ macro_rules! functor { }); ($name:expr, [$($dt:ident($($value:expr),*)),+]) => ({ { - let arity = count_tt!($($dt) +); + use crate::machine::heap::*; - vec![ HeapCellValue::NamedStr(arity, clause_name!($name), None), - $(functor_term!( $dt($($value),*), arity, [], addendum ),)+ ] + let arity = count_tt!($($dt) +); + #[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) => ( @@ -112,13 +120,28 @@ macro_rules! functor_term { (number($e:expr), $arity:expr, $aux_lens:expr, $addendum:ident) => ( $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))) ); - (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) ); - (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) ); (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 { ($lco:expr, $machine_st:expr) => {{ 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 { - ($atom_tbl:expr, $code_dir:expr, $op_dir:expr, $modules:expr) => { + ($code_dir:expr, $op_dir:expr, $modules:expr) => { IndexStore { - atom_tbl: $atom_tbl, code_dir: $code_dir, - module_dir: ModuleDir::new(), - dynamic_code_dir: DynamicCodeDir::new(), + extensible_predicates: ExtensiblePredicates::new(), global_variables: GlobalVarDir::new(), - in_situ_code_dir: InSituCodeDir::new(), - in_situ_module_dir: ModuleStubDir::new(), - op_dir: $op_dir, + meta_predicates: MetaPredicateDir::new(), modules: $modules, - stream_aliases: StreamAliasDir::new(), + op_dir: $op_dir, 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 { ($lvl:expr, $cons:expr, $r:expr) => { QueryInstruction::PutConstant($lvl, $cons, $r) @@ -387,6 +384,7 @@ macro_rules! get_level_and_unify { }; } +/* macro_rules! unwind_protect { ($e: expr, $protected: expr) => { match $e { @@ -398,7 +396,8 @@ macro_rules! unwind_protect { } }; } - +*/ +/* macro_rules! discard_result { ($f: expr) => { match $f { @@ -406,7 +405,7 @@ macro_rules! discard_result { } }; } - +*/ macro_rules! ar_reg { ($r: expr) => { ArithmeticTerm::Reg($r) @@ -414,7 +413,7 @@ macro_rules! ar_reg { } macro_rules! atom_from { - ($self:expr, $indices:expr, $e:expr) => { + ($self:expr, $e:expr) => { match $e { Addr::Con(h) if $self.heap.atom_at(h) => { match &$self.heap[h] { @@ -427,7 +426,7 @@ macro_rules! atom_from { } } Addr::Char(c) => { - clause_name!(c.to_string(), $indices.atom_tbl.clone()) + clause_name!(c.to_string(), $self.atom_tbl) } _ => { 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; + } + } + }}; +} diff --git a/src/main.rs b/src/main.rs index 89168bf9..07684b61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ extern crate nix; extern crate openssl; extern crate ordered_float; #[macro_use] -extern crate prolog_parser; +extern crate prolog_parser_rebis; #[macro_use] extern crate ref_thread_local; extern crate ring; @@ -35,6 +35,7 @@ use crate::nix::sys::signal; mod macros; mod allocator; mod arithmetic; +mod machine; mod codegen; mod clause_types; mod debray_allocator; @@ -45,7 +46,6 @@ mod heap_print; mod indexing; mod instructions; mod iterators; -mod machine; mod read; mod targets; mod write; diff --git a/src/read.rs b/src/read.rs index 5e972a08..ba975201 100644 --- a/src/read.rs +++ b/src/read.rs @@ -1,6 +1,6 @@ -use crate::prolog_parser::ast::*; -use crate::prolog_parser::parser::*; -use crate::prolog_parser::tabled_rc::TabledData; +use crate::prolog_parser_rebis::ast::*; +use crate::prolog_parser_rebis::parser::*; +use crate::prolog_parser_rebis::tabled_rc::TabledData; use crate::forms::*; use crate::iterators::*; @@ -195,7 +195,7 @@ impl MachineState { let term = { 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 diff --git a/src/targets.rs b/src/targets.rs index 643ea1d5..a75d3f79 100644 --- a/src/targets.rs +++ b/src/targets.rs @@ -1,4 +1,4 @@ -use crate::prolog_parser::ast::*; +use crate::prolog_parser_rebis::ast::*; use crate::clause_types::*; use crate::forms::*; diff --git a/src/toplevel.pl b/src/toplevel.pl index bbada3a2..9513b671 100644 --- a/src/toplevel.pl +++ b/src/toplevel.pl @@ -1,10 +1,18 @@ -:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2, - argv/1]). +:- module('$toplevel', [argv/1, + copy_term/3, + predicate_property/2, + prolog_load_context/2]). + +:- use_module(library(loader)). :- use_module(library(charsio)). +:- use_module(library(iso_ext)). :- use_module(library(lists)). :- use_module(library(si)). +:- use_module(library('$project_atts')). +:- use_module(library('$atts')). + :- dynamic(argv/1). '$repl'([_|Args0]) :- @@ -109,9 +117,6 @@ read_and_match :- instruction_match(Term, VarList). -% make compile_batch, a system routine, callable. -compile_batch :- '$compile_batch'. - instruction_match(Term, VarList) :- ( var(Term) -> throw(error(instantiation_error, repl/0)) @@ -119,38 +124,43 @@ instruction_match(Term, VarList) :- !, ( atom(Item) -> ( Item == user -> - catch(compile_batch, E, print_exception_with_check(E)) - ; consult(Item) + catch(load(user_input), E, print_exception_with_check(E)) + ; + consult(Item) ) ; - catch(throw(error(type_error(atom, Item), repl/0)), + catch(type_error(atom, Item, repl/0), E, print_exception_with_check(E)) ) ; Term = end_of_file -> 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 -get_b_value(B) :- '$get_b_value'(B). -clear_attribute_goals :- '$clear_attribute_goals'. +submit_query_and_print_results_(Term, VarList) :- + '$get_b_value'(B), + 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) :- - ( expand_goals(Term0, Term) -> true - ; Term0 = Term - ), + expand_goal(call(Term0), user, Term), + !, setup_call_cleanup(bb_put('$first_answer', true), - ( get_b_value(B), call(Term), write_eqs_and_read_input(B, VarList), - ! - ; % 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_(Term, VarList), bb_put('$first_answer', false)). + needs_bracketing(Value, Op) :- catch((functor(Value, F, _), current_op(EqPrec, EqSpec, Op), @@ -254,12 +264,12 @@ write_eqs_and_read_input(B, VarList) :- ( B0 == B -> ( Goals == [] -> write('true.'), nl - ; thread_goals(Goals, ThreadedGoals, (',')), + ; loader:thread_goals(Goals, ThreadedGoals, (',')), write_eq(ThreadedGoals, NewVarList0, 20), write('.'), nl ) - ; thread_goals(Goals, ThreadedGoals, (',')), + ; loader:thread_goals(Goals, ThreadedGoals, (',')), write_eq(ThreadedGoals, NewVarList0, 20), read_input(ThreadedGoals, NewVarList0) ). @@ -353,133 +363,3 @@ print_exception_with_check(E) :- % is expected to be printed instead. ; 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 - ). diff --git a/src/write.rs b/src/write.rs index cf40509d..bbb28e30 100644 --- a/src/write.rs +++ b/src/write.rs @@ -1,5 +1,6 @@ use crate::clause_types::*; use crate::forms::*; +use crate::indexing::IndexingCodePtr; use crate::instructions::*; use crate::machine::machine_errors::*; use crate::machine::machine_indices::*; @@ -10,14 +11,8 @@ impl fmt::Display for LocalCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { LocalCodePtr::DirEntry(p) => write!(f, "LocalCodePtr::DirEntry({})", p), - LocalCodePtr::InSituDirEntry(p) => write!(f, "LocalCodePtr::InSituDirEntry({})", p), - LocalCodePtr::TopLevel(cn, p) => write!(f, "LocalCodePtr::TopLevel({}, {})", cn, p), - LocalCodePtr::UserGoalExpansion(p) => { - write!(f, "LocalCodePtr::UserGoalExpansion({})", p) - } - LocalCodePtr::UserTermExpansion(p) => { - write!(f, "LocalCodePtr::UserTermExpansion({})", p) - } + LocalCodePtr::Halt => write!(f, "LocalCodePtr::Halt"), + LocalCodePtr::IndexingBuf(p, o, i) => write!(f, "LocalCodePtr::IndexingBuf({}, {}, {})", p, o, i), } } } @@ -25,16 +20,52 @@ impl fmt::Display for LocalCodePtr { impl fmt::Display for REPLCodePtr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - REPLCodePtr::CompileBatch => - write!(f, "REPLCodePtr::CompileBatch"), + REPLCodePtr::AddDynamicPredicate => + write!(f, "REPLCodePtr::AddDynamicPredicate"), + REPLCodePtr::AddGoalExpansionClause => + write!(f, "REPLCodePtr::AddGoalExpansionClause"), + REPLCodePtr::AddTermExpansionClause => + write!(f, "REPLCodePtr::AddTermExpansionClause"), + REPLCodePtr::BuiltInProperty => + write!(f, "REPLCodePtr::BuiltInProperty"), + 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 => write!(f, "REPLCodePtr::UseModule"), - REPLCodePtr::UseQualifiedModule => - write!(f, "REPLCodePtr::UseQualifiedModule"), - REPLCodePtr::UseModuleFromFile => - write!(f, "REPLCodePtr::UseModuleFromFile"), - REPLCodePtr::UseQualifiedModuleFromFile => - write!(f, "REPLCodePtr::UseQualifiedModuleFromFile") + REPLCodePtr::MetaPredicateProperty => + write!(f, "REPLCodePtr::MetaPredicateProperty"), + REPLCodePtr::CompilePendingPredicates => + write!(f, "REPLCodePtr::CompilePendingPredicates"), } } } @@ -45,9 +76,6 @@ impl fmt::Display for IndexPtr { &IndexPtr::DynamicUndefined => write!(f, "undefined"), &IndexPtr::Undefined => write!(f, "undefined"), &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 +96,27 @@ impl fmt::Display for FactInstruction { &FactInstruction::GetStructure(ref ct, ref arity, ref 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) => { write!(f, "fact:get_variable {}, A{}", x, a) } &FactInstruction::UnifyConstant(ref constant) => { write!(f, "unify_constant {}", constant) } - &FactInstruction::UnifyVariable(ref r) => write!(f, "unify_variable {}", r), - &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), + &FactInstruction::UnifyVariable(ref r) => { + write!(f, "unify_variable {}", r) + } + &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 +179,16 @@ impl fmt::Display for CompareTermQT { impl fmt::Display for ClauseType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &ClauseType::System(SystemClauseType::SetCutPoint(r)) => write!(f, "$set_cp({})", r), - &ClauseType::Named(ref name, _, ref idx) | &ClauseType::Op(ref name, _, ref idx) => { - let idx = idx.0.borrow(); - write!(f, "{}:{}/{}", idx.1, name, idx.0) + &ClauseType::System(SystemClauseType::SetCutPoint(r)) => { + write!(f, "$set_cp({})", r) + } + &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 +200,7 @@ impl fmt::Display for HeapCellValue { &HeapCellValue::Atom(ref atom, _) => write!(f, "{}", atom.as_str()), &HeapCellValue::DBRef(ref db_ref) => write!(f, "{}", db_ref), &HeapCellValue::Integer(ref n) => write!(f, "{}", n), + &HeapCellValue::LoadStatePayload(_) => write!(f, "LoadStatePayload"), &HeapCellValue::Rational(ref n) => write!(f, "{}", n), &HeapCellValue::NamedStr(arity, ref name, Some(ref cell)) => write!( f, @@ -209,6 +252,7 @@ impl fmt::Display for Addr { &Addr::CutPoint(cp) => write!(f, "Addr::CutPoint({})", cp), &Addr::Con(ref c) => write!(f, "Addr::Con({})", c), &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::HeapCell(h) => write!(f, "Addr::HeapCell({})", h), &Addr::StackCell(fr, sc) => write!(f, "Addr::StackCell({}, {})", fr, sc), @@ -244,6 +288,9 @@ impl fmt::Display for ControlInstruction { &ControlInstruction::JmpBy(arity, offset, pvs, true) => { write!(f, "jmp_by_execute {}/{}, {}", offset, arity, pvs) } + &ControlInstruction::RevJmpBy(offset) => { + write!(f, "rev_jmp_by {}", offset) + } &ControlInstruction::Proceed => write!(f, "proceed"), } } @@ -262,13 +309,33 @@ impl fmt::Display for IndexedChoiceInstruction { impl fmt::Display for ChoiceInstruction { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - &ChoiceInstruction::TryMeElse(offset) => write!(f, "try_me_else {}", offset), + &ChoiceInstruction::TryMeElse(offset) => + write!(f, "try_me_else {}", offset), &ChoiceInstruction::DefaultRetryMeElse(offset) => { write!(f, "retry_me_else_by_default {}", offset) } - &ChoiceInstruction::RetryMeElse(offset) => write!(f, "retry_me_else {}", offset), - &ChoiceInstruction::DefaultTrustMe => write!(f, "trust_me_by_default"), - &ChoiceInstruction::TrustMe => write!(f, "trust_me"), + &ChoiceInstruction::RetryMeElse(offset) => + write!(f, "retry_me_else {}", offset), + &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 +346,11 @@ impl fmt::Display for IndexingInstruction { &IndexingInstruction::SwitchOnTerm(a, v, c, l, s) => { write!(f, "switch_on_term {}, {}, {}, {}, {}", a, v, c, l, s) } - &IndexingInstruction::SwitchOnConstant(_, num_cs, _) => { - write!(f, "switch_on_constant {}", num_cs) + &IndexingInstruction::SwitchOnConstant(ref constants) => { + write!(f, "switch_on_constant {}", constants.len()) } - &IndexingInstruction::SwitchOnStructure(_, num_ss, _) => { - write!(f, "switch_on_structure {}", num_ss) + &IndexingInstruction::SwitchOnStructure(ref structures) => { + write!(f, "switch_on_structure {}", structures.len()) } } } @@ -295,36 +362,40 @@ impl fmt::Display for SessionError { &SessionError::ExistenceError(ref err) => { write!(f, "{}", err) } - &SessionError::CannotOverwriteBuiltIn(ref msg) => { - write!(f, "cannot overwrite {}", msg) - } - &SessionError::CannotOverwriteImport(ref msg) => { - write!(f, "cannot overwrite import {}", msg) - } - &SessionError::InvalidFileName(ref filename) => { - write!(f, "filename {} is invalid", filename) - } - &SessionError::ModuleDoesNotContainExport(ref module, ref key) => { - write!( - f, - "module {} does not contain claimed export {}/{}", - module, - key.0, - key.1, - ) - } + // &SessionError::CannotOverwriteBuiltIn(ref msg) => { + // write!(f, "cannot overwrite {}", msg) + // } + // &SessionError::CannotOverwriteImport(ref msg) => { + // write!(f, "cannot overwrite import {}", msg) + // } + // &SessionError::InvalidFileName(ref filename) => { + // write!(f, "filename {} is invalid", filename) + // } + // &SessionError::ModuleDoesNotContainExport(ref module, ref key) => { + // write!( + // f, + // "module {} does not contain claimed export {}/{}", + // module, + // key.0, + // key.1, + // ) + // } &SessionError::OpIsInfixAndPostFix(_) => { write!(f, "cannot define an op to be both postfix and infix.") } &SessionError::NamelessEntry => { write!(f, "the predicate head is not an atom or clause.") } - &SessionError::ParserError(ref e) => { - write!(f, "syntax_error({})", e.as_str()) + &SessionError::CompilationError(ref e) => { + write!(f, "syntax_error({:?})", e) } &SessionError::QueryCannotBeDefinedAsFact => { 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 +435,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 { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { @@ -372,7 +460,13 @@ impl fmt::Display for Line { &Line::Control(ref control_instr) => write!(f, "{}", control_instr), &Line::Cut(ref cut_instr) => write!(f, "{}", cut_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::Query(ref query_instr) => write!(f, "{}", query_instr), }