From b7dd76bf37cfbf8341a18d52f4ec61df4efacf93 Mon Sep 17 00:00:00 2001 From: Mark Thom Date: Sat, 16 Feb 2019 16:34:38 -0700 Subject: [PATCH] add library(reif) --- README.md | 2 +- src/prolog/codegen.rs | 12 ++-- src/prolog/instructions.rs | 12 ++-- src/prolog/lib/reif.pl | 73 ++++++++++++++++++++++ src/prolog/machine/attributed_variables.rs | 4 +- src/prolog/machine/machine_errors.rs | 2 + src/prolog/machine/machine_state.rs | 42 +++++++++++++ src/prolog/machine/mod.rs | 2 + src/prolog/machine/system_calls.rs | 2 +- 9 files changed, 136 insertions(+), 15 deletions(-) create mode 100644 src/prolog/lib/reif.pl diff --git a/README.md b/README.md index 3e3e0e4a..81d91531 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Extend rusty-wam to include the following, among other features: - [x] Support for `attribute_goals/2` and `project_attributes/2` - [ ] `call_residue/2` and `call_residue_vars/2` * `if_` and related predicates, following the developments of the - paper "Indexing `dif/2`". + paper "Indexing `dif/2`" (_in progress_). * All-solutions predicates (`findall/{3,4}`, `bagof/3`, `setof/3`). * Clause creation and destruction (`asserta/1`, `assertz/1`, `retract/1`, `abolish/1`) with logical update semantics. diff --git a/src/prolog/codegen.rs b/src/prolog/codegen.rs index 24ad1676..80ae6824 100644 --- a/src/prolog/codegen.rs +++ b/src/prolog/codegen.rs @@ -457,16 +457,14 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator Ok(match terms[0].as_ref() { &Term::Var(ref vr, ref name) => { - let mut target = Vec::new(); + let mut target = vec![]; self.marker.reset_arg(2); self.marker.mark_var(name.clone(), Level::Shallow, vr, term_loc, &mut target); if !target.is_empty() { - for query_instr in target { - code.push(Line::Query(query_instr)); - } + code.extend(target.into_iter().map(Line::Query)); } if use_default_call_policy { @@ -476,9 +474,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator } }, &Term::Constant(_, ref c @ Constant::Number(_)) => { - code.push(Line::Query(put_constant!(Level::Shallow, - c.clone(), - temp_v!(1)))); + code.push(Line::Query(put_constant!(Level::Shallow, c.clone(), temp_v!(1)))); if use_default_call_policy { code.push(is_call_by_default!(temp_v!(1), at.unwrap_or(interm!(1)))) @@ -510,7 +506,7 @@ impl<'a, TermMarker: Allocator<'a>> CodeGenerator code.extend(target.into_iter().map(|query_instr| Line::Query(query_instr))); } - code.push(get_level_and_unify!(cell.get().norm())); + code.push(get_level_and_unify!(cell.get().norm())); } fn compile_seq(&mut self, iter: ChunkedIterator<'a>, conjunct_info: &ConjunctInfo<'a>, diff --git a/src/prolog/instructions.rs b/src/prolog/instructions.rs index a20f50d7..99a4832e 100644 --- a/src/prolog/instructions.rs +++ b/src/prolog/instructions.rs @@ -382,6 +382,7 @@ pub enum BuiltInClauseType { NotEq, PartialString, Read, + ReifySwitch, Sort, } @@ -459,9 +460,10 @@ impl BuiltInClauseType { &BuiltInClauseType::KeySort => clause_name!("keysort"), &BuiltInClauseType::Nl => clause_name!("nl"), &BuiltInClauseType::NotEq => clause_name!("\\=="), + &BuiltInClauseType::PartialString => clause_name!("partial_string"), &BuiltInClauseType::Read => clause_name!("read"), + &BuiltInClauseType::ReifySwitch => clause_name!("$reify_switch"), &BuiltInClauseType::Sort => clause_name!("sort"), - &BuiltInClauseType::PartialString => clause_name!("partial_string") } } @@ -480,9 +482,10 @@ impl BuiltInClauseType { &BuiltInClauseType::KeySort => 2, &BuiltInClauseType::NotEq => 2, &BuiltInClauseType::Nl => 0, + &BuiltInClauseType::PartialString => 1, &BuiltInClauseType::Read => 1, + &BuiltInClauseType::ReifySwitch => 3, &BuiltInClauseType::Sort => 2, - &BuiltInClauseType::PartialString => 1, } } @@ -506,9 +509,10 @@ impl BuiltInClauseType { ("keysort", 2) => Some(BuiltInClauseType::KeySort), ("nl", 0) => Some(BuiltInClauseType::Nl), ("\\==", 2) => Some(BuiltInClauseType::NotEq), - ("sort", 2) => Some(BuiltInClauseType::Sort), - ("read", 1) => Some(BuiltInClauseType::Read), ("partial_string", 2) => Some(BuiltInClauseType::PartialString), + ("read", 1) => Some(BuiltInClauseType::Read), + ("$reify_switch", 3) => Some(BuiltInClauseType::ReifySwitch), + ("sort", 2) => Some(BuiltInClauseType::Sort), _ => None } } diff --git a/src/prolog/lib/reif.pl b/src/prolog/lib/reif.pl new file mode 100644 index 00000000..dc7a68a0 --- /dev/null +++ b/src/prolog/lib/reif.pl @@ -0,0 +1,73 @@ +:- module(reif, [if_/3, (=)/3, (,)/3, (;)/3, cond_t/3, dif/3, + memberd_t/3, tfilter/3, tmember/2, tmember_t/3, + tpartition/4]). + +:- use_module(library(control), [(\=)/2]). +:- use_module(library(dif)). + +/* in essence, '$reify_switch'(T, Then_0, Else_0) is this: + ( T == true -> call(Then_0) + ; T == false -> call(Else_0) + ; nonvar(T) -> throw(error(type_error(boolean, T), _)) + ; throw(error(instantiation_error, _)) + ). + but without creating choice points. +*/ + +if_(If_1, Then_0, Else_0) :- + call(If_1, T), + '$reify_switch'(T, Then_0, Else_0). + +=(X, Y, T) :- + ( X == Y -> T = true + ; X \= Y -> T = false + ; T = true, X = Y + ; T = false, dif(X, Y) + ). + +dif(X, Y, T) :- + =(X, Y, NT), + non(NT, T). + +non(true, false). +non(false, true). + +tfilter(C_2, Es, Fs) :- + i_tfilter(Es, C_2, Fs). + +i_tfilter([], _, []). +i_tfilter([E|Es], C_2, Fs0) :- + if_(call(C_2, E), Fs0 = [E|Fs], Fs0 = Fs), + i_tfilter(Es, C_2, Fs). + +tpartition(P_2, Xs, Ts, Fs) :- + i_tpartition(Xs, P_2, Ts, Fs). + +i_tpartition([], _P_2, [], []). +i_tpartition([X|Xs], P_2, Ts0, Fs0) :- + if_( call(P_2, X) + , ( Ts0 = [X|Ts], Fs0 = Fs ) + , ( Fs0 = [X|Fs], Ts0 = Ts ) ), + i_tpartition(Xs, P_2, Ts, Fs). + +','(A_1, B_1, T) :- + if_(A_1, call(B_1, T), T = false). + +';'(A_1, B_1, T) :- + if_(A_1, T = true, call(B_1, T)). + +cond_t(If_1, Then_0, T) :- + if_(If_1, ( Then_0, T = true ), T = false ). + +memberd_t(E, Xs, T) :- + i_memberd_t(Xs, E, T). + +i_memberd_t([], _, false). +i_memberd_t([X|Xs], E, T) :- + if_( X = E, T = true, i_memberd_t(Xs, E, T) ). + +tmember(P_2, [X|Xs]) :- + if_( call(P_2, X), true, tmember(P_2, Xs) ). + +tmember_t(P_2, [X|Xs], T) :- + if_( call(P_2, X), T = true, tmember_t(P_2, Xs, T) ). diff --git a/src/prolog/machine/attributed_variables.rs b/src/prolog/machine/attributed_variables.rs index 770bd36b..af776697 100644 --- a/src/prolog/machine/attributed_variables.rs +++ b/src/prolog/machine/attributed_variables.rs @@ -156,12 +156,14 @@ impl MachineState { fn print_attribute_goals(&mut self, var_dict: &HeapVarDict) { - let attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); + let mut attr_goals = mem::replace(&mut self.attr_var_init.attribute_goals, vec![]); if attr_goals.is_empty() { return; } + self.term_dedup(&mut attr_goals); + let mut output = PrinterOutputter::new(); for goal_addr in attr_goals { diff --git a/src/prolog/machine/machine_errors.rs b/src/prolog/machine/machine_errors.rs index 909ad4cb..4a3af940 100644 --- a/src/prolog/machine/machine_errors.rs +++ b/src/prolog/machine/machine_errors.rs @@ -114,6 +114,7 @@ impl MachineError { pub enum ValidType { Atom, Atomic, + Boolean, // Byte, Callable, // Character, @@ -134,6 +135,7 @@ impl ValidType { match self { ValidType::Atom => "atom", ValidType::Atomic => "atomic", + ValidType::Boolean => "boolean", // ValidType::Byte => "byte", ValidType::Callable => "callable", // ValidType::Character => "character", diff --git a/src/prolog/machine/machine_state.rs b/src/prolog/machine/machine_state.rs index ec979842..ae6847c1 100644 --- a/src/prolog/machine/machine_state.rs +++ b/src/prolog/machine/machine_state.rs @@ -572,6 +572,48 @@ pub(crate) trait CallPolicy: Any { return_from_clause!(machine_st.last_call, machine_st) }, + &BuiltInClauseType::ReifySwitch => { + let truth_value = machine_st[temp_v!(1)].clone(); + let truth_value = machine_st.store(machine_st.deref(truth_value)); + + match truth_value { + Addr::Con(Constant::Atom(atom, spec)) => + match atom.as_str() { + "true" => { + let t_branch = machine_st[temp_v!(2)].clone(); + + machine_st[temp_v!(1)] = t_branch; + self.call_n(machine_st, 1, indices) + }, + "false" => { + let f_branch = machine_st[temp_v!(3)].clone(); + + machine_st[temp_v!(1)] = f_branch; + self.call_n(machine_st, 1, indices) + } + _ => { + let truth_value = Addr::Con(Constant::Atom(atom, spec)); + + let stub = MachineError::functor_stub(clause_name!("if_"), 3); + let err = MachineError::type_error(ValidType::Boolean, truth_value); + + Err(machine_st.error_form(err, stub)) + } + }, + ref addr if addr.is_ref() => { + let stub = MachineError::functor_stub(clause_name!("if_"), 3); + let err = MachineError::instantiation_error(); + + Err(machine_st.error_form(err, stub)) + }, + addr => { + let stub = MachineError::functor_stub(clause_name!("if_"), 3); + let err = MachineError::type_error(ValidType::Boolean, addr); + + Err(machine_st.error_form(err, stub)) + } + } + }, &BuiltInClauseType::CopyTerm => { machine_st.duplicate_term(); return_from_clause!(machine_st.last_call, machine_st) diff --git a/src/prolog/machine/mod.rs b/src/prolog/machine/mod.rs index 54f27231..89feda2f 100644 --- a/src/prolog/machine/mod.rs +++ b/src/prolog/machine/mod.rs @@ -321,6 +321,7 @@ static DCGS: &str = include_str!("../lib/dcgs.pl"); static ATTS: &str = include_str!("../lib/atts.pl"); static DIF: &str = include_str!("../lib/dif.pl"); static FREEZE: &str = include_str!("../lib/freeze.pl"); +static REIF: &str = include_str!("../lib/reif.pl"); impl Machine { fn compile_special_forms(&mut self) { @@ -351,6 +352,7 @@ impl Machine { compile_user_module(self, ATTS.as_bytes()); compile_user_module(self, DIF.as_bytes()); compile_user_module(self, FREEZE.as_bytes()); + compile_user_module(self, REIF.as_bytes()); } pub fn new() -> Self { diff --git a/src/prolog/machine/system_calls.rs b/src/prolog/machine/system_calls.rs index c3b4c9fe..1152c8c7 100644 --- a/src/prolog/machine/system_calls.rs +++ b/src/prolog/machine/system_calls.rs @@ -409,7 +409,7 @@ impl MachineState { for (h, addr) in bindings { self.heap[h] = HeapCellValue::Addr(addr); } - }, + }, &SystemClauseType::RemoveCallPolicyCheck => { let restore_default = match call_policy.downcast_mut::().ok() { -- 2.54.0