25 Commits

Author SHA1 Message Date
Mark Thom
17b2510480 update version number 2019-11-16 19:18:41 -07:00
Mark Thom
bcfd7cbf8d begin migrating tests to pure prolog, correct bug in toplevel 2019-11-16 19:15:07 -07:00
Mark Thom
cee3dbc453 quote values and goals in equations, eliminate dead code, correct retract/1 2019-11-16 17:15:25 -07:00
Mark Thom
ed985c3cfe move more of the toplevel from rust into prolog 2019-11-16 00:26:15 -07:00
Mark Thom
4ad62e4606 add warnings when initialization goals fail (#168) 2019-10-30 00:25:17 -06:00
Mark Thom
d34811aa36 handle asserts in modules a little better (#223, #224) 2019-10-30 00:14:36 -06:00
Mark Thom
b90d69a45b install asserted predicates into modules from initialization directives (#222) 2019-10-29 00:06:51 -06:00
Mark Thom
81f220a4d2 replace \n\r and \r\n by \n (#221) 2019-10-27 20:50:21 -06:00
Mark Thom
e594ade84d finish #214, add needed ambiguity checks if 0 is the final character 2019-10-27 19:23:35 -06:00
Mark Thom
0dcd9e5805 correct sign/1 (#216) 2019-10-27 14:18:32 -06:00
Mark Thom
67a00e4deb update to prolog_parser v0.8.34 with increased MAX_ARITY (#218) 2019-10-27 13:10:32 -06:00
Mark Thom
e656e7fbae add sign/1 (#216) and gcd/2 (#217) as evaluable functors, update the README 2019-10-27 13:05:05 -06:00
Mark Thom
0fdf0d8d06 correct #215 by fixing bug in ambiguity_check 2019-10-27 12:32:18 -06:00
Mark Thom
7cdbd2f16c add consult/1 and shorthand for consult/1 (#214) 2019-10-27 11:33:49 -06:00
Mark Thom
ccfcc654a5 remove module from toplevel in unqualified use_module 2019-10-26 12:39:42 -06:00
Mark Thom
2eea0528b1 remove all mention of [clear] from the README 2019-10-26 01:35:26 -06:00
Mark Thom
a358431d30 reload files properly (re: #213) 2019-10-26 01:34:41 -06:00
Mark Thom
e9c1556c32 remove scratch comments from clpb.pl 2019-10-22 21:19:01 -06:00
Mark Thom
1b1879a6fa fix attributed variables bug causing weighted_maximum/3 example to omit a variable binding 2019-10-20 14:50:46 -06:00
Mark Thom
24e5e39c28 add order preserving tidy_trail, fix random_labeling/2 2019-10-19 00:29:50 -06:00
Mark Thom
ab9a14cc6a add randomness predicates, small but consequential changes to TrailRef 2019-10-17 00:21:21 -06:00
Mark Thom
a641822a1b Merge pull request #206 from triska/master
weighted_maximum/3 now works
2019-10-16 16:17:05 -03:00
Markus Triska
145fee0d36 weighted_maximum/3 now works 2019-10-16 19:18:38 +02:00
Markus Triska
567af2648c support must_be(var, ...) 2019-10-16 19:18:38 +02:00
Mark Thom
42a3bdc357 eliminate lingering attribute goals 2019-10-16 11:38:33 -03:00
38 changed files with 888 additions and 4455 deletions

View File

@@ -1,6 +1,6 @@
[package]
name = "scryer-prolog"
version = "0.8.111"
version = "0.8.116"
authors = ["Mark Thom <markjordanthom@gmail.com>"]
build = "build.rs"
repository = "https://github.com/mthom/scryer-prolog"
@@ -19,7 +19,7 @@ lazy_static = "1.4.0"
libc = "0.2.62"
nix = "0.15.0"
ordered-float = "0.5.0"
prolog_parser = "0.8.33"
prolog_parser = "0.8.34"
ref_thread_local = "0.0.0"
rug = "1.4.0"
rustyline = "5.0.3"

View File

@@ -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`
`bb_put/2` (non-backtrackable) and `bb_b_put/2`
(backtrackable).
- [ ] clp(B) and clp($\mathbb{Z}$) as builtin libraries (_in progress_).
- [ ] Streams and predicates for stream control (_in progress_).
- [ ] An incremental compacting garbage collector satisfying the five
properties of "Precise Garbage Collection in Prolog."
- [ ] Mode declarations.
- [ ] Extensions for clp(FD).
## Phase 3
@@ -93,7 +93,7 @@ strings.
First, install the latest stable version of
[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:
```
@@ -101,13 +101,27 @@ $> cargo install scryer-prolog
```
cargo will download and install the libraries Scryer Prolog uses
automatically. You can find the `scryer-prolog` executable in
`~/.cargo/bin`.
automatically from crates.io. You can find the `scryer-prolog`
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,
and BSD variants on which Rust runs. Windows support hinges on
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
@@ -120,7 +134,7 @@ The following predicates are built-in to Scryer.
`abs/1`, `sin/1`, `cos/1`, `tan/1`, `asin/1`, `acos/1`,
`atan/1`, `atan2/2`, `log/1`, `exp/1`, `sqrt/1`, `float/1`,
`truncate/1`, `round/1`, `floor/1`, `ceiling/1`, `pi/0`,
`min/1`, `max/1`
`min/1`, `max/1`, `gcd/2`, `sign/1`
* Comparison operators: `>`, `<`, `=<`, `>=`, `=:=`, `=\=`.
* `(:)/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
a number preceded by an underscore (`X = _0` in an example above).
To clear the database, type
```
?- [clear].
```
To quit scryer-prolog, type
```
?- halt.

View File

@@ -159,6 +159,7 @@ impl<'a> ArithmeticEvaluator<'a> {
"round" => Ok(ArithmeticInstruction::Round(a1, t)),
"ceiling" => Ok(ArithmeticInstruction::Ceiling(a1, t)),
"floor" => Ok(ArithmeticInstruction::Floor(a1, t)),
"sign" => Ok(ArithmeticInstruction::Sign(a1, t)),
"\\" => Ok(ArithmeticInstruction::BitwiseComplement(a1, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name, None),
@@ -192,6 +193,7 @@ impl<'a> ArithmeticEvaluator<'a> {
"xor" => Ok(ArithmeticInstruction::Xor(a1, a2, t)),
"mod" => Ok(ArithmeticInstruction::Mod(a1, a2, t)),
"rem" => Ok(ArithmeticInstruction::Rem(a1, a2, t)),
"gcd" => Ok(ArithmeticInstruction::Gcd(a1, a2, t)),
"atan2" => Ok(ArithmeticInstruction::ATan2(a1, a2, t)),
_ => Err(ArithmeticError::NonEvaluableFunctor(
Constant::Atom(name, None),

View File

@@ -2,6 +2,7 @@ use prolog_parser::ast::*;
use crate::prolog::forms::Number;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::rug::rand::RandState;
use ref_thread_local::RefThreadLocal;
@@ -81,6 +82,10 @@ pub enum InlinedClauseType {
IsVar(RegType),
}
ref_thread_local! {
pub static managed RANDOM_STATE: RandState<'static> = RandState::new();
}
ref_thread_local! {
pub static managed CLAUSE_TYPE_FORMS: BTreeMap<(&'static str, usize), ClauseType> = {
let mut m = BTreeMap::new();
@@ -157,8 +162,7 @@ pub enum SystemClauseType {
AtomChars,
AtomCodes,
AtomLength,
ModuleAssertDynamicPredicateToFront,
ModuleAssertDynamicPredicateToBack,
CallAttributeGoals,
CharCode,
CharsToNumber,
CodesToNumber,
@@ -171,6 +175,7 @@ pub enum SystemClauseType {
EnqueueAttributedVar,
ExpandGoal,
ExpandTerm,
FetchAttributeGoals,
FetchGlobalVar,
FetchGlobalVarWithOffset,
GetChar,
@@ -195,6 +200,8 @@ pub enum SystemClauseType {
InstallSCCCleaner,
InstallInferenceCounter,
LiftedHeapLength,
ModuleAssertDynamicPredicateToFront,
ModuleAssertDynamicPredicateToBack,
ModuleOf,
ModuleRetractClause,
NoSuchPredicate,
@@ -223,12 +230,14 @@ pub enum SystemClauseType {
GetCutPoint,
GetDoubleQuotes,
InstallNewBlock,
Maybe,
RawInputReadChar,
ResetBlock,
ReturnFromAttributeGoals,
ReturnFromVerifyAttr,
SetBall,
SetCutPointByDefault(RegType),
SetDoubleQuotes,
SetSeed,
SkipMaxList,
Succeed,
TermVariables,
@@ -250,20 +259,12 @@ impl SystemClauseType {
&SystemClauseType::AtomChars => clause_name!("$atom_chars"),
&SystemClauseType::AtomCodes => clause_name!("$atom_codes"),
&SystemClauseType::AtomLength => clause_name!("$atom_length"),
&SystemClauseType::ModuleAssertDynamicPredicateToFront => {
clause_name!("$module_asserta")
}
&SystemClauseType::ModuleAssertDynamicPredicateToBack => {
clause_name!("$module_assertz")
}
&SystemClauseType::CallAttributeGoals => clause_name!("$call_attribute_goals"),
&SystemClauseType::CharCode => clause_name!("$char_code"),
&SystemClauseType::CharsToNumber => clause_name!("$chars_to_number"),
&SystemClauseType::CodesToNumber => clause_name!("$codes_to_number"),
&SystemClauseType::CheckCutPoint => clause_name!("$check_cp"),
&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::UseQualifiedModule) => {
clause_name!("$use_qualified_module")
@@ -282,6 +283,7 @@ impl SystemClauseType {
&SystemClauseType::EnqueueAttributedVar => clause_name!("$enqueue_attr_var"),
&SystemClauseType::ExpandTerm => clause_name!("$expand_term"),
&SystemClauseType::ExpandGoal => clause_name!("$expand_goal"),
&SystemClauseType::FetchAttributeGoals => clause_name!("$fetch_attribute_goals"),
&SystemClauseType::FetchGlobalVar => clause_name!("$fetch_global_var"),
&SystemClauseType::FetchGlobalVarWithOffset => {
clause_name!("$fetch_global_var_with_offset")
@@ -319,16 +321,25 @@ impl SystemClauseType {
clause_name!("$install_inference_counter")
}
&SystemClauseType::LiftedHeapLength => clause_name!("$lh_length"),
&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::ModuleOf => clause_name!("$module_of"),
&SystemClauseType::NoSuchPredicate => clause_name!("$no_such_predicate"),
&SystemClauseType::NumberToChars => clause_name!("$number_to_chars"),
&SystemClauseType::NumberToCodes => clause_name!("$number_to_codes"),
&SystemClauseType::RawInputReadChar => clause_name!("$raw_input_read_char"),
&SystemClauseType::RedoAttrVarBindings => clause_name!("$redo_attr_var_bindings"),
&SystemClauseType::RemoveCallPolicyCheck => clause_name!("$remove_call_policy_check"),
&SystemClauseType::RemoveInferenceCounter => clause_name!("$remove_inference_counter"),
&SystemClauseType::RestoreCutPolicy => clause_name!("$restore_cut_policy"),
&SystemClauseType::SetCutPoint(_) => clause_name!("$set_cp"),
&SystemClauseType::SetSeed => clause_name!("$set_seed"),
&SystemClauseType::StoreGlobalVar => clause_name!("$store_global_var"),
&SystemClauseType::StoreGlobalVarWithOffset => {
clause_name!("$store_global_var_with_offset")
@@ -348,9 +359,6 @@ impl SystemClauseType {
&SystemClauseType::ResetGlobalVarAtOffset => clause_name!("$reset_global_var_at_offset"),
&SystemClauseType::RetractClause => clause_name!("$retract_clause"),
&SystemClauseType::ResetBlock => clause_name!("$reset_block"),
&SystemClauseType::ReturnFromAttributeGoals => {
clause_name!("$return_from_attribute_goals")
}
&SystemClauseType::ReturnFromVerifyAttr => clause_name!("$return_from_verify_attr"),
&SystemClauseType::SetBall => clause_name!("$set_ball"),
&SystemClauseType::SetCutPointByDefault(_) => clause_name!("$set_cp_by_default"),
@@ -378,6 +386,7 @@ impl SystemClauseType {
("$module_assertz", 5) => Some(SystemClauseType::ModuleAssertDynamicPredicateToBack),
("$asserta", 4) => Some(SystemClauseType::AssertDynamicPredicateToFront),
("$assertz", 4) => Some(SystemClauseType::AssertDynamicPredicateToBack),
("$call_attribute_goals", 2) => Some(SystemClauseType::CallAttributeGoals),
("$char_code", 2) => Some(SystemClauseType::CharCode),
("$chars_to_number", 2) => Some(SystemClauseType::CharsToNumber),
("$codes_to_number", 2) => Some(SystemClauseType::CodesToNumber),
@@ -395,6 +404,7 @@ impl SystemClauseType {
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
("$expand_term", 2) => Some(SystemClauseType::ExpandTerm),
("$expand_goal", 2) => Some(SystemClauseType::ExpandGoal),
("$fetch_attribute_goals", 1) => Some(SystemClauseType::FetchAttributeGoals),
("$fetch_global_var", 2) => Some(SystemClauseType::FetchGlobalVar),
("$fetch_global_var_with_offset", 3) => Some(SystemClauseType::FetchGlobalVarWithOffset),
("$get_char", 1) => Some(SystemClauseType::GetChar),
@@ -417,6 +427,7 @@ impl SystemClauseType {
("$install_scc_cleaner", 2) => Some(SystemClauseType::InstallSCCCleaner),
("$install_inference_counter", 3) => Some(SystemClauseType::InstallInferenceCounter),
("$lh_length", 1) => Some(SystemClauseType::LiftedHeapLength),
("$maybe", 0) => Some(SystemClauseType::Maybe),
("$module_of", 2) => Some(SystemClauseType::ModuleOf),
("$module_retract_clause", 5) => Some(SystemClauseType::ModuleRetractClause),
("$module_head_is_dynamic", 2) => Some(SystemClauseType::ModuleHeadIsDynamic),
@@ -439,23 +450,21 @@ impl SystemClauseType {
("$get_current_block", 1) => Some(SystemClauseType::GetCurrentBlock),
("$get_cp", 1) => Some(SystemClauseType::GetCutPoint),
("$install_new_block", 1) => Some(SystemClauseType::InstallNewBlock),
("$raw_input_read_char", 1) => Some(SystemClauseType::RawInputReadChar),
("$read_query_term", 2) => Some(SystemClauseType::ReadQueryTerm),
("$read_term", 2) => Some(SystemClauseType::ReadTerm),
("$reset_block", 1) => Some(SystemClauseType::ResetBlock),
("$reset_global_var_at_key", 1) => Some(SystemClauseType::ResetGlobalVarAtKey),
("$reset_global_var_at_offset", 3) => Some(SystemClauseType::ResetGlobalVarAtOffset),
("$retract_clause", 4) => Some(SystemClauseType::RetractClause),
("$return_from_attribute_goals", 0) => Some(SystemClauseType::ReturnFromAttributeGoals),
("$return_from_verify_attr", 0) => Some(SystemClauseType::ReturnFromVerifyAttr),
("$set_ball", 1) => Some(SystemClauseType::SetBall),
("$set_cp_by_default", 1) => Some(SystemClauseType::SetCutPointByDefault(temp_v!(1))),
("$set_double_quotes", 1) => Some(SystemClauseType::SetDoubleQuotes),
("$set_seed", 1) => Some(SystemClauseType::SetSeed),
("$skip_max_list", 4) => Some(SystemClauseType::SkipMaxList),
("$store_global_var", 2) => Some(SystemClauseType::StoreGlobalVar),
("$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),
("$truncate_lh_to", 1) => Some(SystemClauseType::TruncateLiftedHeapTo),
("$unwind_stack", 0) => Some(SystemClauseType::UnwindStack),

View File

@@ -191,7 +191,7 @@ impl<'a> VariableFixtures<'a> {
for term_ref in iter {
if let &TermRef::Var(lvl, cell, ref var) = &term_ref {
let mut status = self.perm_vars.remove(var).unwrap_or((
let mut status = self.perm_vars.swap_remove(var).unwrap_or((
VarStatus::Temp(chunk_num, TempVarData::new(lt_arity)),
Vec::new(),
));

View File

@@ -338,6 +338,7 @@ pub struct Module {
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 inserted_expansions: bool, // has the module been successfully inserted into toplevel??
pub is_impromptu_module: bool,
}
#[derive(Clone, PartialEq, Eq)]

View File

@@ -329,7 +329,7 @@ pub fn requires_space(atom: &str, op: &str) -> bool {
.next()
.map(|oc| {
if ac == '0' {
oc == 'b' || oc == 'x' || oc == 'o' || oc == '\''
oc == '\'' || oc == '(' || alpha_numeric_char!(oc)
} else if alpha_numeric_char!(ac) {
oc == '(' || alpha_numeric_char!(oc)
} else if graphic_token_char!(ac) {
@@ -625,6 +625,10 @@ impl<'a, Outputter: HCValueOutputter> HCPrinter<'a, Outputter> {
iter.stack().last().cloned().and_then(|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() {
Some(var) => {
if !self.printed_vars.contains(&addr) {

View File

@@ -189,6 +189,8 @@ pub enum ArithmeticInstruction {
Or(ArithmeticTerm, ArithmeticTerm, usize),
Mod(ArithmeticTerm, ArithmeticTerm, usize),
Rem(ArithmeticTerm, ArithmeticTerm, usize),
Gcd(ArithmeticTerm, ArithmeticTerm, usize),
Sign(ArithmeticTerm, usize),
Cos(ArithmeticTerm, usize),
Sin(ArithmeticTerm, usize),
Tan(ArithmeticTerm, usize),
@@ -314,6 +316,10 @@ impl ArithmeticInstruction {
&ArithmeticInstruction::ATan2(ref at_1, ref 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::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),
@@ -358,14 +364,6 @@ pub enum 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 {
match self {
&ControlInstruction::Allocate(num_frames) => {

View File

@@ -20,7 +20,7 @@
'$default_attr_list'([PG | PGs], Module, AttrVar) -->
( { '$module_of'(Module, PG) } -> [Module:put_atts(AttrVar, PG)]
; true
; { true }
),
'$default_attr_list'(PGs, Module, AttrVar).
'$default_attr_list'([], _, _) --> [].

View File

@@ -150,7 +150,8 @@ comma_errors(G1, G2, B) :- '$call_with_default_policy'(','(G1, G2, B)).
','(!, Atom, B) :- Atom == !, '$set_cp'(B).
','(!, G, B) :- '$set_cp'(B), G.
','(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)).
','(G, Atom, B) :- Atom == !, !, G, '$set_cp'(B).
','(G1, G2, _) :- G1, G2.
@@ -561,12 +562,13 @@ assertz(Clause) :-
).
first_match_index([Clause0 | Clauses], Clause1, N0, N) :-
( Clause0 \= Clause1 -> N1 is N0 + 1,
first_match_index(Clauses, Clause1, N1, N)
( Clause0 \= Clause1 ->
N1 is N0 + 1,
first_match_index(Clauses, Clause1, N1, N)
; N0 = N, Clause0 = Clause1
).
retract_clauses([Clause|Clauses0], Head, Body, Name, Arity) :-
retract_clauses([Clause | Clauses0], Head, Body, Name, Arity) :-
functor(VarHead, Name, Arity),
findall((VarHead :- VarBody), clause(VarHead, VarBody), Clauses1),
first_match_index(Clauses1, (Head :- Body), 0, N),
@@ -574,7 +576,7 @@ retract_clauses([Clause|Clauses0], Head, Body, Name, Arity) :-
; true
),
'$retract_clause'(Name, Arity, N, Clauses1).
retract_clauses([_|Clauses0], Head, Body, Name, Arity) :-
retract_clauses([_ | Clauses0], Head, Body, Name, Arity) :-
retract_clauses(Clauses0, Head, Body, Name, Arity).
call_retract(Head, Body, Name, Arity) :-

View File

@@ -34,7 +34,7 @@
:- use_module(library(lists)).
:- use_module(library(non_iso)).
:- use_module(library(dcgs)).
%:- use_module(library(types)).
:- use_module(library(error), []).
:- attribute
clpb/1,
@@ -77,8 +77,8 @@ must_be(list(What), Where, Term) :- !,
must_be(ground, _, Term) :- !,
functor(Term, _, _).
must_be(Type, Goal-Arg, Term) :-
must_be(Term, Type, Goal, Arg).
must_be(Type, _, Term) :-
error:must_be(Type, Term).
clpz_list(Nil, _) :- Nil == [].
clpz_list(Ls, Where) :-
@@ -87,7 +87,6 @@ clpz_list(Ls, Where) :-
; Ls = [_|Rest],
clpz_list(Rest, Where)
).
instantiation_error(Term) :- instantiation_error(Term, unknown(Term)-1).
@@ -139,7 +138,10 @@ partition(Pred, Ls0, As, Bs) :-
include(Pred, Ls0, As),
exclude(Pred, Ls0, Bs).
sum_list(Ls, S) :- sumlist(Ls, S).
sum_list(Ls, S) :-
foldl(sum_, Ls, 0, S).
sum_(L, S0, S) :- S is S0 + L.
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Pairs.
@@ -1157,7 +1159,7 @@ labeling_var(V) :- V == 1, !.
labeling_var(V) :- domain_error(clpb_variable, V).
variables_in_index_order(Vs0, Vs) :-
maplist(var_with_index, Vs0, IVs0),
maplist(var_with_index, Vs0, IVs0),
keysort(IVs0, IVs),
pairs_values(IVs, Vs).
@@ -1242,8 +1244,7 @@ bdd_count(Node, VNum, Count) :-
bdd_count(High, VNum, HCount),
bdd_pow(Low, V, VNum, LPow),
bdd_pow(High, V, VNum, HPow),
Count0 is LPow*LCount + HPow*HCount,
Count = Count0
Count is LPow*LCount + HPow*HCount
)
).
@@ -1507,7 +1508,7 @@ max_variable_node(Node, V0-N0, V-N) :-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
ands_fusion(Ands0, Ands) :-
maplist(with_variables, Ands0, Pairs0),
maplist(with_variables, Ands0, Pairs0),
keysort(Pairs0, Pairs),
group_pairs_by_key(Pairs, Groups),
pairs_values(Groups, Andss),

View File

@@ -51,4 +51,5 @@ gather_dif_goals([(X \== Y) | Goals]) -->
attribute_goals(X) -->
{ get_atts(X, +dif(Goals)) },
gather_dif_goals(Goals).
gather_dif_goals(Goals),
{ put_atts(X, -dif(_)) }.

View File

@@ -33,6 +33,10 @@ must_be(Type, Term) :-
must_be_(Type, _) :-
var(Type),
instantiation_error(Type).
must_be_(var, Term) :-
( var(Term) -> true
; throw(error(uninstantiation_error, _))
).
must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(list, Term) :- check_(ilist, list, Term).
@@ -52,6 +56,7 @@ type(type).
type(integer).
type(atom).
type(list).
type(var).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
can_be(Type, Term)

View File

@@ -26,6 +26,7 @@ gather_freeze_goals(Attrs, _) -->
!.
gather_freeze_goals([frozen(X) | _], Var) -->
[freeze(Var, X)],
{ put_atts(Var, -frozen(_)) },
!.
gather_freeze_goals([_ | Attrs], Var) -->
gather_freeze_goals(Attrs, Var).

View File

@@ -3,6 +3,7 @@
maplist/4, maplist/5, maplist/6, maplist/7,
maplist/8, maplist/9]).
length(Xs, N) :-
var(N), !,
'$skip_max_list'(M, -1, Xs, Xs0),
@@ -30,17 +31,22 @@ length_rundown([_|Xs], N) :-
N1 is N-1,
length_rundown(Xs, N1).
member(X, [X|_]).
member(X, [_|Xs]) :- member(X, Xs).
select(X, [X|Xs], Xs).
select(X, [Y|Xs], [Y|Ys]) :- select(X, Xs, Ys).
append([], R, R).
append([X|L], R, [X|S]) :- append(L, R, S).
memberchk(X, Xs) :- member(X, Xs), !.
reverse(Xs, Ys) :-
( nonvar(Xs) -> reverse(Xs, Ys, [], Xs)
; reverse(Ys, Xs, [], Ys)
@@ -50,6 +56,7 @@ reverse([], [], YsRev, YsRev).
reverse([X1|Xs], [Y1|Ys], YsPreludeRev, Xss) :-
reverse(Xs, Ys, [Y1|YsPreludeRev], Xss).
maplist(_, []).
maplist(Cont1, [E1|E1s]) :-
call(Cont1, E1),

View File

@@ -4,8 +4,8 @@
%% ?- use_module(library(non_iso)).
:- module(non_iso, [bb_b_put/2, bb_get/2, bb_put/2, call_cleanup/2,
call_with_inference_limit/3, forall/2,
setup_call_cleanup/3, variant/2]).
call_with_inference_limit/3, forall/2, maybe/0,
set_random/1, setup_call_cleanup/3, variant/2]).
forall(Generate, Test) :-
\+ (Generate, \+ Test).
@@ -125,3 +125,17 @@ call_with_inference_limit(_, _, R, Bb, B) :-
'$call_with_default_policy'(handle_ile(B, Ball, R)).
variant(X, Y) :- '$variant'(X, Y).
% succeeds with probability 0.5.
maybe :- '$maybe'.
set_random(Seed) :-
( nonvar(Seed) ->
( Seed = 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(instantiation_error, set_random/1))
).

View File

@@ -25,6 +25,7 @@ verify_attrs([], _, _, []).
call_verify_attributes(Attrs, _, _, []) :-
var(Attrs), !.
call_verify_attributes([], _, _, []).
call_verify_attributes([Attr|Attrs], Var, Value, ListOfGoalLists) :-
gather_modules([Attr|Attrs], Modules0),
sort(Modules0, Modules),

View File

@@ -1,7 +1,5 @@
use crate::prolog::machine::*;
use indexmap::IndexSet;
use std::vec::IntoIter;
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) bindings: Bindings,
pub(super) cp: LocalCodePtr,
pub(super) instigating_p: LocalCodePtr,
pub(super) verify_attrs_loc: usize,
pub(super) project_attrs_loc: usize,
}
@@ -24,6 +23,7 @@ impl AttrVarInitializer {
attribute_goals: vec![],
attr_var_queue: vec![],
bindings: vec![],
instigating_p: LocalCodePtr::default(),
cp: LocalCodePtr::default(),
verify_attrs_loc,
project_attrs_loc,
@@ -34,16 +34,19 @@ impl AttrVarInitializer {
pub(super) fn reset(&mut self) {
self.attr_var_queue.clear();
self.bindings.clear();
self.attribute_goals.clear();
}
}
impl MachineState {
pub(super) fn push_attr_var_binding(&mut self, h: usize, addr: Addr) {
if self.attr_var_init.bindings.is_empty() {
self.attr_var_init.instigating_p = self.p.local();
if self.last_call {
self.attr_var_init.cp = self.cp;
} 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);
@@ -96,54 +99,18 @@ impl MachineState {
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) {
let rs = MAX_ARITY;
// 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);
self.allocate(self.num_of_args + 2);
let e = self.e;
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][rs + 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 + 1] = Addr::Con(Constant::Usize(self.b0));
self.and_stack[e][self.num_of_args + 2] = Addr::Con(Constant::Usize(self.num_of_args));
self.verify_attributes();
@@ -151,57 +118,4 @@ impl MachineState {
self.b0 = self.b;
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)
}
}

View File

@@ -62,25 +62,34 @@ fn load_module<R: Read>(
stream: ParsingStream<R>,
suppress_warnings: bool,
listing_src: ClauseName,
) -> Result<Option<ClauseName>, SessionError> {
) -> Result<ClauseName, SessionError> {
// follow the operation of compile_user_module, but before
// compiling, check that a module is declared in the file. if not,
// throw an exception.
let mut indices = default_index_store!(wam.indices.atom_tbl.clone());
setup_indices(wam, clause_name!("builtins"), &mut indices)?;
let mut compiler = ListingCompiler::new(
&wam.code_repo,
suppress_warnings,
listing_src,
listing_src.clone(),
);
let results = compiler.gather_items(wam, stream, &mut indices);
let module_name = if let Some(ref module) = &compiler.module {
Some(module.module_decl.name.clone())
module.module_decl.name.clone()
} 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))
@@ -97,7 +106,7 @@ fn load_module_from_file(
wam: &mut Machine,
filename: &str,
suppress_warnings: bool,
) -> Result<Option<ClauseName>, SessionError> {
) -> Result<ClauseName, SessionError> {
let path = fix_filename(wam.indices.atom_tbl.clone(), filename)?;
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()))
}
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(
code_repo: &mut CodeRepo,
hook: CompileTimeHook,
@@ -311,25 +258,21 @@ fn add_hooks_to_mockup(
preds.1.extend(expansions.1.into_iter());
}
fn setup_module_expansions(wam: &mut Machine, module_name: ClauseName) {
match wam.indices.modules.get(&module_name) {
Some(module) => {
let term_expansions = module.term_expansions.clone();
let goal_expansions = module.goal_expansions.clone();
fn setup_module_expansions(wam: &mut Machine, module: &Module) {
let term_expansions = module.term_expansions.clone();
let goal_expansions = module.goal_expansions.clone();
add_hooks_to_mockup(
&mut wam.code_repo,
CompileTimeHook::TermExpansion,
term_expansions,
);
add_hooks_to_mockup(
&mut wam.code_repo,
CompileTimeHook::GoalExpansion,
goal_expansions,
);
}
_ => unreachable!(),
}
add_hooks_to_mockup(
&mut wam.code_repo,
CompileTimeHook::TermExpansion,
term_expansions,
);
add_hooks_to_mockup(
&mut wam.code_repo,
CompileTimeHook::GoalExpansion,
goal_expansions,
);
}
pub(super) fn compile_into_module<R: Read>(
@@ -339,13 +282,21 @@ pub(super) fn compile_into_module<R: Read>(
name: ClauseName,
) -> EvalSession {
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());
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,
Err(e) => {
if let Some(module) = compiler.module.take() {
wam.indices.insert_module(module);
}
compiler.drop_expansions(wam.machine_flags(), &mut wam.code_repo);
EvalSession::from(e)
}
@@ -355,29 +306,28 @@ pub(super) fn compile_into_module<R: Read>(
fn compile_into_module_impl<R: Read>(
wam: &mut Machine,
compiler: &mut ListingCompiler,
module_name: ClauseName,
module: Module,
src: ParsingStream<R>,
mut indices: IndexStore,
) -> 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();
wam.code_repo
.compile_hook(CompileTimeHook::TermExpansion, flags)?;
wam.code_repo
.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
wam.code_repo.compile_hook(CompileTimeHook::TermExpansion, flags)?;
wam.code_repo.compile_hook(CompileTimeHook::GoalExpansion, flags)?;
let results = compiler.gather_items(wam, src, &mut indices)?;
let module_code =
compiler.generate_code(results.worker_results, wam, &mut indices.code_dir, 0)?;
let mut clause_code_generator = ClauseCodeGenerator::new(module_code.len(), module_name.clone());
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
update_module_indices(wam, module_name, indices);
wam.code_repo.code.extend(module_code.into_iter());
add_module_code(wam, compiler.module.take().unwrap(), module_code, indices);
clause_code_generator.add_clause_code(wam, results.dynamic_clause_map);
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(
&mut self,
dynamic_clause_map: &DynamicClauseMap,
@@ -491,29 +442,15 @@ pub struct ListingCompiler {
listing_src: ClauseName // a file? a module?
}
fn add_toplevel_code(wam: &mut Machine, code: Code, mut indices: IndexStore) {
let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());
let op_dir = mem::replace(&mut indices.op_dir, OpDir::new());
wam.add_batched_code(code, code_dir);
wam.add_batched_ops(op_dir);
fn add_toplevel_code(wam: &mut Machine, code: Code, indices: IndexStore) {
wam.add_batched_code(code, indices.code_dir);
wam.add_batched_ops(indices.op_dir);
}
#[inline]
fn add_module_code(wam: &mut Machine, mut module: Module, code: Code, mut indices: IndexStore) {
let code_dir = mem::replace(&mut indices.code_dir, CodeDir::new());
let op_dir = mem::replace(&mut indices.op_dir, OpDir::new());
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));
}
}
fn add_module_code(wam: &mut Machine, mut module: Module, code: Code, indices: IndexStore) {
module.code_dir.extend(indices.code_dir);
module.op_dir.extend(indices.op_dir.into_iter());
wam.add_module(module, code);
}
@@ -543,9 +480,8 @@ fn load_library(
) -> Result<ClauseName, SessionError> {
match LIBRARIES.borrow().get(name.as_str()) {
Some(code) => {
let module_name = load_module(wam, parsing_stream(code.as_bytes()),
suppress_warnings, name.clone())?;
module_name.ok_or(SessionError::NoModuleDeclaration(name))
load_module(wam, parsing_stream(code.as_bytes()),
suppress_warnings, name.clone())
}
None => Err(SessionError::ModuleNotFound)
}
@@ -848,28 +784,19 @@ impl ListingCompiler {
}
Declaration::UseModule(ModuleSource::File(filename)) => {
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)
} else {
Ok(())
}
self.use_module(name, &mut wam.code_repo, flags, &mut wam.indices, indices)
}
Declaration::UseQualifiedModule(ModuleSource::File(filename), exports) => {
let name = load_module_from_file(wam, filename.as_str(), true)?;
if let Some(name) = name {
self.use_qualified_module(
name,
&mut wam.code_repo,
flags,
&exports,
&mut wam.indices,
indices,
)
} else {
Ok(())
}
self.use_qualified_module(
name,
&mut wam.code_repo,
flags,
&exports,
&mut wam.indices,
indices,
)
}
Declaration::ModuleInitialization(query_terms, queue) => {
self.initialization_goals.0.extend(query_terms.into_iter());
@@ -901,7 +828,7 @@ impl ListingCompiler {
CodeIndex::dynamic_undefined(self.get_module_name()));
}
&Declaration::Hook(hook, _, ref queue) if self.module.is_none() => worker
.term_stream
.term_stream
.incr_expansion_lens(hook.user_scope(), 1, queue.len()),
&Declaration::Hook(hook, _, ref queue) if !hook.has_module_scope() => {
worker.term_stream.incr_expansion_lens(hook, 1, queue.len())
@@ -996,6 +923,7 @@ fn compile_work_impl(
&mut indices.code_dir,
0
)?;
let toplvl_code = compiler.generate_code(
results.toplevel_results,
wam,
@@ -1004,8 +932,10 @@ fn compile_work_impl(
)?;
if let Some(ref mut module) = &mut compiler.module {
module.user_term_expansions = results.addition_results.take_term_expansions();
module.user_goal_expansions = results.addition_results.take_goal_expansions();
if !module.is_impromptu_module {
module.user_term_expansions = results.addition_results.take_term_expansions();
module.user_goal_expansions = results.addition_results.take_goal_expansions();
}
}
let flags = wam.machine_flags();
@@ -1013,7 +943,13 @@ fn compile_work_impl(
wam.code_repo.compile_hook(CompileTimeHook::UserTermExpansion, 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 =
ClauseCodeGenerator::new(module_code.len() + toplvl_code.len(),
module.module_decl.name.clone());
@@ -1021,9 +957,22 @@ fn compile_work_impl(
wam.check_toplevel_code(&results.toplevel_indices)?;
clause_code_generator.generate_clause_code(&results.dynamic_clause_map, wam)?;
add_module_code(wam, module, module_code, indices);
add_toplevel_code(wam, toplvl_code, results.toplevel_indices);
if let Some(ref module) = wam.indices.modules.swap_remove(&module.module_decl.name) {
wam.indices.remove_module(clause_name!("user"), module);
}
if module.is_impromptu_module {
add_module_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);
} else {
add_non_module_code(
@@ -1039,7 +988,10 @@ fn compile_work_impl(
)?;
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 {

View File

@@ -30,7 +30,7 @@ impl Machine {
match module.as_str() {
"user" => compile_user_module(self, src, true, user_src),
_ => compile_into_module(self, module, src, name)
_ => compile_into_module(self, module, src, name)
}
}
None => compile_user_module(self, src, true, user_src),
@@ -76,16 +76,27 @@ impl Machine {
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) {
let (name, arity) = self.get_predicate_key(name, arity);
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
self.make_undefined(name.clone(), arity);
self.indices.remove_code_index((name.clone(), arity));
self.indices
.remove_clause_subsection(name.owning_module(), name, arity);
self.indices.remove_clause_subsection(name.owning_module(), name, arity);
}
fn abolish_dynamic_clause_in_module(&mut self, name: RegType, arity: RegType, module: RegType) {
@@ -106,15 +117,10 @@ impl Machine {
_ => unreachable!(),
};
if let Some(idx) = self.indices.code_dir.get(&(name.clone(), arity)) {
if idx.module_name() == module_name {
set_code_index!(idx, IndexPtr::DynamicUndefined, clause_name!("user"));
}
}
self.make_undefined_in_module(module_name.clone(), name.clone(), arity);
self.indices.remove_code_index((name.clone(), arity));
self.indices
.remove_clause_subsection(module_name, name, arity);
self.indices.remove_clause_subsection(module_name, name, arity);
}
fn handle_eval_result_from_dynamic_compile(
@@ -210,6 +216,10 @@ impl Machine {
let mut addrs = VecDeque::from(addrs);
addrs.remove(index);
if addrs.is_empty() {
self.make_undefined(name.clone(), arity);
}
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => return self.machine_st.throw_exception(err),
@@ -239,6 +249,10 @@ impl Machine {
let mut addrs = VecDeque::from(addrs);
addrs.remove(index);
if addrs.is_empty() {
self.make_undefined(name.clone(), arity);
}
self.print_new_dynamic_clause(addrs, name.clone(), arity)
}
Err(err) => return self.machine_st.throw_exception(err),

View File

@@ -143,9 +143,6 @@ impl MachineError {
"private_procedure",
clause_name!("module_does_not_exist"),
),
SessionError::NoModuleDeclaration(name) => {
Self::existence_error(h, ExistenceError::Module(name))
}
SessionError::OpIsInfixAndPostFix(op) => {
Self::permission_error(PermissionError::Create, "operator", op)
}
@@ -538,18 +535,13 @@ pub enum SessionError {
ModuleDoesNotContainExport,
ModuleNotFound,
NamelessEntry,
NoModuleDeclaration(ClauseName),
OpIsInfixAndPostFix(ClauseName),
ParserError(ParserError),
UserPrompt,
}
pub enum EvalSession {
EntrySuccess,
Error(SessionError),
InitialQuerySuccess(AllocVarDict),
QueryFailure,
SubsequentQuerySuccess,
}
impl From<SessionError> for EvalSession {

View File

@@ -178,10 +178,11 @@ impl From<Ref> for Addr {
}
}
#[derive(Clone)]
#[derive(Clone, Copy)]
pub enum TrailRef {
Ref(Ref),
AttrVarLink(usize, Addr),
AttrVarHeapLink(usize),
AttrVarListLink(usize, usize),
}
impl From<Ref> for TrailRef {
@@ -299,7 +300,6 @@ pub enum DynamicTransactionType {
#[derive(Clone, Copy, PartialOrd, Ord, PartialEq, Eq)]
pub enum REPLCodePtr {
CompileBatch,
SubmitQueryAndPrintResults,
UseModule,
UseQualifiedModule,
UseModuleFromFile,
@@ -467,7 +467,7 @@ pub struct IndexStore {
pub(super) op_dir: OpDir,
}
impl IndexStore {
impl IndexStore {
pub fn predicate_exists(
&self,
name: ClauseName,

View File

@@ -318,7 +318,7 @@ impl MachineState {
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.num_of_args = arity;
self.b0 = self.b;
@@ -706,7 +706,7 @@ pub(crate) trait CallPolicy: Any {
&BuiltInClauseType::Nl => {
let mut stdout = stdout();
write!(stdout, "\n\r").unwrap();
write!(stdout, "\n").unwrap();
stdout.flush().unwrap();
return_from_clause!(machine_st.last_call, machine_st)
}

View File

@@ -6,7 +6,6 @@ use crate::prolog::arithmetic::*;
use crate::prolog::clause_types::*;
use crate::prolog::forms::*;
use crate::prolog::heap_iter::*;
use crate::prolog::heap_print::*;
use crate::prolog::instructions::*;
use crate::prolog::machine::INTERRUPT;
use crate::prolog::machine::and_stack::*;
@@ -27,7 +26,6 @@ use indexmap::{IndexMap, IndexSet};
use std::cmp::{max, min, Ordering};
use std::f64;
use std::mem;
use std::rc::Rc;
macro_rules! try_numeric_result {
($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(
&mut self,
pdl: &mut Vec<Addr>,
@@ -648,9 +613,15 @@ impl MachineState {
self.tr += 1;
}
}
TrailRef::AttrVarLink(h, prev_addr) => {
TrailRef::AttrVarHeapLink(h) => {
if h < self.hb {
self.trail.push(TrailRef::AttrVarLink(h, prev_addr));
self.trail.push(TrailRef::AttrVarHeapLink(h));
self.tr += 1;
}
}
TrailRef::AttrVarListLink(h, l) => {
if h < self.hb {
self.trail.push(TrailRef::AttrVarListLink(h, l));
self.tr += 1;
}
}
@@ -680,7 +651,7 @@ impl MachineState {
// additions, now that deleted attributes can be undeleted by
// backtracking.
for i in (a1..a2).rev() {
match self.trail[i].clone() {
match self.trail[i] {
TrailRef::Ref(Ref::HeapCell(h)) => {
self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h))
}
@@ -690,8 +661,11 @@ impl MachineState {
TrailRef::Ref(Ref::StackCell(fr, sc)) => {
self.and_stack[fr][sc] = Addr::StackCell(fr, sc)
}
TrailRef::AttrVarLink(h, prev_addr) => {
self.heap[h] = HeapCellValue::Addr(prev_addr)
TrailRef::AttrVarHeapLink(h) => {
self.heap[h] = HeapCellValue::Addr(Addr::HeapCell(h));
}
TrailRef::AttrVarListLink(h, l) => {
self.heap[h] = HeapCellValue::Addr(Addr::Lis(l));
}
}
}
@@ -732,28 +706,21 @@ impl MachineState {
}
let b = self.b - 1;
let mut i = self.or_stack[b].tr;
let hb = self.hb;
let mut offset = 0;
while i < self.tr {
let tr_i = self.trail[i].clone();
let hb = self.hb;
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::HeapCell(tr_i))
| TrailRef::AttrVarLink(tr_i, _) => {
if tr_i < hb {
i += 1;
} else {
let tr = self.tr;
let val = self.trail[tr - 1].clone();
self.trail[i] = val;
self.trail.pop();
self.tr -= 1;
}
}
| TrailRef::Ref(Ref::HeapCell(tr_i))
| TrailRef::AttrVarHeapLink(tr_i)
| TrailRef::AttrVarListLink(tr_i, _) =>
if tr_i >= hb {
offset += 1;
} else {
self.trail[i - offset] = self.trail[i];
},
TrailRef::Ref(Ref::StackCell(fr, _)) => {
let b = self.b - 1;
let fr_gi = self.and_stack[fr].global_index;
let b_gi = if !self.or_stack.is_empty() {
self.or_stack[b].global_index
@@ -761,18 +728,17 @@ impl MachineState {
0
};
if fr_gi < b_gi {
i += 1;
if fr_gi >= b_gi {
offset += 1;
} else {
let tr = self.tr;
let val = self.trail[tr - 1].clone();
self.trail[i] = val;
self.trail.pop();
self.tr -= 1;
self.trail[i - offset] = self.trail[i];
}
}
};
}
}
self.tr -= offset;
self.trail.truncate(self.tr);
}
#[inline]
@@ -939,6 +905,7 @@ impl MachineState {
"mod" => interms.push(Number::Integer(self.modulus(a1, a2)?)),
"rem" => interms.push(Number::Integer(self.remainder(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))
}
@@ -966,6 +933,7 @@ impl MachineState {
"ceiling" => interms.push(Number::Integer(self.ceiling(a1))),
"floor" => interms.push(Number::Integer(self.floor(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))
}
@@ -1098,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> {
let f1 = result_f(&n1, rnd_f);
let f2 = result_f(&n2, rnd_f);
@@ -1354,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> {
let stub = MachineError::functor_stub(clause_name!("(rem)"), 2);
@@ -1439,6 +1437,13 @@ impl MachineState {
self.interms[t - 1] = try_or_fail!(self, self.int_pow(n1, n2));
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) => {
let n1 = try_or_fail!(self, self.get_number(a1));
let n2 = try_or_fail!(self, self.get_number(a2));
@@ -1476,6 +1481,12 @@ impl MachineState {
self.interms[t - 1] = n1.abs();
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) => {
let n1 = try_or_fail!(self, self.get_number(a1));
@@ -1665,7 +1676,7 @@ impl MachineState {
} else if s.is_expandable() {
self.heap
.push(HeapCellValue::Addr(Addr::Con(Constant::String(s.clone()))));
self.s = h;
self.mode = MachineMode::Read;
} else {
@@ -3230,6 +3241,8 @@ impl MachineState {
)
),
};
self.last_call = false;
}
pub(super) fn execute_ctrl_instr(
@@ -3265,7 +3278,7 @@ impl MachineState {
self.b0 = self.b;
self.p += offset;
}
&ControlInstruction::Proceed => self.p = CodePtr::Local(self.cp.clone()),
&ControlInstruction::Proceed => self.p = CodePtr::Local(self.cp.clone())
};
}
@@ -3424,56 +3437,4 @@ impl MachineState {
self.heap_locs.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![]);
}
}

View File

@@ -2,12 +2,11 @@ use prolog_parser::ast::*;
use prolog_parser::tabled_rc::*;
use crate::prolog::clause_types::*;
use crate::prolog::fixtures::*;
use crate::prolog::forms::*;
use crate::prolog::heap_print::*;
use crate::prolog::instructions::*;
use crate::prolog::machine::heap::Heap;
use crate::prolog::read::*;
use crate::prolog::write::{next_keypress, ContinueResult};
mod and_stack;
mod attributed_variables;
@@ -35,21 +34,18 @@ use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use crate::prolog::machine::machine_state::*;
use crate::prolog::machine::modules::*;
use crate::prolog::machine::toplevel::stream_to_toplevel;
use crate::prolog::read::PrologStream;
use indexmap::IndexMap;
use std::collections::VecDeque;
use std::fs::File;
use std::io::{stdout, Read, Write};
use std::io::Read;
use std::mem;
use std::ops::Index;
use std::rc::Rc;
use std::sync::atomic::AtomicBool;
use termion::raw::IntoRawMode;
pub struct MachinePolicies {
call_policy: Box<dyn CallPolicy>,
cut_policy: Box<dyn CutPolicy>,
@@ -71,6 +67,7 @@ impl MachinePolicies {
pub struct Machine {
pub(super) machine_st: MachineState,
pub(super) inner_heap: Heap,
pub(super) policies: MachinePolicies,
pub(super) indices: IndexStore,
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) {
if let Some(ref code_idx) = self.code_dir.get(&(name.clone(), arity)) {
if !code_idx.is_undefined() {
println!("warning: overwriting {}/{}", &name, arity);
println!("Warning: overwriting {}/{}", &name, arity);
}
let (p, module_name) = idx.0.borrow().clone();
@@ -182,7 +179,8 @@ impl Machine {
Ok(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)
@@ -190,14 +188,28 @@ impl Machine {
Ok(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();
compile_user_module(self, parsing_stream(TOPLEVEL.as_bytes()),
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) {
@@ -226,14 +238,17 @@ impl Machine {
self.machine_st.reset();
}
pub fn run_init_code(&mut self, code: Code) {
let old_machine_st = self.machine_st.sink_to_snapshot();
self.machine_st.reset();
pub fn run_init_code(&mut self, code: Code) -> bool {
let old_machine_st = self.sink_to_snapshot();
self.machine_st.reset();
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) {
@@ -254,12 +269,13 @@ impl Machine {
self.machine_st[temp_v!(1)] = list_addr;
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 {
let mut wam = Machine {
machine_st: MachineState::new(),
inner_heap: Heap::with_capacity(256 * 256),
policies: MachinePolicies::new(),
indices: IndexStore::new(),
code_repo: CodeRepo::new(),
@@ -288,7 +304,10 @@ impl Machine {
compile_user_module(&mut wam, parsing_stream(SI.as_bytes()), true,
clause_name!("si"));
wam.compile_top_level();
if wam.compile_top_level().is_err() {
panic!("Loading '$toplevel' module failed");
}
wam.compile_scryerrc();
wam
@@ -370,17 +389,6 @@ impl Machine {
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) {
let h = self.machine_st.heap.h;
@@ -440,29 +448,27 @@ impl Machine {
let load_result = match to_src(name) {
ModuleSource::Library(name) =>
if !self.indices.modules.contains_key(&name) {
load_library(self, name, false).map(Some)
if let Some(module) = self.indices.take_module(name.clone()) {
self.indices.remove_module(clause_name!("user"), &module);
self.indices.modules.insert(name.clone(), module);
Ok(name)
} else {
Ok(Some(name))
load_library(self, name, false)
},
ModuleSource::File(name) =>
load_module_from_file(self, name.as_str(), false)
};
let result = load_result.and_then(|name|
if let Some(name) = name {
let module = self.indices.take_module(name).unwrap();
let result = load_result.and_then(|name| {
let module = self.indices.take_module(name.clone()).unwrap();
// remove previous exports.
self.indices.remove_module(clause_name!("user"), &module);
self.indices.use_module(&mut self.code_repo, self.machine_st.flags,
&module)?;
Ok(self.indices.insert_module(module))
} else {
Ok(())
if !module.is_impromptu_module {
self.indices.use_module(&mut self.code_repo, self.machine_st.flags, &module)?;
}
);
Ok(self.indices.insert_module(module))
});
self.code_repo.cached_query = cached_query;
@@ -487,31 +493,30 @@ impl Machine {
let load_result = match to_src(name) {
ModuleSource::Library(name) =>
if !self.indices.modules.contains_key(&name) {
load_library(self, name, false).map(Some)
if let Some(module) = self.indices.take_module(name.clone()) {
self.indices.remove_module(clause_name!("user"), &module);
self.indices.modules.insert(name.clone(), module);
Ok(name)
} else {
Ok(Some(name))
load_library(self, name, false)
},
ModuleSource::File(name) =>
load_module_from_file(self, name.as_str(), false)
};
let result = load_result.and_then(|name|
if let Some(name) = name {
let module = self.indices.take_module(name).unwrap();
let result = load_result.and_then(|name| {
let module = self.indices.take_module(name.clone()).unwrap();
// remove previous exports.
self.indices.remove_module(clause_name!("user"), &module);
if !module.is_impromptu_module {
self.indices.use_qualified_module(&mut self.code_repo,
self.machine_st.flags,
&module,
&exports)?;
Ok(self.indices.insert_module(module))
} else {
Ok(())
}
);
Ok(self.indices.insert_module(module))
});
self.code_repo.cached_query = cached_query;
@@ -532,55 +537,6 @@ impl Machine {
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 =>
self.use_module(ModuleSource::Library),
REPLCodePtr::UseModuleFromFile =>
@@ -594,157 +550,78 @@ impl Machine {
self.machine_st.p = CodePtr::Local(p);
}
fn propagate_exception_to_toplevel(&mut self, snapshot: MachineState) {
let ball = self.machine_st.ball.take();
fn sink_to_snapshot(&mut self) -> MachineState {
let mut snapshot = MachineState::with_capacity(0);
snapshot.hb = self.machine_st.hb;
snapshot.e = self.machine_st.e;
snapshot.b = self.machine_st.b;
snapshot.b0 = self.machine_st.b0;
snapshot.s = self.machine_st.s;
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;
self.machine_st.absorb_snapshot(snapshot);
self.machine_st.ball = ball;
snapshot.fail = self.machine_st.fail;
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;
let h = self.machine_st.heap.h;
let stub = self.machine_st.ball.copy_and_align(h);
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![]);
self.machine_st.throw_exception(stub);
return;
snapshot
}
fn handle_eval_session(&mut self, result: EvalSession, snapshot: MachineState) {
match result {
EvalSession::InitialQuerySuccess(alloc_locs) => loop {
let bindings = {
let output = PrinterOutputter::new();
self.toplevel_heap_view(output).result()
};
fn absorb_snapshot(&mut self, mut snapshot: MachineState) {
self.machine_st.hb = snapshot.hb;
self.machine_st.e = snapshot.e;
self.machine_st.b = snapshot.b;
self.machine_st.b0 = snapshot.b0;
self.machine_st.s = snapshot.s;
self.machine_st.tr = snapshot.tr;
self.machine_st.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) {
if bindings.is_empty() {
let space = if requires_space(&attr_goals, ".") {
" "
} else {
""
};
self.inner_heap = self.machine_st.heap.take();
self.inner_heap.truncate(0);
if !attr_goals.is_empty() {
println!("{}{}.", attr_goals, space);
} else {
println!("true.");
}
self.machine_st.heap = snapshot.heap.take();
self.machine_st.mode = snapshot.mode;
self.machine_st.and_stack = snapshot.and_stack.take();
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.absorb_snapshot(snapshot);
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);
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![]);
}
pub(super) fn run_query(&mut self, alloc_locs: &AllocVarDict) {
pub(super) fn run_query(&mut self) {
self.machine_st.cp = LocalCodePtr::TopLevel(0, self.code_repo.size_of_cached_query());
let end_ptr = CodePtr::Local(self.machine_st.cp);
while self.machine_st.p < end_ptr {
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(
&mut self.indices,
&mut self.policies,
@@ -763,63 +640,18 @@ impl Machine {
self.dynamic_transaction(trans_type, 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;
break;
}
self.code_repo.cached_query = cached_query;
}
_ => {
if self.machine_st.heap_locs.is_empty() {
self.machine_st.record_var_places(0, alloc_locs);
}
break;
}
_ =>
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)]
pub fn test_heap_view<Outputter>(&self, mut output: Outputter) -> Outputter
where
@@ -836,63 +668,9 @@ impl Machine {
output
}
pub fn or_stack_is_empty(&self) -> bool {
self.machine_st.b == 0
}
}
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(
&mut self,
instr: &Line,
@@ -1048,7 +826,13 @@ impl MachineState {
CodePtr::VerifyAttrInterrupt(_) => {
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 {
break;
}

View File

@@ -22,6 +22,7 @@ impl Module {
code_dir: CodeDir::new(),
op_dir: default_op_dir(),
inserted_expansions: false,
is_impromptu_module: false,
}
}
@@ -162,7 +163,7 @@ pub trait SubModuleUser {
self.insert_dir_entry(name, arity, code_data.clone());
true
} else {
found_op
found_op || submodule.is_impromptu_module
}
}

View File

@@ -1,10 +1,9 @@
driver(QueryVars, AttrVars) :-
'$attribute_goals_driver'(QueryVars, AttrVars) :-
gather_modules(AttrVars, Modules0, _),
sort(Modules0, Modules),
call_project_attributes(Modules, QueryVars, AttrVars),
call_attribute_goals(Modules, call_query_var_goals, QueryVars),
call_attribute_goals(Modules, call_attr_var_goals, AttrVars),
'$return_from_attribute_goals'.
call_attribute_goals(Modules, call_attr_var_goals, AttrVars).
enqueue_goals(Goals0) :-
nonvar(Goals0),

View File

@@ -17,14 +17,39 @@ use crate::prolog::ordered_float::OrderedFloat;
use crate::prolog::read::{readline, PrologStream};
use crate::prolog::rug::Integer;
use crate::ref_thread_local::RefThreadLocal;
use indexmap::{IndexMap, IndexSet};
use std::collections::VecDeque;
use std::io::{stdout, Write};
use std::io::{stdin, stdout, Write};
use std::iter::once;
use std::mem;
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 {
hare: usize,
tortoise: usize,
@@ -679,7 +704,8 @@ impl MachineState {
let c = self.int_to_char_code(&n, "atom_codes", 2)?;
chars.push(c as char);
}
&Addr::Con(Constant::CharCode(c)) => chars.push(c as char),
&Addr::Con(Constant::CharCode(c)) =>
chars.push(c as char),
_ => {
let err = MachineError::type_error(
ValidType::Integer,
@@ -713,6 +739,17 @@ impl MachineState {
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 => {
let stub = MachineError::functor_stub(clause_name!("number_chars"), 2);
@@ -1018,8 +1055,14 @@ impl MachineState {
tail
};
let trail_ref = match old_addr {
Addr::HeapCell(h) => TrailRef::AttrVarHeapLink(h),
Addr::Lis(l) => TrailRef::AttrVarListLink(l1 + 1, l),
_ => unreachable!()
};
self.heap[l1 + 1] = HeapCellValue::Addr(tail);
self.trail(TrailRef::AttrVarLink(l1 + 1, old_addr));
self.trail(trail_ref);
}
}
}
@@ -1041,7 +1084,7 @@ impl MachineState {
};
self.heap[h + 1] = HeapCellValue::Addr(tail);
self.trail(TrailRef::AttrVarLink(h + 1, Addr::Lis(l)));
self.trail(TrailRef::AttrVarListLink(h + 1, l));
}
_ => unreachable!(),
}
@@ -1255,6 +1298,19 @@ impl MachineState {
_ => self.fail = true,
}
}
&SystemClauseType::Maybe => {
let result = {
let mut rand = RANDOM_STATE.borrow_mut();
if rand.bits(1) == 0 {
true
} else {
false
}
};
self.fail = result;
}
&SystemClauseType::OpDeclaration => {
let priority = self[temp_v!(1)].clone();
let specifier = self[temp_v!(2)].clone();
@@ -1307,6 +1363,17 @@ impl MachineState {
&SystemClauseType::TruncateIfNoLiftedHeapGrowth => {
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 => {
let attr_var = self.store(self.deref(self[temp_v!(1)].clone()));
let attr_var_list = match attr_var {
@@ -1348,6 +1415,18 @@ impl MachineState {
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,
}
}
@@ -1663,11 +1742,6 @@ impl MachineState {
self.p = CodePtr::DynamicTransaction(trans_type, p);
return Ok(());
}
&SystemClauseType::ReturnFromAttributeGoals => {
self.deallocate();
self.p = CodePtr::Local(LocalCodePtr::TopLevel(0, 0));
return Ok(());
}
&SystemClauseType::ReturnFromVerifyAttr => {
let e = self.e;
let frame_len = self.and_stack[e].len();
@@ -1817,6 +1891,21 @@ impl MachineState {
&SystemClauseType::InstallNewBlock => {
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 => {
readline::set_prompt(true);
let result = self.read_term(current_input_stream, indices);
@@ -1834,6 +1923,31 @@ impl MachineState {
}
&SystemClauseType::SetBall =>
self.set_ball(),
&SystemClauseType::SetSeed => {
let seed = self.store(self.deref(self[temp_v!(1)].clone()));
let seed = match seed {
Addr::Con(Constant::Integer(n)) =>
n,
Addr::Con(Constant::CharCode(c)) =>
Integer::from(c),
Addr::Con(Constant::Rational(r)) => {
if r.denom() == &1 {
r.numer().clone()
} else {
self.fail = true;
return Ok(());
}
}
_ => {
self.fail = true;
return Ok(());
}
};
let mut rand = RANDOM_STATE.borrow_mut();
rand.seed(&seed);
}
&SystemClauseType::SkipMaxList =>
if let Err(err) = self.skip_max_list() {
return Err(err);

View File

@@ -136,11 +136,6 @@ impl<'a, R: Read> TermStream<'a, R> {
pub fn top_level_terms(&mut self) -> Vec<(Term, usize, usize)> {
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]
pub fn incr_expansion_lens(&mut self, hook: CompileTimeHook, len: usize, queue_len: usize) {

View File

@@ -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> {
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 {
flags: MachineFlags,
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 struct TopLevelBatchWorker<'a, R: Read> {

View File

@@ -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 {
($r: expr) => {
Line::Cut(CutInstruction::GetLevelAndUnify($r))

View File

@@ -1,8 +1,4 @@
/*
* inserting the modules should not result in the insertion of
* code. this is because they're already loaded by this point -- see
* Machine::new.
*/
:- module('$toplevel', ['$repl'/1, consult/1, use_module/1, use_module/2]).
:- use_module(library(lists)).
:- use_module(library(si)).
@@ -27,12 +23,88 @@
% make '$compile_batch', a system routine, callable.
'$$compile_batch' :- '$compile_batch'.
'$instruction_match'([user], []) :-
!, catch('$$compile_batch', E, '$print_exception_with_check'(E)).
'$instruction_match'([Item], []) :-
( 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) :-
'$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) :-
write_term('caught: ', [quoted(false)]),
writeq(E),
@@ -61,6 +133,11 @@
; throw(error(instantiation_error, Source))
).
consult(Item) :-
( atom(Item) -> use_module(Item)
; throw(error(type_error(atom, Item), consult/1))
).
use_module(Module) :-
( nonvar(Module) ->
( Module = library(Filename) -> '$use_module'(Filename)
@@ -90,40 +167,50 @@ user:term_expansion(Term0, (:- initialization(ExpandedGoals))) :-
expand_goals(Goals, ExpandedGoals),
Goals \== ExpandedGoals.
expand_goals(Goals, ExpandedGoals) :-
nonvar(Goals),
expand_goals(UnexpandedGoals, ExpandedGoals) :-
nonvar(UnexpandedGoals),
var(ExpandedGoals),
( expand_goal(UnexpandedGoals, Goals) -> true
; Goals = UnexpandedGoals
),
( Goals = (Goal0, Goals0) ->
( expand_goal(Goal0, Goal1) ->
Expanded = true,
expand_goals(Goals0, Goals1),
thread_goals(Goal1, ExpandedGoals, Goals1)
thread_goals(Goal1, ExpandedGoals, Goals1, (','))
; expand_goals(Goals0, Goals1),
ExpandedGoals = (Goal0, Goals1)
)
; expand_goal(Goals, ExpandedGoals0) ->
thread_goals(ExpandedGoals0, ExpandedGoals)
; Goals = (Goals0 -> Goals1) ->
expand_goals(Goals0, ExpandedGoals0),
expand_goals(Goals1, ExpandedGoals1),
ExpandedGoals = (ExpandedGoals0 -> ExpandedGoals1)
; Goals = (Goals0 ; Goals1) ->
expand_goals(Goals0, ExpandedGoals0),
expand_goals(Goals1, ExpandedGoals1),
ExpandedGoals = (ExpandedGoals0 ; ExpandedGoals1)
; thread_goals(Goals, ExpandedGoals, (','))
; Goals = ExpandedGoals
).
thread_goals(Goals0, Goals1, Hole) :-
thread_goals(Goals0, Goals1, Hole, Functor) :-
nonvar(Goals0),
( Goals0 = [G | Gs] ->
( Gs == [] ->
Goals1 = (G, Hole)
; Goals1 = (G, Goals2),
thread_goals(Gs, Goals2, Hole)
Goals1 =.. [Functor, G, Hole]
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Hole, Functor)
)
; Goals1 = (Goals0, Hole)
; Goals1 =.. [Functor, Goals0, Hole]
).
thread_goals(Goals0, Goals1) :-
thread_goals(Goals0, Goals1, Functor) :-
nonvar(Goals0),
( Goals0 = [G | Gs] ->
( Gs = [] ->
Goals1 = G
; Goals1 = (G, Goals2),
thread_goals(Gs, Goals2)
; Goals1 =.. [Functor, G, Goals2],
thread_goals(Gs, Goals2, Functor)
)
; Goals1 = Goals0
).

View File

@@ -4,11 +4,7 @@ use crate::prolog::instructions::*;
use crate::prolog::machine::machine_errors::*;
use crate::prolog::machine::machine_indices::*;
use termion::event::Key;
use termion::input::TermRead;
use std::fmt;
use std::io::stdin;
impl fmt::Display for LocalCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -29,10 +25,8 @@ impl fmt::Display for LocalCodePtr {
impl fmt::Display for REPLCodePtr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
REPLCodePtr::CompileBatch => write!(f, "REPLCodePtr::CompileBatch"),
REPLCodePtr::SubmitQueryAndPrintResults => {
write!(f, "REPLCodePtr::SubmitQueryAndPrintResults")
}
REPLCodePtr::CompileBatch =>
write!(f, "REPLCodePtr::CompileBatch"),
REPLCodePtr::UseModule =>
write!(f, "REPLCodePtr::UseModule"),
REPLCodePtr::UseQualifiedModule =>
@@ -268,9 +262,6 @@ impl fmt::Display for SessionError {
&SessionError::ModuleDoesNotContainExport => {
write!(f, "module does not contain claimed export.")
}
&SessionError::NoModuleDeclaration(ref name) => {
write!(f, "file {}.pl lacks an expected module declaration.", name)
}
&SessionError::OpIsInfixAndPostFix(_) => {
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.")
}
&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) => {
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) => {
write!(f, "shl {}, {}, @{}", a1, a2, t)
}
@@ -380,6 +373,7 @@ impl fmt::Display for ArithmeticInstruction {
write!(f, "atan2 {}, {}, @{}", a1, a2, 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::Cos(ref a, ref t) => write!(f, "cos {}, @{}", 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
}

File diff suppressed because it is too large Load Diff

64
src/tests/builtins.pl Normal file
View 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
View 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
View 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
View 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).