[package]
name = "scryer-prolog"
-version = "0.8.41"
+version = "0.8.42"
repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust."
downcast = "0.10.0"
num = "0.2"
ordered-float = "0.5.0"
-prolog_parser = "0.8.15"
+prolog_parser = "0.8.16"
readline_rs_compat = { version = "0.1.7", optional = true }
ref_thread_local = "0.0.0"
* `compound/1`
* `copy_term/2`
* `current_predicate/1`
+* `current_op/3`
* `cyclic_term/1`
* `dif/2`
* `expand_goal/2`
GetClause,
GetModuleClause,
GetNextDBRef,
+ GetNextOpDBRef,
LookupDBRef,
+ LookupOpDBRef,
Halt,
ModuleHeadIsDynamic,
GetLiftedHeapFromOffset,
&SystemClauseType::GetBValue => clause_name!("$get_b_value"),
&SystemClauseType::GetClause => clause_name!("$get_clause"),
&SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
+ &SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
&SystemClauseType::LookupDBRef => clause_name!("$lookup_db_ref"),
+ &SystemClauseType::LookupOpDBRef => clause_name!("$lookup_op_db_ref"),
&SystemClauseType::GetDoubleQuotes => clause_name!("$get_double_quotes"),
&SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef),
+ ("$get_next_op_db_ref", 2) => Some(SystemClauseType::GetNextOpDBRef),
("$lookup_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
+ ("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
("$module_call", 2) => Some(SystemClauseType::DynamicModuleResolution),
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),
abolish/1, asserta/1, assertz/1, bagof/3, bb_b_put/2,
bb_get/2, bb_put/2, call_cleanup/2,
call_with_inference_limit/3, catch/3, clause/2,
- current_predicate/1, current_prolog_flag/2, expand_goal/2,
- expand_term/2, findall/3, findall/4, halt/0, once/1, op/3,
- repeat/0, retract/1, set_prolog_flag/2, setof/3,
+ current_predicate/1, current_op/3, current_prolog_flag/2,
+ expand_goal/2, expand_term/2, findall/3, findall/4, halt/0,
+ once/1, op/3, repeat/0, retract/1, set_prolog_flag/2, setof/3,
setup_call_cleanup/3, term_variables/2, throw/1, true/0,
false/0, write/1, write_canonical/1, writeq/1, write_term/2]).
between:between(0, Max, N)
).
+'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
+ '$lookup_op_db_ref'(Ref, Priority, Spec, Op).
+'$iterate_op_db_refs'(Ref, Priority, Spec, Op) :-
+ '$get_next_op_db_ref'(Ref, NextRef),
+ '$iterate_op_db_refs'(NextRef, Priority, Spec, Op).
+
+current_op(Priority, Spec, Op) :-
+ ( nonvar(Op), \+ atom(Op)
+ -> throw(error(type_error(atom, Op), current_op/3))
+ ; '$get_next_op_db_ref'(Ref, _),
+ '$iterate_op_db_refs'(Ref, Priority, Spec, Op)
+ ).
+
list_of_op_atoms(Var) :-
var(Var), throw(error(instantiation_error, op/3)). % 8.14.3.3 c)
list_of_op_atoms([Atom|Atoms]) :-
use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::rc::Rc;
+#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct OrderedOpDirKey(pub ClauseName, pub Fixity);
+
+pub type OssifiedOpDir = BTreeMap<OrderedOpDirKey, (usize, Specifier)>;
+
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum DBRef {
BuiltInPred(ClauseName, usize, Option<SharedOpDesc>),
- NamedPred(ClauseName, usize, Option<SharedOpDesc>)
+ NamedPred(ClauseName, usize, Option<SharedOpDesc>),
+ Op(usize, Specifier, ClauseName, Rc<OssifiedOpDir>, SharedOpDesc)
}
#[derive(Clone, PartialEq, Eq, Hash)]
},
None => self.fail = true
}
+ },
+ &DBRef::Op(_, spec, ref name, ref op_dir, _) => {
+ let fixity = match spec {
+ XF | YF => Fixity::Post,
+ FX | FY => Fixity::Pre,
+ _ => Fixity::In
+ };
+
+ let key = OrderedOpDirKey(name.clone(), fixity);
+
+ match op_dir.range(key ..).skip(1).next() {
+ Some((OrderedOpDirKey(name, _), (priority, spec))) => {
+ let a2 = self[temp_v!(2)].clone();
+
+ if let Some(r) = a2.as_var() {
+ self.bind(r, Addr::DBRef(DBRef::Op(*priority, *spec, name.clone(),
+ op_dir.clone(),
+ SharedOpDesc::new(*priority, *spec))));
+ } else {
+ self.fail = true;
+ }
+ },
+ None => self.fail = true
+ }
}
}
}
return Ok(());
}
},
+ Addr::DBRef(DBRef::Op(..)) => self.fail = true,
Addr::DBRef(ref db_ref) =>
self.get_next_db_ref(&indices, db_ref),
_ => {
}
};
},
+ &SystemClauseType::GetNextOpDBRef => {
+ let a1 = self[temp_v!(1)].clone();
+
+ match self.store(self.deref(a1)) {
+ addr @ Addr::HeapCell(_)
+ | addr @ Addr::StackCell(..)
+ | addr @ Addr::AttrVar(_) => {
+ let mut unossified_op_dir = OssifiedOpDir::new();
+
+ unossified_op_dir.extend(indices.op_dir.iter().filter_map(|(key, op_dir_val)| {
+ let (name, fixity) = key.clone();
+
+ let prec = op_dir_val.shared_op_desc().prec();
+
+ if prec == 0 {
+ return None;
+ }
+
+ let assoc = op_dir_val.shared_op_desc().assoc();
+
+ Some((OrderedOpDirKey(name, fixity), (prec, assoc)))
+ }));
+
+ let ossified_op_dir = Rc::new(unossified_op_dir);
+
+ match ossified_op_dir.iter().next() {
+ Some((OrderedOpDirKey(name, _), (priority, spec))) => {
+ let db_ref = DBRef::Op(*priority, *spec, name.clone(),
+ ossified_op_dir.clone(),
+ SharedOpDesc::new(*priority, *spec));
+ let r = addr.as_var().unwrap();
+
+ self.bind(r, Addr::DBRef(db_ref));
+ },
+ None => {
+ self.fail = true;
+ return Ok(());
+ }
+ }
+ },
+ Addr::DBRef(DBRef::BuiltInPred(..)) | Addr::DBRef(DBRef::NamedPred(..)) =>
+ self.fail = true,
+ Addr::DBRef(ref db_ref) =>
+ self.get_next_db_ref(&indices, db_ref),
+ _ => {
+ self.fail = true;
+ }
+ }
+ },
&SystemClauseType::LookupDBRef => {
let a1 = self[temp_v!(1)].clone();
if !self.fail {
self.unify(a3, Addr::Con(Constant::Number(arity)));
}
- }
+ },
+ _ => self.fail = true
+ },
+ _ => self.fail = true
+ }
+ },
+ &SystemClauseType::LookupOpDBRef => {
+ let a1 = self[temp_v!(1)].clone();
+
+ match self.store(self.deref(a1)) {
+ Addr::DBRef(db_ref) =>
+ match db_ref {
+ DBRef::Op(priority, spec, name, _, shared_op_desc) => {
+
+
+ let prec = self[temp_v!(2)].clone();
+ let specifier = self[temp_v!(3)].clone();
+ let op = self[temp_v!(4)].clone();
+
+ let spec = match spec {
+ FX => "fx",
+ FY => "fy",
+ XF => "xf",
+ YF => "yf",
+ XFX => "xfx",
+ XFY => "xfy",
+ YFX => "yfx",
+ _ => {
+ self.fail = true;
+ return Ok(());
+ }
+ };
+
+ let a2 = Number::Integer(Rc::new(BigInt::from_usize(priority).unwrap()));
+ let a3 = Addr::Con(Constant::Atom(clause_name!(spec), None));
+ let a4 = Addr::Con(Constant::Atom(name, Some(shared_op_desc)));
+
+ self.unify(Addr::Con(Constant::Number(a2)), prec);
+
+ if !self.fail {
+ self.unify(a3, specifier);
+ }
+
+ if !self.fail {
+ self.unify(a4, op);
+ }
+ },
+ _ => self.fail = true
},
_ => self.fail = true
}
},
&SystemClauseType::OpDeclaration => {
let priority = self[temp_v!(1)].clone();
- let specifier = self[temp_v!(2)].clone();
+ let specifier = self[temp_v!(2)].clone();
let op = self[temp_v!(3)].clone();
let priority = match self.store(self.deref(priority)) {
let result = to_op_decl(priority, specifier.as_str(), op)
.map_err(SessionError::from)
- .and_then(|op_decl| {
+ .and_then(|op_decl| {
if op_decl.0 == 0 {
Ok(op_decl.remove(&mut indices.op_dir))
} else {
impl fmt::Display for DBRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
- &DBRef::BuiltInPred(ref name, arity, _) => write!(f, "db_ref:builtin:{}/{}", name, arity),
- &DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity)
+ &DBRef::BuiltInPred(ref name, arity, _) => write!(f, "db_ref:builtin:{}/{}", name, arity),
+ &DBRef::NamedPred(ref name, arity, _) => write!(f, "db_ref:named:{}/{}", name, arity),
+ &DBRef::Op(priority, spec, ref name, ..) => write!(f, "db_ref:op({}, {}, {})", priority,
+ spec, name)
}
}
}