add current_op/3
This commit is contained in:
@@ -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"
|
||||||
|
|
||||||
|
|||||||
@@ -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`
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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]) :-
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user