add current_op/3

This commit is contained in:
Mark Thom
2019-04-05 21:25:49 -06:00
parent 03f2190d6b
commit 272b4f6d8d
7 changed files with 160 additions and 11 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "scryer-prolog" name = "scryer-prolog"
version = "0.8.41" version = "0.8.42"
authors = ["Mark Thom <markjordanthom@gmail.com>"] authors = ["Mark Thom <markjordanthom@gmail.com>"]
repository = "https://github.com/mthom/scryer-prolog" repository = "https://github.com/mthom/scryer-prolog"
description = "A modern Prolog implementation written mostly in Rust." description = "A modern Prolog implementation written mostly in Rust."
@@ -14,7 +14,7 @@ cfg-if = "0.1.7"
downcast = "0.10.0" downcast = "0.10.0"
num = "0.2" num = "0.2"
ordered-float = "0.5.0" ordered-float = "0.5.0"
prolog_parser = "0.8.15" prolog_parser = "0.8.16"
readline_rs_compat = { version = "0.1.7", optional = true } readline_rs_compat = { version = "0.1.7", optional = true }
ref_thread_local = "0.0.0" ref_thread_local = "0.0.0"

View File

@@ -175,6 +175,7 @@ The following predicates are built-in to Scryer.
* `compound/1` * `compound/1`
* `copy_term/2` * `copy_term/2`
* `current_predicate/1` * `current_predicate/1`
* `current_op/3`
* `cyclic_term/1` * `cyclic_term/1`
* `dif/2` * `dif/2`
* `expand_goal/2` * `expand_goal/2`

View File

@@ -180,7 +180,9 @@ pub enum SystemClauseType {
GetClause, GetClause,
GetModuleClause, GetModuleClause,
GetNextDBRef, GetNextDBRef,
GetNextOpDBRef,
LookupDBRef, LookupDBRef,
LookupOpDBRef,
Halt, Halt,
ModuleHeadIsDynamic, ModuleHeadIsDynamic,
GetLiftedHeapFromOffset, GetLiftedHeapFromOffset,
@@ -254,7 +256,9 @@ impl SystemClauseType {
&SystemClauseType::GetBValue => clause_name!("$get_b_value"), &SystemClauseType::GetBValue => clause_name!("$get_b_value"),
&SystemClauseType::GetClause => clause_name!("$get_clause"), &SystemClauseType::GetClause => clause_name!("$get_clause"),
&SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"), &SystemClauseType::GetNextDBRef => clause_name!("$get_next_db_ref"),
&SystemClauseType::GetNextOpDBRef => clause_name!("$get_next_op_db_ref"),
&SystemClauseType::LookupDBRef => clause_name!("$lookup_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::GetDoubleQuotes => clause_name!("$get_double_quotes"),
&SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"), &SystemClauseType::GetModuleClause => clause_name!("$get_module_clause"),
&SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"), &SystemClauseType::GetSCCCleaner => clause_name!("$get_scc_cleaner"),
@@ -312,7 +316,9 @@ impl SystemClauseType {
("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute), ("$del_attr_non_head", 1) => Some(SystemClauseType::DeleteAttribute),
("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute), ("$del_attr_head", 1) => Some(SystemClauseType::DeleteHeadAttribute),
("$get_next_db_ref", 2) => Some(SystemClauseType::GetNextDBRef), ("$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_db_ref", 3) => Some(SystemClauseType::LookupDBRef),
("$lookup_op_db_ref", 4) => Some(SystemClauseType::LookupOpDBRef),
("$module_call", 2) => Some(SystemClauseType::DynamicModuleResolution), ("$module_call", 2) => Some(SystemClauseType::DynamicModuleResolution),
("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal), ("$enqueue_attribute_goal", 1) => Some(SystemClauseType::EnqueueAttributeGoal),
("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar), ("$enqueue_attr_var", 1) => Some(SystemClauseType::EnqueueAttributedVar),

View File

@@ -9,9 +9,9 @@
abolish/1, asserta/1, assertz/1, bagof/3, bb_b_put/2, abolish/1, asserta/1, assertz/1, bagof/3, bb_b_put/2,
bb_get/2, bb_put/2, call_cleanup/2, bb_get/2, bb_put/2, call_cleanup/2,
call_with_inference_limit/3, catch/3, clause/2, call_with_inference_limit/3, catch/3, clause/2,
current_predicate/1, current_prolog_flag/2, expand_goal/2, current_predicate/1, current_op/3, current_prolog_flag/2,
expand_term/2, findall/3, findall/4, halt/0, once/1, op/3, expand_goal/2, expand_term/2, findall/3, findall/4, halt/0,
repeat/0, retract/1, set_prolog_flag/2, setof/3, 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, setup_call_cleanup/3, term_variables/2, throw/1, true/0,
false/0, write/1, write_canonical/1, writeq/1, write_term/2]). false/0, write/1, write_canonical/1, writeq/1, write_term/2]).
@@ -714,6 +714,19 @@ current_predicate(Pred) :-
between:between(0, Max, N) 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) :- list_of_op_atoms(Var) :-
var(Var), throw(error(instantiation_error, op/3)). % 8.14.3.3 c) var(Var), throw(error(instantiation_error, op/3)). % 8.14.3.3 c)
list_of_op_atoms([Atom|Atoms]) :- list_of_op_atoms([Atom|Atoms]) :-

View File

@@ -12,10 +12,16 @@ use std::mem;
use std::ops::{Add, AddAssign, Sub, SubAssign}; use std::ops::{Add, AddAssign, Sub, SubAssign};
use std::rc::Rc; 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)] #[derive(Clone, PartialEq, Eq, Hash)]
pub enum DBRef { pub enum DBRef {
BuiltInPred(ClauseName, usize, Option<SharedOpDesc>), 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)] #[derive(Clone, PartialEq, Eq, Hash)]

View File

@@ -268,6 +268,30 @@ impl MachineState {
}, },
None => self.fail = true 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
}
} }
} }
} }
@@ -540,6 +564,7 @@ impl MachineState {
return Ok(()); return Ok(());
} }
}, },
Addr::DBRef(DBRef::Op(..)) => self.fail = true,
Addr::DBRef(ref db_ref) => Addr::DBRef(ref db_ref) =>
self.get_next_db_ref(&indices, db_ref), self.get_next_db_ref(&indices, db_ref),
_ => { _ => {
@@ -547,6 +572,55 @@ impl MachineState {
} }
}; };
}, },
&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 => { &SystemClauseType::LookupDBRef => {
let a1 = self[temp_v!(1)].clone(); let a1 = self[temp_v!(1)].clone();
@@ -564,14 +638,61 @@ impl MachineState {
if !self.fail { if !self.fail {
self.unify(a3, Addr::Con(Constant::Number(arity))); 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 _ => self.fail = true
} }
}, },
&SystemClauseType::OpDeclaration => { &SystemClauseType::OpDeclaration => {
let priority = self[temp_v!(1)].clone(); 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 op = self[temp_v!(3)].clone();
let priority = match self.store(self.deref(priority)) { let priority = match self.store(self.deref(priority)) {
@@ -595,7 +716,7 @@ impl MachineState {
let result = to_op_decl(priority, specifier.as_str(), op) let result = to_op_decl(priority, specifier.as_str(), op)
.map_err(SessionError::from) .map_err(SessionError::from)
.and_then(|op_decl| { .and_then(|op_decl| {
if op_decl.0 == 0 { if op_decl.0 == 0 {
Ok(op_decl.remove(&mut indices.op_dir)) Ok(op_decl.remove(&mut indices.op_dir))
} else { } else {

View File

@@ -162,8 +162,10 @@ impl fmt::Display for HeapCellValue {
impl fmt::Display for DBRef { impl fmt::Display for DBRef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
&DBRef::BuiltInPred(ref name, arity, _) => write!(f, "db_ref:builtin:{}/{}", 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::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)
} }
} }
} }