Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17b2510480 | ||
|
|
bcfd7cbf8d | ||
|
|
cee3dbc453 | ||
|
|
ed985c3cfe | ||
|
|
4ad62e4606 | ||
|
|
d34811aa36 | ||
|
|
b90d69a45b | ||
|
|
81f220a4d2 | ||
|
|
e594ade84d | ||
|
|
0dcd9e5805 | ||
|
|
67a00e4deb | ||
|
|
e656e7fbae | ||
|
|
0fdf0d8d06 | ||
|
|
7cdbd2f16c | ||
|
|
ccfcc654a5 | ||
|
|
2eea0528b1 | ||
|
|
a358431d30 | ||
|
|
e9c1556c32 | ||
|
|
1b1879a6fa | ||
|
|
24e5e39c28 |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "scryer-prolog"
|
name = "scryer-prolog"
|
||||||
version = "0.8.113"
|
version = "0.8.116"
|
||||||
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
authors = ["Mark Thom <markjordanthom@gmail.com>"]
|
||||||
build = "build.rs"
|
build = "build.rs"
|
||||||
repository = "https://github.com/mthom/scryer-prolog"
|
repository = "https://github.com/mthom/scryer-prolog"
|
||||||
@@ -19,7 +19,7 @@ lazy_static = "1.4.0"
|
|||||||
libc = "0.2.62"
|
libc = "0.2.62"
|
||||||
nix = "0.15.0"
|
nix = "0.15.0"
|
||||||
ordered-float = "0.5.0"
|
ordered-float = "0.5.0"
|
||||||
prolog_parser = "0.8.33"
|
prolog_parser = "0.8.34"
|
||||||
ref_thread_local = "0.0.0"
|
ref_thread_local = "0.0.0"
|
||||||
rug = "1.4.0"
|
rug = "1.4.0"
|
||||||
rustyline = "5.0.3"
|
rustyline = "5.0.3"
|
||||||
|
|||||||
31
README.md
31
README.md
@@ -50,11 +50,11 @@ Extend Scryer Prolog to include the following, among other features:
|
|||||||
- [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
|
- [x] Backtrackable and non-backtrackable global variables via `bb_get/2`
|
||||||
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
|
||||||
(backtrackable).
|
(backtrackable).
|
||||||
|
- [ ] clp(B) and clp($\mathbb{Z}$) as builtin libraries (_in progress_).
|
||||||
- [ ] Streams and predicates for stream control (_in progress_).
|
- [ ] Streams and predicates for stream control (_in progress_).
|
||||||
- [ ] An incremental compacting garbage collector satisfying the five
|
- [ ] An incremental compacting garbage collector satisfying the five
|
||||||
properties of "Precise Garbage Collection in Prolog."
|
properties of "Precise Garbage Collection in Prolog."
|
||||||
- [ ] Mode declarations.
|
- [ ] Mode declarations.
|
||||||
- [ ] Extensions for clp(FD).
|
|
||||||
|
|
||||||
## Phase 3
|
## Phase 3
|
||||||
|
|
||||||
@@ -93,7 +93,7 @@ strings.
|
|||||||
|
|
||||||
First, install the latest stable version of
|
First, install the latest stable version of
|
||||||
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
[Rust](https://www.rust-lang.org/en-US/install.html) using your
|
||||||
preferred method. Then install the latest Scryer Prolog with cargo,
|
preferred method. Then install Scryer Prolog with cargo,
|
||||||
like so:
|
like so:
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -101,13 +101,27 @@ $> cargo install scryer-prolog
|
|||||||
```
|
```
|
||||||
|
|
||||||
cargo will download and install the libraries Scryer Prolog uses
|
cargo will download and install the libraries Scryer Prolog uses
|
||||||
automatically. You can find the `scryer-prolog` executable in
|
automatically from crates.io. You can find the `scryer-prolog`
|
||||||
`~/.cargo/bin`.
|
executable in `~/.cargo/bin`.
|
||||||
|
|
||||||
|
Publishing Rust crates to crates.io and pushing to git are entirely
|
||||||
|
distinct, independent processes, so to be sure you have the latest
|
||||||
|
commit, it is recommended to clone directly from this git repository,
|
||||||
|
which can be done as follows:
|
||||||
|
|
||||||
|
```
|
||||||
|
$> git clone https://github.com/mthom/scryer-prolog
|
||||||
|
$> cd scryer-prolog
|
||||||
|
$> cargo run [--release]
|
||||||
|
```
|
||||||
|
|
||||||
|
The optional `--release` flag will perform various optimizations,
|
||||||
|
producing a faster executable.
|
||||||
|
|
||||||
Note on compatibility: Scryer Prolog should work on Linux, Mac OS X,
|
Note on compatibility: Scryer Prolog should work on Linux, Mac OS X,
|
||||||
and BSD variants on which Rust runs. Windows support hinges on
|
and BSD variants on which Rust runs. Windows support hinges on
|
||||||
rustyline and Termion being functional in that environment, which to
|
rustyline and Termion being functional in that environment, which to
|
||||||
my knowledge is not currently the case.
|
my knowledge is not presently the case.
|
||||||
|
|
||||||
## Built-in predicates
|
## Built-in predicates
|
||||||
|
|
||||||
@@ -120,7 +134,7 @@ The following predicates are built-in to Scryer.
|
|||||||
`abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`,
|
`abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`,
|
||||||
`atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`,
|
`atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`,
|
||||||
`truncate/1`, `round/1`, `floor/1`, `ceiling/1`, `pi/0`,
|
`truncate/1`, `round/1`, `floor/1`, `ceiling/1`, `pi/0`,
|
||||||
`min/1`, `max/1`
|
`min/1`, `max/1`, `gcd/2`, `sign/1`
|
||||||
* Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`.
|
* Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`.
|
||||||
* `(:)/2`
|
* `(:)/2`
|
||||||
* `(@>)/2`
|
* `(@>)/2`
|
||||||
@@ -285,11 +299,6 @@ Note that the values of variables belonging to successful queries are
|
|||||||
printed out, on one line each. Uninstantiated variables are denoted by
|
printed out, on one line each. Uninstantiated variables are denoted by
|
||||||
a number preceded by an underscore (`X = _0` in an example above).
|
a number preceded by an underscore (`X = _0` in an example above).
|
||||||
|
|
||||||
To clear the database, type
|
|
||||||
```
|
|
||||||
?- [clear].
|
|
||||||
```
|
|
||||||
|
|
||||||
To quit scryer-prolog, type
|
To quit scryer-prolog, type
|
||||||
```
|
```
|
||||||
?- halt.
|
?- halt.
|
||||||
|
|||||||
@@ -159,6 +159,7 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
"round" => Ok(ArithmeticInstruction::Round(a1, t)),
|
"round" => Ok(ArithmeticInstruction::Round(a1, t)),
|
||||||
"ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
|
"ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
|
||||||
"floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
|
"floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
|
||||||
|
"sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
|
||||||
"\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
|
"\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
|
||||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
Constant::Atom(name, None),
|
Constant::Atom(name, None),
|
||||||
@@ -192,6 +193,7 @@ impl<'a> ArithmeticEvaluator<'a> {
|
|||||||
"xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
|
"xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
|
||||||
"mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
|
"mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
|
||||||
"rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
|
"rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
|
||||||
|
"gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
|
||||||
"atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
|
"atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
|
||||||
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
_ => Err(ArithmeticError::NonEvaluableFunctor(
|
||||||
Constant::Atom(name, None),
|
Constant::Atom(name, None),
|
||||||
|
|||||||
@@ -162,8 +162,7 @@ pub enum SystemClauseType {
|
|||||||
AtomChars,
|
AtomChars,
|
||||||
AtomCodes,
|
AtomCodes,
|
||||||
AtomLength,
|
AtomLength,
|
||||||
ModuleAssertDynamicPredicateToFront,
|
CallAttributeGoals,
|
||||||
ModuleAssertDynamicPredicateToBack,
|
|
||||||
CharCode,
|
CharCode,
|
||||||
CharsToNumber,
|
CharsToNumber,
|
||||||
CodesToNumber,
|
CodesToNumber,
|
||||||
@@ -176,6 +175,7 @@ pub enum SystemClauseType {
|
|||||||
EnqueueAttributedVar,
|
EnqueueAttributedVar,
|
||||||
ExpandGoal,
|
ExpandGoal,
|
||||||
ExpandTerm,
|
ExpandTerm,
|
||||||
|
FetchAttributeGoals,
|
||||||
FetchGlobalVar,
|
FetchGlobalVar,
|
||||||
FetchGlobalVarWithOffset,
|
FetchGlobalVarWithOffset,
|
||||||
GetChar,
|
GetChar,
|
||||||
@@ -200,6 +200,8 @@ pub enum SystemClauseType {
|
|||||||
InstallSCCCleaner,
|
InstallSCCCleaner,
|
||||||
InstallInferenceCounter,
|
InstallInferenceCounter,
|
||||||
LiftedHeapLength,
|
LiftedHeapLength,
|
||||||
|
ModuleAssertDynamicPredicateToFront,
|
||||||
|
ModuleAssertDynamicPredicateToBack,
|
||||||
ModuleOf,
|
ModuleOf,
|
||||||
ModuleRetractClause,
|
ModuleRetractClause,
|
||||||
NoSuchPredicate,
|
NoSuchPredicate,
|
||||||
@@ -229,8 +231,8 @@ pub enum SystemClauseType {
|
|||||||
GetDoubleQuotes,
|
GetDoubleQuotes,
|
||||||
InstallNewBlock,
|
InstallNewBlock,
|
||||||
Maybe,
|
Maybe,
|
||||||
|
RawInputReadChar,
|
||||||
ResetBlock,
|
ResetBlock,
|
||||||
ReturnFromAttributeGoals,
|
|
||||||
ReturnFromVerifyAttr,
|
ReturnFromVerifyAttr,
|
||||||
SetBall,
|
SetBall,
|
||||||
SetCutPointByDefault(RegType),
|
SetCutPointByDefault(RegType),
|
||||||
@@ -257,20 +259,12 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
|
||||||
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
|
||||||
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
|
||||||
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
|
||||||
clause_name!("$module_asserta")
|
|
||||||
}
|
|
||||||
&SystemClauseType::ModuleAssertDynamicPredicateToBack => {
|
|
||||||
clause_name!("$module_assertz")
|
|
||||||
}
|
|
||||||
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
&SystemClauseType::CharCode => clause_name!("$char_code"),
|
||||||
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
|
||||||
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
|
||||||
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
&SystemClauseType::REPL(REPLCodePtr::CompileBatch) => clause_name!("$compile_batch"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::SubmitQueryAndPrintResults) => {
|
|
||||||
clause_name!("$submit_query_and_print_results")
|
|
||||||
}
|
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
&SystemClauseType::REPL(REPLCodePtr::UseModule) => clause_name!("$use_module"),
|
||||||
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
&SystemClauseType::REPL(REPLCodePtr::UseQualifiedModule) => {
|
||||||
clause_name!("$use_qualified_module")
|
clause_name!("$use_qualified_module")
|
||||||
@@ -289,6 +283,7 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
|
||||||
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
|
||||||
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
|
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
|
||||||
|
&SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"),
|
||||||
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
|
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
|
||||||
&SystemClauseType::FetchGlobalVarWithOffset => {
|
&SystemClauseType::FetchGlobalVarWithOffset => {
|
||||||
clause_name!("$fetch_global_var_with_offset")
|
clause_name!("$fetch_global_var_with_offset")
|
||||||
@@ -327,11 +322,18 @@ impl SystemClauseType {
|
|||||||
}
|
}
|
||||||
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
|
||||||
&SystemClauseType::Maybe => clause_name!("maybe"),
|
&SystemClauseType::Maybe => clause_name!("maybe"),
|
||||||
|
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
|
||||||
|
clause_name!("$module_asserta")
|
||||||
|
}
|
||||||
|
&SystemClauseType::ModuleAssertDynamicPredicateToBack => {
|
||||||
|
clause_name!("$module_assertz")
|
||||||
|
}
|
||||||
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
&SystemClauseType::ModuleHeadIsDynamic => clause_name!("$module_head_is_dynamic"),
|
||||||
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
&SystemClauseType::ModuleOf => clause_name!("$module_of"),
|
||||||
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
|
||||||
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
|
||||||
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
|
||||||
|
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
|
||||||
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
|
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
|
||||||
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
|
||||||
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
|
||||||
@@ -357,9 +359,6 @@ impl SystemClauseType {
|
|||||||
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
|
||||||
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
|
||||||
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
|
||||||
&SystemClauseType::ReturnFromAttributeGoals => {
|
|
||||||
clause_name!("$return_from_attribute_goals")
|
|
||||||
}
|
|
||||||
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
|
||||||
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
&SystemClauseType::SetBall => clause_name!("$set_ball"),
|
||||||
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
|
||||||
@@ -387,6 +386,7 @@ impl SystemClauseType {
|
|||||||
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
|
||||||
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
|
||||||
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
|
||||||
|
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
|
||||||
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
("$char_code", 2) => Some(SystemClauseType::CharCode),
|
||||||
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
|
||||||
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
|
||||||
@@ -404,6 +404,7 @@ impl SystemClauseType {
|
|||||||
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
|
||||||
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
|
||||||
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
|
||||||
|
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
|
||||||
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
|
||||||
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
|
||||||
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
("$get_char", 1) => Some(SystemClauseType::GetChar),
|
||||||
@@ -449,13 +450,13 @@ impl SystemClauseType {
|
|||||||
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
|
||||||
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
|
||||||
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
|
||||||
|
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
|
||||||
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
|
||||||
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
|
||||||
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
|
||||||
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
|
||||||
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
|
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
|
||||||
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
|
||||||
("$return_from_attribute_goals", 0) => Some(SystemClauseType::ReturnFromAttributeGoals),
|
|
||||||
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
|
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
|
||||||
("$set_ball", 1) => Some(SystemClauseType::SetBall),
|
("$set_ball", 1) => Some(SystemClauseType::SetBall),
|
||||||
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
|
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
|
||||||
@@ -464,9 +465,6 @@ impl SystemClauseType {
|
|||||||
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
|
||||||
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
|
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
|
||||||
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
("$store_global_var_with_offset", 2) => Some(SystemClauseType::StoreGlobalVarWithOffset),
|
||||||
("$submit_query_and_print_results", 2) => Some(SystemClauseType::REPL(
|
|
||||||
REPLCodePtr::SubmitQueryAndPrintResults,
|
|
||||||
)),
|
|
||||||
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
("$term_variables", 2) => Some(SystemClauseType::TermVariables),
|
||||||
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
|
||||||
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),
|
||||||
|
|||||||
@@ -338,6 +338,7 @@ pub struct Module {
|
|||||||
pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
|
pub user_term_expansions: (Predicate, VecDeque<TopLevel>), // term expansions inherited from the user scope.
|
||||||
pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
|
pub user_goal_expansions: (Predicate, VecDeque<TopLevel>), // same for goal_expansions.
|
||||||
pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
|
pub inserted_expansions: bool, // has the module been successfully inserted into toplevel??
|
||||||
|
pub is_impromptu_module: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Eq)]
|
#[derive(Clone, PartialEq, Eq)]
|
||||||
|
|||||||
@@ -329,7 +329,7 @@ pub fn requires_space(atom: &str, op: &str) -> bool {
|
|||||||
.next()
|
.next()
|
||||||
.map(|oc| {
|
.map(|oc| {
|
||||||
if ac == '0' {
|
if ac == '0' {
|
||||||
oc == 'b' || oc == 'x' || oc == 'o' || oc == '\''
|
oc == '\'' || oc == '(' || alpha_numeric_char!(oc)
|
||||||
} else if alpha_numeric_char!(ac) {
|
} else if alpha_numeric_char!(ac) {
|
||||||
oc == '(' || alpha_numeric_char!(oc)
|
oc == '(' || alpha_numeric_char!(oc)
|
||||||
} else if graphic_token_char!(ac) {
|
} else if graphic_token_char!(ac) {
|
||||||
@@ -625,6 +625,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
|
|||||||
iter.stack().last().cloned().and_then(|addr| {
|
iter.stack().last().cloned().and_then(|addr| {
|
||||||
let addr = self.machine_st.store(self.machine_st.deref(addr));
|
let addr = self.machine_st.store(self.machine_st.deref(addr));
|
||||||
|
|
||||||
|
if let Some(var) = self.var_names.get(&addr) {
|
||||||
|
self.heap_locs.insert(addr.clone(), Rc::new(var.clone()));
|
||||||
|
}
|
||||||
|
|
||||||
match self.heap_locs.get(&addr).cloned() {
|
match self.heap_locs.get(&addr).cloned() {
|
||||||
Some(var) => {
|
Some(var) => {
|
||||||
if !self.printed_vars.contains(&addr) {
|
if !self.printed_vars.contains(&addr) {
|
||||||
|
|||||||
@@ -189,6 +189,8 @@ pub enum ArithmeticInstruction {
|
|||||||
Or(ArithmeticTerm, ArithmeticTerm, usize),
|
Or(ArithmeticTerm, ArithmeticTerm, usize),
|
||||||
Mod(ArithmeticTerm, ArithmeticTerm, usize),
|
Mod(ArithmeticTerm, ArithmeticTerm, usize),
|
||||||
Rem(ArithmeticTerm, ArithmeticTerm, usize),
|
Rem(ArithmeticTerm, ArithmeticTerm, usize),
|
||||||
|
Gcd(ArithmeticTerm, ArithmeticTerm, usize),
|
||||||
|
Sign(ArithmeticTerm, usize),
|
||||||
Cos(ArithmeticTerm, usize),
|
Cos(ArithmeticTerm, usize),
|
||||||
Sin(ArithmeticTerm, usize),
|
Sin(ArithmeticTerm, usize),
|
||||||
Tan(ArithmeticTerm, usize),
|
Tan(ArithmeticTerm, usize),
|
||||||
@@ -314,6 +316,10 @@ impl ArithmeticInstruction {
|
|||||||
&ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
|
&ArithmeticInstruction::ATan2(ref at_1, ref at_2, t) => {
|
||||||
arith_instr_bin_functor(h, "rem", at_1, at_2, t)
|
arith_instr_bin_functor(h, "rem", at_1, at_2, t)
|
||||||
}
|
}
|
||||||
|
&ArithmeticInstruction::Gcd(ref at_1, ref at_2, t) => {
|
||||||
|
arith_instr_bin_functor(h, "gcd", at_1, at_2, t)
|
||||||
|
}
|
||||||
|
&ArithmeticInstruction::Sign(ref at, t) => arith_instr_unary_functor(h, "sign", at, t),
|
||||||
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
|
&ArithmeticInstruction::Cos(ref at, t) => arith_instr_unary_functor(h, "cos", at, t),
|
||||||
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
|
&ArithmeticInstruction::Sin(ref at, t) => arith_instr_unary_functor(h, "sin", at, t),
|
||||||
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
|
&ArithmeticInstruction::Tan(ref at, t) => arith_instr_unary_functor(h, "tan", at, t),
|
||||||
@@ -358,14 +364,6 @@ pub enum ControlInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ControlInstruction {
|
impl ControlInstruction {
|
||||||
pub fn is_jump_instr(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
&ControlInstruction::CallClause(..) => true,
|
|
||||||
&ControlInstruction::JmpBy(..) => true,
|
|
||||||
_ => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_functor(&self) -> MachineStub {
|
pub fn to_functor(&self) -> MachineStub {
|
||||||
match self {
|
match self {
|
||||||
&ControlInstruction::Allocate(num_frames) => {
|
&ControlInstruction::Allocate(num_frames) => {
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
'$default_attr_list'([PG | PGs], Module, AttrVar) -->
|
'$default_attr_list'([PG | PGs], Module, AttrVar) -->
|
||||||
( { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)]
|
( { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)]
|
||||||
; true
|
; { true }
|
||||||
),
|
),
|
||||||
'$default_attr_list'(PGs, Module, AttrVar).
|
'$default_attr_list'(PGs, Module, AttrVar).
|
||||||
'$default_attr_list'([], _, _) --> [].
|
'$default_attr_list'([], _, _) --> [].
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)).
|
|||||||
','(!, Atom, B) :- Atom == !, '$set_cp'(B).
|
','(!, Atom, B) :- Atom == !, '$set_cp'(B).
|
||||||
','(!, G, B) :- '$set_cp'(B), G.
|
','(!, G, B) :- '$set_cp'(B), G.
|
||||||
','(G, CF, B) :- compound(CF),
|
','(G, CF, B) :- compound(CF),
|
||||||
'$call_with_default_policy'(CF = ','(G1, G2)), !, G,
|
'$call_with_default_policy'(CF = ','(G1, G2)),
|
||||||
|
!, G,
|
||||||
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
'$call_with_default_policy'(comma_errors(G1, G2, B)).
|
||||||
','(G, Atom, B) :- Atom == !, !, G, '$set_cp'(B).
|
','(G, Atom, B) :- Atom == !, !, G, '$set_cp'(B).
|
||||||
','(G1, G2, _) :- G1, G2.
|
','(G1, G2, _) :- G1, G2.
|
||||||
@@ -561,7 +562,8 @@ assertz(Clause) :-
|
|||||||
).
|
).
|
||||||
|
|
||||||
first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
|
first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
|
||||||
( Clause0 \= Clause1 -> N1 is N0 + 1,
|
( Clause0 \= Clause1 ->
|
||||||
|
N1 is N0 + 1,
|
||||||
first_match_index(Clauses, Clause1, N1, N)
|
first_match_index(Clauses, Clause1, N1, N)
|
||||||
; N0 = N, Clause0 = Clause1
|
; N0 = N, Clause0 = Clause1
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -1244,8 +1244,7 @@ bdd_count(Node, VNum, Count) :-
|
|||||||
bdd_count(High, VNum, HCount),
|
bdd_count(High, VNum, HCount),
|
||||||
bdd_pow(Low, V, VNum, LPow),
|
bdd_pow(Low, V, VNum, LPow),
|
||||||
bdd_pow(High, V, VNum, HPow),
|
bdd_pow(High, V, VNum, HPow),
|
||||||
Count0 is LPow*LCount + HPow*HCount,
|
Count is LPow*LCount + HPow*HCount
|
||||||
Count = Count0
|
|
||||||
)
|
)
|
||||||
).
|
).
|
||||||
|
|
||||||
|
|||||||
@@ -51,4 +51,5 @@ gather_dif_goals([(X \== Y) | Goals]) -->
|
|||||||
|
|
||||||
attribute_goals(X) -->
|
attribute_goals(X) -->
|
||||||
{ get_atts(X, +dif(Goals)) },
|
{ get_atts(X, +dif(Goals)) },
|
||||||
gather_dif_goals(Goals).
|
gather_dif_goals(Goals),
|
||||||
|
{ put_atts(X, -dif(_)) }.
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ gather_freeze_goals(Attrs, _) -->
|
|||||||
!.
|
!.
|
||||||
gather_freeze_goals([frozen(X) | _], Var) -->
|
gather_freeze_goals([frozen(X) | _], Var) -->
|
||||||
[freeze(Var, X)],
|
[freeze(Var, X)],
|
||||||
|
{ put_atts(Var, -frozen(_)) },
|
||||||
!.
|
!.
|
||||||
gather_freeze_goals([_ | Attrs], Var) -->
|
gather_freeze_goals([_ | Attrs], Var) -->
|
||||||
gather_freeze_goals(Attrs, Var).
|
gather_freeze_goals(Attrs, Var).
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
maplist/4, maplist/5, maplist/6, maplist/7,
|
maplist/4, maplist/5, maplist/6, maplist/7,
|
||||||
maplist/8, maplist/9]).
|
maplist/8, maplist/9]).
|
||||||
|
|
||||||
|
|
||||||
length(Xs, N) :-
|
length(Xs, N) :-
|
||||||
var(N), !,
|
var(N), !,
|
||||||
'$skip_max_list'(M, -1, Xs, Xs0),
|
'$skip_max_list'(M, -1, Xs, Xs0),
|
||||||
@@ -30,17 +31,22 @@ length_rundown([_|Xs], N) :-
|
|||||||
N1 is N-1,
|
N1 is N-1,
|
||||||
length_rundown(Xs, N1).
|
length_rundown(Xs, N1).
|
||||||
|
|
||||||
|
|
||||||
member(X, [X|_]).
|
member(X, [X|_]).
|
||||||
member(X, [_|Xs]) :- member(X, Xs).
|
member(X, [_|Xs]) :- member(X, Xs).
|
||||||
|
|
||||||
|
|
||||||
select(X, [X|Xs], Xs).
|
select(X, [X|Xs], Xs).
|
||||||
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
|
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
|
||||||
|
|
||||||
|
|
||||||
append([], R, R).
|
append([], R, R).
|
||||||
append([X|L], R, [X|S]) :- append(L, R, S).
|
append([X|L], R, [X|S]) :- append(L, R, S).
|
||||||
|
|
||||||
|
|
||||||
memberchk(X, Xs) :- member(X, Xs), !.
|
memberchk(X, Xs) :- member(X, Xs), !.
|
||||||
|
|
||||||
|
|
||||||
reverse(Xs, Ys) :-
|
reverse(Xs, Ys) :-
|
||||||
( nonvar(Xs) -> reverse(Xs, Ys, [], Xs)
|
( nonvar(Xs) -> reverse(Xs, Ys, [], Xs)
|
||||||
; reverse(Ys, Xs, [], Ys)
|
; reverse(Ys, Xs, [], Ys)
|
||||||
@@ -50,6 +56,7 @@ reverse([], [], YsRev, YsRev).
|
|||||||
reverse([X1|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
|
reverse([X1|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
|
||||||
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
|
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
|
||||||
|
|
||||||
|
|
||||||
maplist(_, []).
|
maplist(_, []).
|
||||||
maplist(Cont1, [E1|E1s]) :-
|
maplist(Cont1, [E1|E1s]) :-
|
||||||
call(Cont1, E1),
|
call(Cont1, E1),
|
||||||
|
|||||||
@@ -132,7 +132,8 @@ maybe :- '$maybe'.
|
|||||||
set_random(Seed) :-
|
set_random(Seed) :-
|
||||||
( nonvar(Seed) ->
|
( nonvar(Seed) ->
|
||||||
( Seed = seed(S) ->
|
( Seed = seed(S) ->
|
||||||
( integer(S) -> '$set_seed'(S)
|
( var(S) -> throw(error(instantiation_error, set_random/1))
|
||||||
|
; integer(S) -> '$set_seed'(S)
|
||||||
; throw(error(type_error(integer(S), set_random/1)))
|
; throw(error(type_error(integer(S), set_random/1)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ verify_attrs([], _, _, []).
|
|||||||
|
|
||||||
call_verify_attributes(Attrs, _, _, []) :-
|
call_verify_attributes(Attrs, _, _, []) :-
|
||||||
var(Attrs), !.
|
var(Attrs), !.
|
||||||
|
call_verify_attributes([], _, _, []).
|
||||||
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
|
||||||
gather_modules([Attr|Attrs], Modules0),
|
gather_modules([Attr|Attrs], Modules0),
|
||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
use crate::prolog::machine::*;
|
use crate::prolog::machine::*;
|
||||||
|
|
||||||
use indexmap::IndexSet;
|
|
||||||
|
|
||||||
use std::vec::IntoIter;
|
use std::vec::IntoIter;
|
||||||
|
|
||||||
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
|
pub static VERIFY_ATTRS: &str = include_str!("attributed_variables.pl");
|
||||||
@@ -14,6 +12,7 @@ pub(super) struct AttrVarInitializer {
|
|||||||
pub(super) attr_var_queue: Vec<usize>,
|
pub(super) attr_var_queue: Vec<usize>,
|
||||||
pub(super) bindings: Bindings,
|
pub(super) bindings: Bindings,
|
||||||
pub(super) cp: LocalCodePtr,
|
pub(super) cp: LocalCodePtr,
|
||||||
|
pub(super) instigating_p: LocalCodePtr,
|
||||||
pub(super) verify_attrs_loc: usize,
|
pub(super) verify_attrs_loc: usize,
|
||||||
pub(super) project_attrs_loc: usize,
|
pub(super) project_attrs_loc: usize,
|
||||||
}
|
}
|
||||||
@@ -24,6 +23,7 @@ impl AttrVarInitializer {
|
|||||||
attribute_goals: vec![],
|
attribute_goals: vec![],
|
||||||
attr_var_queue: vec![],
|
attr_var_queue: vec![],
|
||||||
bindings: vec![],
|
bindings: vec![],
|
||||||
|
instigating_p: LocalCodePtr::default(),
|
||||||
cp: LocalCodePtr::default(),
|
cp: LocalCodePtr::default(),
|
||||||
verify_attrs_loc,
|
verify_attrs_loc,
|
||||||
project_attrs_loc,
|
project_attrs_loc,
|
||||||
@@ -41,10 +41,12 @@ impl AttrVarInitializer {
|
|||||||
impl MachineState {
|
impl MachineState {
|
||||||
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
|
||||||
if self.attr_var_init.bindings.is_empty() {
|
if self.attr_var_init.bindings.is_empty() {
|
||||||
|
self.attr_var_init.instigating_p = self.p.local();
|
||||||
|
|
||||||
if self.last_call {
|
if self.last_call {
|
||||||
self.attr_var_init.cp = self.cp;
|
self.attr_var_init.cp = self.cp;
|
||||||
} else {
|
} else {
|
||||||
self.attr_var_init.cp = self.p.local();
|
self.attr_var_init.cp = self.p.local() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
|
self.p = CodePtr::VerifyAttrInterrupt(self.attr_var_init.verify_attrs_loc);
|
||||||
@@ -97,54 +99,18 @@ impl MachineState {
|
|||||||
attr_vars.into_iter()
|
attr_vars.into_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn populate_project_attr_lists(&mut self) -> (Addr, Addr) {
|
|
||||||
let mut query_vars = IndexSet::new();
|
|
||||||
let attr_vars = self.gather_attr_vars_created_since(0);
|
|
||||||
|
|
||||||
for (_, addr) in self.heap_locs.iter() {
|
|
||||||
let iter = self.acyclic_pre_order_iter(addr.clone());
|
|
||||||
|
|
||||||
for value in iter {
|
|
||||||
match value {
|
|
||||||
HeapCellValue::Addr(Addr::HeapCell(h)) => {
|
|
||||||
query_vars.insert(Addr::HeapCell(h));
|
|
||||||
}
|
|
||||||
HeapCellValue::Addr(Addr::StackCell(fr, sc)) => {
|
|
||||||
query_vars.insert(Addr::StackCell(fr, sc));
|
|
||||||
}
|
|
||||||
HeapCellValue::Addr(Addr::AttrVar(h)) => {
|
|
||||||
query_vars.insert(Addr::AttrVar(h));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let query_var_list = Addr::HeapCell(self.heap.to_list(query_vars.into_iter()));
|
|
||||||
let attr_var_list = Addr::HeapCell(self.heap.to_list(attr_vars));
|
|
||||||
|
|
||||||
(query_var_list, attr_var_list)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
|
pub(super) fn verify_attr_interrupt(&mut self, p: usize) {
|
||||||
let rs = MAX_ARITY;
|
self.allocate(self.num_of_args + 2);
|
||||||
|
|
||||||
// store temp vars in perm vars slots along with self.b0 and
|
|
||||||
// self.num_of_args. why self.b0? if we return to a NeckCut
|
|
||||||
// after finishing the interrupt, it won't work correctly if
|
|
||||||
// self.b == self.b0. we must change it back when we return,
|
|
||||||
// as if nothing happened.
|
|
||||||
self.allocate(rs + 2);
|
|
||||||
|
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
self.and_stack[e].interrupt_cp = self.attr_var_init.cp;
|
self.and_stack[e].interrupt_cp = self.attr_var_init.cp;
|
||||||
|
|
||||||
for i in 1..rs + 1 {
|
for i in 1 .. self.num_of_args + 1 {
|
||||||
self.and_stack[e][i] = self[RegType::Temp(i)].clone();
|
self.and_stack[e][i] = self[RegType::Temp(i)].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
self.and_stack[e][rs + 1] = Addr::Con(Constant::Usize(self.b0));
|
self.and_stack[e][self.num_of_args + 1] = Addr::Con(Constant::Usize(self.b0));
|
||||||
self.and_stack[e][rs + 2] = Addr::Con(Constant::Usize(self.num_of_args));
|
self.and_stack[e][self.num_of_args + 2] = Addr::Con(Constant::Usize(self.num_of_args));
|
||||||
|
|
||||||
self.verify_attributes();
|
self.verify_attributes();
|
||||||
|
|
||||||
@@ -152,57 +118,4 @@ impl MachineState {
|
|||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
self.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_attribute_goals_string(&mut self, op_dir: &OpDir) -> String {
|
|
||||||
let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]);
|
|
||||||
|
|
||||||
if attr_goals.is_empty() {
|
|
||||||
return String::from("");
|
|
||||||
}
|
|
||||||
|
|
||||||
attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2));
|
|
||||||
self.term_dedup(&mut attr_goals);
|
|
||||||
|
|
||||||
let mut output = PrinterOutputter::new();
|
|
||||||
|
|
||||||
for goal_addr in attr_goals {
|
|
||||||
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
|
||||||
printer.see_all_locs();
|
|
||||||
|
|
||||||
printer.numbervars = false;
|
|
||||||
printer.quoted = true;
|
|
||||||
|
|
||||||
output = printer.print(goal_addr);
|
|
||||||
output.append(", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
// cut trailing ", "
|
|
||||||
let output_len = output.len();
|
|
||||||
output.truncate(output_len - 2);
|
|
||||||
|
|
||||||
output.result()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Machine {
|
|
||||||
pub fn attribute_goals(&mut self) -> String {
|
|
||||||
let p = self.machine_st.attr_var_init.project_attrs_loc;
|
|
||||||
let (query_vars, attr_vars) = self.machine_st.populate_project_attr_lists();
|
|
||||||
|
|
||||||
self.machine_st.allocate(0);
|
|
||||||
|
|
||||||
self.machine_st[temp_v!(1)] = query_vars;
|
|
||||||
self.machine_st[temp_v!(2)] = attr_vars;
|
|
||||||
|
|
||||||
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(p));
|
|
||||||
self.machine_st.query_stepper(
|
|
||||||
&mut self.indices,
|
|
||||||
&mut self.policies,
|
|
||||||
&mut self.code_repo,
|
|
||||||
&mut readline::input_stream(),
|
|
||||||
);
|
|
||||||
|
|
||||||
self.machine_st
|
|
||||||
.print_attribute_goals_string(&self.indices.op_dir)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ fn load_module<R: Read>(
|
|||||||
stream: ParsingStream<R>,
|
stream: ParsingStream<R>,
|
||||||
suppress_warnings: bool,
|
suppress_warnings: bool,
|
||||||
listing_src: ClauseName,
|
listing_src: ClauseName,
|
||||||
) -> Result<Option<ClauseName>, SessionError> {
|
) -> Result<ClauseName, SessionError> {
|
||||||
// follow the operation of compile_user_module, but before
|
// follow the operation of compile_user_module, but before
|
||||||
// compiling, check that a module is declared in the file. if not,
|
// compiling, check that a module is declared in the file. if not,
|
||||||
// throw an exception.
|
// throw an exception.
|
||||||
@@ -72,15 +72,24 @@ fn load_module<R: Read>(
|
|||||||
let mut compiler = ListingCompiler::new(
|
let mut compiler = ListingCompiler::new(
|
||||||
&wam.code_repo,
|
&wam.code_repo,
|
||||||
suppress_warnings,
|
suppress_warnings,
|
||||||
listing_src,
|
listing_src.clone(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let results = compiler.gather_items(wam, stream, &mut indices);
|
let results = compiler.gather_items(wam, stream, &mut indices);
|
||||||
|
|
||||||
let module_name = if let Some(ref module) = &compiler.module {
|
let module_name = if let Some(ref module) = &compiler.module {
|
||||||
Some(module.module_decl.name.clone())
|
module.module_decl.name.clone()
|
||||||
} else {
|
} else {
|
||||||
None
|
// this impromptu definition (namely, its exports) will be filled out later.
|
||||||
|
let module_decl = ModuleDecl { name: listing_src, exports: vec![] };
|
||||||
|
|
||||||
|
let mut module = Module::new(module_decl, wam.indices.atom_tbl.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))
|
results.and_then(|results| compile_work_impl(&mut compiler, wam, indices, results))
|
||||||
@@ -97,7 +106,7 @@ fn load_module_from_file(
|
|||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
filename: &str,
|
filename: &str,
|
||||||
suppress_warnings: bool,
|
suppress_warnings: bool,
|
||||||
) -> Result<Option<ClauseName>, SessionError> {
|
) -> Result<ClauseName, SessionError> {
|
||||||
let path = fix_filename(wam.indices.atom_tbl.clone(), filename)?;
|
let path = fix_filename(wam.indices.atom_tbl.clone(), filename)?;
|
||||||
let filename = clause_name!(path.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
let filename = clause_name!(path.to_string_lossy().to_string(), wam.indices.atom_tbl);
|
||||||
|
|
||||||
@@ -234,68 +243,6 @@ fn compile_query(
|
|||||||
Ok((code, cg.take_vars()))
|
Ok((code, cg.take_vars()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_decl(
|
|
||||||
wam: &mut Machine,
|
|
||||||
compiler: &mut ListingCompiler,
|
|
||||||
decl: Declaration,
|
|
||||||
) -> Result<IndexStore, SessionError> {
|
|
||||||
let flags = wam.machine_flags();
|
|
||||||
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
|
|
||||||
|
|
||||||
compiler.process_decl(decl, wam, &mut indices, flags)?;
|
|
||||||
|
|
||||||
Ok(indices)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn compile_term(wam: &mut Machine, packet: TopLevelPacket) -> EvalSession {
|
|
||||||
match packet {
|
|
||||||
TopLevelPacket::Query(terms, queue) => {
|
|
||||||
match compile_query(terms, queue, wam.machine_flags()) {
|
|
||||||
Ok((code, vars)) => wam.submit_query(code, vars),
|
|
||||||
Err(e) => EvalSession::from(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TopLevelPacket::Decl(TopLevel::Declaration(decl), _) => {
|
|
||||||
let mut compiler = ListingCompiler::new(&wam.code_repo, false, clause_name!("user"));
|
|
||||||
let indices = try_eval_session!(compile_decl(wam, &mut compiler, decl));
|
|
||||||
|
|
||||||
try_eval_session!(wam.check_toplevel_code(&indices));
|
|
||||||
add_toplevel_code(wam, vec![], indices);
|
|
||||||
|
|
||||||
EvalSession::EntrySuccess
|
|
||||||
}
|
|
||||||
_ => EvalSession::from(SessionError::UserPrompt),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update_module_indices(wam: &Machine, module_name: ClauseName, mut indices: IndexStore) {
|
|
||||||
match wam.indices.modules.get(&module_name) {
|
|
||||||
Some(module) => {
|
|
||||||
let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());
|
|
||||||
|
|
||||||
// replace the "user" module src's in the indices with module_name.
|
|
||||||
for (key, idx) in code_dir.iter() {
|
|
||||||
let p = idx.0.borrow().0;
|
|
||||||
|
|
||||||
match module.code_dir.get(&key) {
|
|
||||||
Some(idx) => set_code_index!(idx, p, module_name.clone()),
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match wam.indices.code_dir.get(&key) {
|
|
||||||
Some(idx) => {
|
|
||||||
if idx.0.borrow().1 == module_name {
|
|
||||||
set_code_index!(idx, p, module_name.clone());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
fn add_hooks_to_mockup(
|
fn add_hooks_to_mockup(
|
||||||
code_repo: &mut CodeRepo,
|
code_repo: &mut CodeRepo,
|
||||||
hook: CompileTimeHook,
|
hook: CompileTimeHook,
|
||||||
@@ -311,9 +258,7 @@ fn add_hooks_to_mockup(
|
|||||||
preds.1.extend(expansions.1.into_iter());
|
preds.1.extend(expansions.1.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_module_expansions(wam: &mut Machine, module_name: ClauseName) {
|
fn setup_module_expansions(wam: &mut Machine, module: &Module) {
|
||||||
match wam.indices.modules.get(&module_name) {
|
|
||||||
Some(module) => {
|
|
||||||
let term_expansions = module.term_expansions.clone();
|
let term_expansions = module.term_expansions.clone();
|
||||||
let goal_expansions = module.goal_expansions.clone();
|
let goal_expansions = module.goal_expansions.clone();
|
||||||
|
|
||||||
@@ -322,15 +267,13 @@ fn setup_module_expansions(wam: &mut Machine, module_name: ClauseName) {
|
|||||||
CompileTimeHook::TermExpansion,
|
CompileTimeHook::TermExpansion,
|
||||||
term_expansions,
|
term_expansions,
|
||||||
);
|
);
|
||||||
|
|
||||||
add_hooks_to_mockup(
|
add_hooks_to_mockup(
|
||||||
&mut wam.code_repo,
|
&mut wam.code_repo,
|
||||||
CompileTimeHook::GoalExpansion,
|
CompileTimeHook::GoalExpansion,
|
||||||
goal_expansions,
|
goal_expansions,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn compile_into_module<R: Read>(
|
pub(super) fn compile_into_module<R: Read>(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
@@ -339,13 +282,21 @@ pub(super) fn compile_into_module<R: Read>(
|
|||||||
name: ClauseName,
|
name: ClauseName,
|
||||||
) -> EvalSession {
|
) -> EvalSession {
|
||||||
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
|
let mut indices = default_index_store!(wam.atom_tbl_of(&name));
|
||||||
try_eval_session!(setup_indices(wam, module_name.clone(), &mut indices));
|
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_name.clone());
|
let mut compiler = ListingCompiler::new(&wam.code_repo, true, module_name.clone());
|
||||||
|
|
||||||
match compile_into_module_impl(wam, &mut compiler, module_name, src, indices) {
|
match compile_into_module_impl(wam, &mut compiler, module, src, indices) {
|
||||||
Ok(()) => EvalSession::EntrySuccess,
|
Ok(()) => EvalSession::EntrySuccess,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
if let Some(module) = compiler.module.take() {
|
||||||
|
wam.indices.insert_module(module);
|
||||||
|
}
|
||||||
|
|
||||||
compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo);
|
compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo);
|
||||||
EvalSession::from(e)
|
EvalSession::from(e)
|
||||||
}
|
}
|
||||||
@@ -355,29 +306,28 @@ pub(super) fn compile_into_module<R: Read>(
|
|||||||
fn compile_into_module_impl<R: Read>(
|
fn compile_into_module_impl<R: Read>(
|
||||||
wam: &mut Machine,
|
wam: &mut Machine,
|
||||||
compiler: &mut ListingCompiler,
|
compiler: &mut ListingCompiler,
|
||||||
module_name: ClauseName,
|
module: Module,
|
||||||
src: ParsingStream<R>,
|
src: ParsingStream<R>,
|
||||||
mut indices: IndexStore,
|
mut indices: IndexStore,
|
||||||
) -> Result<(), SessionError> {
|
) -> Result<(), SessionError> {
|
||||||
setup_module_expansions(wam, module_name.clone());
|
setup_module_expansions(wam, &module);
|
||||||
|
|
||||||
|
let module_name = module.module_decl.name.clone();
|
||||||
|
compiler.module = Some(module);
|
||||||
|
|
||||||
let flags = wam.machine_flags();
|
let flags = wam.machine_flags();
|
||||||
|
|
||||||
wam.code_repo
|
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?;
|
||||||
.compile_hook(CompileTimeHook::TermExpansion, flags)?;
|
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
|
||||||
wam.code_repo
|
|
||||||
.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
|
|
||||||
|
|
||||||
let results = compiler.gather_items(wam, src, &mut indices)?;
|
let results = compiler.gather_items(wam, src, &mut indices)?;
|
||||||
let module_code =
|
let module_code =
|
||||||
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?;
|
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?;
|
||||||
|
|
||||||
let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len(), module_name.clone());
|
let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len(), module_name.clone());
|
||||||
|
|
||||||
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
|
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
|
||||||
|
add_module_code(wam, compiler.module.take().unwrap(), module_code, indices);
|
||||||
update_module_indices(wam, module_name, indices);
|
|
||||||
|
|
||||||
wam.code_repo.code.extend(module_code.into_iter());
|
|
||||||
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
||||||
|
|
||||||
Ok(compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo))
|
Ok(compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo))
|
||||||
@@ -410,6 +360,7 @@ impl ClauseCodeGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// compiles the latest version of clause/2.
|
||||||
fn generate_clause_code(
|
fn generate_clause_code(
|
||||||
&mut self,
|
&mut self,
|
||||||
dynamic_clause_map: &DynamicClauseMap,
|
dynamic_clause_map: &DynamicClauseMap,
|
||||||
@@ -491,29 +442,15 @@ pub struct ListingCompiler {
|
|||||||
listing_src: ClauseName // a file? a module?
|
listing_src: ClauseName // a file? a module?
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_toplevel_code(wam: &mut Machine, code: Code, mut indices: IndexStore) {
|
fn add_toplevel_code(wam: &mut Machine, code: Code, indices: IndexStore) {
|
||||||
let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());
|
wam.add_batched_code(code, indices.code_dir);
|
||||||
let op_dir = mem::replace(&mut indices.op_dir, OpDir::new());
|
wam.add_batched_ops(indices.op_dir);
|
||||||
|
|
||||||
wam.add_batched_code(code, code_dir);
|
|
||||||
wam.add_batched_ops(op_dir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add_module_code(wam: &mut Machine, mut module: Module, code: Code, mut indices: IndexStore) {
|
fn add_module_code(wam: &mut Machine, mut module: Module, code: Code, indices: IndexStore) {
|
||||||
let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());
|
module.code_dir.extend(indices.code_dir);
|
||||||
let op_dir = mem::replace(&mut indices.op_dir, OpDir::new());
|
module.op_dir.extend(indices.op_dir.into_iter());
|
||||||
|
|
||||||
module.code_dir.extend(code_dir);
|
|
||||||
module.op_dir.extend(op_dir.into_iter());
|
|
||||||
|
|
||||||
for (name, arity) in indices.code_dir.keys().cloned() {
|
|
||||||
if name.owning_module() == module.module_decl.name {
|
|
||||||
wam.indices
|
|
||||||
.dynamic_code_dir
|
|
||||||
.swap_remove(&(name.owning_module(), name, arity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
wam.add_module(module, code);
|
wam.add_module(module, code);
|
||||||
}
|
}
|
||||||
@@ -543,9 +480,8 @@ fn load_library(
|
|||||||
) -> Result<ClauseName, SessionError> {
|
) -> Result<ClauseName, SessionError> {
|
||||||
match LIBRARIES.borrow().get(name.as_str()) {
|
match LIBRARIES.borrow().get(name.as_str()) {
|
||||||
Some(code) => {
|
Some(code) => {
|
||||||
let module_name = load_module(wam, parsing_stream(code.as_bytes()),
|
load_module(wam, parsing_stream(code.as_bytes()),
|
||||||
suppress_warnings, name.clone())?;
|
suppress_warnings, name.clone())
|
||||||
module_name.ok_or(SessionError::NoModuleDeclaration(name))
|
|
||||||
}
|
}
|
||||||
None => Err(SessionError::ModuleNotFound)
|
None => Err(SessionError::ModuleNotFound)
|
||||||
}
|
}
|
||||||
@@ -848,17 +784,11 @@ impl ListingCompiler {
|
|||||||
}
|
}
|
||||||
Declaration::UseModule(ModuleSource::File(filename)) => {
|
Declaration::UseModule(ModuleSource::File(filename)) => {
|
||||||
let name = load_module_from_file(wam, filename.as_str(), true)?;
|
let name = load_module_from_file(wam, filename.as_str(), true)?;
|
||||||
|
|
||||||
if let Some(name) = name {
|
|
||||||
self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices)
|
self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices)
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => {
|
Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => {
|
||||||
let name = load_module_from_file(wam, filename.as_str(), true)?;
|
let name = load_module_from_file(wam, filename.as_str(), true)?;
|
||||||
|
|
||||||
if let Some(name) = name {
|
|
||||||
self.use_qualified_module(
|
self.use_qualified_module(
|
||||||
name,
|
name,
|
||||||
&mut wam.code_repo,
|
&mut wam.code_repo,
|
||||||
@@ -867,9 +797,6 @@ impl ListingCompiler {
|
|||||||
&mut wam.indices,
|
&mut wam.indices,
|
||||||
indices,
|
indices,
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Declaration::ModuleInitialization(query_terms, queue) => {
|
Declaration::ModuleInitialization(query_terms, queue) => {
|
||||||
self.initialization_goals.0.extend(query_terms.into_iter());
|
self.initialization_goals.0.extend(query_terms.into_iter());
|
||||||
@@ -996,6 +923,7 @@ fn compile_work_impl(
|
|||||||
&mut indices.code_dir,
|
&mut indices.code_dir,
|
||||||
0
|
0
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let toplvl_code = compiler.generate_code(
|
let toplvl_code = compiler.generate_code(
|
||||||
results.toplevel_results,
|
results.toplevel_results,
|
||||||
wam,
|
wam,
|
||||||
@@ -1004,16 +932,24 @@ fn compile_work_impl(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(ref mut module) = &mut compiler.module {
|
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_term_expansions = results.addition_results.take_term_expansions();
|
||||||
module.user_goal_expansions = results.addition_results.take_goal_expansions();
|
module.user_goal_expansions = results.addition_results.take_goal_expansions();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let flags = wam.machine_flags();
|
let flags = wam.machine_flags();
|
||||||
|
|
||||||
wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags)?;
|
wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, flags)?;
|
||||||
wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags)?;
|
wam.code_repo.compile_hook(CompileTimeHook::UserGoalExpansion, flags)?;
|
||||||
|
|
||||||
if let Some(module) = compiler.module.take() {
|
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")
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
let mut clause_code_generator =
|
let mut clause_code_generator =
|
||||||
ClauseCodeGenerator::new(module_code.len() + toplvl_code.len(),
|
ClauseCodeGenerator::new(module_code.len() + toplvl_code.len(),
|
||||||
module.module_decl.name.clone());
|
module.module_decl.name.clone());
|
||||||
@@ -1021,9 +957,22 @@ fn compile_work_impl(
|
|||||||
wam.check_toplevel_code(&results.toplevel_indices)?;
|
wam.check_toplevel_code(&results.toplevel_indices)?;
|
||||||
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
|
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
|
||||||
|
|
||||||
add_module_code(wam, module, module_code, indices);
|
if let Some(ref module) = wam.indices.modules.swap_remove(&module.module_decl.name) {
|
||||||
add_toplevel_code(wam, toplvl_code, results.toplevel_indices);
|
wam.indices.remove_module(clause_name!("user"), module);
|
||||||
|
}
|
||||||
|
|
||||||
|
if module.is_impromptu_module {
|
||||||
|
add_module_code(wam, module, module_code, indices);
|
||||||
|
|
||||||
|
let module = wam.indices.take_module(compiler.listing_src.clone()).unwrap();
|
||||||
|
|
||||||
|
wam.indices.use_module(&mut wam.code_repo, wam.machine_st.flags, &module)?;
|
||||||
|
wam.indices.insert_module(module);
|
||||||
|
} else {
|
||||||
|
add_module_code(wam, module, module_code, indices);
|
||||||
|
}
|
||||||
|
|
||||||
|
add_toplevel_code(wam, toplvl_code, results.toplevel_indices);
|
||||||
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
|
||||||
} else {
|
} else {
|
||||||
add_non_module_code(
|
add_non_module_code(
|
||||||
@@ -1039,7 +988,10 @@ fn compile_work_impl(
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
if init_goal_code.len() > 0 {
|
if init_goal_code.len() > 0 {
|
||||||
wam.run_init_code(init_goal_code);
|
if !wam.run_init_code(init_goal_code) {
|
||||||
|
println!("Warning: initialization goal for {} failed",
|
||||||
|
compiler.listing_src);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !compiler.suppress_warnings {
|
if !compiler.suppress_warnings {
|
||||||
|
|||||||
@@ -76,16 +76,27 @@ impl Machine {
|
|||||||
output.result()
|
output.result()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_undefined(&mut self, name: ClauseName, arity: usize) {
|
||||||
|
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) {
|
fn abolish_dynamic_clause(&mut self, name: RegType, arity: RegType) {
|
||||||
let (name, arity) = self.get_predicate_key(name, arity);
|
let (name, arity) = self.get_predicate_key(name, arity);
|
||||||
|
|
||||||
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
|
self.make_undefined(name.clone(), arity);
|
||||||
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.indices.remove_code_index((name.clone(), arity));
|
self.indices.remove_code_index((name.clone(), arity));
|
||||||
self.indices
|
self.indices.remove_clause_subsection(name.owning_module(), name, arity);
|
||||||
.remove_clause_subsection(name.owning_module(), name, arity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
|
fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
|
||||||
@@ -106,15 +117,10 @@ impl Machine {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
|
self.make_undefined_in_module(module_name.clone(), name.clone(), arity);
|
||||||
if idx.module_name() == module_name {
|
|
||||||
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.indices.remove_code_index((name.clone(), arity));
|
self.indices.remove_code_index((name.clone(), arity));
|
||||||
self.indices
|
self.indices.remove_clause_subsection(module_name, name, arity);
|
||||||
.remove_clause_subsection(module_name, name, arity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_eval_result_from_dynamic_compile(
|
fn handle_eval_result_from_dynamic_compile(
|
||||||
@@ -210,6 +216,10 @@ impl Machine {
|
|||||||
let mut addrs = VecDeque::from(addrs);
|
let mut addrs = VecDeque::from(addrs);
|
||||||
addrs.remove(index);
|
addrs.remove(index);
|
||||||
|
|
||||||
|
if addrs.is_empty() {
|
||||||
|
self.make_undefined(name.clone(), arity);
|
||||||
|
}
|
||||||
|
|
||||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||||
}
|
}
|
||||||
Err(err) => return self.machine_st.throw_exception(err),
|
Err(err) => return self.machine_st.throw_exception(err),
|
||||||
@@ -239,6 +249,10 @@ impl Machine {
|
|||||||
let mut addrs = VecDeque::from(addrs);
|
let mut addrs = VecDeque::from(addrs);
|
||||||
addrs.remove(index);
|
addrs.remove(index);
|
||||||
|
|
||||||
|
if addrs.is_empty() {
|
||||||
|
self.make_undefined(name.clone(), arity);
|
||||||
|
}
|
||||||
|
|
||||||
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
self.print_new_dynamic_clause(addrs, name.clone(), arity)
|
||||||
}
|
}
|
||||||
Err(err) => return self.machine_st.throw_exception(err),
|
Err(err) => return self.machine_st.throw_exception(err),
|
||||||
|
|||||||
@@ -143,9 +143,6 @@ impl MachineError {
|
|||||||
"private_procedure",
|
"private_procedure",
|
||||||
clause_name!("module_does_not_exist"),
|
clause_name!("module_does_not_exist"),
|
||||||
),
|
),
|
||||||
SessionError::NoModuleDeclaration(name) => {
|
|
||||||
Self::existence_error(h, ExistenceError::Module(name))
|
|
||||||
}
|
|
||||||
SessionError::OpIsInfixAndPostFix(op) => {
|
SessionError::OpIsInfixAndPostFix(op) => {
|
||||||
Self::permission_error(PermissionError::Create, "operator", op)
|
Self::permission_error(PermissionError::Create, "operator", op)
|
||||||
}
|
}
|
||||||
@@ -538,18 +535,13 @@ pub enum SessionError {
|
|||||||
ModuleDoesNotContainExport,
|
ModuleDoesNotContainExport,
|
||||||
ModuleNotFound,
|
ModuleNotFound,
|
||||||
NamelessEntry,
|
NamelessEntry,
|
||||||
NoModuleDeclaration(ClauseName),
|
|
||||||
OpIsInfixAndPostFix(ClauseName),
|
OpIsInfixAndPostFix(ClauseName),
|
||||||
ParserError(ParserError),
|
ParserError(ParserError),
|
||||||
UserPrompt,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum EvalSession {
|
pub enum EvalSession {
|
||||||
EntrySuccess,
|
EntrySuccess,
|
||||||
Error(SessionError),
|
Error(SessionError),
|
||||||
InitialQuerySuccess(AllocVarDict),
|
|
||||||
QueryFailure,
|
|
||||||
SubsequentQuerySuccess,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SessionError> for EvalSession {
|
impl From<SessionError> for EvalSession {
|
||||||
|
|||||||
@@ -300,7 +300,6 @@ pub enum DynamicTransactionType {
|
|||||||
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
|
||||||
pub enum REPLCodePtr {
|
pub enum REPLCodePtr {
|
||||||
CompileBatch,
|
CompileBatch,
|
||||||
SubmitQueryAndPrintResults,
|
|
||||||
UseModule,
|
UseModule,
|
||||||
UseQualifiedModule,
|
UseQualifiedModule,
|
||||||
UseModuleFromFile,
|
UseModuleFromFile,
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ impl MachineState {
|
|||||||
Ok(codes)
|
Ok(codes)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_at_index(&mut self, arity: usize, p: usize) {
|
pub(super) fn call_at_index(&mut self, arity: usize, p: usize) {
|
||||||
self.cp.assign_if_local(self.p.clone() + 1);
|
self.cp.assign_if_local(self.p.clone() + 1);
|
||||||
self.num_of_args = arity;
|
self.num_of_args = arity;
|
||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
@@ -706,7 +706,7 @@ pub(crate) trait CallPolicy: Any {
|
|||||||
&BuiltInClauseType::Nl => {
|
&BuiltInClauseType::Nl => {
|
||||||
let mut stdout = stdout();
|
let mut stdout = stdout();
|
||||||
|
|
||||||
write!(stdout, "\n\r").unwrap();
|
write!(stdout, "\n").unwrap();
|
||||||
stdout.flush().unwrap();
|
stdout.flush().unwrap();
|
||||||
return_from_clause!(machine_st.last_call, machine_st)
|
return_from_clause!(machine_st.last_call, machine_st)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use crate::prolog::arithmetic::*;
|
|||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
use crate::prolog::heap_iter::*;
|
use crate::prolog::heap_iter::*;
|
||||||
use crate::prolog::heap_print::*;
|
|
||||||
use crate::prolog::instructions::*;
|
use crate::prolog::instructions::*;
|
||||||
use crate::prolog::machine::INTERRUPT;
|
use crate::prolog::machine::INTERRUPT;
|
||||||
use crate::prolog::machine::and_stack::*;
|
use crate::prolog::machine::and_stack::*;
|
||||||
@@ -27,7 +26,6 @@ use indexmap::{IndexMap, IndexSet};
|
|||||||
use std::cmp::{max, min, Ordering};
|
use std::cmp::{max, min, Ordering};
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
macro_rules! try_numeric_result {
|
macro_rules! try_numeric_result {
|
||||||
($s: ident, $e: expr, $caller: expr) => {{
|
($s: ident, $e: expr, $caller: expr) => {{
|
||||||
@@ -208,39 +206,6 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn print_var_eq<Outputter>(
|
|
||||||
&self,
|
|
||||||
var: Rc<Var>,
|
|
||||||
addr: Addr,
|
|
||||||
op_dir: &OpDir,
|
|
||||||
mut output: Outputter,
|
|
||||||
) -> Outputter
|
|
||||||
where
|
|
||||||
Outputter: HCValueOutputter,
|
|
||||||
{
|
|
||||||
let orig_len = output.len();
|
|
||||||
|
|
||||||
output.begin_new_var();
|
|
||||||
|
|
||||||
output.append(var.as_str());
|
|
||||||
output.append(" = ");
|
|
||||||
|
|
||||||
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
|
||||||
|
|
||||||
printer.numbervars = false;
|
|
||||||
printer.quoted = true;
|
|
||||||
|
|
||||||
let mut output = printer.print(addr);
|
|
||||||
|
|
||||||
let bad_ending = format!("= {}", &var);
|
|
||||||
|
|
||||||
if output.ends_with(&bad_ending) {
|
|
||||||
output.truncate(orig_len);
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn unify_strings(
|
pub(super) fn unify_strings(
|
||||||
&mut self,
|
&mut self,
|
||||||
pdl: &mut Vec<Addr>,
|
pdl: &mut Vec<Addr>,
|
||||||
@@ -741,29 +706,21 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let b = self.b - 1;
|
let b = self.b - 1;
|
||||||
let mut i = self.or_stack[b].tr;
|
|
||||||
|
|
||||||
while i < self.tr {
|
|
||||||
let tr_i = self.trail[i];
|
|
||||||
let hb = self.hb;
|
let hb = self.hb;
|
||||||
|
let mut offset = 0;
|
||||||
|
|
||||||
match tr_i {
|
for i in self.or_stack[b].tr .. self.tr {
|
||||||
|
match self.trail[i] {
|
||||||
TrailRef::Ref(Ref::AttrVar(tr_i))
|
TrailRef::Ref(Ref::AttrVar(tr_i))
|
||||||
| TrailRef::Ref(Ref::HeapCell(tr_i))
|
| TrailRef::Ref(Ref::HeapCell(tr_i))
|
||||||
| TrailRef::AttrVarHeapLink(tr_i)
|
| TrailRef::AttrVarHeapLink(tr_i)
|
||||||
| TrailRef::AttrVarListLink(tr_i, _) => {
|
| TrailRef::AttrVarListLink(tr_i, _) =>
|
||||||
if tr_i < hb {
|
if tr_i >= hb {
|
||||||
i += 1;
|
offset += 1;
|
||||||
} else {
|
} else {
|
||||||
let tr = self.tr;
|
self.trail[i - offset] = self.trail[i];
|
||||||
let val = self.trail[tr - 1].clone();
|
},
|
||||||
self.trail[i] = val;
|
|
||||||
self.trail.pop();
|
|
||||||
self.tr -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TrailRef::Ref(Ref::StackCell(fr, _)) => {
|
TrailRef::Ref(Ref::StackCell(fr, _)) => {
|
||||||
let b = self.b - 1;
|
|
||||||
let fr_gi = self.and_stack[fr].global_index;
|
let fr_gi = self.and_stack[fr].global_index;
|
||||||
let b_gi = if !self.or_stack.is_empty() {
|
let b_gi = if !self.or_stack.is_empty() {
|
||||||
self.or_stack[b].global_index
|
self.or_stack[b].global_index
|
||||||
@@ -771,20 +728,19 @@ impl MachineState {
|
|||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
if fr_gi < b_gi {
|
if fr_gi >= b_gi {
|
||||||
i += 1;
|
offset += 1;
|
||||||
} else {
|
} else {
|
||||||
let tr = self.tr;
|
self.trail[i - offset] = self.trail[i];
|
||||||
let val = self.trail[tr - 1];
|
|
||||||
self.trail[i] = val;
|
|
||||||
self.trail.pop();
|
|
||||||
self.tr -= 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.tr -= offset;
|
||||||
|
self.trail.truncate(self.tr);
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn write_char_to_string(&mut self, s: &mut StringList, c: char) -> bool {
|
fn write_char_to_string(&mut self, s: &mut StringList, c: char) -> bool {
|
||||||
self.pstr_trail(s.clone());
|
self.pstr_trail(s.clone());
|
||||||
@@ -949,6 +905,7 @@ impl MachineState {
|
|||||||
"mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)),
|
"mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)),
|
||||||
"rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)),
|
"rem" => interms.push(Number::Integer(self.remainder(a1, a2)?)),
|
||||||
"atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))),
|
"atan2" => interms.push(Number::Float(OrderedFloat(self.atan2(a1, a2)?))),
|
||||||
|
"gcd" => interms.push(Number::Integer(self.gcd(a1, a2)?)),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(self.error_form(MachineError::instantiation_error(), caller))
|
return Err(self.error_form(MachineError::instantiation_error(), caller))
|
||||||
}
|
}
|
||||||
@@ -976,6 +933,7 @@ impl MachineState {
|
|||||||
"ceiling" => interms.push(Number::Integer(self.ceiling(a1))),
|
"ceiling" => interms.push(Number::Integer(self.ceiling(a1))),
|
||||||
"floor" => interms.push(Number::Integer(self.floor(a1))),
|
"floor" => interms.push(Number::Integer(self.floor(a1))),
|
||||||
"\\" => interms.push(Number::Integer(self.bitwise_complement(a1)?)),
|
"\\" => interms.push(Number::Integer(self.bitwise_complement(a1)?)),
|
||||||
|
"sign" => interms.push(Number::Integer(self.sign(a1))),
|
||||||
_ => {
|
_ => {
|
||||||
return Err(self.error_form(MachineError::instantiation_error(), caller))
|
return Err(self.error_form(MachineError::instantiation_error(), caller))
|
||||||
}
|
}
|
||||||
@@ -1108,6 +1066,26 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn gcd(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
|
||||||
|
match (n1, n2) {
|
||||||
|
(Number::Integer(n1), Number::Integer(n2)) => {
|
||||||
|
Ok(n1.gcd(&n2))
|
||||||
|
}
|
||||||
|
(Number::Float(f), _) | (_, Number::Float(f)) => {
|
||||||
|
let n = Addr::Con(Constant::Float(f));
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
|
||||||
|
|
||||||
|
Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub))
|
||||||
|
}
|
||||||
|
(Number::Rational(r), _) | (_, Number::Rational(r)) => {
|
||||||
|
let n = Addr::Con(Constant::Rational(r));
|
||||||
|
let stub = MachineError::functor_stub(clause_name!("gcd"), 2);
|
||||||
|
|
||||||
|
Err(self.error_form(MachineError::type_error(ValidType::Integer, n), stub))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn float_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
|
fn float_pow(&self, n1: Number, n2: Number) -> Result<Number, MachineStub> {
|
||||||
let f1 = result_f(&n1, rnd_f);
|
let f1 = result_f(&n1, rnd_f);
|
||||||
let f2 = result_f(&n2, rnd_f);
|
let f2 = result_f(&n2, rnd_f);
|
||||||
@@ -1364,6 +1342,16 @@ impl MachineState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn sign(&self, n: Number) -> Integer {
|
||||||
|
if n.is_positive() {
|
||||||
|
Integer::from(1)
|
||||||
|
} else if n.is_negative() {
|
||||||
|
Integer::from(-1)
|
||||||
|
} else {
|
||||||
|
Integer::from(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn remainder(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
|
fn remainder(&self, n1: Number, n2: Number) -> Result<Integer, MachineStub> {
|
||||||
let stub = MachineError::functor_stub(clause_name!("(rem)"), 2);
|
let stub = MachineError::functor_stub(clause_name!("(rem)"), 2);
|
||||||
|
|
||||||
@@ -1449,6 +1437,13 @@ impl MachineState {
|
|||||||
self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2));
|
self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2));
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
|
&ArithmeticInstruction::Gcd(ref a1, ref a2, t) => {
|
||||||
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
let n2 = try_or_fail!(self, self.get_number(a2));
|
||||||
|
|
||||||
|
self.interms[t - 1] = Number::Integer(try_or_fail!(self, self.gcd(n1, n2)));
|
||||||
|
self.p += 1;
|
||||||
|
}
|
||||||
&ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
|
&ArithmeticInstruction::Pow(ref a1, ref a2, t) => {
|
||||||
let n1 = try_or_fail!(self, self.get_number(a1));
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
let n2 = try_or_fail!(self, self.get_number(a2));
|
let n2 = try_or_fail!(self, self.get_number(a2));
|
||||||
@@ -1486,6 +1481,12 @@ impl MachineState {
|
|||||||
self.interms[t - 1] = n1.abs();
|
self.interms[t - 1] = n1.abs();
|
||||||
self.p += 1;
|
self.p += 1;
|
||||||
}
|
}
|
||||||
|
&ArithmeticInstruction::Sign(ref a1, t) => {
|
||||||
|
let n = try_or_fail!(self, self.get_number(a1));
|
||||||
|
|
||||||
|
self.interms[t - 1] = Number::Integer(self.sign(n));
|
||||||
|
self.p += 1;
|
||||||
|
}
|
||||||
&ArithmeticInstruction::Neg(ref a1, t) => {
|
&ArithmeticInstruction::Neg(ref a1, t) => {
|
||||||
let n1 = try_or_fail!(self, self.get_number(a1));
|
let n1 = try_or_fail!(self, self.get_number(a1));
|
||||||
|
|
||||||
@@ -3240,6 +3241,8 @@ impl MachineState {
|
|||||||
)
|
)
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.last_call = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn execute_ctrl_instr(
|
pub(super) fn execute_ctrl_instr(
|
||||||
@@ -3275,7 +3278,7 @@ impl MachineState {
|
|||||||
self.b0 = self.b;
|
self.b0 = self.b;
|
||||||
self.p += offset;
|
self.p += offset;
|
||||||
}
|
}
|
||||||
&ControlInstruction::Proceed => self.p = CodePtr::Local(self.cp.clone()),
|
&ControlInstruction::Proceed => self.p = CodePtr::Local(self.cp.clone())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3434,56 +3437,4 @@ impl MachineState {
|
|||||||
self.heap_locs.clear();
|
self.heap_locs.clear();
|
||||||
self.lifted_heap.clear();
|
self.lifted_heap.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn sink_to_snapshot(&mut self) -> MachineState {
|
|
||||||
let mut snapshot = MachineState::with_capacity(0);
|
|
||||||
|
|
||||||
snapshot.hb = self.hb;
|
|
||||||
snapshot.e = self.e;
|
|
||||||
snapshot.b = self.b;
|
|
||||||
snapshot.b0 = self.b0;
|
|
||||||
snapshot.s = self.s;
|
|
||||||
snapshot.tr = self.tr;
|
|
||||||
snapshot.pstr_tr = self.pstr_tr;
|
|
||||||
snapshot.num_of_args = self.num_of_args;
|
|
||||||
|
|
||||||
snapshot.fail = self.fail;
|
|
||||||
snapshot.trail = mem::replace(&mut self.trail, vec![]);
|
|
||||||
snapshot.pstr_trail = mem::replace(&mut self.pstr_trail, vec![]);
|
|
||||||
snapshot.heap = self.heap.take();
|
|
||||||
snapshot.mode = self.mode;
|
|
||||||
snapshot.and_stack = self.and_stack.take();
|
|
||||||
snapshot.or_stack = self.or_stack.take();
|
|
||||||
snapshot.registers = mem::replace(&mut self.registers, vec![]);
|
|
||||||
snapshot.block = self.block;
|
|
||||||
|
|
||||||
snapshot.ball = self.ball.take();
|
|
||||||
snapshot.lifted_heap = mem::replace(&mut self.lifted_heap, vec![]);
|
|
||||||
|
|
||||||
snapshot
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
|
|
||||||
self.hb = snapshot.hb;
|
|
||||||
self.e = snapshot.e;
|
|
||||||
self.b = snapshot.b;
|
|
||||||
self.b0 = snapshot.b0;
|
|
||||||
self.s = snapshot.s;
|
|
||||||
self.tr = snapshot.tr;
|
|
||||||
self.pstr_tr = snapshot.pstr_tr;
|
|
||||||
self.num_of_args = snapshot.num_of_args;
|
|
||||||
|
|
||||||
self.fail = snapshot.fail;
|
|
||||||
self.trail = mem::replace(&mut snapshot.trail, vec![]);
|
|
||||||
self.pstr_trail = mem::replace(&mut snapshot.pstr_trail, vec![]);
|
|
||||||
self.heap = snapshot.heap.take();
|
|
||||||
self.mode = snapshot.mode;
|
|
||||||
self.and_stack = snapshot.and_stack.take();
|
|
||||||
self.or_stack = snapshot.or_stack.take();
|
|
||||||
self.registers = mem::replace(&mut snapshot.registers, vec![]);
|
|
||||||
self.block = snapshot.block;
|
|
||||||
|
|
||||||
self.ball = snapshot.ball.take();
|
|
||||||
self.lifted_heap = mem::replace(&mut snapshot.lifted_heap, vec![]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ use prolog_parser::ast::*;
|
|||||||
use prolog_parser::tabled_rc::*;
|
use prolog_parser::tabled_rc::*;
|
||||||
|
|
||||||
use crate::prolog::clause_types::*;
|
use crate::prolog::clause_types::*;
|
||||||
use crate::prolog::fixtures::*;
|
|
||||||
use crate::prolog::forms::*;
|
use crate::prolog::forms::*;
|
||||||
use crate::prolog::heap_print::*;
|
use crate::prolog::heap_print::*;
|
||||||
use crate::prolog::instructions::*;
|
use crate::prolog::instructions::*;
|
||||||
|
use crate::prolog::machine::heap::Heap;
|
||||||
use crate::prolog::read::*;
|
use crate::prolog::read::*;
|
||||||
use crate::prolog::write::{next_keypress, ContinueResult};
|
|
||||||
|
|
||||||
mod and_stack;
|
mod and_stack;
|
||||||
mod attributed_variables;
|
mod attributed_variables;
|
||||||
@@ -35,21 +34,18 @@ use crate::prolog::machine::machine_errors::*;
|
|||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
use crate::prolog::machine::machine_state::*;
|
use crate::prolog::machine::machine_state::*;
|
||||||
use crate::prolog::machine::modules::*;
|
use crate::prolog::machine::modules::*;
|
||||||
use crate::prolog::machine::toplevel::stream_to_toplevel;
|
|
||||||
use crate::prolog::read::PrologStream;
|
use crate::prolog::read::PrologStream;
|
||||||
|
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{stdout, Read, Write};
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::ops::Index;
|
use std::ops::Index;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::atomic::AtomicBool;
|
use std::sync::atomic::AtomicBool;
|
||||||
|
|
||||||
use termion::raw::IntoRawMode;
|
|
||||||
|
|
||||||
pub struct MachinePolicies {
|
pub struct MachinePolicies {
|
||||||
call_policy: Box<dyn CallPolicy>,
|
call_policy: Box<dyn CallPolicy>,
|
||||||
cut_policy: Box<dyn CutPolicy>,
|
cut_policy: Box<dyn CutPolicy>,
|
||||||
@@ -71,6 +67,7 @@ impl MachinePolicies {
|
|||||||
|
|
||||||
pub struct Machine {
|
pub struct Machine {
|
||||||
pub(super) machine_st: MachineState,
|
pub(super) machine_st: MachineState,
|
||||||
|
pub(super) inner_heap: Heap,
|
||||||
pub(super) policies: MachinePolicies,
|
pub(super) policies: MachinePolicies,
|
||||||
pub(super) indices: IndexStore,
|
pub(super) indices: IndexStore,
|
||||||
pub(super) code_repo: CodeRepo,
|
pub(super) code_repo: CodeRepo,
|
||||||
@@ -126,7 +123,7 @@ impl SubModuleUser for IndexStore {
|
|||||||
fn insert_dir_entry(&mut self, name: ClauseName, arity: usize, idx: CodeIndex) {
|
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 let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
|
||||||
if !code_idx.is_undefined() {
|
if !code_idx.is_undefined() {
|
||||||
println!("warning: overwriting {}/{}", &name, arity);
|
println!("Warning: overwriting {}/{}", &name, arity);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (p, module_name) = idx.0.borrow().clone();
|
let (p, module_name) = idx.0.borrow().clone();
|
||||||
@@ -182,7 +179,8 @@ impl Machine {
|
|||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
self.machine_st.attr_var_init.verify_attrs_loc = p;
|
self.machine_st.attr_var_init.verify_attrs_loc = p;
|
||||||
}
|
}
|
||||||
Err(_) => panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
|
Err(_) =>
|
||||||
|
panic!("Machine::compile_special_forms() failed at VERIFY_ATTRS"),
|
||||||
}
|
}
|
||||||
|
|
||||||
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
|
match compile_special_form(self, parsing_stream(PROJECT_ATTRS.as_bytes()), project_attrs_src)
|
||||||
@@ -190,14 +188,28 @@ impl Machine {
|
|||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
self.machine_st.attr_var_init.project_attrs_loc = p;
|
self.machine_st.attr_var_init.project_attrs_loc = p;
|
||||||
}
|
}
|
||||||
Err(e) => panic!("Machine::compile_special_forms() failed at PROJECT_ATTRS: {}", e),
|
Err(e) =>
|
||||||
|
panic!("Machine::compile_special_forms() failed at PROJECT_ATTRS: {}", e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_top_level(&mut self) {
|
fn compile_top_level(&mut self) -> Result<(), SessionError>
|
||||||
|
{
|
||||||
self.toplevel_idx = self.code_repo.code.len();
|
self.toplevel_idx = self.code_repo.code.len();
|
||||||
compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()),
|
compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()),
|
||||||
true, clause_name!("toplevel.pl"));
|
true, clause_name!("toplevel.pl"));
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Err(SessionError::ModuleNotFound)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_scryerrc(&mut self) {
|
fn compile_scryerrc(&mut self) {
|
||||||
@@ -226,14 +238,17 @@ impl Machine {
|
|||||||
self.machine_st.reset();
|
self.machine_st.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_init_code(&mut self, code: Code) {
|
pub fn run_init_code(&mut self, code: Code) -> bool {
|
||||||
let old_machine_st = self.machine_st.sink_to_snapshot();
|
let old_machine_st = self.sink_to_snapshot();
|
||||||
self.machine_st.reset();
|
self.machine_st.reset();
|
||||||
|
|
||||||
self.code_repo.cached_query = code;
|
self.code_repo.cached_query = code;
|
||||||
self.run_query(&AllocVarDict::new());
|
self.run_query();
|
||||||
|
|
||||||
self.machine_st.absorb_snapshot(old_machine_st);
|
let result = self.machine_st.fail;
|
||||||
|
self.absorb_snapshot(old_machine_st);
|
||||||
|
|
||||||
|
!result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_top_level(&mut self) {
|
pub fn run_top_level(&mut self) {
|
||||||
@@ -254,12 +269,13 @@ impl Machine {
|
|||||||
self.machine_st[temp_v!(1)] = list_addr;
|
self.machine_st[temp_v!(1)] = list_addr;
|
||||||
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
|
self.machine_st.p = CodePtr::Local(LocalCodePtr::DirEntry(self.toplevel_idx));
|
||||||
|
|
||||||
self.run_query(&AllocVarDict::new());
|
self.run_query();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(prolog_stream: PrologStream) -> Self {
|
pub fn new(prolog_stream: PrologStream) -> Self {
|
||||||
let mut wam = Machine {
|
let mut wam = Machine {
|
||||||
machine_st: MachineState::new(),
|
machine_st: MachineState::new(),
|
||||||
|
inner_heap: Heap::with_capacity(256 * 256),
|
||||||
policies: MachinePolicies::new(),
|
policies: MachinePolicies::new(),
|
||||||
indices: IndexStore::new(),
|
indices: IndexStore::new(),
|
||||||
code_repo: CodeRepo::new(),
|
code_repo: CodeRepo::new(),
|
||||||
@@ -288,7 +304,10 @@ impl Machine {
|
|||||||
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
|
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
|
||||||
clause_name!("si"));
|
clause_name!("si"));
|
||||||
|
|
||||||
wam.compile_top_level();
|
if wam.compile_top_level().is_err() {
|
||||||
|
panic!("Loading '$toplevel' module failed");
|
||||||
|
}
|
||||||
|
|
||||||
wam.compile_scryerrc();
|
wam.compile_scryerrc();
|
||||||
|
|
||||||
wam
|
wam
|
||||||
@@ -370,17 +389,6 @@ impl Machine {
|
|||||||
self.code_repo.code.extend(code.into_iter());
|
self.code_repo.code.extend(code.into_iter());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn submit_query(&mut self, code: Code, alloc_locs: AllocVarDict) -> EvalSession {
|
|
||||||
self.code_repo.cached_query = code;
|
|
||||||
self.run_query(&alloc_locs);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
|
||||||
EvalSession::QueryFailure
|
|
||||||
} else {
|
|
||||||
EvalSession::InitialQuerySuccess(alloc_locs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
fn throw_session_error(&mut self, err: SessionError, key: PredicateKey) {
|
||||||
let h = self.machine_st.heap.h;
|
let h = self.machine_st.heap.h;
|
||||||
|
|
||||||
@@ -440,29 +448,27 @@ impl Machine {
|
|||||||
|
|
||||||
let load_result = match to_src(name) {
|
let load_result = match to_src(name) {
|
||||||
ModuleSource::Library(name) =>
|
ModuleSource::Library(name) =>
|
||||||
if !self.indices.modules.contains_key(&name) {
|
if let Some(module) = self.indices.take_module(name.clone()) {
|
||||||
load_library(self, name, false).map(Some)
|
self.indices.remove_module(clause_name!("user"), &module);
|
||||||
|
self.indices.modules.insert(name.clone(), module);
|
||||||
|
|
||||||
|
Ok(name)
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(name))
|
load_library(self, name, false)
|
||||||
},
|
},
|
||||||
ModuleSource::File(name) =>
|
ModuleSource::File(name) =>
|
||||||
load_module_from_file(self, name.as_str(), false)
|
load_module_from_file(self, name.as_str(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_result.and_then(|name|
|
let result = load_result.and_then(|name| {
|
||||||
if let Some(name) = name {
|
let module = self.indices.take_module(name.clone()).unwrap();
|
||||||
let module = self.indices.take_module(name).unwrap();
|
|
||||||
|
|
||||||
// remove previous exports.
|
if !module.is_impromptu_module {
|
||||||
self.indices.remove_module(clause_name!("user"), &module);
|
self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?;
|
||||||
self.indices.use_module(&mut self.code_repo, self.machine_st.flags,
|
}
|
||||||
&module)?;
|
|
||||||
|
|
||||||
Ok(self.indices.insert_module(module))
|
Ok(self.indices.insert_module(module))
|
||||||
} else {
|
});
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
|
|
||||||
@@ -487,31 +493,30 @@ impl Machine {
|
|||||||
|
|
||||||
let load_result = match to_src(name) {
|
let load_result = match to_src(name) {
|
||||||
ModuleSource::Library(name) =>
|
ModuleSource::Library(name) =>
|
||||||
if !self.indices.modules.contains_key(&name) {
|
if let Some(module) = self.indices.take_module(name.clone()) {
|
||||||
load_library(self, name, false).map(Some)
|
self.indices.remove_module(clause_name!("user"), &module);
|
||||||
|
self.indices.modules.insert(name.clone(), module);
|
||||||
|
|
||||||
|
Ok(name)
|
||||||
} else {
|
} else {
|
||||||
Ok(Some(name))
|
load_library(self, name, false)
|
||||||
},
|
},
|
||||||
ModuleSource::File(name) =>
|
ModuleSource::File(name) =>
|
||||||
load_module_from_file(self, name.as_str(), false)
|
load_module_from_file(self, name.as_str(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let result = load_result.and_then(|name|
|
let result = load_result.and_then(|name| {
|
||||||
if let Some(name) = name {
|
let module = self.indices.take_module(name.clone()).unwrap();
|
||||||
let module = self.indices.take_module(name).unwrap();
|
|
||||||
|
|
||||||
// remove previous exports.
|
if !module.is_impromptu_module {
|
||||||
self.indices.remove_module(clause_name!("user"), &module);
|
|
||||||
self.indices.use_qualified_module(&mut self.code_repo,
|
self.indices.use_qualified_module(&mut self.code_repo,
|
||||||
self.machine_st.flags,
|
self.machine_st.flags,
|
||||||
&module,
|
&module,
|
||||||
&exports)?;
|
&exports)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(self.indices.insert_module(module))
|
Ok(self.indices.insert_module(module))
|
||||||
} else {
|
});
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
|
|
||||||
@@ -532,55 +537,6 @@ impl Machine {
|
|||||||
self.throw_session_error(e, (clause_name!("repl"), 0));
|
self.throw_session_error(e, (clause_name!("repl"), 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
REPLCodePtr::SubmitQueryAndPrintResults => {
|
|
||||||
let term = self.machine_st[temp_v!(1)].clone();
|
|
||||||
let stub = MachineError::functor_stub(clause_name!("repl"), 0);
|
|
||||||
|
|
||||||
let s = match self.machine_st.try_from_list(temp_v!(2), stub) {
|
|
||||||
Ok(addrs) => {
|
|
||||||
let mut var_dict = HeapVarDict::new();
|
|
||||||
|
|
||||||
for addr in addrs {
|
|
||||||
match addr {
|
|
||||||
Addr::Str(s) => {
|
|
||||||
let var_atom = match self.machine_st.heap[s + 1].as_addr(s + 1)
|
|
||||||
{
|
|
||||||
Addr::Con(Constant::Atom(var_atom, _)) => {
|
|
||||||
Rc::new(var_atom.to_string())
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let var_addr = self.machine_st.heap[s + 2].as_addr(s + 2);
|
|
||||||
var_dict.insert(var_atom, var_addr);
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.heap_locs = var_dict;
|
|
||||||
let term_output = self.machine_st.print_query(term, &self.indices.op_dir);
|
|
||||||
|
|
||||||
term_output.result()
|
|
||||||
}
|
|
||||||
Err(err_stub) => {
|
|
||||||
self.machine_st.throw_exception(err_stub);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let stream = parsing_stream(s.as_bytes());
|
|
||||||
|
|
||||||
let snapshot = self.machine_st.sink_to_snapshot();
|
|
||||||
self.machine_st.reset();
|
|
||||||
|
|
||||||
let result = match stream_to_toplevel(stream, self) {
|
|
||||||
Ok(packet) => compile_term(self, packet),
|
|
||||||
Err(e) => EvalSession::from(e),
|
|
||||||
};
|
|
||||||
|
|
||||||
self.handle_eval_session(result, snapshot);
|
|
||||||
}
|
|
||||||
REPLCodePtr::UseModule =>
|
REPLCodePtr::UseModule =>
|
||||||
self.use_module(ModuleSource::Library),
|
self.use_module(ModuleSource::Library),
|
||||||
REPLCodePtr::UseModuleFromFile =>
|
REPLCodePtr::UseModuleFromFile =>
|
||||||
@@ -594,157 +550,78 @@ impl Machine {
|
|||||||
self.machine_st.p = CodePtr::Local(p);
|
self.machine_st.p = CodePtr::Local(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn propagate_exception_to_toplevel(&mut self, snapshot: MachineState) {
|
fn sink_to_snapshot(&mut self) -> MachineState {
|
||||||
let ball = self.machine_st.ball.take();
|
let mut snapshot = MachineState::with_capacity(0);
|
||||||
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
snapshot.hb = self.machine_st.hb;
|
||||||
self.machine_st.ball = ball;
|
snapshot.e = self.machine_st.e;
|
||||||
|
snapshot.b = self.machine_st.b;
|
||||||
|
snapshot.b0 = self.machine_st.b0;
|
||||||
|
snapshot.s = self.machine_st.s;
|
||||||
|
snapshot.tr = self.machine_st.tr;
|
||||||
|
snapshot.pstr_tr = self.machine_st.pstr_tr;
|
||||||
|
snapshot.p = self.machine_st.p.clone();
|
||||||
|
snapshot.cp = self.machine_st.cp;
|
||||||
|
snapshot.attr_var_init = mem::replace(
|
||||||
|
&mut self.machine_st.attr_var_init,
|
||||||
|
AttrVarInitializer::new(0, 0)
|
||||||
|
);
|
||||||
|
snapshot.num_of_args = self.machine_st.num_of_args;
|
||||||
|
|
||||||
let h = self.machine_st.heap.h;
|
snapshot.fail = self.machine_st.fail;
|
||||||
let stub = self.machine_st.ball.copy_and_align(h);
|
snapshot.trail = mem::replace(&mut self.machine_st.trail, vec![]);
|
||||||
|
snapshot.pstr_trail = mem::replace(&mut self.machine_st.pstr_trail, vec![]);
|
||||||
|
snapshot.heap = self.machine_st.heap.take();
|
||||||
|
snapshot.mode = self.machine_st.mode;
|
||||||
|
snapshot.and_stack = self.machine_st.and_stack.take();
|
||||||
|
snapshot.or_stack = self.machine_st.or_stack.take();
|
||||||
|
snapshot.registers = mem::replace(&mut self.machine_st.registers, vec![]);
|
||||||
|
snapshot.block = self.machine_st.block;
|
||||||
|
|
||||||
self.machine_st.throw_exception(stub);
|
snapshot.ball = self.machine_st.ball.take();
|
||||||
|
snapshot.heap_locs = mem::replace(&mut self.machine_st.heap_locs, IndexMap::new());
|
||||||
|
snapshot.lifted_heap = mem::replace(&mut self.machine_st.lifted_heap, vec![]);
|
||||||
|
|
||||||
return;
|
snapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_eval_session(&mut self, result: EvalSession, snapshot: MachineState) {
|
fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
|
||||||
match result {
|
self.machine_st.hb = snapshot.hb;
|
||||||
EvalSession::InitialQuerySuccess(alloc_locs) => loop {
|
self.machine_st.e = snapshot.e;
|
||||||
let bindings = {
|
self.machine_st.b = snapshot.b;
|
||||||
let output = PrinterOutputter::new();
|
self.machine_st.b0 = snapshot.b0;
|
||||||
self.toplevel_heap_view(output).result()
|
self.machine_st.s = snapshot.s;
|
||||||
};
|
self.machine_st.tr = snapshot.tr;
|
||||||
|
self.machine_st.pstr_tr = snapshot.pstr_tr;
|
||||||
|
self.machine_st.p = snapshot.p;
|
||||||
|
self.machine_st.cp = snapshot.cp;
|
||||||
|
self.machine_st.attr_var_init = snapshot.attr_var_init;
|
||||||
|
self.machine_st.num_of_args = snapshot.num_of_args;
|
||||||
|
|
||||||
let attr_goals = self.attribute_goals();
|
self.machine_st.fail = snapshot.fail;
|
||||||
|
self.machine_st.trail = mem::replace(&mut snapshot.trail, vec![]);
|
||||||
|
self.machine_st.pstr_trail = mem::replace(&mut snapshot.pstr_trail, vec![]);
|
||||||
|
|
||||||
if !(self.machine_st.b > 0) {
|
self.inner_heap = self.machine_st.heap.take();
|
||||||
if bindings.is_empty() {
|
self.inner_heap.truncate(0);
|
||||||
let space = if requires_space(&attr_goals, ".") {
|
|
||||||
" "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
|
|
||||||
if !attr_goals.is_empty() {
|
self.machine_st.heap = snapshot.heap.take();
|
||||||
println!("{}{}.", attr_goals, space);
|
self.machine_st.mode = snapshot.mode;
|
||||||
} else {
|
self.machine_st.and_stack = snapshot.and_stack.take();
|
||||||
println!("true.");
|
self.machine_st.or_stack = snapshot.or_stack.take();
|
||||||
|
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.heap_locs = mem::replace(&mut snapshot.heap_locs, IndexMap::new());
|
||||||
|
self.machine_st.lifted_heap = mem::replace(&mut snapshot.lifted_heap, vec![]);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
pub(super) fn run_query(&mut self) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else if bindings.is_empty() && attr_goals.is_empty() {
|
|
||||||
print!("true");
|
|
||||||
stdout().flush().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
if !attr_goals.is_empty() {
|
|
||||||
if bindings.is_empty() {
|
|
||||||
print!("{}", attr_goals);
|
|
||||||
} else {
|
|
||||||
print!("{}, {}", bindings, attr_goals);
|
|
||||||
}
|
|
||||||
} else if !bindings.is_empty() {
|
|
||||||
print!("{}", bindings);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.machine_st.b > 0 {
|
|
||||||
let keypress = {
|
|
||||||
let mut raw_stdout = stdout().into_raw_mode().unwrap();
|
|
||||||
raw_stdout.flush().unwrap();
|
|
||||||
next_keypress()
|
|
||||||
};
|
|
||||||
|
|
||||||
let result = match keypress {
|
|
||||||
ContinueResult::ContinueQuery => {
|
|
||||||
print!(" ;\r\n");
|
|
||||||
self.continue_query(&alloc_locs)
|
|
||||||
}
|
|
||||||
ContinueResult::Conclude => {
|
|
||||||
print!(" ...\r\n");
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
EvalSession::QueryFailure => {
|
|
||||||
if self.machine_st.ball.stub.len() > 0 {
|
|
||||||
self.propagate_exception_to_toplevel(snapshot);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
print!("false.\r\n");
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EvalSession::Error(err) => {
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
|
||||||
self.throw_session_error(err, (clause_name!("repl"), 0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if bindings.is_empty() && attr_goals.is_empty() {
|
|
||||||
print!("true.\r\n");
|
|
||||||
} else {
|
|
||||||
let space = if !attr_goals.is_empty() {
|
|
||||||
if requires_space(&attr_goals, ".") {
|
|
||||||
" "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if requires_space(&bindings, ".") {
|
|
||||||
" "
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
print!("{}.\r\n", space);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
EvalSession::Error(err) => {
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
|
||||||
self.throw_session_error(err, (clause_name!("repl"), 0));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
EvalSession::QueryFailure =>
|
|
||||||
if self.machine_st.ball.stub.len() > 0 {
|
|
||||||
return self.propagate_exception_to_toplevel(snapshot);
|
|
||||||
} else {
|
|
||||||
println!("false.");
|
|
||||||
},
|
|
||||||
_ => println!("true.")
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.absorb_snapshot(snapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(super) fn run_query(&mut self, alloc_locs: &AllocVarDict) {
|
|
||||||
self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
|
self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
|
||||||
let end_ptr = CodePtr::Local(self.machine_st.cp);
|
let end_ptr = CodePtr::Local(self.machine_st.cp);
|
||||||
|
|
||||||
while self.machine_st.p < end_ptr {
|
while self.machine_st.p < end_ptr {
|
||||||
if let CodePtr::Local(LocalCodePtr::TopLevel(mut cn, p)) = self.machine_st.p {
|
|
||||||
match &self.code_repo[LocalCodePtr::TopLevel(cn, p)] {
|
|
||||||
&Line::Control(ref ctrl_instr) if ctrl_instr.is_jump_instr() => {
|
|
||||||
self.machine_st.record_var_places(cn, alloc_locs);
|
|
||||||
cn += 1;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.p = top_level_code_ptr!(cn, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.machine_st.query_stepper(
|
self.machine_st.query_stepper(
|
||||||
&mut self.indices,
|
&mut self.indices,
|
||||||
&mut self.policies,
|
&mut self.policies,
|
||||||
@@ -763,63 +640,18 @@ impl Machine {
|
|||||||
self.dynamic_transaction(trans_type, p);
|
self.dynamic_transaction(trans_type, p);
|
||||||
|
|
||||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
|
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
|
||||||
if self.machine_st.heap_locs.is_empty() {
|
|
||||||
self.machine_st.record_var_places(0, alloc_locs);
|
|
||||||
}
|
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.code_repo.cached_query = cached_query;
|
self.code_repo.cached_query = cached_query;
|
||||||
}
|
}
|
||||||
_ => {
|
_ =>
|
||||||
if self.machine_st.heap_locs.is_empty() {
|
break
|
||||||
self.machine_st.record_var_places(0, alloc_locs);
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn continue_query(&mut self, alloc_locs: &AllocVarDict) -> EvalSession {
|
|
||||||
if !self.or_stack_is_empty() {
|
|
||||||
let b = self.machine_st.b - 1;
|
|
||||||
self.machine_st.p = self.machine_st.or_stack[b].bp.clone();
|
|
||||||
|
|
||||||
if let CodePtr::Local(LocalCodePtr::TopLevel(_, 0)) = self.machine_st.p {
|
|
||||||
self.machine_st.fail = true;
|
|
||||||
return EvalSession::QueryFailure;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.run_query(alloc_locs);
|
|
||||||
|
|
||||||
if self.machine_st.fail {
|
|
||||||
EvalSession::QueryFailure
|
|
||||||
} else {
|
|
||||||
EvalSession::SubsequentQuerySuccess
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
EvalSession::QueryFailure
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn toplevel_heap_view<Outputter>(&self, mut output: Outputter) -> Outputter
|
|
||||||
where
|
|
||||||
Outputter: HCValueOutputter,
|
|
||||||
{
|
|
||||||
for (var, addr) in self.machine_st.heap_locs.iter() {
|
|
||||||
let addr = self.machine_st.store(self.machine_st.deref(addr.clone()));
|
|
||||||
output = self
|
|
||||||
.machine_st
|
|
||||||
.print_var_eq(var.clone(), addr, &self.indices.op_dir, output);
|
|
||||||
}
|
|
||||||
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn test_heap_view<Outputter>(&self, mut output: Outputter) -> Outputter
|
pub fn test_heap_view<Outputter>(&self, mut output: Outputter) -> Outputter
|
||||||
where
|
where
|
||||||
@@ -836,63 +668,9 @@ impl Machine {
|
|||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn or_stack_is_empty(&self) -> bool {
|
|
||||||
self.machine_st.b == 0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MachineState {
|
impl MachineState {
|
||||||
fn record_var_places(&mut self, chunk_num: usize, alloc_locs: &AllocVarDict) {
|
|
||||||
for (var, var_data) in alloc_locs {
|
|
||||||
match var_data {
|
|
||||||
&VarData::Perm(p) if p > 0 => {
|
|
||||||
if !self.heap_locs.contains_key(var) {
|
|
||||||
let e = self.e;
|
|
||||||
let r = var_data.as_reg_type().reg_num();
|
|
||||||
let addr = self.and_stack[e][r].clone();
|
|
||||||
|
|
||||||
self.heap_locs.insert(var.clone(), addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&VarData::Temp(cn, _, _) if cn == chunk_num => {
|
|
||||||
let r = var_data.as_reg_type();
|
|
||||||
|
|
||||||
if r.reg_num() != 0 {
|
|
||||||
let addr = self[r].clone();
|
|
||||||
self.heap_locs.insert(var.clone(), addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn print_query(&mut self, addr: Addr, op_dir: &OpDir) -> PrinterOutputter {
|
|
||||||
let flags = self.flags;
|
|
||||||
|
|
||||||
let mut output = {
|
|
||||||
self.flags = MachineFlags {
|
|
||||||
double_quotes: DoubleQuotes::Atom,
|
|
||||||
};
|
|
||||||
|
|
||||||
let output = PrinterOutputter::new();
|
|
||||||
let mut printer = HCPrinter::from_heap_locs(&self, op_dir, output);
|
|
||||||
|
|
||||||
printer.quoted = true;
|
|
||||||
printer.numbervars = false;
|
|
||||||
printer.drop_toplevel_spec();
|
|
||||||
|
|
||||||
printer.see_all_locs();
|
|
||||||
printer.print(addr)
|
|
||||||
};
|
|
||||||
|
|
||||||
self.flags = flags;
|
|
||||||
|
|
||||||
output.append(".");
|
|
||||||
output
|
|
||||||
}
|
|
||||||
|
|
||||||
fn dispatch_instr(
|
fn dispatch_instr(
|
||||||
&mut self,
|
&mut self,
|
||||||
instr: &Line,
|
instr: &Line,
|
||||||
@@ -1048,7 +826,13 @@ impl MachineState {
|
|||||||
CodePtr::VerifyAttrInterrupt(_) => {
|
CodePtr::VerifyAttrInterrupt(_) => {
|
||||||
self.p = CodePtr::Local(self.attr_var_init.cp);
|
self.p = CodePtr::Local(self.attr_var_init.cp);
|
||||||
|
|
||||||
if !self.verify_attr_stepper(indices, policies, code_repo, prolog_stream) {
|
let instigating_p = CodePtr::Local(self.attr_var_init.instigating_p);
|
||||||
|
let instigating_instr = code_repo.lookup_instr(false, &instigating_p).unwrap();
|
||||||
|
|
||||||
|
if !instigating_instr.as_ref().is_head_instr() {
|
||||||
|
let cp = self.p.local();
|
||||||
|
self.run_verify_attr_interrupt(cp);
|
||||||
|
} else if !self.verify_attr_stepper(indices, policies, code_repo, prolog_stream) {
|
||||||
if self.fail {
|
if self.fail {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ impl Module {
|
|||||||
code_dir: CodeDir::new(),
|
code_dir: CodeDir::new(),
|
||||||
op_dir: default_op_dir(),
|
op_dir: default_op_dir(),
|
||||||
inserted_expansions: false,
|
inserted_expansions: false,
|
||||||
|
is_impromptu_module: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +163,7 @@ pub trait SubModuleUser {
|
|||||||
self.insert_dir_entry(name, arity, code_data.clone());
|
self.insert_dir_entry(name, arity, code_data.clone());
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
found_op
|
found_op || submodule.is_impromptu_module
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
driver(QueryVars, AttrVars) :-
|
'$attribute_goals_driver'(QueryVars, AttrVars) :-
|
||||||
gather_modules(AttrVars, Modules0, _),
|
gather_modules(AttrVars, Modules0, _),
|
||||||
sort(Modules0, Modules),
|
sort(Modules0, Modules),
|
||||||
call_project_attributes(Modules, QueryVars, AttrVars),
|
call_project_attributes(Modules, QueryVars, AttrVars),
|
||||||
call_attribute_goals(Modules, call_query_var_goals, QueryVars),
|
call_attribute_goals(Modules, call_query_var_goals, QueryVars),
|
||||||
call_attribute_goals(Modules, call_attr_var_goals, AttrVars),
|
call_attribute_goals(Modules, call_attr_var_goals, AttrVars).
|
||||||
'$return_from_attribute_goals'.
|
|
||||||
|
|
||||||
enqueue_goals(Goals0) :-
|
enqueue_goals(Goals0) :-
|
||||||
nonvar(Goals0),
|
nonvar(Goals0),
|
||||||
|
|||||||
@@ -22,11 +22,34 @@ use crate::ref_thread_local::RefThreadLocal;
|
|||||||
use indexmap::{IndexMap, IndexSet};
|
use indexmap::{IndexMap, IndexSet};
|
||||||
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io::{stdout, Write};
|
use std::io::{stdin, stdout, Write};
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::termion::event::Key;
|
||||||
|
use crate::termion::input::TermRead;
|
||||||
|
use crate::termion::raw::IntoRawMode;
|
||||||
|
|
||||||
|
pub enum ContinueResult {
|
||||||
|
ContinueQuery,
|
||||||
|
Conclude,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn next_keypress() -> ContinueResult {
|
||||||
|
let stdin = stdin();
|
||||||
|
|
||||||
|
for c in stdin.keys() {
|
||||||
|
match c.unwrap() {
|
||||||
|
Key::Char(' ') | Key::Char(';') => return ContinueResult::ContinueQuery,
|
||||||
|
Key::Char('.') => return ContinueResult::Conclude,
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContinueResult::Conclude
|
||||||
|
}
|
||||||
|
|
||||||
struct BrentAlgState {
|
struct BrentAlgState {
|
||||||
hare: usize,
|
hare: usize,
|
||||||
tortoise: usize,
|
tortoise: usize,
|
||||||
@@ -716,6 +739,17 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify(a2, Addr::Con(Constant::Integer(len)));
|
self.unify(a2, Addr::Con(Constant::Integer(len)));
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::CallAttributeGoals => {
|
||||||
|
let p = self.attr_var_init.project_attrs_loc;
|
||||||
|
|
||||||
|
if self.last_call {
|
||||||
|
self.execute_at_index(2, p);
|
||||||
|
} else {
|
||||||
|
self.call_at_index(2, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
&SystemClauseType::CharsToNumber => {
|
&SystemClauseType::CharsToNumber => {
|
||||||
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
|
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
|
||||||
|
|
||||||
@@ -1329,6 +1363,17 @@ impl MachineState {
|
|||||||
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
|
||||||
self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList))
|
self.truncate_if_no_lifted_heap_diff(|_| Addr::Con(Constant::EmptyList))
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::FetchAttributeGoals => {
|
||||||
|
let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]);
|
||||||
|
|
||||||
|
attr_goals.sort_unstable_by(|a1, a2| self.compare_term_test(a1, a2));
|
||||||
|
self.term_dedup(&mut attr_goals);
|
||||||
|
|
||||||
|
let attr_goals = Addr::HeapCell(self.heap.to_list(attr_goals.into_iter()));
|
||||||
|
let target = self[temp_v!(1)].clone();
|
||||||
|
|
||||||
|
self.unify(attr_goals, target);
|
||||||
|
}
|
||||||
&SystemClauseType::GetAttributedVariableList => {
|
&SystemClauseType::GetAttributedVariableList => {
|
||||||
let attr_var = self.store(self.deref(self[temp_v!(1)].clone()));
|
let attr_var = self.store(self.deref(self[temp_v!(1)].clone()));
|
||||||
let attr_var_list = match attr_var {
|
let attr_var_list = match attr_var {
|
||||||
@@ -1370,6 +1415,18 @@ impl MachineState {
|
|||||||
|
|
||||||
self.unify(var_list_addr, list_addr);
|
self.unify(var_list_addr, list_addr);
|
||||||
}
|
}
|
||||||
|
Addr::Con(Constant::Integer(n)) => {
|
||||||
|
if let Some(b) = n.to_usize() {
|
||||||
|
let iter = self.gather_attr_vars_created_since(b);
|
||||||
|
|
||||||
|
let var_list_addr = Addr::HeapCell(self.heap.to_list(iter));
|
||||||
|
let list_addr = self[temp_v!(2)].clone();
|
||||||
|
|
||||||
|
self.unify(var_list_addr, list_addr);
|
||||||
|
} else {
|
||||||
|
self.fail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => self.fail = true,
|
_ => self.fail = true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1685,11 +1742,6 @@ impl MachineState {
|
|||||||
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
self.p = CodePtr::DynamicTransaction(trans_type, p);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
&SystemClauseType::ReturnFromAttributeGoals => {
|
|
||||||
self.deallocate();
|
|
||||||
self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0));
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
&SystemClauseType::ReturnFromVerifyAttr => {
|
&SystemClauseType::ReturnFromVerifyAttr => {
|
||||||
let e = self.e;
|
let e = self.e;
|
||||||
let frame_len = self.and_stack[e].len();
|
let frame_len = self.and_stack[e].len();
|
||||||
@@ -1839,6 +1891,21 @@ impl MachineState {
|
|||||||
&SystemClauseType::InstallNewBlock => {
|
&SystemClauseType::InstallNewBlock => {
|
||||||
self.install_new_block(temp_v!(1));
|
self.install_new_block(temp_v!(1));
|
||||||
}
|
}
|
||||||
|
&SystemClauseType::RawInputReadChar => {
|
||||||
|
let keypress = {
|
||||||
|
let mut raw_stdout = stdout().into_raw_mode().unwrap();
|
||||||
|
raw_stdout.flush().unwrap();
|
||||||
|
next_keypress()
|
||||||
|
};
|
||||||
|
|
||||||
|
let c = match keypress {
|
||||||
|
ContinueResult::ContinueQuery => ';',
|
||||||
|
ContinueResult::Conclude => '.'
|
||||||
|
};
|
||||||
|
|
||||||
|
let target = self[temp_v!(1)].clone();
|
||||||
|
self.unify(Addr::Con(Constant::Char(c)), target);
|
||||||
|
}
|
||||||
&SystemClauseType::ReadQueryTerm => {
|
&SystemClauseType::ReadQueryTerm => {
|
||||||
readline::set_prompt(true);
|
readline::set_prompt(true);
|
||||||
let result = self.read_term(current_input_stream, indices);
|
let result = self.read_term(current_input_stream, indices);
|
||||||
|
|||||||
@@ -137,11 +137,6 @@ impl<'a, R: Read> TermStream<'a, R> {
|
|||||||
mem::replace(&mut self.top_level_terms, vec![])
|
mem::replace(&mut self.top_level_terms, vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn add_to_top(&mut self, buf: &str) {
|
|
||||||
self.parser.add_to_top(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
|
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {
|
||||||
match hook {
|
match hook {
|
||||||
|
|||||||
@@ -303,13 +303,6 @@ fn is_consistent(tl: &TopLevel, clauses: &Vec<PredicateClause>) -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deque_to_packet(head: TopLevel, deque: VecDeque<TopLevel>) -> TopLevelPacket {
|
|
||||||
match head {
|
|
||||||
TopLevel::Query(query) => TopLevelPacket::Query(query, deque),
|
|
||||||
tl => TopLevelPacket::Decl(tl, deque),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError> {
|
fn merge_clauses(tls: &mut VecDeque<TopLevel>) -> Result<TopLevel, ParserError> {
|
||||||
let mut clauses: Vec<PredicateClause> = vec![];
|
let mut clauses: Vec<PredicateClause> = vec![];
|
||||||
|
|
||||||
@@ -496,11 +489,6 @@ fn setup_declaration<'a, 'b, 'c, R: Read>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum TopLevelPacket {
|
|
||||||
Query(Vec<QueryTerm>, VecDeque<TopLevel>),
|
|
||||||
Decl(TopLevel, VecDeque<TopLevel>),
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RelationWorker {
|
struct RelationWorker {
|
||||||
flags: MachineFlags,
|
flags: MachineFlags,
|
||||||
dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
|
dynamic_clauses: Vec<(Term, Term)>, // Head, Body.
|
||||||
@@ -902,39 +890,6 @@ impl RelationWorker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stream_to_toplevel<R: Read>(
|
|
||||||
mut buffer: ParsingStream<R>,
|
|
||||||
wam: &mut Machine,
|
|
||||||
) -> Result<TopLevelPacket, SessionError> {
|
|
||||||
let flags = wam.machine_flags();
|
|
||||||
let mut term_stream = TermStream::new(
|
|
||||||
&mut buffer,
|
|
||||||
wam.indices.atom_tbl(),
|
|
||||||
wam.machine_flags(),
|
|
||||||
wam,
|
|
||||||
);
|
|
||||||
|
|
||||||
term_stream.add_to_top("?- ");
|
|
||||||
|
|
||||||
let term = term_stream.read_term(&OpDir::new())?;
|
|
||||||
let mut code_dir = CodeDir::new();
|
|
||||||
|
|
||||||
let line_num = term_stream.line_num();
|
|
||||||
let col_num = term_stream.col_num();
|
|
||||||
|
|
||||||
let mut rel_worker = RelationWorker::new(flags, line_num, col_num);
|
|
||||||
let mut indices = CompositeIndices::new(
|
|
||||||
&mut term_stream,
|
|
||||||
IndexSource::TermStream,
|
|
||||||
Some(IndexSource::Local(&mut code_dir))
|
|
||||||
);
|
|
||||||
|
|
||||||
let tl = rel_worker.try_term_to_tl(&mut indices, term, true)?;
|
|
||||||
let queue = rel_worker.parse_queue(&mut indices)?;
|
|
||||||
|
|
||||||
Ok(deque_to_packet(tl, queue))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), Vec<(Term, Term)>>;
|
pub type DynamicClauseMap = IndexMap<(ClauseName, usize), Vec<(Term, Term)>>;
|
||||||
|
|
||||||
pub struct TopLevelBatchWorker<'a, R: Read> {
|
pub struct TopLevelBatchWorker<'a, R: Read> {
|
||||||
|
|||||||
@@ -262,12 +262,6 @@ macro_rules! put_constant {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! top_level_code_ptr {
|
|
||||||
($p:expr, $q_sz:expr) => {
|
|
||||||
CodePtr::Local(LocalCodePtr::TopLevel($p, $q_sz))
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! get_level_and_unify {
|
macro_rules! get_level_and_unify {
|
||||||
($r: expr) => {
|
($r: expr) => {
|
||||||
Line::Cut(CutInstruction::GetLevelAndUnify($r))
|
Line::Cut(CutInstruction::GetLevelAndUnify($r))
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
/*
|
:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2]).
|
||||||
* inserting the modules should not result in the insertion of
|
|
||||||
* code. this is because they're already loaded by this point -- see
|
|
||||||
* Machine::new.
|
|
||||||
*/
|
|
||||||
|
|
||||||
:- use_module(library(lists)).
|
:- use_module(library(lists)).
|
||||||
:- use_module(library(si)).
|
:- use_module(library(si)).
|
||||||
@@ -27,12 +23,88 @@
|
|||||||
% make '$compile_batch', a system routine, callable.
|
% make '$compile_batch', a system routine, callable.
|
||||||
'$$compile_batch' :- '$compile_batch'.
|
'$$compile_batch' :- '$compile_batch'.
|
||||||
|
|
||||||
'$instruction_match'([user], []) :-
|
'$instruction_match'([Item], []) :-
|
||||||
!, catch('$$compile_batch', E, '$print_exception_with_check'(E)).
|
( atom(Item) -> !,
|
||||||
|
( Item == user ->
|
||||||
|
catch('$$compile_batch', E, '$print_exception_with_check'(E))
|
||||||
|
; consult(Item)
|
||||||
|
)
|
||||||
|
; catch(throw(error(type_error(atom, Item), repl/0)),
|
||||||
|
'$print_exception_with_check'(E))
|
||||||
|
).
|
||||||
'$instruction_match'(Term, VarList) :-
|
'$instruction_match'(Term, VarList) :-
|
||||||
'$submit_query_and_print_results'(Term, VarList),
|
'$submit_query_and_print_results'(Term, VarList),
|
||||||
!.
|
!.
|
||||||
|
|
||||||
|
'$submit_query_and_print_results'(Term0, VarList) :-
|
||||||
|
( expand_goals(Term0, Term) -> true
|
||||||
|
; Term = Term0
|
||||||
|
),
|
||||||
|
( '$get_b_value'(B), call(Term), '$write_eqs_and_read_input'(B, VarList), !
|
||||||
|
; write('false.'), nl
|
||||||
|
).
|
||||||
|
|
||||||
|
'$write_goal'(G, VarList) :-
|
||||||
|
( G = (Var = Value) ->
|
||||||
|
write(Var),
|
||||||
|
write(' = '),
|
||||||
|
write_term(Value, [quoted(true), variable_names(VarList)])
|
||||||
|
; G == [] ->
|
||||||
|
write('true')
|
||||||
|
; write_term(G, [quoted(true), variable_names(VarList)])
|
||||||
|
).
|
||||||
|
|
||||||
|
'$write_eq'((G1, G2), VarList) :-
|
||||||
|
!,
|
||||||
|
'$write_goal'(G1, VarList),
|
||||||
|
write(', '),
|
||||||
|
'$write_eq'(G2, VarList).
|
||||||
|
'$write_eq'(G, VarList) :-
|
||||||
|
'$write_goal'(G, VarList).
|
||||||
|
|
||||||
|
'$write_eqs_and_read_input'(B, VarList) :-
|
||||||
|
sort(VarList, SortedVarList),
|
||||||
|
'$get_b_value'(B0),
|
||||||
|
'$gather_goals'(SortedVarList, VarList, Goals),
|
||||||
|
( B0 == B ->
|
||||||
|
( Goals == [] ->
|
||||||
|
write('true.'), nl
|
||||||
|
; thread_goals(Goals, ThreadedGoals, (',')),
|
||||||
|
'$write_eq'(ThreadedGoals, VarList),
|
||||||
|
write(' .'),
|
||||||
|
nl
|
||||||
|
)
|
||||||
|
; repeat,
|
||||||
|
thread_goals(Goals, ThreadedGoals, (',')),
|
||||||
|
'$write_eq'(ThreadedGoals, VarList),
|
||||||
|
'$raw_input_read_char'(C),
|
||||||
|
( C == (';'), !,
|
||||||
|
write(' ;'), nl, false
|
||||||
|
; C == ('.'), !,
|
||||||
|
write(' ...'), nl
|
||||||
|
)
|
||||||
|
).
|
||||||
|
|
||||||
|
'$gather_query_vars'([_ = Var | Vars], QueryVars) :-
|
||||||
|
( var(Var) ->
|
||||||
|
QueryVars = [Var | QueryVars1],
|
||||||
|
'$gather_query_vars'(Vars, QueryVars1)
|
||||||
|
; '$gather_query_vars'(Vars, QueryVars)
|
||||||
|
).
|
||||||
|
'$gather_query_vars'([], []).
|
||||||
|
|
||||||
|
'$gather_goals'([], VarList, Goals) :-
|
||||||
|
'$get_attr_var_queue_beyond'(0, AttrVars),
|
||||||
|
'$gather_query_vars'(VarList, QueryVars),
|
||||||
|
'$call_attribute_goals'(QueryVars, AttrVars),
|
||||||
|
'$fetch_attribute_goals'(Goals).
|
||||||
|
'$gather_goals'([Var = Value | Pairs], VarList, Goals) :-
|
||||||
|
( nonvar(Value) ->
|
||||||
|
Goals = [Var = Value | Goals0],
|
||||||
|
'$gather_goals'(Pairs, VarList, Goals0)
|
||||||
|
; '$gather_goals'(Pairs, VarList, Goals)
|
||||||
|
).
|
||||||
|
|
||||||
'$print_exception'(E) :-
|
'$print_exception'(E) :-
|
||||||
write_term('caught: ', [quoted(false)]),
|
write_term('caught: ', [quoted(false)]),
|
||||||
writeq(E),
|
writeq(E),
|
||||||
@@ -61,6 +133,11 @@
|
|||||||
; throw(error(instantiation_error, Source))
|
; throw(error(instantiation_error, Source))
|
||||||
).
|
).
|
||||||
|
|
||||||
|
consult(Item) :-
|
||||||
|
( atom(Item) -> use_module(Item)
|
||||||
|
; throw(error(type_error(atom, Item), consult/1))
|
||||||
|
).
|
||||||
|
|
||||||
use_module(Module) :-
|
use_module(Module) :-
|
||||||
( nonvar(Module) ->
|
( nonvar(Module) ->
|
||||||
( Module = library(Filename) -> '$use_module'(Filename)
|
( Module = library(Filename) -> '$use_module'(Filename)
|
||||||
@@ -90,40 +167,50 @@ user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
|
|||||||
expand_goals(Goals, ExpandedGoals),
|
expand_goals(Goals, ExpandedGoals),
|
||||||
Goals \== ExpandedGoals.
|
Goals \== ExpandedGoals.
|
||||||
|
|
||||||
expand_goals(Goals, ExpandedGoals) :-
|
expand_goals(UnexpandedGoals, ExpandedGoals) :-
|
||||||
nonvar(Goals),
|
nonvar(UnexpandedGoals),
|
||||||
var(ExpandedGoals),
|
var(ExpandedGoals),
|
||||||
|
( expand_goal(UnexpandedGoals, Goals) -> true
|
||||||
|
; Goals = UnexpandedGoals
|
||||||
|
),
|
||||||
( Goals = (Goal0, Goals0) ->
|
( Goals = (Goal0, Goals0) ->
|
||||||
( expand_goal(Goal0, Goal1) ->
|
( expand_goal(Goal0, Goal1) ->
|
||||||
Expanded = true,
|
Expanded = true,
|
||||||
expand_goals(Goals0, Goals1),
|
expand_goals(Goals0, Goals1),
|
||||||
thread_goals(Goal1, ExpandedGoals, Goals1)
|
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
|
||||||
; expand_goals(Goals0, Goals1),
|
; expand_goals(Goals0, Goals1),
|
||||||
ExpandedGoals = (Goal0, Goals1)
|
ExpandedGoals = (Goal0, Goals1)
|
||||||
)
|
)
|
||||||
; expand_goal(Goals, ExpandedGoals0) ->
|
; Goals = (Goals0 -> Goals1) ->
|
||||||
thread_goals(ExpandedGoals0, ExpandedGoals)
|
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)
|
||||||
|
; thread_goals(Goals, ExpandedGoals, (','))
|
||||||
; Goals = ExpandedGoals
|
; Goals = ExpandedGoals
|
||||||
).
|
).
|
||||||
|
|
||||||
thread_goals(Goals0, Goals1, Hole) :-
|
thread_goals(Goals0, Goals1, Hole, Functor) :-
|
||||||
nonvar(Goals0),
|
nonvar(Goals0),
|
||||||
( Goals0 = [G | Gs] ->
|
( Goals0 = [G | Gs] ->
|
||||||
( Gs == [] ->
|
( Gs == [] ->
|
||||||
Goals1 = (G, Hole)
|
Goals1 =.. [Functor, G, Hole]
|
||||||
; Goals1 = (G, Goals2),
|
; Goals1 =.. [Functor, G, Goals2],
|
||||||
thread_goals(Gs, Goals2, Hole)
|
thread_goals(Gs, Goals2, Hole, Functor)
|
||||||
)
|
)
|
||||||
; Goals1 = (Goals0, Hole)
|
; Goals1 =.. [Functor, Goals0, Hole]
|
||||||
).
|
).
|
||||||
|
|
||||||
thread_goals(Goals0, Goals1) :-
|
thread_goals(Goals0, Goals1, Functor) :-
|
||||||
nonvar(Goals0),
|
nonvar(Goals0),
|
||||||
( Goals0 = [G | Gs] ->
|
( Goals0 = [G | Gs] ->
|
||||||
( Gs = [] ->
|
( Gs = [] ->
|
||||||
Goals1 = G
|
Goals1 = G
|
||||||
; Goals1 = (G, Goals2),
|
; Goals1 =.. [Functor, G, Goals2],
|
||||||
thread_goals(Gs, Goals2)
|
thread_goals(Gs, Goals2, Functor)
|
||||||
)
|
)
|
||||||
; Goals1 = Goals0
|
; Goals1 = Goals0
|
||||||
).
|
).
|
||||||
|
|||||||
@@ -4,11 +4,7 @@ use crate::prolog::instructions::*;
|
|||||||
use crate::prolog::machine::machine_errors::*;
|
use crate::prolog::machine::machine_errors::*;
|
||||||
use crate::prolog::machine::machine_indices::*;
|
use crate::prolog::machine::machine_indices::*;
|
||||||
|
|
||||||
use termion::event::Key;
|
|
||||||
use termion::input::TermRead;
|
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::io::stdin;
|
|
||||||
|
|
||||||
impl fmt::Display for LocalCodePtr {
|
impl fmt::Display for LocalCodePtr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
@@ -29,10 +25,8 @@ impl fmt::Display for LocalCodePtr {
|
|||||||
impl fmt::Display for REPLCodePtr {
|
impl fmt::Display for REPLCodePtr {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
REPLCodePtr::CompileBatch => write!(f, "REPLCodePtr::CompileBatch"),
|
REPLCodePtr::CompileBatch =>
|
||||||
REPLCodePtr::SubmitQueryAndPrintResults => {
|
write!(f, "REPLCodePtr::CompileBatch"),
|
||||||
write!(f, "REPLCodePtr::SubmitQueryAndPrintResults")
|
|
||||||
}
|
|
||||||
REPLCodePtr::UseModule =>
|
REPLCodePtr::UseModule =>
|
||||||
write!(f, "REPLCodePtr::UseModule"),
|
write!(f, "REPLCodePtr::UseModule"),
|
||||||
REPLCodePtr::UseQualifiedModule =>
|
REPLCodePtr::UseQualifiedModule =>
|
||||||
@@ -268,9 +262,6 @@ impl fmt::Display for SessionError {
|
|||||||
&SessionError::ModuleDoesNotContainExport => {
|
&SessionError::ModuleDoesNotContainExport => {
|
||||||
write!(f, "module does not contain claimed export.")
|
write!(f, "module does not contain claimed export.")
|
||||||
}
|
}
|
||||||
&SessionError::NoModuleDeclaration(ref name) => {
|
|
||||||
write!(f, "file {}.pl lacks an expected module declaration.", name)
|
|
||||||
}
|
|
||||||
&SessionError::OpIsInfixAndPostFix(_) => {
|
&SessionError::OpIsInfixAndPostFix(_) => {
|
||||||
write!(f, "cannot define an op to be both postfix and infix.")
|
write!(f, "cannot define an op to be both postfix and infix.")
|
||||||
}
|
}
|
||||||
@@ -278,7 +269,6 @@ impl fmt::Display for SessionError {
|
|||||||
write!(f, "the predicate head is not an atom or clause.")
|
write!(f, "the predicate head is not an atom or clause.")
|
||||||
}
|
}
|
||||||
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
|
&SessionError::ParserError(ref e) => write!(f, "syntax_error({})", e.as_str()),
|
||||||
&SessionError::UserPrompt => write!(f, "enter predicate at [user] prompt"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,6 +345,9 @@ impl fmt::Display for ArithmeticInstruction {
|
|||||||
&ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => {
|
&ArithmeticInstruction::RDiv(ref a1, ref a2, ref t) => {
|
||||||
write!(f, "rdiv {}, {}, @{}", a1, a2, t)
|
write!(f, "rdiv {}, {}, @{}", a1, a2, t)
|
||||||
}
|
}
|
||||||
|
&ArithmeticInstruction::Gcd(ref a1, ref a2, ref t) => {
|
||||||
|
write!(f, "gcd {}, {}, @{}", a1, a2, t)
|
||||||
|
}
|
||||||
&ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => {
|
&ArithmeticInstruction::Shl(ref a1, ref a2, ref t) => {
|
||||||
write!(f, "shl {}, {}, @{}", a1, a2, t)
|
write!(f, "shl {}, {}, @{}", a1, a2, t)
|
||||||
}
|
}
|
||||||
@@ -380,6 +373,7 @@ impl fmt::Display for ArithmeticInstruction {
|
|||||||
write!(f, "atan2 {}, {}, @{}", a1, a2, t)
|
write!(f, "atan2 {}, {}, @{}", a1, a2, t)
|
||||||
}
|
}
|
||||||
&ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t),
|
&ArithmeticInstruction::Plus(ref a, ref t) => write!(f, "plus {}, @{}", a, t),
|
||||||
|
&ArithmeticInstruction::Sign(ref a, ref t) => write!(f, "sign {}, @{}", a, t),
|
||||||
&ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t),
|
&ArithmeticInstruction::Neg(ref a, ref t) => write!(f, "neg {}, @{}", a, t),
|
||||||
&ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t),
|
&ArithmeticInstruction::Cos(ref a, ref t) => write!(f, "cos {}, @{}", a, t),
|
||||||
&ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t),
|
&ArithmeticInstruction::Sin(ref a, ref t) => write!(f, "sin {}, @{}", a, t),
|
||||||
@@ -421,22 +415,3 @@ impl fmt::Display for Level {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum ContinueResult {
|
|
||||||
ContinueQuery,
|
|
||||||
Conclude,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn next_keypress() -> ContinueResult {
|
|
||||||
let stdin = stdin();
|
|
||||||
|
|
||||||
for c in stdin.keys() {
|
|
||||||
match c.unwrap() {
|
|
||||||
Key::Char(' ') | Key::Char(';') => return ContinueResult::ContinueQuery,
|
|
||||||
Key::Char('.') => return ContinueResult::Conclude,
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ContinueResult::Conclude
|
|
||||||
}
|
|
||||||
|
|||||||
3541
src/tests.rs
3541
src/tests.rs
File diff suppressed because it is too large
Load Diff
64
src/tests/builtins.pl
Normal file
64
src/tests/builtins.pl
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
|
||||||
|
:- use_module(library(lists)).
|
||||||
|
|
||||||
|
test_queries_on_builtins :-
|
||||||
|
\+ atom(_),
|
||||||
|
atom(a),
|
||||||
|
\+ atom("string"),
|
||||||
|
atom([]),
|
||||||
|
\+ atom(1),
|
||||||
|
\+ atom(0),
|
||||||
|
\+ atom(0.0),
|
||||||
|
\+ atom([a,b,c]),
|
||||||
|
\+ atom(atop(the_trees)),
|
||||||
|
\+ atomic(_),
|
||||||
|
atomic(a),
|
||||||
|
atomic("string"),
|
||||||
|
atomic([]),
|
||||||
|
atomic(1),
|
||||||
|
atomic(0),
|
||||||
|
atomic(0.0),
|
||||||
|
\+ atomic([a,b,c]),
|
||||||
|
\+ atomic(atop(the_trees)),
|
||||||
|
( var(X), X = 3, atomic(X) ),
|
||||||
|
\+ ( var(X), X = 3, var(X) ),
|
||||||
|
arg(1, f(a,b,c,d), a),
|
||||||
|
arg(2, f(a,b,c,d), b),
|
||||||
|
arg(3, f(a,b,c,d), c),
|
||||||
|
arg(4, f(a,b,c,d), d),
|
||||||
|
catch(arg(_, f, _), error(instantiation_error, _), true),
|
||||||
|
\+ arg(1, f(arg, not_arg, not_arg), not_arg),
|
||||||
|
arg(2, f(arg, not_arg, not_arg), not_arg),
|
||||||
|
arg(3, f(arg, not_arg, not_arg), not_arg),
|
||||||
|
functor(f(a,b,c), f, 3),
|
||||||
|
catch(functor(_,"sdf",3),error(type_error(atom,[s,d,f]),_),true),
|
||||||
|
f(1,2,3) =.. [f,1,2,3],
|
||||||
|
length([a,b,c], 3),
|
||||||
|
copy_term([[[[X,Y],Y],X]],[[[[Z,V],V],Z]]),
|
||||||
|
\+ ( X = g(X,Y), Y = f(X), copy_term(Y,g(Z)) ),
|
||||||
|
(X = g(X,Y), Y = f(X), copy_term(Y,f(Z))),
|
||||||
|
float(3.14159269),
|
||||||
|
\+ float(3),
|
||||||
|
\+ float("sdfsa"),
|
||||||
|
\+ float(structure(functor)),
|
||||||
|
\+ float([1,2,3]),
|
||||||
|
\+ float([1,2,_]),
|
||||||
|
\+ (X is 3 rdiv 4, float(X)),
|
||||||
|
( X is 3 rdiv 4, rational(X) ),
|
||||||
|
\+ rational(3),
|
||||||
|
\+ rational(f(_)),
|
||||||
|
\+ rational("sdfa"),
|
||||||
|
\+ rational(atom),
|
||||||
|
\+ rational(structure(f)),
|
||||||
|
\+ rational([1,2,3]),
|
||||||
|
\+ rational([1,2,_]),
|
||||||
|
compound(functor(compound)),
|
||||||
|
compound(f(_)),
|
||||||
|
compound([1,2,3]),
|
||||||
|
\+ compound([]),
|
||||||
|
\+ compound(3.14159269),
|
||||||
|
\+ compound(3),
|
||||||
|
\+ compound("sdfsa"),
|
||||||
|
\+ compound(atom).
|
||||||
|
|
||||||
|
:- initialization(test_queries_on_builtins).
|
||||||
26
src/tests/facts.pl
Normal file
26
src/tests/facts.pl
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
:- dynamic(p/2).
|
||||||
|
:- dynamic(p/3).
|
||||||
|
|
||||||
|
p(Z, Z).
|
||||||
|
clouds(are, nice).
|
||||||
|
p(Z, h(Z, W), f(W)).
|
||||||
|
|
||||||
|
test_queries_on_facts :-
|
||||||
|
findall(Z, p(Z, Z), [Z]),
|
||||||
|
findall(Z, p(Z, z), [z]),
|
||||||
|
findall(Z, p(Z, w), [w]),
|
||||||
|
\+ p(z, w),
|
||||||
|
p(w, w),
|
||||||
|
\+ clouds(Z, Z),
|
||||||
|
findall(Z, clouds(are, Z), [nice]),
|
||||||
|
\+ p(z, h(z, z), f(w)),
|
||||||
|
p(z, h(z, w), f(w)),
|
||||||
|
findall(W, p(z, h(z, W), f(w)), [w]),
|
||||||
|
findall(Z, p(Z, h(Z, w), f(Z)), [w]),
|
||||||
|
\+ p(z, h(Z, w), f(Z)),
|
||||||
|
retract(p(_,_,_)),
|
||||||
|
assertz(p(Z, h(Z, W), f(W))),
|
||||||
|
p(f(f(a)), h(f(f(a)), f(a)), f(f(a))),
|
||||||
|
retract(p(Z, h(Z, W), f(W))).
|
||||||
|
|
||||||
|
:- initialization(test_queries_on_facts).
|
||||||
37
src/tests/predicates.pl
Normal file
37
src/tests/predicates.pl
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
:- dynamic(p/2).
|
||||||
|
:- dynamic(p/3).
|
||||||
|
|
||||||
|
:- dynamic(q/1).
|
||||||
|
|
||||||
|
p(_, a).
|
||||||
|
p(b, _).
|
||||||
|
|
||||||
|
test_queries_on_predicates :-
|
||||||
|
findall(Y, p(x, Y), [a]),
|
||||||
|
findall(X, p(X, a), [_,b]),
|
||||||
|
findall(X, p(b, X), [a,_]),
|
||||||
|
findall(X, p(X, X), [a,b]),
|
||||||
|
p(b, a),
|
||||||
|
\+ p(a, b),
|
||||||
|
retract(p(_,a)),
|
||||||
|
retract(p(b,_)),
|
||||||
|
assertz(p(_, _,a)),
|
||||||
|
assertz(p(_,a,_)),
|
||||||
|
assertz(p(_,_,a)),
|
||||||
|
findall(X, p(c,d,X), [a,a]),
|
||||||
|
findall(X, p(a,a,a), [a,a,a]),
|
||||||
|
\+ p(b,c,d),
|
||||||
|
findall(., retract(p(_,_,_)), _),
|
||||||
|
assertz(p(_, a)),
|
||||||
|
assertz(q(z)),
|
||||||
|
findall(Y, p(_,Y), [a]),
|
||||||
|
p(x,a),
|
||||||
|
p(_,a),
|
||||||
|
\+ p(_,b),
|
||||||
|
assertz((p(X, Y) :- q(Z), p(X, X))),
|
||||||
|
once(p(X,b)),
|
||||||
|
retract((p(X, Y) :- q(Z), p(X, X))),
|
||||||
|
retract(q(z)).
|
||||||
|
|
||||||
|
:- initialization(test_queries_on_predicates).
|
||||||
55
src/tests/rules.pl
Normal file
55
src/tests/rules.pl
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
:- dynamic(p/3).
|
||||||
|
:- dynamic(p/2).
|
||||||
|
:- dynamic(q/2).
|
||||||
|
:- dynamic(r/2).
|
||||||
|
:- dynamic(r/1).
|
||||||
|
:- dynamic(h/1).
|
||||||
|
|
||||||
|
p(X, Y) :- q(X, Z), r(Z, Y).
|
||||||
|
q(q, s).
|
||||||
|
r(s, t).
|
||||||
|
|
||||||
|
test_queries_on_rules :-
|
||||||
|
findall([X,Y], p(X, Y), [[q, t]]),
|
||||||
|
p(q, t),
|
||||||
|
\+ p(t, q),
|
||||||
|
findall(T, p(q, T), [t]),
|
||||||
|
\+ p(t, t),
|
||||||
|
retract((p(X,Y) :- q(X,Z), r(Z, Y))),
|
||||||
|
retract(q(_,_)),
|
||||||
|
assertz((p(X,_) :- q(f(f(X)), _), r(_, _))),
|
||||||
|
assertz(q(f(f(X)), r)),
|
||||||
|
p(_,_),
|
||||||
|
retract(q(_,_)),
|
||||||
|
assertz(q(f(f(x)), r)),
|
||||||
|
findall(X, p(X,_), [x]),
|
||||||
|
retract((p(X,_) :- q(f(f(X)), _), r(_, _))),
|
||||||
|
retract(q(_,_)),
|
||||||
|
assertz((p(X, Y) :- q(X, Y), r(X, Y))),
|
||||||
|
assertz(q(s, t)),
|
||||||
|
retract(r(_,_)),
|
||||||
|
assertz((r(X, Y) :- r(a))),
|
||||||
|
assertz(r(a)),
|
||||||
|
findall([X,Y], p(X, Y), [[s,t]]),
|
||||||
|
\+ p(t, _),
|
||||||
|
findall(T, p(s, T), [t]),
|
||||||
|
findall(S, p(S, t), [s]),
|
||||||
|
assertz((p(f(f(a), g(b), X), g(b), h) :- q(X, Y))),
|
||||||
|
retract(q(_,_)),
|
||||||
|
assertz(q(_,_)),
|
||||||
|
findall([X,Y,Z], p(f(X, Y, Z), g(b), h), [[f(a), g(b), _]]),
|
||||||
|
\+ p(f(X, g(_), Z), g(Z), X),
|
||||||
|
findall([X,Y,Z], p(f(X, g(Y), Z), g(Z), h), [[f(a), b, b]]),
|
||||||
|
findall([X,Y,Z], p(Z, Y, X), [[h, g(b), f(f(a),g(b),_)]]),
|
||||||
|
findall([X,Y,Z], p(f(X, Y, Z), Y, h), [[f(a), g(b), _]]),
|
||||||
|
retract((p(X, Y) :- q(X, Y), r(X, Y))),
|
||||||
|
retract((p(f(f(a), g(b), X), g(b), h) :- q(X, _))),
|
||||||
|
assertz((p(_, f(_, Y, _)) :- h(Y))),
|
||||||
|
assertz(h(y)),
|
||||||
|
findall(Y, p(_, f(_, Y, _)), [y]).
|
||||||
|
p(_, f(_, y, _)),
|
||||||
|
\+ p(_, f(_, z, _)),
|
||||||
|
retract((p(_, f(_, Y, _)) :- h(Y))).
|
||||||
|
|
||||||
|
:- initialization(test_queries_on_rules).
|
||||||
|
|
||||||
Reference in New Issue
Block a user